* [PATCH net-next v2 1/2] openvswitch: remove unused functions
From: Jiri Benc @ 2016-10-19 9:26 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA; +Cc: dev-yBygre7rU0TnMu66kgdUjQ
In-Reply-To: <cover.1476869133.git.jbenc-H+wXaHxf7aLQT0dZR+AlfA@public.gmane.org>
ovs_vport_deferred_free is not used anywhere. It's the only caller of
free_vport_rcu thus this one can be removed, too.
Signed-off-by: Jiri Benc <jbenc@redhat.com>
---
new in v2
---
net/openvswitch/vport.c | 16 ----------------
net/openvswitch/vport.h | 1 -
2 files changed, 17 deletions(-)
diff --git a/net/openvswitch/vport.c b/net/openvswitch/vport.c
index 7387418ac514..9d0a87845843 100644
--- a/net/openvswitch/vport.c
+++ b/net/openvswitch/vport.c
@@ -465,22 +465,6 @@ int ovs_vport_receive(struct vport *vport, struct sk_buff *skb,
}
EXPORT_SYMBOL_GPL(ovs_vport_receive);
-static void free_vport_rcu(struct rcu_head *rcu)
-{
- struct vport *vport = container_of(rcu, struct vport, rcu);
-
- ovs_vport_free(vport);
-}
-
-void ovs_vport_deferred_free(struct vport *vport)
-{
- if (!vport)
- return;
-
- call_rcu(&vport->rcu, free_vport_rcu);
-}
-EXPORT_SYMBOL_GPL(ovs_vport_deferred_free);
-
static unsigned int packet_length(const struct sk_buff *skb)
{
unsigned int length = skb->len - ETH_HLEN;
diff --git a/net/openvswitch/vport.h b/net/openvswitch/vport.h
index f01f28a567ad..46e5b69927c7 100644
--- a/net/openvswitch/vport.h
+++ b/net/openvswitch/vport.h
@@ -149,7 +149,6 @@ struct vport_ops {
struct vport *ovs_vport_alloc(int priv_size, const struct vport_ops *,
const struct vport_parms *);
void ovs_vport_free(struct vport *);
-void ovs_vport_deferred_free(struct vport *vport);
#define VPORT_ALIGN 8
--
1.8.3.1
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev
^ permalink raw reply related
* [PATCH net-next v2 0/2] openvswitch: remove unused code
From: Jiri Benc @ 2016-10-19 9:26 UTC (permalink / raw)
To: netdev-u79uwXL29TY76Z2rM5mHXA; +Cc: dev-yBygre7rU0TnMu66kgdUjQ
Removed unused functions and unnecessary EXPORT_SYMBOLs from openvswitch.
Jiri Benc (2):
openvswitch: remove unused functions
openvswitch: remove unnecessary EXPORT_SYMBOLs
net/openvswitch/datapath.c | 2 --
net/openvswitch/vport-netdev.c | 1 -
net/openvswitch/vport.c | 17 -----------------
net/openvswitch/vport.h | 1 -
4 files changed, 21 deletions(-)
--
1.8.3.1
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev
^ permalink raw reply
* [PATCH] net: fs_enet: Use net_device_stats from struct net_device
From: Tobias Klauser @ 2016-10-19 9:24 UTC (permalink / raw)
To: Pantelis Antoniou, Vitaly Bordug; +Cc: netdev, linuxppc-dev
Instead of using a private copy of struct net_device_stats in struct
fs_enet_private, use stats from struct net_device. Also remove the now
unnecessary .ndo_get_stats function.
Signed-off-by: Tobias Klauser <tklauser@distanz.ch>
---
.../net/ethernet/freescale/fs_enet/fs_enet-main.c | 43 +++++++++-------------
drivers/net/ethernet/freescale/fs_enet/fs_enet.h | 1 -
2 files changed, 18 insertions(+), 26 deletions(-)
diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
index 925d1bca6a26..44f50e168703 100644
--- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
+++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
@@ -118,22 +118,22 @@ static int fs_enet_napi(struct napi_struct *napi, int budget)
BD_ENET_TX_RL | BD_ENET_TX_UN | BD_ENET_TX_CSL)) {
if (sc & BD_ENET_TX_HB) /* No heartbeat */
- fep->stats.tx_heartbeat_errors++;
+ dev->stats.tx_heartbeat_errors++;
if (sc & BD_ENET_TX_LC) /* Late collision */
- fep->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
if (sc & BD_ENET_TX_RL) /* Retrans limit */
- fep->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
if (sc & BD_ENET_TX_UN) /* Underrun */
- fep->stats.tx_fifo_errors++;
+ dev->stats.tx_fifo_errors++;
if (sc & BD_ENET_TX_CSL) /* Carrier lost */
- fep->stats.tx_carrier_errors++;
+ dev->stats.tx_carrier_errors++;
if (sc & (BD_ENET_TX_LC | BD_ENET_TX_RL | BD_ENET_TX_UN)) {
- fep->stats.tx_errors++;
+ dev->stats.tx_errors++;
do_restart = 1;
}
} else
- fep->stats.tx_packets++;
+ dev->stats.tx_packets++;
if (sc & BD_ENET_TX_READY) {
dev_warn(fep->dev,
@@ -145,7 +145,7 @@ static int fs_enet_napi(struct napi_struct *napi, int budget)
* but we eventually sent the packet OK.
*/
if (sc & BD_ENET_TX_DEF)
- fep->stats.collisions++;
+ dev->stats.collisions++;
/* unmap */
if (fep->mapped_as_page[dirtyidx])
@@ -212,19 +212,19 @@ static int fs_enet_napi(struct napi_struct *napi, int budget)
*/
if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_CL |
BD_ENET_RX_NO | BD_ENET_RX_CR | BD_ENET_RX_OV)) {
- fep->stats.rx_errors++;
+ dev->stats.rx_errors++;
/* Frame too long or too short. */
if (sc & (BD_ENET_RX_LG | BD_ENET_RX_SH))
- fep->stats.rx_length_errors++;
+ dev->stats.rx_length_errors++;
/* Frame alignment */
if (sc & (BD_ENET_RX_NO | BD_ENET_RX_CL))
- fep->stats.rx_frame_errors++;
+ dev->stats.rx_frame_errors++;
/* CRC Error */
if (sc & BD_ENET_RX_CR)
- fep->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
/* FIFO overrun */
if (sc & BD_ENET_RX_OV)
- fep->stats.rx_crc_errors++;
+ dev->stats.rx_crc_errors++;
skbn = fep->rx_skbuff[curidx];
} else {
@@ -233,9 +233,9 @@ static int fs_enet_napi(struct napi_struct *napi, int budget)
/*
* Process the incoming frame.
*/
- fep->stats.rx_packets++;
+ dev->stats.rx_packets++;
pkt_len = CBDR_DATLEN(bdp) - 4; /* remove CRC */
- fep->stats.rx_bytes += pkt_len + 4;
+ dev->stats.rx_bytes += pkt_len + 4;
if (pkt_len <= fpi->rx_copybreak) {
/* +2 to make IP header L1 cache aligned */
@@ -277,7 +277,7 @@ static int fs_enet_napi(struct napi_struct *napi, int budget)
received++;
netif_receive_skb(skb);
} else {
- fep->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
skbn = skb;
}
}
@@ -543,7 +543,7 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
curidx = bdp - fep->tx_bd_base;
len = skb->len;
- fep->stats.tx_bytes += len;
+ dev->stats.tx_bytes += len;
if (nr_frags)
len -= skb->data_len;
fep->tx_free -= nr_frags + 1;
@@ -619,7 +619,7 @@ static void fs_timeout(struct net_device *dev)
unsigned long flags;
int wake = 0;
- fep->stats.tx_errors++;
+ dev->stats.tx_errors++;
spin_lock_irqsave(&fep->lock, flags);
@@ -774,12 +774,6 @@ static int fs_enet_close(struct net_device *dev)
return 0;
}
-static struct net_device_stats *fs_enet_get_stats(struct net_device *dev)
-{
- struct fs_enet_private *fep = netdev_priv(dev);
- return &fep->stats;
-}
-
/*************************************************************************/
static void fs_get_drvinfo(struct net_device *dev,
@@ -905,7 +899,6 @@ extern void fs_mii_disconnect(struct net_device *dev);
static const struct net_device_ops fs_enet_netdev_ops = {
.ndo_open = fs_enet_open,
.ndo_stop = fs_enet_close,
- .ndo_get_stats = fs_enet_get_stats,
.ndo_start_xmit = fs_enet_start_xmit,
.ndo_tx_timeout = fs_timeout,
.ndo_set_rx_mode = fs_set_multicast_list,
diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet.h b/drivers/net/ethernet/freescale/fs_enet/fs_enet.h
index fee24c822fad..5ce516c8a62a 100644
--- a/drivers/net/ethernet/freescale/fs_enet/fs_enet.h
+++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet.h
@@ -137,7 +137,6 @@ struct fs_enet_private {
cbd_t __iomem *cur_rx;
cbd_t __iomem *cur_tx;
int tx_free;
- struct net_device_stats stats;
struct timer_list phy_timer_list;
const struct phy_info *phy;
u32 msg_enable;
--
2.9.0
^ permalink raw reply related
* Re: [PATCH 08/10] mm: replace __access_remote_vm() write parameter with gup_flags
From: Michal Hocko @ 2016-10-19 9:23 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Jan Kara, linux-mm, Linus Torvalds, Hugh Dickins, Dave Hansen,
Rik van Riel, Mel Gorman, Andrew Morton, adi-buildroot-devel,
ceph-devel, dri-devel, intel-gfx, kvm, linux-alpha,
linux-arm-kernel, linux-cris-kernel, linux-fbdev, linux-fsdevel,
linux-ia64, linux-kernel, linux-media, linux-mips, linux-rdma,
linux-s390, linux-samsung-soc, linux-scsi, linux-security-module,
linux-sh
In-Reply-To: <20161019090646.GA24243@lucifer>
On Wed 19-10-16 10:06:46, Lorenzo Stoakes wrote:
> On Wed, Oct 19, 2016 at 10:52:05AM +0200, Michal Hocko wrote:
> > yes this is the desirable and expected behavior.
> >
> > > wonder if this is desirable behaviour or whether this ought to be limited to
> > > ptrace system calls. Regardless, by making the flag more visible it makes it
> > > easier to see that this is happening.
> >
> > mem_open already enforces PTRACE_MODE_ATTACH
>
> Ah I missed this, that makes a lot of sense, thanks!
>
> I still wonder whether other invocations of access_remote_vm() in fs/proc/base.c
> (the principle caller of this function) need FOLL_FORCE, for example the various
> calls that simply read data from other processes, so I think the point stands
> about keeping this explicit.
I do agree. Making them explicit will help to clean them up later,
should there be a need.
--
Michal Hocko
SUSE Labs
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH net-next] openvswitch: remove unnecessary EXPORT_SYMBOLs
From: Jiri Benc @ 2016-10-19 9:10 UTC (permalink / raw)
To: Pravin Shelar; +Cc: ovs dev, Linux Kernel Network Developers
In-Reply-To: <CAOrHB_CkJ0vz3HekYU4HA6rukgE3g1j6ECFyY+RxZjPV9uwjYw-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
On Tue, 18 Oct 2016 12:48:33 -0700, Pravin Shelar wrote:
> ovs_vport_deferred_free() is not used anywhere. can you remove it?
Good point. Will do.
Jiri
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev
^ permalink raw reply
* Re: [PATCH 00/10] mm: adjust get_user_pages* functions to explicitly pass FOLL_* flags
From: Michal Hocko @ 2016-10-19 9:07 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: linux-mm, Linus Torvalds, Jan Kara, Hugh Dickins, Dave Hansen,
Rik van Riel, Mel Gorman, Andrew Morton, adi-buildroot-devel,
ceph-devel, dri-devel, intel-gfx, kvm, linux-alpha,
linux-arm-kernel, linux-cris-kernel, linux-fbdev, linux-fsdevel,
linux-ia64, linux-kernel, linux-media, linux-mips, linux-rdma,
linux-s390, linux-samsung-soc, linux-scsi, linux-security-module,
linux-sh@
In-Reply-To: <20161019085815.GA22239@lucifer>
On Wed 19-10-16 09:58:15, Lorenzo Stoakes wrote:
> On Tue, Oct 18, 2016 at 05:30:50PM +0200, Michal Hocko wrote:
> > I am wondering whether we can go further. E.g. it is not really clear to
> > me whether we need an explicit FOLL_REMOTE when we can in fact check
> > mm != current->mm and imply that. Maybe there are some contexts which
> > wouldn't work, I haven't checked.
>
> This flag is set even when /proc/self/mem is used. I've not looked deeply into
> this flag but perhaps accessing your own memory this way can be considered
> 'remote' since you're not accessing it directly. On the other hand, perhaps this
> is just mistaken in this case?
My understanding of the flag is quite limited as well. All I know it is
related to protection keys and it is needed to bypass protection check.
See arch_vma_access_permitted. See also 1b2ee1266ea6 ("mm/core: Do not
enforce PKEY permissions on remote mm access").
--
Michal Hocko
SUSE Labs
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH 08/10] mm: replace __access_remote_vm() write parameter with gup_flags
From: Lorenzo Stoakes @ 2016-10-19 9:06 UTC (permalink / raw)
To: Michal Hocko
Cc: Jan Kara, linux-mm, Linus Torvalds, Hugh Dickins, Dave Hansen,
Rik van Riel, Mel Gorman, Andrew Morton, adi-buildroot-devel,
ceph-devel, dri-devel, intel-gfx, kvm, linux-alpha,
linux-arm-kernel, linux-cris-kernel, linux-fbdev, linux-fsdevel,
linux-ia64, linux-kernel, linux-media, linux-mips, linux-rdma,
linux-s390, linux-samsung-soc, linux-scsi, linux-security-module,
linux-sh
In-Reply-To: <20161019085204.GD7517@dhcp22.suse.cz>
On Wed, Oct 19, 2016 at 10:52:05AM +0200, Michal Hocko wrote:
> yes this is the desirable and expected behavior.
>
> > wonder if this is desirable behaviour or whether this ought to be limited to
> > ptrace system calls. Regardless, by making the flag more visible it makes it
> > easier to see that this is happening.
>
> mem_open already enforces PTRACE_MODE_ATTACH
Ah I missed this, that makes a lot of sense, thanks!
I still wonder whether other invocations of access_remote_vm() in fs/proc/base.c
(the principle caller of this function) need FOLL_FORCE, for example the various
calls that simply read data from other processes, so I think the point stands
about keeping this explicit.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: Need help with mdiobus_register and phy
From: Zefir Kurtisi @ 2016-10-19 8:55 UTC (permalink / raw)
To: Timur Tabi, Andrew Lunn; +Cc: Florian Fainelli, netdev
In-Reply-To: <58061831.6080005@codeaurora.org>
On 10/18/2016 02:40 PM, Timur Tabi wrote:
> Zefir Kurtisi wrote:
>
>>> I have never seen the original problem that you noticed. When I use the generic
>>> phy driver instead of the at803x driver, everything works great for me. Perhaps
>>> the problem that you noticed only occurs with the Gianfar NIC?
>>>
>> You mean it works for you in SGMII mode without glitches?
>
> That is correct.
>
>> Then it might in fact be
>> an unfortunate rare or unique combination that we chose.
>
> That is what I expect.
>
>> I'd need some time to get that tested, and since our device might be the only one
>> requiring the fix, I am fine with keeping the patch private. Feel free to revert
>> it, if required, I'll provide a revised one.
>
> I'm in no hurry to get this fixed. Do you need a couple weeks to run some tests?
> It would be good to know for sure that your fix is needed only on your platform.
>
Ok then, if you can wait some days, I'll prepare and provide you a more detailed
failure report to allow you testing if the issue happens with other NICs.
^ permalink raw reply
* Re: [PATCH 00/10] mm: adjust get_user_pages* functions to explicitly pass FOLL_* flags
From: Lorenzo Stoakes @ 2016-10-19 8:58 UTC (permalink / raw)
To: Michal Hocko
Cc: linux-mips, linux-fbdev, Jan Kara, kvm, linux-sh, Dave Hansen,
dri-devel, linux-mm, netdev, sparclinux, linux-ia64, linux-s390,
linux-samsung-soc, linux-scsi, linux-rdma, x86, Hugh Dickins,
linux-media, Rik van Riel, intel-gfx, adi-buildroot-devel,
ceph-devel, linux-arm-kernel, linux-cris-kernel, Linus Torvalds,
linuxppc-dev, linux-kernel, linux-security-module, linux-alpha,
lin
In-Reply-To: <20161018153050.GC13117@dhcp22.suse.cz>
On Tue, Oct 18, 2016 at 05:30:50PM +0200, Michal Hocko wrote:
> I am wondering whether we can go further. E.g. it is not really clear to
> me whether we need an explicit FOLL_REMOTE when we can in fact check
> mm != current->mm and imply that. Maybe there are some contexts which
> wouldn't work, I haven't checked.
This flag is set even when /proc/self/mem is used. I've not looked deeply into
this flag but perhaps accessing your own memory this way can be considered
'remote' since you're not accessing it directly. On the other hand, perhaps this
is just mistaken in this case?
> I guess there is more work in that area and I do not want to impose all
> that work on you, but I couldn't resist once I saw you playing in that
> area ;) Definitely a good start!
Thanks, I am more than happy to go as far down this rabbit hole as is helpful,
no imposition at all :)
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* Re: [PATCH 08/10] mm: replace __access_remote_vm() write parameter with gup_flags
From: Michal Hocko @ 2016-10-19 8:52 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Jan Kara, linux-mm, Linus Torvalds, Hugh Dickins, Dave Hansen,
Rik van Riel, Mel Gorman, Andrew Morton, adi-buildroot-devel,
ceph-devel, dri-devel, intel-gfx, kvm, linux-alpha,
linux-arm-kernel, linux-cris-kernel, linux-fbdev, linux-fsdevel,
linux-ia64, linux-kernel, linux-media, linux-mips, linux-rdma,
linux-s390, linux-samsung-soc, linux-scsi, linux-security-module,
linux-sh
In-Reply-To: <20161019084045.GA19441@lucifer>
On Wed 19-10-16 09:40:45, Lorenzo Stoakes wrote:
> On Wed, Oct 19, 2016 at 10:13:52AM +0200, Michal Hocko wrote:
> > On Wed 19-10-16 09:59:03, Jan Kara wrote:
> > > On Thu 13-10-16 01:20:18, Lorenzo Stoakes wrote:
> > > > This patch removes the write parameter from __access_remote_vm() and replaces it
> > > > with a gup_flags parameter as use of this function previously _implied_
> > > > FOLL_FORCE, whereas after this patch callers explicitly pass this flag.
> > > >
> > > > We make this explicit as use of FOLL_FORCE can result in surprising behaviour
> > > > (and hence bugs) within the mm subsystem.
> > > >
> > > > Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>
> > >
> > > So I'm not convinced this (and the following two patches) is actually
> > > helping much. By grepping for FOLL_FORCE we will easily see that any caller
> > > of access_remote_vm() gets that semantics and can thus continue search
> >
> > I am really wondering. Is there anything inherent that would require
> > FOLL_FORCE for access_remote_vm? I mean FOLL_FORCE is a really
> > non-trivial thing. It doesn't obey vma permissions so we should really
> > minimize its usage. Do all of those users really need FOLL_FORCE?
>
> I wonder about this also, for example by accessing /proc/self/mem you trigger
> access_remote_vm() and consequently get_user_pages_remote() meaning FOLL_FORCE
> is implied and you can use /proc/self/mem to override any VMA permissions. I
yes this is the desirable and expected behavior.
> wonder if this is desirable behaviour or whether this ought to be limited to
> ptrace system calls. Regardless, by making the flag more visible it makes it
> easier to see that this is happening.
mem_open already enforces PTRACE_MODE_ATTACH
--
Michal Hocko
SUSE Labs
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH 08/10] mm: replace __access_remote_vm() write parameter with gup_flags
From: Lorenzo Stoakes @ 2016-10-19 8:40 UTC (permalink / raw)
To: Michal Hocko
Cc: Jan Kara, linux-mm, Linus Torvalds, Hugh Dickins, Dave Hansen,
Rik van Riel, Mel Gorman, Andrew Morton, adi-buildroot-devel,
ceph-devel, dri-devel, intel-gfx, kvm, linux-alpha,
linux-arm-kernel, linux-cris-kernel, linux-fbdev, linux-fsdevel,
linux-ia64, linux-kernel, linux-media, linux-mips, linux-rdma,
linux-s390, linux-samsung-soc, linux-scsi, linux-security-module,
linux-sh
In-Reply-To: <20161019081352.GB7562@dhcp22.suse.cz>
On Wed, Oct 19, 2016 at 10:13:52AM +0200, Michal Hocko wrote:
> On Wed 19-10-16 09:59:03, Jan Kara wrote:
> > On Thu 13-10-16 01:20:18, Lorenzo Stoakes wrote:
> > > This patch removes the write parameter from __access_remote_vm() and replaces it
> > > with a gup_flags parameter as use of this function previously _implied_
> > > FOLL_FORCE, whereas after this patch callers explicitly pass this flag.
> > >
> > > We make this explicit as use of FOLL_FORCE can result in surprising behaviour
> > > (and hence bugs) within the mm subsystem.
> > >
> > > Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>
> >
> > So I'm not convinced this (and the following two patches) is actually
> > helping much. By grepping for FOLL_FORCE we will easily see that any caller
> > of access_remote_vm() gets that semantics and can thus continue search
>
> I am really wondering. Is there anything inherent that would require
> FOLL_FORCE for access_remote_vm? I mean FOLL_FORCE is a really
> non-trivial thing. It doesn't obey vma permissions so we should really
> minimize its usage. Do all of those users really need FOLL_FORCE?
I wonder about this also, for example by accessing /proc/self/mem you trigger
access_remote_vm() and consequently get_user_pages_remote() meaning FOLL_FORCE
is implied and you can use /proc/self/mem to override any VMA permissions. I
wonder if this is desirable behaviour or whether this ought to be limited to
ptrace system calls. Regardless, by making the flag more visible it makes it
easier to see that this is happening.
Note that this /proc/self/mem behaviour is what triggered the bug that brought
about this discussion in the first place -
https://marc.info/?l=linux-mm&m=147363447105059 - as using /proc/self/mem this
way on PROT_NONE memory broke some assumptions.
On the other hand I see your point Jan in that you know any caller of these
functions will have FOLL_FORCE implied, and you have to decide to stop passing
the flag at _some_ point in the stack, however it seems fairly sane to have that
stopping point exist outside of exported gup functions so the gup interface
forces explicitness but callers can wrap things as they need.
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [v12, 0/8] Fix eSDHC host version register bug
From: gregkh-hQyY1W1yCW8ekmWlsbkhG0B+6BGkLq7r @ 2016-10-19 8:27 UTC (permalink / raw)
To: Y.B. Lu
Cc: Mark Rutland, Ulf Hansson, X.B. Xie, M.H. Lian,
linux-i2c-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-clk,
Qiang Zhao, Russell King, Bhupesh Sharma, Jochen Friedrich,
Claudiu Manoil,
devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, Arnd Bergmann,
Scott Wood, Rob Herring, Santosh Shilimkar,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r@public.gmane.org,
netdev-u79uwXL29TY76Z2rM5mHXA@public.gmane.org, linux-mmc,
linux-kernel-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Leo Li <l
In-Reply-To: <AM5PR0401MB2529BA70C6E7AF7C71631A47F8D20-oQ3wXcTHOqqGPub0A97BiI3W/0Ik+aLCnBOFsp37pqbUKgpGm//BTAC/G2K4zDHf@public.gmane.org>
On Wed, Oct 19, 2016 at 02:47:07AM +0000, Y.B. Lu wrote:
> + Greg
>
> Hi Greg,
>
> I submitted this patchset for a MMC bug fix, and introduce the below patch which needs your ACK.
> > > Arnd Bergmann (1):
> > > base: soc: introduce soc_device_match() interface
> https://patchwork.kernel.org/patch/9342913/
>
> Could you help to review it and give some comments or ACK.
> Thank you very much.
Now acked.
^ permalink raw reply
* Re: [PATCH 08/10] mm: replace __access_remote_vm() write parameter with gup_flags
From: Michal Hocko @ 2016-10-19 8:13 UTC (permalink / raw)
To: Jan Kara
Cc: linux-mips, linux-fbdev, linux-ia64, kvm, linux-sh, Dave Hansen,
dri-devel, linux-mm, netdev, sparclinux, linux-s390,
linux-samsung-soc, linux-scsi, linux-rdma, x86, Hugh Dickins,
linux-media, Rik van Riel, intel-gfx, adi-buildroot-devel,
ceph-devel, linux-arm-kernel, Lorenzo Stoakes, linux-cris-kernel,
Linus Torvalds, linuxppc-dev, linux-kernel, linux-security-module,
linux-alpha
In-Reply-To: <20161019075903.GP29967@quack2.suse.cz>
On Wed 19-10-16 09:59:03, Jan Kara wrote:
> On Thu 13-10-16 01:20:18, Lorenzo Stoakes wrote:
> > This patch removes the write parameter from __access_remote_vm() and replaces it
> > with a gup_flags parameter as use of this function previously _implied_
> > FOLL_FORCE, whereas after this patch callers explicitly pass this flag.
> >
> > We make this explicit as use of FOLL_FORCE can result in surprising behaviour
> > (and hence bugs) within the mm subsystem.
> >
> > Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>
>
> So I'm not convinced this (and the following two patches) is actually
> helping much. By grepping for FOLL_FORCE we will easily see that any caller
> of access_remote_vm() gets that semantics and can thus continue search
I am really wondering. Is there anything inherent that would require
FOLL_FORCE for access_remote_vm? I mean FOLL_FORCE is a really
non-trivial thing. It doesn't obey vma permissions so we should really
minimize its usage. Do all of those users really need FOLL_FORCE?
Anyway I would rather see the flag explicit and used at more places than
hidden behind a helper function.
--
Michal Hocko
SUSE Labs
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* Re: [RFC 5/6] qedi: Add support for iSCSI session management.
From: Hannes Reinecke @ 2016-10-19 8:03 UTC (permalink / raw)
To: manish.rangankar, lduncan, cleech
Cc: martin.petersen, jejb, linux-scsi, netdev, Yuval.Mintz,
QLogic-Storage-Upstream, Nilesh Javali, Adheer Chandravanshi,
Chad Dupuis, Saurav Kashyap, Arun Easi
In-Reply-To: <1476853273-22960-6-git-send-email-manish.rangankar@cavium.com>
On 10/19/2016 07:01 AM, manish.rangankar@cavium.com wrote:
> From: Manish Rangankar <manish.rangankar@cavium.com>
>
> This patch adds support for iscsi_transport LLD Login,
> Logout, NOP-IN/NOP-OUT, Async, Reject PDU processing
> and Firmware async event handling support.
>
> 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>
> ---
> drivers/scsi/qedi/qedi_fw.c | 1123 ++++++++++++++++++++++++++++
> drivers/scsi/qedi/qedi_gbl.h | 67 ++
> drivers/scsi/qedi/qedi_iscsi.c | 1604 ++++++++++++++++++++++++++++++++++++++++
> drivers/scsi/qedi/qedi_iscsi.h | 228 ++++++
> drivers/scsi/qedi/qedi_main.c | 164 ++++
> 5 files changed, 3186 insertions(+)
> create mode 100644 drivers/scsi/qedi/qedi_fw.c
> create mode 100644 drivers/scsi/qedi/qedi_gbl.h
> create mode 100644 drivers/scsi/qedi/qedi_iscsi.c
> create mode 100644 drivers/scsi/qedi/qedi_iscsi.h
>
> diff --git a/drivers/scsi/qedi/qedi_fw.c b/drivers/scsi/qedi/qedi_fw.c
> new file mode 100644
> index 0000000..a820785
> --- /dev/null
> +++ b/drivers/scsi/qedi/qedi_fw.c
> @@ -0,0 +1,1123 @@
> +/*
> + * 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/blkdev.h>
> +#include <scsi/scsi_tcq.h>
> +#include <linux/delay.h>
> +
> +#include "qedi.h"
> +#include "qedi_iscsi.h"
> +#include "qedi_gbl.h"
> +
> +static int qedi_send_iscsi_tmf(struct qedi_conn *qedi_conn,
> + struct iscsi_task *mtask);
> +
> +void qedi_iscsi_unmap_sg_list(struct qedi_cmd *cmd)
> +{
> + struct scsi_cmnd *sc = cmd->scsi_cmd;
> +
> + if (cmd->io_tbl.sge_valid && sc) {
> + scsi_dma_unmap(sc);
> + cmd->io_tbl.sge_valid = 0;
> + }
> +}
> +
> +static void qedi_process_logout_resp(struct qedi_ctx *qedi,
> + union iscsi_cqe *cqe,
> + struct iscsi_task *task,
> + struct qedi_conn *qedi_conn)
> +{
> + struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
> + struct iscsi_logout_rsp *resp_hdr;
> + struct iscsi_session *session = conn->session;
> + struct iscsi_logout_response_hdr *cqe_logout_response;
> + struct qedi_cmd *cmd;
> +
> + cmd = (struct qedi_cmd *)task->dd_data;
> + cqe_logout_response = &cqe->cqe_common.iscsi_hdr.logout_response;
> + spin_lock(&session->back_lock);
> + resp_hdr = (struct iscsi_logout_rsp *)&qedi_conn->gen_pdu.resp_hdr;
> + memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
> + resp_hdr->opcode = cqe_logout_response->opcode;
> + resp_hdr->flags = cqe_logout_response->flags;
> + resp_hdr->hlength = 0;
> +
> + resp_hdr->itt = build_itt(cqe->cqe_solicited.itid, conn->session->age);
> + resp_hdr->statsn = cpu_to_be32(cqe_logout_response->stat_sn);
> + resp_hdr->exp_cmdsn = cpu_to_be32(cqe_logout_response->exp_cmd_sn);
> + resp_hdr->max_cmdsn = cpu_to_be32(cqe_logout_response->max_cmd_sn);
> +
> + resp_hdr->t2wait = cpu_to_be32(cqe_logout_response->time2wait);
> + resp_hdr->t2retain = cpu_to_be32(cqe_logout_response->time2retain);
> +
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID,
> + "Freeing tid=0x%x for cid=0x%x\n",
> + cmd->task_id, qedi_conn->iscsi_conn_id);
> +
> + if (likely(cmd->io_cmd_in_list)) {
> + cmd->io_cmd_in_list = false;
> + list_del_init(&cmd->io_cmd);
> + qedi_conn->active_cmd_count--;
> + } else {
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
> + "Active cmd list node already deleted, tid=0x%x, cid=0x%x, io_cmd_node=%p\n",
> + cmd->task_id, qedi_conn->iscsi_conn_id,
> + &cmd->io_cmd);
> + }
> +
> + cmd->state = RESPONSE_RECEIVED;
> + qedi_clear_task_idx(qedi, cmd->task_id);
> + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, NULL, 0);
> +
> + spin_unlock(&session->back_lock);
> +}
> +
> +static void qedi_process_text_resp(struct qedi_ctx *qedi,
> + union iscsi_cqe *cqe,
> + struct iscsi_task *task,
> + struct qedi_conn *qedi_conn)
> +{
> + struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
> + struct iscsi_session *session = conn->session;
> + struct iscsi_task_context *task_ctx;
> + struct iscsi_text_rsp *resp_hdr_ptr;
> + struct iscsi_text_response_hdr *cqe_text_response;
> + struct qedi_cmd *cmd;
> + int pld_len;
> + u32 *tmp;
> +
> + cmd = (struct qedi_cmd *)task->dd_data;
> + task_ctx = (struct iscsi_task_context *)qedi_get_task_mem(&qedi->tasks,
> + cmd->task_id);
> +
> + cqe_text_response = &cqe->cqe_common.iscsi_hdr.text_response;
> + spin_lock(&session->back_lock);
> + resp_hdr_ptr = (struct iscsi_text_rsp *)&qedi_conn->gen_pdu.resp_hdr;
> + memset(resp_hdr_ptr, 0, sizeof(struct iscsi_hdr));
> + resp_hdr_ptr->opcode = cqe_text_response->opcode;
> + resp_hdr_ptr->flags = cqe_text_response->flags;
> + resp_hdr_ptr->hlength = 0;
> +
> + hton24(resp_hdr_ptr->dlength,
> + (cqe_text_response->hdr_second_dword &
> + ISCSI_TEXT_RESPONSE_HDR_DATA_SEG_LEN_MASK));
> + tmp = (u32 *)resp_hdr_ptr->dlength;
> +
> + resp_hdr_ptr->itt = build_itt(cqe->cqe_solicited.itid,
> + conn->session->age);
> + resp_hdr_ptr->ttt = cqe_text_response->ttt;
> + resp_hdr_ptr->statsn = cpu_to_be32(cqe_text_response->stat_sn);
> + resp_hdr_ptr->exp_cmdsn = cpu_to_be32(cqe_text_response->exp_cmd_sn);
> + resp_hdr_ptr->max_cmdsn = cpu_to_be32(cqe_text_response->max_cmd_sn);
> +
> + pld_len = cqe_text_response->hdr_second_dword &
> + ISCSI_TEXT_RESPONSE_HDR_DATA_SEG_LEN_MASK;
> + qedi_conn->gen_pdu.resp_wr_ptr = qedi_conn->gen_pdu.resp_buf + pld_len;
> +
> + memset(task_ctx, '\0', sizeof(*task_ctx));
> +
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID,
> + "Freeing tid=0x%x for cid=0x%x\n",
> + cmd->task_id, qedi_conn->iscsi_conn_id);
> +
> + if (likely(cmd->io_cmd_in_list)) {
> + cmd->io_cmd_in_list = false;
> + list_del_init(&cmd->io_cmd);
> + qedi_conn->active_cmd_count--;
> + } else {
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
> + "Active cmd list node already deleted, tid=0x%x, cid=0x%x, io_cmd_node=%p\n",
> + cmd->task_id, qedi_conn->iscsi_conn_id,
> + &cmd->io_cmd);
> + }
> +
> + cmd->state = RESPONSE_RECEIVED;
> + qedi_clear_task_idx(qedi, cmd->task_id);
> +
> + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr_ptr,
> + qedi_conn->gen_pdu.resp_buf,
> + (qedi_conn->gen_pdu.resp_wr_ptr -
> + qedi_conn->gen_pdu.resp_buf));
> + spin_unlock(&session->back_lock);
> +}
> +
> +static void qedi_process_login_resp(struct qedi_ctx *qedi,
> + union iscsi_cqe *cqe,
> + struct iscsi_task *task,
> + struct qedi_conn *qedi_conn)
> +{
> + struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
> + struct iscsi_session *session = conn->session;
> + struct iscsi_task_context *task_ctx;
> + struct iscsi_login_rsp *resp_hdr_ptr;
> + struct iscsi_login_response_hdr *cqe_login_response;
> + struct qedi_cmd *cmd;
> + int pld_len;
> + u32 *tmp;
> +
> + cmd = (struct qedi_cmd *)task->dd_data;
> +
> + cqe_login_response = &cqe->cqe_common.iscsi_hdr.login_response;
> + task_ctx = (struct iscsi_task_context *)qedi_get_task_mem(&qedi->tasks,
> + cmd->task_id);
> + spin_lock(&session->back_lock);
> + resp_hdr_ptr = (struct iscsi_login_rsp *)&qedi_conn->gen_pdu.resp_hdr;
> + memset(resp_hdr_ptr, 0, sizeof(struct iscsi_login_rsp));
> + resp_hdr_ptr->opcode = cqe_login_response->opcode;
> + resp_hdr_ptr->flags = cqe_login_response->flags_attr;
> + resp_hdr_ptr->hlength = 0;
> +
> + hton24(resp_hdr_ptr->dlength,
> + (cqe_login_response->hdr_second_dword &
> + ISCSI_LOGIN_RESPONSE_HDR_DATA_SEG_LEN_MASK));
> + tmp = (u32 *)resp_hdr_ptr->dlength;
> + resp_hdr_ptr->itt = build_itt(cqe->cqe_solicited.itid,
> + conn->session->age);
> + resp_hdr_ptr->tsih = cqe_login_response->tsih;
> + resp_hdr_ptr->statsn = cpu_to_be32(cqe_login_response->stat_sn);
> + resp_hdr_ptr->exp_cmdsn = cpu_to_be32(cqe_login_response->exp_cmd_sn);
> + resp_hdr_ptr->max_cmdsn = cpu_to_be32(cqe_login_response->max_cmd_sn);
> + resp_hdr_ptr->status_class = cqe_login_response->status_class;
> + resp_hdr_ptr->status_detail = cqe_login_response->status_detail;
> + pld_len = cqe_login_response->hdr_second_dword &
> + ISCSI_LOGIN_RESPONSE_HDR_DATA_SEG_LEN_MASK;
> + qedi_conn->gen_pdu.resp_wr_ptr = qedi_conn->gen_pdu.resp_buf + pld_len;
> +
> + if (likely(cmd->io_cmd_in_list)) {
> + cmd->io_cmd_in_list = false;
> + list_del_init(&cmd->io_cmd);
> + qedi_conn->active_cmd_count--;
> + }
> +
> + memset(task_ctx, '\0', sizeof(*task_ctx));
> +
> + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr_ptr,
> + qedi_conn->gen_pdu.resp_buf,
> + (qedi_conn->gen_pdu.resp_wr_ptr -
> + qedi_conn->gen_pdu.resp_buf));
> +
> + spin_unlock(&session->back_lock);
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID,
> + "Freeing tid=0x%x for cid=0x%x\n",
> + cmd->task_id, qedi_conn->iscsi_conn_id);
> + cmd->state = RESPONSE_RECEIVED;
> + qedi_clear_task_idx(qedi, cmd->task_id);
> +}
> +
> +static void qedi_get_rq_bdq_buf(struct qedi_ctx *qedi,
> + struct iscsi_cqe_unsolicited *cqe,
> + char *ptr, int len)
> +{
> + u16 idx = 0;
> +
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
> + "pld_len [%d], bdq_prod_idx [%d], idx [%d]\n",
> + len, qedi->bdq_prod_idx,
> + (qedi->bdq_prod_idx % qedi->rq_num_entries));
> +
> + /* Obtain buffer address from rqe_opaque */
> + idx = cqe->rqe_opaque.lo;
> + if ((idx < 0) || (idx > (QEDI_BDQ_NUM - 1))) {
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
> + "wrong idx %d returned by FW, dropping the unsolicited pkt\n",
> + idx);
> + return;
> + }
> +
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
> + "rqe_opaque.lo [0x%p], rqe_opaque.hi [0x%p], idx [%d]\n",
> + cqe->rqe_opaque.lo, cqe->rqe_opaque.hi, idx);
> +
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
> + "unsol_cqe_type = %d\n", cqe->unsol_cqe_type);
> + switch (cqe->unsol_cqe_type) {
> + case ISCSI_CQE_UNSOLICITED_SINGLE:
> + case ISCSI_CQE_UNSOLICITED_FIRST:
> + if (len)
> + memcpy(ptr, (void *)qedi->bdq[idx].buf_addr, len);
> + break;
> + case ISCSI_CQE_UNSOLICITED_MIDDLE:
> + case ISCSI_CQE_UNSOLICITED_LAST:
> + break;
> + default:
> + break;
> + }
> +}
> +
> +static void qedi_put_rq_bdq_buf(struct qedi_ctx *qedi,
> + struct iscsi_cqe_unsolicited *cqe,
> + int count)
> +{
> + u16 tmp;
> + u16 idx = 0;
> + struct scsi_bd *pbl;
> +
> + /* Obtain buffer address from rqe_opaque */
> + idx = cqe->rqe_opaque.lo;
> + if ((idx < 0) || (idx > (QEDI_BDQ_NUM - 1))) {
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
> + "wrong idx %d returned by FW, dropping the unsolicited pkt\n",
> + idx);
> + return;
> + }
> +
> + pbl = (struct scsi_bd *)qedi->bdq_pbl;
> + pbl += (qedi->bdq_prod_idx % qedi->rq_num_entries);
> + pbl->address.hi =
> + cpu_to_le32((u32)(((u64)(qedi->bdq[idx].buf_dma)) >> 32));
> + pbl->address.lo =
> + cpu_to_le32(((u32)(((u64)(qedi->bdq[idx].buf_dma)) &
> + 0xffffffff)));
> + 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, idx);
> + pbl->opaque.hi = cpu_to_le32((u32)(((u64)0) >> 32));
> + pbl->opaque.lo = cpu_to_le32(((u32)(((u64)idx) & 0xffffffff)));
> +
> + /* Increment producer to let f/w know we've handled the frame */
> + qedi->bdq_prod_idx += count;
> +
> + 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);
> +}
> +
> +static void qedi_unsol_pdu_adjust_bdq(struct qedi_ctx *qedi,
> + struct iscsi_cqe_unsolicited *cqe,
> + u32 pdu_len, u32 num_bdqs,
> + char *bdq_data)
> +{
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
> + "num_bdqs [%d]\n", num_bdqs);
> +
> + qedi_get_rq_bdq_buf(qedi, cqe, bdq_data, pdu_len);
> + qedi_put_rq_bdq_buf(qedi, cqe, (num_bdqs + 1));
> +}
> +
> +static int qedi_process_nopin_mesg(struct qedi_ctx *qedi,
> + union iscsi_cqe *cqe,
> + struct iscsi_task *task,
> + struct qedi_conn *qedi_conn, u16 que_idx)
> +{
> + struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
> + struct iscsi_session *session = conn->session;
> + struct iscsi_nop_in_hdr *cqe_nop_in;
> + struct iscsi_nopin *hdr;
> + struct qedi_cmd *cmd;
> + int tgt_async_nop = 0;
> + u32 scsi_lun[2];
> + u32 pdu_len, num_bdqs;
> + char bdq_data[QEDI_BDQ_BUF_SIZE];
> + unsigned long flags;
> +
> + spin_lock_bh(&session->back_lock);
> + cqe_nop_in = &cqe->cqe_common.iscsi_hdr.nop_in;
> +
> + pdu_len = cqe_nop_in->hdr_second_dword &
> + ISCSI_NOP_IN_HDR_DATA_SEG_LEN_MASK;
> + num_bdqs = pdu_len / QEDI_BDQ_BUF_SIZE;
> +
> + hdr = (struct iscsi_nopin *)&qedi_conn->gen_pdu.resp_hdr;
> + memset(hdr, 0, sizeof(struct iscsi_hdr));
> + hdr->opcode = cqe_nop_in->opcode;
> + hdr->max_cmdsn = cpu_to_be32(cqe_nop_in->max_cmd_sn);
> + hdr->exp_cmdsn = cpu_to_be32(cqe_nop_in->exp_cmd_sn);
> + hdr->statsn = cpu_to_be32(cqe_nop_in->stat_sn);
> + hdr->ttt = cpu_to_be32(cqe_nop_in->ttt);
> +
> + if (cqe->cqe_common.cqe_type == ISCSI_CQE_TYPE_UNSOLICITED) {
> + spin_lock_irqsave(&qedi->hba_lock, flags);
> + qedi_unsol_pdu_adjust_bdq(qedi, &cqe->cqe_unsolicited,
> + pdu_len, num_bdqs, bdq_data);
> + hdr->itt = RESERVED_ITT;
> + tgt_async_nop = 1;
> + spin_unlock_irqrestore(&qedi->hba_lock, flags);
> + goto done;
> + }
> +
> + /* Response to one of our nop-outs */
> + if (task) {
> + cmd = task->dd_data;
> + hdr->flags = ISCSI_FLAG_CMD_FINAL;
> + hdr->itt = build_itt(cqe->cqe_solicited.itid,
> + conn->session->age);
> + scsi_lun[0] = 0xffffffff;
> + scsi_lun[1] = 0xffffffff;
> + memcpy(&hdr->lun, scsi_lun, sizeof(struct scsi_lun));
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_TID,
> + "Freeing tid=0x%x for cid=0x%x\n",
> + cmd->task_id, qedi_conn->iscsi_conn_id);
> + cmd->state = RESPONSE_RECEIVED;
> + spin_lock(&qedi_conn->list_lock);
> + if (likely(cmd->io_cmd_in_list)) {
> + cmd->io_cmd_in_list = false;
> + list_del_init(&cmd->io_cmd);
> + qedi_conn->active_cmd_count--;
> + }
> +
> + spin_unlock(&qedi_conn->list_lock);
> + qedi_clear_task_idx(qedi, cmd->task_id);
> + }
> +
> +done:
> + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr, bdq_data, pdu_len);
> +
> + spin_unlock_bh(&session->back_lock);
> + return tgt_async_nop;
> +}
> +
> +static void qedi_process_async_mesg(struct qedi_ctx *qedi,
> + union iscsi_cqe *cqe,
> + struct iscsi_task *task,
> + struct qedi_conn *qedi_conn,
> + u16 que_idx)
> +{
> + struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
> + struct iscsi_session *session = conn->session;
> + struct iscsi_async_msg_hdr *cqe_async_msg;
> + struct iscsi_async *resp_hdr;
> + u32 scsi_lun[2];
> + u32 pdu_len, num_bdqs;
> + char bdq_data[QEDI_BDQ_BUF_SIZE];
> + unsigned long flags;
> +
> + spin_lock_bh(&session->back_lock);
> +
> + cqe_async_msg = &cqe->cqe_common.iscsi_hdr.async_msg;
> + pdu_len = cqe_async_msg->hdr_second_dword &
> + ISCSI_ASYNC_MSG_HDR_DATA_SEG_LEN_MASK;
> + num_bdqs = pdu_len / QEDI_BDQ_BUF_SIZE;
> +
> + if (cqe->cqe_common.cqe_type == ISCSI_CQE_TYPE_UNSOLICITED) {
> + spin_lock_irqsave(&qedi->hba_lock, flags);
> + qedi_unsol_pdu_adjust_bdq(qedi, &cqe->cqe_unsolicited,
> + pdu_len, num_bdqs, bdq_data);
> + spin_unlock_irqrestore(&qedi->hba_lock, flags);
> + }
> +
> + resp_hdr = (struct iscsi_async *)&qedi_conn->gen_pdu.resp_hdr;
> + memset(resp_hdr, 0, sizeof(struct iscsi_hdr));
> + resp_hdr->opcode = cqe_async_msg->opcode;
> + resp_hdr->flags = 0x80;
> +
> + scsi_lun[0] = cpu_to_be32(cqe_async_msg->lun.lo);
> + scsi_lun[1] = cpu_to_be32(cqe_async_msg->lun.hi);
I _think_ we have a SCSI LUN structure ...
> + memcpy(&resp_hdr->lun, scsi_lun, sizeof(struct scsi_lun));
> + resp_hdr->exp_cmdsn = cpu_to_be32(cqe_async_msg->exp_cmd_sn);
> + resp_hdr->max_cmdsn = cpu_to_be32(cqe_async_msg->max_cmd_sn);
> + resp_hdr->statsn = cpu_to_be32(cqe_async_msg->stat_sn);
> +
> + resp_hdr->async_event = cqe_async_msg->async_event;
> + resp_hdr->async_vcode = cqe_async_msg->async_vcode;
> +
> + resp_hdr->param1 = cpu_to_be16(cqe_async_msg->param1_rsrv);
> + resp_hdr->param2 = cpu_to_be16(cqe_async_msg->param2_rsrv);
> + resp_hdr->param3 = cpu_to_be16(cqe_async_msg->param3_rsrv);
> +
> + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)resp_hdr, bdq_data,
> + pdu_len);
> +
> + spin_unlock_bh(&session->back_lock);
> +}
> +
> +static void qedi_process_reject_mesg(struct qedi_ctx *qedi,
> + union iscsi_cqe *cqe,
> + struct iscsi_task *task,
> + struct qedi_conn *qedi_conn,
> + uint16_t que_idx)
> +{
> + struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
> + struct iscsi_session *session = conn->session;
> + struct iscsi_reject_hdr *cqe_reject;
> + struct iscsi_reject *hdr;
> + u32 pld_len, num_bdqs;
> + unsigned long flags;
> +
> + spin_lock_bh(&session->back_lock);
> + cqe_reject = &cqe->cqe_common.iscsi_hdr.reject;
> + pld_len = cqe_reject->hdr_second_dword &
> + ISCSI_REJECT_HDR_DATA_SEG_LEN_MASK;
> + num_bdqs = pld_len / QEDI_BDQ_BUF_SIZE;
> +
> + if (cqe->cqe_common.cqe_type == ISCSI_CQE_TYPE_UNSOLICITED) {
> + spin_lock_irqsave(&qedi->hba_lock, flags);
> + qedi_unsol_pdu_adjust_bdq(qedi, &cqe->cqe_unsolicited,
> + pld_len, num_bdqs, conn->data);
> + spin_unlock_irqrestore(&qedi->hba_lock, flags);
> + }
> + hdr = (struct iscsi_reject *)&qedi_conn->gen_pdu.resp_hdr;
> + memset(hdr, 0, sizeof(struct iscsi_hdr));
> + hdr->opcode = cqe_reject->opcode;
> + hdr->reason = cqe_reject->hdr_reason;
> + hdr->flags = cqe_reject->hdr_flags;
> + hton24(hdr->dlength, (cqe_reject->hdr_second_dword &
> + ISCSI_REJECT_HDR_DATA_SEG_LEN_MASK));
> + hdr->max_cmdsn = cpu_to_be32(cqe_reject->max_cmd_sn);
> + hdr->exp_cmdsn = cpu_to_be32(cqe_reject->exp_cmd_sn);
> + hdr->statsn = cpu_to_be32(cqe_reject->stat_sn);
> + hdr->ffffffff = cpu_to_be32(0xffffffff);
> +
> + __iscsi_complete_pdu(conn, (struct iscsi_hdr *)hdr,
> + conn->data, pld_len);
> + spin_unlock_bh(&session->back_lock);
> +}
> +
> +static void qedi_mtask_completion(struct qedi_ctx *qedi,
> + union iscsi_cqe *cqe,
> + struct iscsi_task *task,
> + struct qedi_conn *conn, uint16_t que_idx)
> +{
> + struct iscsi_conn *iscsi_conn;
> + u32 hdr_opcode;
> +
> + hdr_opcode = cqe->cqe_common.iscsi_hdr.common.hdr_first_byte;
> + iscsi_conn = conn->cls_conn->dd_data;
> +
> + switch (hdr_opcode) {
> + case ISCSI_OPCODE_LOGIN_RESPONSE:
> + qedi_process_login_resp(qedi, cqe, task, conn);
> + break;
> + case ISCSI_OPCODE_TEXT_RESPONSE:
> + qedi_process_text_resp(qedi, cqe, task, conn);
> + break;
> + case ISCSI_OPCODE_LOGOUT_RESPONSE:
> + qedi_process_logout_resp(qedi, cqe, task, conn);
> + break;
> + case ISCSI_OPCODE_NOP_IN:
> + qedi_process_nopin_mesg(qedi, cqe, task, conn, que_idx);
> + break;
> + default:
> + QEDI_ERR(&qedi->dbg_ctx, "unknown opcode\n");
> + }
> +}
> +
> +static void qedi_process_nopin_local_cmpl(struct qedi_ctx *qedi,
> + struct iscsi_cqe_solicited *cqe,
> + struct iscsi_task *task,
> + struct qedi_conn *qedi_conn)
> +{
> + struct iscsi_conn *conn = qedi_conn->cls_conn->dd_data;
> + struct iscsi_session *session = conn->session;
> + struct qedi_cmd *cmd = task->dd_data;
> +
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_UNSOL,
> + "itid=0x%x, cmd task id=0x%x\n",
> + cqe->itid, cmd->task_id);
> +
> + cmd->state = RESPONSE_RECEIVED;
> + qedi_clear_task_idx(qedi, cmd->task_id);
> +
> + spin_lock_bh(&session->back_lock);
> + __iscsi_put_task(task);
> + spin_unlock_bh(&session->back_lock);
> +}
> +
> +void qedi_fp_process_cqes(struct qedi_ctx *qedi, union iscsi_cqe *cqe,
> + uint16_t que_idx)
> +{
> + struct iscsi_task *task = NULL;
> + struct iscsi_nopout *nopout_hdr;
> + struct qedi_conn *q_conn;
> + struct iscsi_conn *conn;
> + struct iscsi_task_context *fw_task_ctx;
> + u32 comp_type;
> + u32 iscsi_cid;
> + u32 hdr_opcode;
> + u32 ptmp_itt = 0;
> + itt_t proto_itt = 0;
> + u8 cqe_err_bits = 0;
> +
> + comp_type = cqe->cqe_common.cqe_type;
> + hdr_opcode = cqe->cqe_common.iscsi_hdr.common.hdr_first_byte;
> + cqe_err_bits =
> + cqe->cqe_common.error_bitmap.error_bits.cqe_error_status_bits;
> +
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
> + "fw_cid=0x%x, cqe type=0x%x, opcode=0x%x\n",
> + cqe->cqe_common.conn_id, comp_type, hdr_opcode);
> +
> + if (comp_type >= MAX_ISCSI_CQES_TYPE) {
> + QEDI_WARN(&qedi->dbg_ctx, "Invalid CqE type\n");
> + return;
> + }
> +
> + 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;
> + }
> +
> + conn = q_conn->cls_conn->dd_data;
> +
> + if (unlikely(cqe_err_bits &&
> + GET_FIELD(cqe_err_bits,
> + CQE_ERROR_BITMAP_DATA_DIGEST_ERR))) {
> + iscsi_conn_failure(conn, ISCSI_ERR_DATA_DGST);
> + return;
> + }
> +
> + switch (comp_type) {
> + case ISCSI_CQE_TYPE_SOLICITED:
> + case ISCSI_CQE_TYPE_SOLICITED_WITH_SENSE:
> + fw_task_ctx =
> + (struct iscsi_task_context *)qedi_get_task_mem(&qedi->tasks,
> + cqe->cqe_solicited.itid);
> + if (fw_task_ctx->ystorm_st_context.state.local_comp == 1) {
> + qedi_get_proto_itt(qedi, cqe->cqe_solicited.itid,
> + &ptmp_itt);
> + proto_itt = build_itt(ptmp_itt, conn->session->age);
> + } else {
> + cqe->cqe_solicited.itid =
> + qedi_get_itt(cqe->cqe_solicited);
> + proto_itt = build_itt(cqe->cqe_solicited.itid,
> + conn->session->age);
> + }
> +
> + spin_lock_bh(&conn->session->back_lock);
> + task = iscsi_itt_to_task(conn, proto_itt);
> + spin_unlock_bh(&conn->session->back_lock);
> +
> + if (!task) {
> + QEDI_WARN(&qedi->dbg_ctx, "task is NULL\n");
> + return;
> + }
> +
> + /* Process NOPIN local completion */
> + nopout_hdr = (struct iscsi_nopout *)task->hdr;
> + if ((nopout_hdr->itt == RESERVED_ITT) &&
> + (cqe->cqe_solicited.itid != (u16)RESERVED_ITT))
> + qedi_process_nopin_local_cmpl(qedi, &cqe->cqe_solicited,
> + task, q_conn);
> + else
> + /* Process other solicited responses */
> + qedi_mtask_completion(qedi, cqe, task, q_conn, que_idx);
> + break;
> + case ISCSI_CQE_TYPE_UNSOLICITED:
> + switch (hdr_opcode) {
> + case ISCSI_OPCODE_NOP_IN:
> + qedi_process_nopin_mesg(qedi, cqe, task, q_conn,
> + que_idx);
> + break;
> + case ISCSI_OPCODE_ASYNC_MSG:
> + qedi_process_async_mesg(qedi, cqe, task, q_conn,
> + que_idx);
> + break;
> + case ISCSI_OPCODE_REJECT:
> + qedi_process_reject_mesg(qedi, cqe, task, q_conn,
> + que_idx);
> + break;
> + }
> + goto exit_fp_process;
> + default:
> + QEDI_ERR(&qedi->dbg_ctx, "Error cqe.\n");
> + break;
> + }
> +
> +exit_fp_process:
> + return;
> +}
> +
> +static void qedi_add_to_sq(struct qedi_conn *qedi_conn, struct iscsi_task *task,
> + u16 tid, uint16_t ptu_invalidate, int is_cleanup)
> +{
> + struct iscsi_wqe *wqe;
> + struct iscsi_wqe_field *cont_field;
> + struct qedi_endpoint *ep;
> + struct scsi_cmnd *sc = task->sc;
> + struct iscsi_login_req *login_hdr;
> + struct qedi_cmd *cmd = task->dd_data;
> +
> + login_hdr = (struct iscsi_login_req *)task->hdr;
> + ep = qedi_conn->ep;
> + wqe = &ep->sq[ep->sq_prod_idx];
> +
> + memset(wqe, 0, sizeof(*wqe));
> +
> + ep->sq_prod_idx++;
> + ep->fw_sq_prod_idx++;
> + if (ep->sq_prod_idx == QEDI_SQ_SIZE)
> + ep->sq_prod_idx = 0;
> +
> + if (is_cleanup) {
> + SET_FIELD(wqe->flags, ISCSI_WQE_WQE_TYPE,
> + ISCSI_WQE_TYPE_TASK_CLEANUP);
> + wqe->task_id = tid;
> + return;
> + }
> +
> + if (ptu_invalidate) {
> + SET_FIELD(wqe->flags, ISCSI_WQE_PTU_INVALIDATE,
> + ISCSI_WQE_SET_PTU_INVALIDATE);
> + }
> +
> + cont_field = &wqe->cont_prevtid_union.cont_field;
> +
> + switch (task->hdr->opcode & ISCSI_OPCODE_MASK) {
> + case ISCSI_OP_LOGIN:
> + case ISCSI_OP_TEXT:
> + SET_FIELD(wqe->flags, ISCSI_WQE_WQE_TYPE,
> + ISCSI_WQE_TYPE_MIDDLE_PATH);
> + SET_FIELD(wqe->flags, ISCSI_WQE_NUM_FAST_SGES,
> + 1);
> + cont_field->contlen_cdbsize_field = ntoh24(login_hdr->dlength);
> + break;
> + case ISCSI_OP_LOGOUT:
> + case ISCSI_OP_NOOP_OUT:
> + case ISCSI_OP_SCSI_TMFUNC:
> + SET_FIELD(wqe->flags, ISCSI_WQE_WQE_TYPE,
> + ISCSI_WQE_TYPE_NORMAL);
> + break;
> + default:
> + if (!sc)
> + break;
> +
> + SET_FIELD(wqe->flags, ISCSI_WQE_WQE_TYPE,
> + ISCSI_WQE_TYPE_NORMAL);
> + cont_field->contlen_cdbsize_field =
> + (sc->sc_data_direction == DMA_TO_DEVICE) ?
> + scsi_bufflen(sc) : 0;
> + if (cmd->use_slowpath)
> + SET_FIELD(wqe->flags, ISCSI_WQE_NUM_FAST_SGES, 0);
> + else
> + SET_FIELD(wqe->flags, ISCSI_WQE_NUM_FAST_SGES,
> + (sc->sc_data_direction ==
> + DMA_TO_DEVICE) ?
> + min((u16)QEDI_FAST_SGE_COUNT,
> + (u16)cmd->io_tbl.sge_valid) : 0);
> + break;
> + }
> +
> + wqe->task_id = tid;
> + /* Make sure SQ data is coherent */
> + wmb();
> +}
> +
> +static void qedi_ring_doorbell(struct qedi_conn *qedi_conn)
> +{
> + struct iscsi_db_data dbell = { 0 };
> +
> + dbell.agg_flags = 0;
> +
> + dbell.params |= DB_DEST_XCM << ISCSI_DB_DATA_DEST_SHIFT;
> + dbell.params |= DB_AGG_CMD_SET << ISCSI_DB_DATA_AGG_CMD_SHIFT;
> + dbell.params |=
> + DQ_XCM_ISCSI_SQ_PROD_CMD << ISCSI_DB_DATA_AGG_VAL_SEL_SHIFT;
> +
> + dbell.sq_prod = qedi_conn->ep->fw_sq_prod_idx;
> + writel(*(u32 *)&dbell, qedi_conn->ep->p_doorbell);
> + /* Make sure fw idx is coherent */
> + wmb();
> + mmiowb();
> + QEDI_INFO(&qedi_conn->qedi->dbg_ctx, QEDI_LOG_MP_REQ,
> + "prod_idx=0x%x, fw_prod_idx=0x%x, cid=0x%x\n",
> + qedi_conn->ep->sq_prod_idx, qedi_conn->ep->fw_sq_prod_idx,
> + qedi_conn->iscsi_conn_id);
> +}
> +
> +int qedi_send_iscsi_login(struct qedi_conn *qedi_conn,
> + struct iscsi_task *task)
> +{
> + struct qedi_ctx *qedi = qedi_conn->qedi;
> + struct iscsi_task_context *fw_task_ctx;
> + struct iscsi_login_req *login_hdr;
> + struct iscsi_login_req_hdr *fw_login_req = NULL;
> + struct iscsi_cached_sge_ctx *cached_sge = NULL;
> + struct iscsi_sge *single_sge = NULL;
> + struct iscsi_sge *req_sge = NULL;
> + struct iscsi_sge *resp_sge = NULL;
> + struct qedi_cmd *qedi_cmd;
> + s16 ptu_invalidate = 0;
> + s16 tid = 0;
> +
> + req_sge = (struct iscsi_sge *)qedi_conn->gen_pdu.req_bd_tbl;
> + resp_sge = (struct iscsi_sge *)qedi_conn->gen_pdu.resp_bd_tbl;
> + qedi_cmd = (struct qedi_cmd *)task->dd_data;
> + login_hdr = (struct iscsi_login_req *)task->hdr;
> +
> + tid = qedi_get_task_idx(qedi);
> + if (tid == -1)
> + return -ENOMEM;
> +
> + fw_task_ctx =
> + (struct iscsi_task_context *)qedi_get_task_mem(&qedi->tasks, tid);
> + memset(fw_task_ctx, 0, sizeof(struct iscsi_task_context));
> +
> + qedi_cmd->task_id = tid;
> +
> + /* Ystorm context */
> + fw_login_req = &fw_task_ctx->ystorm_st_context.pdu_hdr.login_req;
> + fw_login_req->opcode = login_hdr->opcode;
> + fw_login_req->version_min = login_hdr->min_version;
> + fw_login_req->version_max = login_hdr->max_version;
> + fw_login_req->flags_attr = login_hdr->flags;
> + fw_login_req->isid_tabc = *((u16 *)login_hdr->isid + 2);
> + fw_login_req->isid_d = *((u32 *)login_hdr->isid);
> + fw_login_req->tsih = login_hdr->tsih;
> + qedi_update_itt_map(qedi, tid, task->itt);
> + fw_login_req->itt = qedi_set_itt(tid, get_itt(task->itt));
> + fw_login_req->cid = qedi_conn->iscsi_conn_id;
> + fw_login_req->cmd_sn = be32_to_cpu(login_hdr->cmdsn);
> + fw_login_req->exp_stat_sn = be32_to_cpu(login_hdr->exp_statsn);
> + fw_login_req->exp_stat_sn = 0;
> +
> + if (qedi->tid_reuse_count[tid] == QEDI_MAX_TASK_NUM) {
> + ptu_invalidate = 1;
> + qedi->tid_reuse_count[tid] = 0;
> + }
> +
> + fw_task_ctx->ystorm_st_context.state.reuse_count =
> + qedi->tid_reuse_count[tid];
> + fw_task_ctx->mstorm_st_context.reuse_count =
> + qedi->tid_reuse_count[tid]++;
> + cached_sge =
> + &fw_task_ctx->ystorm_st_context.state.sgl_ctx_union.cached_sge;
> + cached_sge->sge.sge_len = req_sge->sge_len;
> + cached_sge->sge.sge_addr.lo = (u32)(qedi_conn->gen_pdu.req_dma_addr);
> + cached_sge->sge.sge_addr.hi =
> + (u32)((u64)qedi_conn->gen_pdu.req_dma_addr >> 32);
> +
> + /* Mstorm context */
> + single_sge = &fw_task_ctx->mstorm_st_context.sgl_union.single_sge;
> + fw_task_ctx->mstorm_st_context.task_type = 0x2;
> + fw_task_ctx->mstorm_ag_context.task_cid = (u16)qedi_conn->iscsi_conn_id;
> + single_sge->sge_addr.lo = resp_sge->sge_addr.lo;
> + single_sge->sge_addr.hi = resp_sge->sge_addr.hi;
> + single_sge->sge_len = resp_sge->sge_len;
> +
> + SET_FIELD(fw_task_ctx->mstorm_st_context.flags.mflags,
> + ISCSI_MFLAGS_SINGLE_SGE, 1);
> + SET_FIELD(fw_task_ctx->mstorm_st_context.flags.mflags,
> + ISCSI_MFLAGS_SLOW_IO, 0);
> + fw_task_ctx->mstorm_st_context.sgl_size = 1;
> + fw_task_ctx->mstorm_st_context.rem_task_size = resp_sge->sge_len;
> +
> + /* Ustorm context */
> + fw_task_ctx->ustorm_st_context.rem_rcv_len = resp_sge->sge_len;
> + fw_task_ctx->ustorm_st_context.exp_data_transfer_len =
> + ntoh24(login_hdr->dlength);
> + fw_task_ctx->ustorm_st_context.exp_data_sn = 0;
> + fw_task_ctx->ustorm_st_context.cq_rss_number = 0;
> + fw_task_ctx->ustorm_st_context.task_type = 0x2;
> + fw_task_ctx->ustorm_ag_context.icid = (u16)qedi_conn->iscsi_conn_id;
> + fw_task_ctx->ustorm_ag_context.exp_data_acked =
> + ntoh24(login_hdr->dlength);
> + SET_FIELD(fw_task_ctx->ustorm_ag_context.flags1,
> + USTORM_ISCSI_TASK_AG_CTX_R2T2RECV, 1);
> + SET_FIELD(fw_task_ctx->ustorm_st_context.flags,
> + USTORM_ISCSI_TASK_ST_CTX_LOCAL_COMP, 0);
> +
> + spin_lock(&qedi_conn->list_lock);
> + list_add_tail(&qedi_cmd->io_cmd, &qedi_conn->active_cmd_list);
> + qedi_cmd->io_cmd_in_list = true;
> + qedi_conn->active_cmd_count++;
> + spin_unlock(&qedi_conn->list_lock);
> +
> + qedi_add_to_sq(qedi_conn, task, tid, ptu_invalidate, false);
> + qedi_ring_doorbell(qedi_conn);
> + return 0;
> +}
> +
> +int qedi_send_iscsi_logout(struct qedi_conn *qedi_conn,
> + struct iscsi_task *task)
> +{
> + struct qedi_ctx *qedi = qedi_conn->qedi;
> + struct iscsi_logout_req_hdr *fw_logout_req = NULL;
> + struct iscsi_task_context *fw_task_ctx = NULL;
> + struct iscsi_logout *logout_hdr = NULL;
> + struct qedi_cmd *qedi_cmd = NULL;
> + s16 tid = 0;
> + s16 ptu_invalidate = 0;
> +
> + qedi_cmd = (struct qedi_cmd *)task->dd_data;
> + logout_hdr = (struct iscsi_logout *)task->hdr;
> +
> + tid = qedi_get_task_idx(qedi);
> + if (tid == -1)
> + return -ENOMEM;
> +
> + fw_task_ctx =
> + (struct iscsi_task_context *)qedi_get_task_mem(&qedi->tasks, tid);
> +
> + memset(fw_task_ctx, 0, sizeof(struct iscsi_task_context));
> + qedi_cmd->task_id = tid;
> +
> + /* Ystorm context */
> + fw_logout_req = &fw_task_ctx->ystorm_st_context.pdu_hdr.logout_req;
> + fw_logout_req->opcode = ISCSI_OPCODE_LOGOUT_REQUEST;
> + fw_logout_req->reason_code = 0x80 | logout_hdr->flags;
> + qedi_update_itt_map(qedi, tid, task->itt);
> + fw_logout_req->itt = qedi_set_itt(tid, get_itt(task->itt));
> + fw_logout_req->exp_stat_sn = be32_to_cpu(logout_hdr->exp_statsn);
> + fw_logout_req->cmd_sn = be32_to_cpu(logout_hdr->cmdsn);
> +
> + if (qedi->tid_reuse_count[tid] == QEDI_MAX_TASK_NUM) {
> + ptu_invalidate = 1;
> + qedi->tid_reuse_count[tid] = 0;
> + }
> + fw_task_ctx->ystorm_st_context.state.reuse_count =
> + qedi->tid_reuse_count[tid];
> + fw_task_ctx->mstorm_st_context.reuse_count =
> + qedi->tid_reuse_count[tid]++;
> + fw_logout_req->cid = qedi_conn->iscsi_conn_id;
> + fw_task_ctx->ystorm_st_context.state.buffer_offset[0] = 0;
> +
> + /* Mstorm context */
> + fw_task_ctx->mstorm_st_context.task_type = ISCSI_TASK_TYPE_MIDPATH;
> + fw_task_ctx->mstorm_ag_context.task_cid = (u16)qedi_conn->iscsi_conn_id;
> +
> + /* Ustorm context */
> + fw_task_ctx->ustorm_st_context.rem_rcv_len = 0;
> + fw_task_ctx->ustorm_st_context.exp_data_transfer_len = 0;
> + fw_task_ctx->ustorm_st_context.exp_data_sn = 0;
> + fw_task_ctx->ustorm_st_context.task_type = ISCSI_TASK_TYPE_MIDPATH;
> + fw_task_ctx->ustorm_st_context.cq_rss_number = 0;
> +
> + SET_FIELD(fw_task_ctx->ustorm_st_context.flags,
> + USTORM_ISCSI_TASK_ST_CTX_LOCAL_COMP, 0);
> + SET_FIELD(fw_task_ctx->ustorm_st_context.reg1.reg1_map,
> + ISCSI_REG1_NUM_FAST_SGES, 0);
> +
> + fw_task_ctx->ustorm_ag_context.icid = (u16)qedi_conn->iscsi_conn_id;
> + SET_FIELD(fw_task_ctx->ustorm_ag_context.flags1,
> + USTORM_ISCSI_TASK_AG_CTX_R2T2RECV, 1);
> +
> + spin_lock(&qedi_conn->list_lock);
> + list_add_tail(&qedi_cmd->io_cmd, &qedi_conn->active_cmd_list);
> + qedi_cmd->io_cmd_in_list = true;
> + qedi_conn->active_cmd_count++;
> + spin_unlock(&qedi_conn->list_lock);
> +
> + qedi_add_to_sq(qedi_conn, task, tid, ptu_invalidate, false);
> + qedi_ring_doorbell(qedi_conn);
> +
> + return 0;
> +}
> +
> +int qedi_send_iscsi_text(struct qedi_conn *qedi_conn,
> + struct iscsi_task *task)
> +{
> + struct qedi_ctx *qedi = qedi_conn->qedi;
> + struct iscsi_task_context *fw_task_ctx;
> + struct iscsi_text_request_hdr *fw_text_request;
> + struct iscsi_cached_sge_ctx *cached_sge;
> + struct iscsi_sge *single_sge;
> + struct qedi_cmd *qedi_cmd;
> + /* For 6.5 hdr iscsi_hdr */
> + struct iscsi_text *text_hdr;
> + struct iscsi_sge *req_sge;
> + struct iscsi_sge *resp_sge;
> + s16 ptu_invalidate = 0;
> + s16 tid = 0;
> +
> + req_sge = (struct iscsi_sge *)qedi_conn->gen_pdu.req_bd_tbl;
> + resp_sge = (struct iscsi_sge *)qedi_conn->gen_pdu.resp_bd_tbl;
> + qedi_cmd = (struct qedi_cmd *)task->dd_data;
> + text_hdr = (struct iscsi_text *)task->hdr;
> +
> + tid = qedi_get_task_idx(qedi);
> + if (tid == -1)
> + return -ENOMEM;
> +
> + fw_task_ctx =
> + (struct iscsi_task_context *)qedi_get_task_mem(&qedi->tasks, tid);
> + memset(fw_task_ctx, 0, sizeof(struct iscsi_task_context));
> +
> + qedi_cmd->task_id = tid;
> +
> + /* Ystorm context */
> + fw_text_request =
> + &fw_task_ctx->ystorm_st_context.pdu_hdr.text_request;
> + fw_text_request->opcode = text_hdr->opcode;
> + fw_text_request->flags_attr = text_hdr->flags;
> +
> + qedi_update_itt_map(qedi, tid, task->itt);
> + fw_text_request->itt = qedi_set_itt(tid, get_itt(task->itt));
> + fw_text_request->ttt = text_hdr->ttt;
> + fw_text_request->cmd_sn = be32_to_cpu(text_hdr->cmdsn);
> + fw_text_request->exp_stat_sn = be32_to_cpu(text_hdr->exp_statsn);
> + fw_text_request->hdr_second_dword = ntoh24(text_hdr->dlength);
> +
> + if (qedi->tid_reuse_count[tid] == QEDI_MAX_TASK_NUM) {
> + ptu_invalidate = 1;
> + qedi->tid_reuse_count[tid] = 0;
> + }
> + fw_task_ctx->ystorm_st_context.state.reuse_count =
> + qedi->tid_reuse_count[tid];
> + fw_task_ctx->mstorm_st_context.reuse_count =
> + qedi->tid_reuse_count[tid]++;
> +
> + cached_sge =
> + &fw_task_ctx->ystorm_st_context.state.sgl_ctx_union.cached_sge;
> + cached_sge->sge.sge_len = req_sge->sge_len;
> + cached_sge->sge.sge_addr.lo = (u32)(qedi_conn->gen_pdu.req_dma_addr);
> + cached_sge->sge.sge_addr.hi =
> + (u32)((u64)qedi_conn->gen_pdu.req_dma_addr >> 32);
> +
> + /* Mstorm context */
> + single_sge = &fw_task_ctx->mstorm_st_context.sgl_union.single_sge;
> + fw_task_ctx->mstorm_st_context.task_type = 0x2;
> + fw_task_ctx->mstorm_ag_context.task_cid = (u16)qedi_conn->iscsi_conn_id;
> + single_sge->sge_addr.lo = resp_sge->sge_addr.lo;
> + single_sge->sge_addr.hi = resp_sge->sge_addr.hi;
> + single_sge->sge_len = resp_sge->sge_len;
> +
> + SET_FIELD(fw_task_ctx->mstorm_st_context.flags.mflags,
> + ISCSI_MFLAGS_SINGLE_SGE, 1);
> + SET_FIELD(fw_task_ctx->mstorm_st_context.flags.mflags,
> + ISCSI_MFLAGS_SLOW_IO, 0);
> + fw_task_ctx->mstorm_st_context.sgl_size = 1;
> + fw_task_ctx->mstorm_st_context.rem_task_size = resp_sge->sge_len;
> +
> + /* Ustorm context */
> + fw_task_ctx->ustorm_ag_context.exp_data_acked =
> + ntoh24(text_hdr->dlength);
> + fw_task_ctx->ustorm_st_context.rem_rcv_len = resp_sge->sge_len;
> + fw_task_ctx->ustorm_st_context.exp_data_transfer_len =
> + ntoh24(text_hdr->dlength);
> + fw_task_ctx->ustorm_st_context.exp_data_sn =
> + be32_to_cpu(text_hdr->exp_statsn);
> + fw_task_ctx->ustorm_st_context.cq_rss_number = 0;
> + fw_task_ctx->ustorm_st_context.task_type = 0x2;
> + fw_task_ctx->ustorm_ag_context.icid = (u16)qedi_conn->iscsi_conn_id;
> + SET_FIELD(fw_task_ctx->ustorm_ag_context.flags1,
> + USTORM_ISCSI_TASK_AG_CTX_R2T2RECV, 1);
> +
> + /* Add command in active command list */
> + spin_lock(&qedi_conn->list_lock);
> + list_add_tail(&qedi_cmd->io_cmd, &qedi_conn->active_cmd_list);
> + qedi_cmd->io_cmd_in_list = true;
> + qedi_conn->active_cmd_count++;
> + spin_unlock(&qedi_conn->list_lock);
> +
> + qedi_add_to_sq(qedi_conn, task, tid, ptu_invalidate, false);
> + qedi_ring_doorbell(qedi_conn);
> +
> + return 0;
> +}
> +
> +int qedi_send_iscsi_nopout(struct qedi_conn *qedi_conn,
> + struct iscsi_task *task,
> + char *datap, int data_len, int unsol)
> +{
> + struct qedi_ctx *qedi = qedi_conn->qedi;
> + struct iscsi_task_context *fw_task_ctx;
> + struct iscsi_nop_out_hdr *fw_nop_out;
> + struct qedi_cmd *qedi_cmd;
> + /* For 6.5 hdr iscsi_hdr */
> + struct iscsi_nopout *nopout_hdr;
> + struct iscsi_cached_sge_ctx *cached_sge;
> + struct iscsi_sge *single_sge;
> + struct iscsi_sge *req_sge;
> + struct iscsi_sge *resp_sge;
> + u32 scsi_lun[2];
> + s16 ptu_invalidate = 0;
> + s16 tid = 0;
> +
> + req_sge = (struct iscsi_sge *)qedi_conn->gen_pdu.req_bd_tbl;
> + resp_sge = (struct iscsi_sge *)qedi_conn->gen_pdu.resp_bd_tbl;
> + qedi_cmd = (struct qedi_cmd *)task->dd_data;
> + nopout_hdr = (struct iscsi_nopout *)task->hdr;
> +
> + tid = qedi_get_task_idx(qedi);
> + if (tid == -1) {
> + QEDI_WARN(&qedi->dbg_ctx, "Invalid tid\n");
> + return -ENOMEM;
> + }
> +
> + fw_task_ctx =
> + (struct iscsi_task_context *)qedi_get_task_mem(&qedi->tasks, tid);
> +
> + memset(fw_task_ctx, 0, sizeof(struct iscsi_task_context));
> + qedi_cmd->task_id = tid;
> +
> + /* Ystorm context */
> + fw_nop_out = &fw_task_ctx->ystorm_st_context.pdu_hdr.nop_out;
> + SET_FIELD(fw_nop_out->flags_attr, ISCSI_NOP_OUT_HDR_CONST1, 1);
> + SET_FIELD(fw_nop_out->flags_attr, ISCSI_NOP_OUT_HDR_RSRV, 0);
> +
> + memcpy(scsi_lun, &nopout_hdr->lun, sizeof(struct scsi_lun));
> + fw_nop_out->lun.lo = be32_to_cpu(scsi_lun[0]);
> + fw_nop_out->lun.hi = be32_to_cpu(scsi_lun[1]);
> +
> + qedi_update_itt_map(qedi, tid, task->itt);
> +
> + if (nopout_hdr->ttt != ISCSI_TTT_ALL_ONES) {
> + fw_nop_out->itt = be32_to_cpu(nopout_hdr->itt);
> + fw_nop_out->ttt = be32_to_cpu(nopout_hdr->ttt);
> + fw_task_ctx->ystorm_st_context.state.buffer_offset[0] = 0;
> + fw_task_ctx->ystorm_st_context.state.local_comp = 1;
> + SET_FIELD(fw_task_ctx->ustorm_st_context.flags,
> + USTORM_ISCSI_TASK_ST_CTX_LOCAL_COMP, 1);
> + } else {
> + fw_nop_out->itt = qedi_set_itt(tid, get_itt(task->itt));
> + fw_nop_out->ttt = ISCSI_TTT_ALL_ONES;
> + fw_task_ctx->ystorm_st_context.state.buffer_offset[0] = 0;
> +
> + spin_lock(&qedi_conn->list_lock);
> + list_add_tail(&qedi_cmd->io_cmd, &qedi_conn->active_cmd_list);
> + qedi_cmd->io_cmd_in_list = true;
> + qedi_conn->active_cmd_count++;
> + spin_unlock(&qedi_conn->list_lock);
> + }
> +
> + fw_nop_out->opcode = ISCSI_OPCODE_NOP_OUT;
> + fw_nop_out->cmd_sn = be32_to_cpu(nopout_hdr->cmdsn);
> + fw_nop_out->exp_stat_sn = be32_to_cpu(nopout_hdr->exp_statsn);
> +
> + cached_sge =
> + &fw_task_ctx->ystorm_st_context.state.sgl_ctx_union.cached_sge;
> + cached_sge->sge.sge_len = req_sge->sge_len;
> + cached_sge->sge.sge_addr.lo = (u32)(qedi_conn->gen_pdu.req_dma_addr);
> + cached_sge->sge.sge_addr.hi =
> + (u32)((u64)qedi_conn->gen_pdu.req_dma_addr >> 32);
> +
> + /* Mstorm context */
> + fw_task_ctx->mstorm_st_context.task_type = ISCSI_TASK_TYPE_MIDPATH;
> + fw_task_ctx->mstorm_ag_context.task_cid = (u16)qedi_conn->iscsi_conn_id;
> +
> + single_sge = &fw_task_ctx->mstorm_st_context.sgl_union.single_sge;
> + single_sge->sge_addr.lo = resp_sge->sge_addr.lo;
> + single_sge->sge_addr.hi = resp_sge->sge_addr.hi;
> + single_sge->sge_len = resp_sge->sge_len;
> + fw_task_ctx->mstorm_st_context.rem_task_size = resp_sge->sge_len;
> +
> + if (qedi->tid_reuse_count[tid] == QEDI_MAX_TASK_NUM) {
> + ptu_invalidate = 1;
> + qedi->tid_reuse_count[tid] = 0;
> + }
> + fw_task_ctx->ystorm_st_context.state.reuse_count =
> + qedi->tid_reuse_count[tid];
> + fw_task_ctx->mstorm_st_context.reuse_count =
> + qedi->tid_reuse_count[tid]++;
> + /* Ustorm context */
> + fw_task_ctx->ustorm_st_context.rem_rcv_len = resp_sge->sge_len;
> + fw_task_ctx->ustorm_st_context.exp_data_transfer_len = data_len;
> + fw_task_ctx->ustorm_st_context.exp_data_sn = 0;
> + fw_task_ctx->ustorm_st_context.task_type = ISCSI_TASK_TYPE_MIDPATH;
> + fw_task_ctx->ustorm_st_context.cq_rss_number = 0;
> +
> + SET_FIELD(fw_task_ctx->ustorm_st_context.reg1.reg1_map,
> + ISCSI_REG1_NUM_FAST_SGES, 0);
> +
> + fw_task_ctx->ustorm_ag_context.icid = (u16)qedi_conn->iscsi_conn_id;
> + SET_FIELD(fw_task_ctx->ustorm_ag_context.flags1,
> + USTORM_ISCSI_TASK_AG_CTX_R2T2RECV, 1);
> +
> + fw_task_ctx->ustorm_st_context.lun.lo = be32_to_cpu(scsi_lun[0]);
> + fw_task_ctx->ustorm_st_context.lun.hi = be32_to_cpu(scsi_lun[1]);
> +
> + qedi_add_to_sq(qedi_conn, task, tid, ptu_invalidate, false);
> + qedi_ring_doorbell(qedi_conn);
> + return 0;
> +}
> diff --git a/drivers/scsi/qedi/qedi_gbl.h b/drivers/scsi/qedi/qedi_gbl.h
> new file mode 100644
> index 0000000..85ea3d7
> --- /dev/null
> +++ b/drivers/scsi/qedi/qedi_gbl.h
> @@ -0,0 +1,67 @@
> +/*
> + * 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_GBL_H_
> +#define _QEDI_GBL_H_
> +
> +#include "qedi_iscsi.h"
> +
> +extern uint io_tracing;
> +extern int do_not_recover;
> +extern struct scsi_host_template qedi_host_template;
> +extern struct iscsi_transport qedi_iscsi_transport;
> +extern const struct qed_iscsi_ops *qedi_ops;
> +extern struct qedi_debugfs_ops qedi_debugfs_ops;
> +extern const struct file_operations qedi_dbg_fops;
> +extern struct device_attribute *qedi_shost_attrs[];
> +
> +int qedi_alloc_sq(struct qedi_ctx *qedi, struct qedi_endpoint *ep);
> +void qedi_free_sq(struct qedi_ctx *qedi, struct qedi_endpoint *ep);
> +
> +int qedi_send_iscsi_login(struct qedi_conn *qedi_conn,
> + struct iscsi_task *task);
> +int qedi_send_iscsi_logout(struct qedi_conn *qedi_conn,
> + struct iscsi_task *task);
> +int qedi_send_iscsi_text(struct qedi_conn *qedi_conn,
> + struct iscsi_task *task);
> +int qedi_send_iscsi_nopout(struct qedi_conn *qedi_conn,
> + struct iscsi_task *task,
> + char *datap, int data_len, int unsol);
> +int qedi_get_task_idx(struct qedi_ctx *qedi);
> +void qedi_clear_task_idx(struct qedi_ctx *qedi, int idx);
> +int qedi_iscsi_cleanup_task(struct iscsi_task *task,
> + bool mark_cmd_node_deleted);
> +void qedi_iscsi_unmap_sg_list(struct qedi_cmd *cmd);
> +void qedi_update_itt_map(struct qedi_ctx *qedi, u32 tid, u32 proto_itt);
> +void qedi_get_proto_itt(struct qedi_ctx *qedi, u32 tid, u32 *proto_itt);
> +void qedi_get_task_tid(struct qedi_ctx *qedi, u32 itt, int16_t *tid);
> +void qedi_process_iscsi_error(struct qedi_endpoint *ep,
> + struct async_data *data);
> +void qedi_start_conn_recovery(struct qedi_ctx *qedi,
> + struct qedi_conn *qedi_conn);
> +struct qedi_conn *qedi_get_conn_from_id(struct qedi_ctx *qedi, u32 iscsi_cid);
> +void qedi_process_tcp_error(struct qedi_endpoint *ep, struct async_data *data);
> +void qedi_mark_device_missing(struct iscsi_cls_session *cls_session);
> +void qedi_mark_device_available(struct iscsi_cls_session *cls_session);
> +void qedi_reset_host_mtu(struct qedi_ctx *qedi, u16 mtu);
> +int qedi_recover_all_conns(struct qedi_ctx *qedi);
> +void qedi_fp_process_cqes(struct qedi_ctx *qedi, union iscsi_cqe *cqe,
> + uint16_t que_idx);
> +void qedi_trace_io(struct qedi_ctx *qedi, struct iscsi_task *task,
> + u16 tid, int8_t direction);
> +int qedi_alloc_id(struct qedi_portid_tbl *id_tbl, u16 id);
> +u16 qedi_alloc_new_id(struct qedi_portid_tbl *id_tbl);
> +void qedi_free_id(struct qedi_portid_tbl *id_tbl, u16 id);
> +int qedi_create_sysfs_ctx_attr(struct qedi_ctx *qedi);
> +void qedi_remove_sysfs_ctx_attr(struct qedi_ctx *qedi);
> +void qedi_clearsq(struct qedi_ctx *qedi,
> + struct qedi_conn *qedi_conn,
> + struct iscsi_task *task);
> +
> +#endif
> diff --git a/drivers/scsi/qedi/qedi_iscsi.c b/drivers/scsi/qedi/qedi_iscsi.c
> new file mode 100644
> index 0000000..caecdb8
> --- /dev/null
> +++ b/drivers/scsi/qedi/qedi_iscsi.c
> @@ -0,0 +1,1604 @@
> +/*
> + * 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/blkdev.h>
> +#include <linux/etherdevice.h>
> +#include <linux/if_ether.h>
> +#include <linux/if_vlan.h>
> +#include <scsi/scsi_tcq.h>
> +
> +#include "qedi.h"
> +#include "qedi_iscsi.h"
> +#include "qedi_gbl.h"
> +
> +int qedi_recover_all_conns(struct qedi_ctx *qedi)
> +{
> + struct qedi_conn *qedi_conn;
> + int i;
> +
> + for (i = 0; i < qedi->max_active_conns; i++) {
> + qedi_conn = qedi_get_conn_from_id(qedi, i);
> + if (!qedi_conn)
> + continue;
> +
> + qedi_start_conn_recovery(qedi, qedi_conn);
> + }
> +
> + return SUCCESS;
> +}
> +
> +static int qedi_eh_host_reset(struct scsi_cmnd *cmd)
> +{
> + struct Scsi_Host *shost = cmd->device->host;
> + struct qedi_ctx *qedi;
> +
> + qedi = (struct qedi_ctx *)iscsi_host_priv(shost);
> +
> + return qedi_recover_all_conns(qedi);
> +}
> +
> +struct scsi_host_template qedi_host_template = {
> + .module = THIS_MODULE,
> + .name = "QLogic QEDI 25/40/100Gb iSCSI Initiator Driver",
> + .proc_name = QEDI_MODULE_NAME,
> + .queuecommand = iscsi_queuecommand,
> + .eh_abort_handler = iscsi_eh_abort,
> + .eh_device_reset_handler = iscsi_eh_device_reset,
> + .eh_target_reset_handler = iscsi_eh_recover_target,
> + .eh_host_reset_handler = qedi_eh_host_reset,
> + .target_alloc = iscsi_target_alloc,
> + .change_queue_depth = scsi_change_queue_depth,
> + .can_queue = QEDI_MAX_ISCSI_TASK,
> + .this_id = -1,
> + .sg_tablesize = QEDI_ISCSI_MAX_BDS_PER_CMD,
> + .max_sectors = 0xffff,
> + .cmd_per_lun = 128,
> + .use_clustering = ENABLE_CLUSTERING,
> + .shost_attrs = qedi_shost_attrs,
> +};
> +
> +static void qedi_conn_free_login_resources(struct qedi_ctx *qedi,
> + struct qedi_conn *qedi_conn)
> +{
> + if (qedi_conn->gen_pdu.resp_bd_tbl) {
> + dma_free_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE,
> + qedi_conn->gen_pdu.resp_bd_tbl,
> + qedi_conn->gen_pdu.resp_bd_dma);
> + qedi_conn->gen_pdu.resp_bd_tbl = NULL;
> + }
> +
> + if (qedi_conn->gen_pdu.req_bd_tbl) {
> + dma_free_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE,
> + qedi_conn->gen_pdu.req_bd_tbl,
> + qedi_conn->gen_pdu.req_bd_dma);
> + qedi_conn->gen_pdu.req_bd_tbl = NULL;
> + }
> +
> + if (qedi_conn->gen_pdu.resp_buf) {
> + dma_free_coherent(&qedi->pdev->dev,
> + ISCSI_DEF_MAX_RECV_SEG_LEN,
> + qedi_conn->gen_pdu.resp_buf,
> + qedi_conn->gen_pdu.resp_dma_addr);
> + qedi_conn->gen_pdu.resp_buf = NULL;
> + }
> +
> + if (qedi_conn->gen_pdu.req_buf) {
> + dma_free_coherent(&qedi->pdev->dev,
> + ISCSI_DEF_MAX_RECV_SEG_LEN,
> + qedi_conn->gen_pdu.req_buf,
> + qedi_conn->gen_pdu.req_dma_addr);
> + qedi_conn->gen_pdu.req_buf = NULL;
> + }
> +}
> +
> +static int qedi_conn_alloc_login_resources(struct qedi_ctx *qedi,
> + struct qedi_conn *qedi_conn)
> +{
> + qedi_conn->gen_pdu.req_buf =
> + dma_alloc_coherent(&qedi->pdev->dev,
> + ISCSI_DEF_MAX_RECV_SEG_LEN,
> + &qedi_conn->gen_pdu.req_dma_addr,
> + GFP_KERNEL);
> + if (!qedi_conn->gen_pdu.req_buf)
> + goto login_req_buf_failure;
> +
> + qedi_conn->gen_pdu.req_buf_size = 0;
> + qedi_conn->gen_pdu.req_wr_ptr = qedi_conn->gen_pdu.req_buf;
> +
> + qedi_conn->gen_pdu.resp_buf =
> + dma_alloc_coherent(&qedi->pdev->dev,
> + ISCSI_DEF_MAX_RECV_SEG_LEN,
> + &qedi_conn->gen_pdu.resp_dma_addr,
> + GFP_KERNEL);
> + if (!qedi_conn->gen_pdu.resp_buf)
> + goto login_resp_buf_failure;
> +
> + qedi_conn->gen_pdu.resp_buf_size = ISCSI_DEF_MAX_RECV_SEG_LEN;
> + qedi_conn->gen_pdu.resp_wr_ptr = qedi_conn->gen_pdu.resp_buf;
> +
> + qedi_conn->gen_pdu.req_bd_tbl =
> + dma_alloc_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE,
> + &qedi_conn->gen_pdu.req_bd_dma, GFP_KERNEL);
> + if (!qedi_conn->gen_pdu.req_bd_tbl)
> + goto login_req_bd_tbl_failure;
> +
> + qedi_conn->gen_pdu.resp_bd_tbl =
> + dma_alloc_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE,
> + &qedi_conn->gen_pdu.resp_bd_dma,
> + GFP_KERNEL);
> + if (!qedi_conn->gen_pdu.resp_bd_tbl)
> + goto login_resp_bd_tbl_failure;
> +
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_SESS,
> + "Allocation successful, cid=0x%x\n",
> + qedi_conn->iscsi_conn_id);
> + return 0;
> +
> +login_resp_bd_tbl_failure:
> + dma_free_coherent(&qedi->pdev->dev, QEDI_PAGE_SIZE,
> + qedi_conn->gen_pdu.req_bd_tbl,
> + qedi_conn->gen_pdu.req_bd_dma);
> + qedi_conn->gen_pdu.req_bd_tbl = NULL;
> +
> +login_req_bd_tbl_failure:
> + dma_free_coherent(&qedi->pdev->dev, ISCSI_DEF_MAX_RECV_SEG_LEN,
> + qedi_conn->gen_pdu.resp_buf,
> + qedi_conn->gen_pdu.resp_dma_addr);
> + qedi_conn->gen_pdu.resp_buf = NULL;
> +login_resp_buf_failure:
> + dma_free_coherent(&qedi->pdev->dev, ISCSI_DEF_MAX_RECV_SEG_LEN,
> + qedi_conn->gen_pdu.req_buf,
> + qedi_conn->gen_pdu.req_dma_addr);
> + qedi_conn->gen_pdu.req_buf = NULL;
> +login_req_buf_failure:
> + iscsi_conn_printk(KERN_ERR, qedi_conn->cls_conn->dd_data,
> + "login resource alloc failed!!\n");
> + return -ENOMEM;
> +}
> +
> +static void qedi_destroy_cmd_pool(struct qedi_ctx *qedi,
> + struct iscsi_session *session)
> +{
> + int i;
> +
> + for (i = 0; i < session->cmds_max; i++) {
> + struct iscsi_task *task = session->cmds[i];
> + struct qedi_cmd *cmd = task->dd_data;
> +
> + if (cmd->io_tbl.sge_tbl)
> + dma_free_coherent(&qedi->pdev->dev,
> + QEDI_ISCSI_MAX_BDS_PER_CMD *
> + sizeof(struct iscsi_sge),
> + cmd->io_tbl.sge_tbl,
> + cmd->io_tbl.sge_tbl_dma);
> +
> + if (cmd->sense_buffer)
> + dma_free_coherent(&qedi->pdev->dev,
> + SCSI_SENSE_BUFFERSIZE,
> + cmd->sense_buffer,
> + cmd->sense_buffer_dma);
> + }
> +}
> +
> +static int qedi_alloc_sget(struct qedi_ctx *qedi, struct iscsi_session *session,
> + struct qedi_cmd *cmd)
> +{
> + struct qedi_io_bdt *io = &cmd->io_tbl;
> + struct iscsi_sge *sge;
> +
> + io->sge_tbl = dma_alloc_coherent(&qedi->pdev->dev,
> + QEDI_ISCSI_MAX_BDS_PER_CMD *
> + sizeof(*sge),
> + &io->sge_tbl_dma, GFP_KERNEL);
> + if (!io->sge_tbl) {
> + iscsi_session_printk(KERN_ERR, session,
> + "Could not allocate BD table.\n");
> + return -ENOMEM;
> + }
> +
> + io->sge_valid = 0;
> + return 0;
> +}
> +
> +static int qedi_setup_cmd_pool(struct qedi_ctx *qedi,
> + struct iscsi_session *session)
> +{
> + int i;
> +
> + for (i = 0; i < session->cmds_max; i++) {
> + struct iscsi_task *task = session->cmds[i];
> + struct qedi_cmd *cmd = task->dd_data;
> +
> + task->hdr = &cmd->hdr;
> + task->hdr_max = sizeof(struct iscsi_hdr);
> +
> + if (qedi_alloc_sget(qedi, session, cmd))
> + goto free_sgets;
> +
> + cmd->sense_buffer = dma_alloc_coherent(&qedi->pdev->dev,
> + SCSI_SENSE_BUFFERSIZE,
> + &cmd->sense_buffer_dma,
> + GFP_KERNEL);
> + if (!cmd->sense_buffer)
> + goto free_sgets;
> + }
> +
> + return 0;
> +
> +free_sgets:
> + qedi_destroy_cmd_pool(qedi, session);
> + return -ENOMEM;
> +}
> +
> +static struct iscsi_cls_session *
> +qedi_session_create(struct iscsi_endpoint *ep, u16 cmds_max,
> + u16 qdepth, uint32_t initial_cmdsn)
> +{
> + struct Scsi_Host *shost;
> + struct iscsi_cls_session *cls_session;
> + struct qedi_ctx *qedi;
> + struct qedi_endpoint *qedi_ep;
> +
> + if (!ep)
> + return NULL;
> +
> + qedi_ep = ep->dd_data;
> + shost = qedi_ep->qedi->shost;
> + qedi = iscsi_host_priv(shost);
> +
> + if (cmds_max > qedi->max_sqes)
> + cmds_max = qedi->max_sqes;
> + else if (cmds_max < QEDI_SQ_WQES_MIN)
> + cmds_max = QEDI_SQ_WQES_MIN;
> +
> + cls_session = iscsi_session_setup(&qedi_iscsi_transport, shost,
> + cmds_max, 0, sizeof(struct qedi_cmd),
> + initial_cmdsn, ISCSI_MAX_TARGET);
> + if (!cls_session) {
> + QEDI_ERR(&qedi->dbg_ctx,
> + "Failed to setup session for ep=%p\n", qedi_ep);
> + return NULL;
> + }
> +
> + if (qedi_setup_cmd_pool(qedi, cls_session->dd_data)) {
> + QEDI_ERR(&qedi->dbg_ctx,
> + "Failed to setup cmd pool for ep=%p\n", qedi_ep);
> + goto session_teardown;
> + }
> +
> + return cls_session;
> +
> +session_teardown:
> + iscsi_session_teardown(cls_session);
> + return NULL;
> +}
> +
> +static void qedi_session_destroy(struct iscsi_cls_session *cls_session)
> +{
> + struct iscsi_session *session = cls_session->dd_data;
> + struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
> + struct qedi_ctx *qedi = iscsi_host_priv(shost);
> +
> + qedi_destroy_cmd_pool(qedi, session);
> + iscsi_session_teardown(cls_session);
> +}
> +
> +static struct iscsi_cls_conn *
> +qedi_conn_create(struct iscsi_cls_session *cls_session, uint32_t cid)
> +{
> + struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
> + struct qedi_ctx *qedi = iscsi_host_priv(shost);
> + struct iscsi_cls_conn *cls_conn;
> + struct qedi_conn *qedi_conn;
> + struct iscsi_conn *conn;
> +
> + cls_conn = iscsi_conn_setup(cls_session, sizeof(*qedi_conn),
> + cid);
> + if (!cls_conn) {
> + QEDI_ERR(&qedi->dbg_ctx,
> + "conn_new: iscsi conn setup failed, cid=0x%x, cls_sess=%p!\n",
> + cid, cls_session);
> + return NULL;
> + }
> +
> + conn = cls_conn->dd_data;
> + qedi_conn = conn->dd_data;
> + qedi_conn->cls_conn = cls_conn;
> + qedi_conn->qedi = qedi;
> + qedi_conn->ep = NULL;
> + qedi_conn->active_cmd_count = 0;
> + INIT_LIST_HEAD(&qedi_conn->active_cmd_list);
> + spin_lock_init(&qedi_conn->list_lock);
> +
> + if (qedi_conn_alloc_login_resources(qedi, qedi_conn)) {
> + iscsi_conn_printk(KERN_ALERT, conn,
> + "conn_new: login resc alloc failed, cid=0x%x, cls_sess=%p!!\n",
> + cid, cls_session);
> + goto free_conn;
> + }
> +
> + return cls_conn;
> +
> +free_conn:
> + iscsi_conn_teardown(cls_conn);
> + return NULL;
> +}
> +
> +void qedi_mark_device_missing(struct iscsi_cls_session *cls_session)
> +{
> + iscsi_block_session(cls_session);
> +}
> +
> +void qedi_mark_device_available(struct iscsi_cls_session *cls_session)
> +{
> + iscsi_unblock_session(cls_session);
> +}
> +
> +static int qedi_bind_conn_to_iscsi_cid(struct qedi_ctx *qedi,
> + struct qedi_conn *qedi_conn)
> +{
> + u32 iscsi_cid = qedi_conn->iscsi_conn_id;
> +
> + if (qedi->cid_que.conn_cid_tbl[iscsi_cid]) {
> + iscsi_conn_printk(KERN_ALERT, qedi_conn->cls_conn->dd_data,
> + "conn bind - entry #%d not free\n",
> + iscsi_cid);
> + return -EBUSY;
> + }
> +
> + qedi->cid_que.conn_cid_tbl[iscsi_cid] = qedi_conn;
> + return 0;
> +}
> +
> +struct qedi_conn *qedi_get_conn_from_id(struct qedi_ctx *qedi, u32 iscsi_cid)
> +{
> + if (!qedi->cid_que.conn_cid_tbl) {
> + QEDI_ERR(&qedi->dbg_ctx, "missing conn<->cid table\n");
> + return NULL;
> +
> + } else if (iscsi_cid >= qedi->max_active_conns) {
> + QEDI_ERR(&qedi->dbg_ctx, "wrong cid #%d\n", iscsi_cid);
> + return NULL;
> + }
> + return qedi->cid_que.conn_cid_tbl[iscsi_cid];
> +}
> +
> +static int qedi_conn_bind(struct iscsi_cls_session *cls_session,
> + struct iscsi_cls_conn *cls_conn,
> + u64 transport_fd, int is_leading)
> +{
> + struct iscsi_conn *conn = cls_conn->dd_data;
> + struct qedi_conn *qedi_conn = conn->dd_data;
> + struct Scsi_Host *shost = iscsi_session_to_shost(cls_session);
> + struct qedi_ctx *qedi = iscsi_host_priv(shost);
> + struct qedi_endpoint *qedi_ep;
> + struct iscsi_endpoint *ep;
> +
> + ep = iscsi_lookup_endpoint(transport_fd);
> + if (!ep)
> + return -EINVAL;
> +
> + qedi_ep = ep->dd_data;
> + if ((qedi_ep->state == EP_STATE_TCP_FIN_RCVD) ||
> + (qedi_ep->state == EP_STATE_TCP_RST_RCVD))
> + return -EINVAL;
> +
> + if (iscsi_conn_bind(cls_session, cls_conn, is_leading))
> + return -EINVAL;
> +
> + qedi_ep->conn = qedi_conn;
> + qedi_conn->ep = qedi_ep;
> + qedi_conn->iscsi_conn_id = qedi_ep->iscsi_cid;
> + qedi_conn->fw_cid = qedi_ep->fw_cid;
> + qedi_conn->cmd_cleanup_req = 0;
> + qedi_conn->cmd_cleanup_cmpl = 0;
> +
> + if (qedi_bind_conn_to_iscsi_cid(qedi, qedi_conn))
> + return -EINVAL;
> +
> + spin_lock_init(&qedi_conn->tmf_work_lock);
> + INIT_LIST_HEAD(&qedi_conn->tmf_work_list);
> + init_waitqueue_head(&qedi_conn->wait_queue);
> + return 0;
> +}
> +
> +static int qedi_iscsi_update_conn(struct qedi_ctx *qedi,
> + struct qedi_conn *qedi_conn)
> +{
> + struct qed_iscsi_params_update *conn_info;
> + struct iscsi_cls_conn *cls_conn = qedi_conn->cls_conn;
> + struct iscsi_conn *conn = cls_conn->dd_data;
> + struct qedi_endpoint *qedi_ep;
> + int rval;
> +
> + qedi_ep = qedi_conn->ep;
> +
> + conn_info = kzalloc(sizeof(*conn_info), GFP_KERNEL);
> + if (!conn_info) {
> + QEDI_ERR(&qedi->dbg_ctx, "memory alloc failed\n");
> + return -ENOMEM;
> + }
> +
> + conn_info->update_flag = 0;
> +
> + if (conn->hdrdgst_en)
> + SET_FIELD(conn_info->update_flag,
> + ISCSI_CONN_UPDATE_RAMROD_PARAMS_HD_EN, true);
> + if (conn->datadgst_en)
> + SET_FIELD(conn_info->update_flag,
> + ISCSI_CONN_UPDATE_RAMROD_PARAMS_DD_EN, true);
> + if (conn->session->initial_r2t_en)
> + SET_FIELD(conn_info->update_flag,
> + ISCSI_CONN_UPDATE_RAMROD_PARAMS_INITIAL_R2T,
> + true);
> + if (conn->session->imm_data_en)
> + SET_FIELD(conn_info->update_flag,
> + ISCSI_CONN_UPDATE_RAMROD_PARAMS_IMMEDIATE_DATA,
> + true);
> +
> + conn_info->max_seq_size = conn->session->max_burst;
> + conn_info->max_recv_pdu_length = conn->max_recv_dlength;
> + conn_info->max_send_pdu_length = conn->max_xmit_dlength;
> + conn_info->first_seq_length = conn->session->first_burst;
> + conn_info->exp_stat_sn = conn->exp_statsn;
> +
> + rval = qedi_ops->update_conn(qedi->cdev, qedi_ep->handle,
> + conn_info);
> + if (rval) {
> + rval = -ENXIO;
> + QEDI_ERR(&qedi->dbg_ctx, "Could not update connection\n");
> + goto update_conn_err;
> + }
> +
> + kfree(conn_info);
> + rval = 0;
> +
> +update_conn_err:
> + return rval;
> +}
> +
> +static u16 qedi_calc_mss(u16 pmtu, u8 is_ipv6, u8 tcp_ts_en, u8 vlan_en)
> +{
> + u16 mss = 0;
> + u16 hdrs = TCP_HDR_LEN;
> +
> + if (is_ipv6)
> + hdrs += IPV6_HDR_LEN;
> + else
> + hdrs += IPV4_HDR_LEN;
> +
> + if (vlan_en)
> + hdrs += VLAN_LEN;
> +
> + mss = pmtu - hdrs;
> +
> + if (tcp_ts_en)
> + mss -= TCP_OPTION_LEN;
> +
> + if (!mss)
> + mss = DEF_MSS;
> +
> + return mss;
> +}
> +
> +static int qedi_iscsi_offload_conn(struct qedi_endpoint *qedi_ep)
> +{
> + struct qedi_ctx *qedi = qedi_ep->qedi;
> + struct qed_iscsi_params_offload *conn_info;
> + int rval;
> + int i;
> +
> + conn_info = kzalloc(sizeof(*conn_info), GFP_KERNEL);
> + if (!conn_info) {
> + QEDI_ERR(&qedi->dbg_ctx,
> + "Failed to allocate memory ep=%p\n", qedi_ep);
> + return -ENOMEM;
> + }
> +
> + ether_addr_copy(conn_info->src.mac, qedi_ep->src_mac);
> + ether_addr_copy(conn_info->dst.mac, qedi_ep->dst_mac);
> +
> + conn_info->src.ip[0] = ntohl(qedi_ep->src_addr[0]);
> + conn_info->dst.ip[0] = ntohl(qedi_ep->dst_addr[0]);
> +
> + if (qedi_ep->ip_type == TCP_IPV4) {
> + conn_info->ip_version = 0;
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
> + "After ntohl: src_addr=%pI4, dst_addr=%pI4\n",
> + qedi_ep->src_addr, qedi_ep->dst_addr);
> + } else {
> + for (i = 1; i < 4; i++) {
> + conn_info->src.ip[i] = ntohl(qedi_ep->src_addr[i]);
> + conn_info->dst.ip[i] = ntohl(qedi_ep->dst_addr[i]);
> + }
> +
> + conn_info->ip_version = 1;
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
> + "After ntohl: src_addr=%pI6, dst_addr=%pI6\n",
> + qedi_ep->src_addr, qedi_ep->dst_addr);
> + }
> +
> + conn_info->src.port = qedi_ep->src_port;
> + conn_info->dst.port = qedi_ep->dst_port;
> +
> + conn_info->layer_code = ISCSI_SLOW_PATH_LAYER_CODE;
> + conn_info->sq_pbl_addr = qedi_ep->sq_pbl_dma;
> + conn_info->vlan_id = qedi_ep->vlan_id;
> +
> + SET_FIELD(conn_info->tcp_flags, TCP_OFFLOAD_PARAMS_TS_EN, 1);
> + SET_FIELD(conn_info->tcp_flags, TCP_OFFLOAD_PARAMS_DA_EN, 1);
> + SET_FIELD(conn_info->tcp_flags, TCP_OFFLOAD_PARAMS_DA_CNT_EN, 1);
> + SET_FIELD(conn_info->tcp_flags, TCP_OFFLOAD_PARAMS_KA_EN, 1);
> +
> + conn_info->default_cq = (qedi_ep->fw_cid % 8);
> +
> + conn_info->ka_max_probe_cnt = DEF_KA_MAX_PROBE_COUNT;
> + conn_info->dup_ack_theshold = 3;
> + conn_info->rcv_wnd = 65535;
> + conn_info->cwnd = DEF_MAX_CWND;
> +
> + conn_info->ss_thresh = 65535;
> + conn_info->srtt = 300;
> + conn_info->rtt_var = 150;
> + conn_info->flow_label = 0;
> + conn_info->ka_timeout = DEF_KA_TIMEOUT;
> + conn_info->ka_interval = DEF_KA_INTERVAL;
> + conn_info->max_rt_time = DEF_MAX_RT_TIME;
> + conn_info->ttl = DEF_TTL;
> + conn_info->tos_or_tc = DEF_TOS;
> + conn_info->remote_port = qedi_ep->dst_port;
> + conn_info->local_port = qedi_ep->src_port;
> +
> + conn_info->mss = qedi_calc_mss(qedi_ep->pmtu,
> + (qedi_ep->ip_type == TCP_IPV6),
> + 1, (qedi_ep->vlan_id != 0));
> +
> + conn_info->rcv_wnd_scale = 4;
> + conn_info->ts_ticks_per_second = 1000;
> + conn_info->da_timeout_value = 200;
> + conn_info->ack_frequency = 2;
> +
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
> + "Default cq index [%d], mss [%d]\n",
> + conn_info->default_cq, conn_info->mss);
> +
> + rval = qedi_ops->offload_conn(qedi->cdev, qedi_ep->handle, conn_info);
> + if (rval)
> + QEDI_ERR(&qedi->dbg_ctx, "offload_conn returned %d, ep=%p\n",
> + rval, qedi_ep);
> +
> + kfree(conn_info);
> + return rval;
> +}
> +
> +static int qedi_conn_start(struct iscsi_cls_conn *cls_conn)
> +{
> + struct iscsi_conn *conn = cls_conn->dd_data;
> + struct qedi_conn *qedi_conn = conn->dd_data;
> + struct qedi_ctx *qedi;
> + int rval;
> +
> + qedi = qedi_conn->qedi;
> +
> + rval = qedi_iscsi_update_conn(qedi, qedi_conn);
> + if (rval) {
> + iscsi_conn_printk(KERN_ALERT, conn,
> + "conn_start: FW oflload conn failed.\n");
> + rval = -EINVAL;
> + goto start_err;
> + }
> +
> + clear_bit(QEDI_CONN_FW_CLEANUP, &qedi_conn->flags);
> + qedi_conn->abrt_conn = 0;
> +
> + rval = iscsi_conn_start(cls_conn);
> + if (rval) {
> + iscsi_conn_printk(KERN_ALERT, conn,
> + "iscsi_conn_start: FW oflload conn failed!!\n");
> + }
> +
> +start_err:
> + return rval;
> +}
> +
> +static void qedi_conn_destroy(struct iscsi_cls_conn *cls_conn)
> +{
> + struct iscsi_conn *conn = cls_conn->dd_data;
> + struct qedi_conn *qedi_conn = conn->dd_data;
> + struct Scsi_Host *shost;
> + struct qedi_ctx *qedi;
> +
> + shost = iscsi_session_to_shost(iscsi_conn_to_session(cls_conn));
> + qedi = iscsi_host_priv(shost);
> +
> + qedi_conn_free_login_resources(qedi, qedi_conn);
> + iscsi_conn_teardown(cls_conn);
> +}
> +
> +static int qedi_ep_get_param(struct iscsi_endpoint *ep,
> + enum iscsi_param param, char *buf)
> +{
> + struct qedi_endpoint *qedi_ep = ep->dd_data;
> + int len;
> +
> + if (!qedi_ep)
> + return -ENOTCONN;
> +
> + switch (param) {
> + case ISCSI_PARAM_CONN_PORT:
> + len = sprintf(buf, "%hu\n", qedi_ep->dst_port);
> + break;
> + case ISCSI_PARAM_CONN_ADDRESS:
> + if (qedi_ep->ip_type == TCP_IPV4)
> + len = sprintf(buf, "%pI4\n", qedi_ep->dst_addr);
> + else
> + len = sprintf(buf, "%pI6\n", qedi_ep->dst_addr);
> + break;
> + default:
> + return -ENOTCONN;
> + }
> +
> + return len;
> +}
> +
> +static int qedi_host_get_param(struct Scsi_Host *shost,
> + enum iscsi_host_param param, char *buf)
> +{
> + struct qedi_ctx *qedi;
> + int len;
> +
> + qedi = iscsi_host_priv(shost);
> +
> + switch (param) {
> + case ISCSI_HOST_PARAM_HWADDRESS:
> + len = sysfs_format_mac(buf, qedi->mac, 6);
> + break;
> + case ISCSI_HOST_PARAM_NETDEV_NAME:
> + len = sprintf(buf, "host%d\n", shost->host_no);
> + break;
> + case ISCSI_HOST_PARAM_IPADDRESS:
> + if (qedi->ip_type == TCP_IPV4)
> + len = sprintf(buf, "%pI4\n", qedi->src_ip);
> + else
> + len = sprintf(buf, "%pI6\n", qedi->src_ip);
> + break;
> + default:
> + return iscsi_host_get_param(shost, param, buf);
> + }
> +
> + return len;
> +}
> +
> +static void qedi_conn_get_stats(struct iscsi_cls_conn *cls_conn,
> + struct iscsi_stats *stats)
> +{
> + struct iscsi_conn *conn = cls_conn->dd_data;
> + struct qed_iscsi_stats iscsi_stats;
> + struct Scsi_Host *shost;
> + struct qedi_ctx *qedi;
> +
> + shost = iscsi_session_to_shost(iscsi_conn_to_session(cls_conn));
> + qedi = iscsi_host_priv(shost);
> + qedi_ops->get_stats(qedi->cdev, &iscsi_stats);
> +
> + conn->txdata_octets = iscsi_stats.iscsi_tx_bytes_cnt;
> + conn->rxdata_octets = iscsi_stats.iscsi_rx_bytes_cnt;
> + conn->dataout_pdus_cnt = (uint32_t)iscsi_stats.iscsi_tx_data_pdu_cnt;
> + conn->datain_pdus_cnt = (uint32_t)iscsi_stats.iscsi_rx_data_pdu_cnt;
> + conn->r2t_pdus_cnt = (uint32_t)iscsi_stats.iscsi_rx_r2t_pdu_cnt;
> +
> + stats->txdata_octets = conn->txdata_octets;
> + stats->rxdata_octets = conn->rxdata_octets;
> + stats->scsicmd_pdus = conn->scsicmd_pdus_cnt;
> + stats->dataout_pdus = conn->dataout_pdus_cnt;
> + stats->scsirsp_pdus = conn->scsirsp_pdus_cnt;
> + stats->datain_pdus = conn->datain_pdus_cnt;
> + stats->r2t_pdus = conn->r2t_pdus_cnt;
> + stats->tmfcmd_pdus = conn->tmfcmd_pdus_cnt;
> + stats->tmfrsp_pdus = conn->tmfrsp_pdus_cnt;
> + stats->digest_err = 0;
> + stats->timeout_err = 0;
> + strcpy(stats->custom[0].desc, "eh_abort_cnt");
> + stats->custom[0].value = conn->eh_abort_cnt;
> + stats->custom_length = 1;
> +}
> +
> +static void qedi_iscsi_prep_generic_pdu_bd(struct qedi_conn *qedi_conn)
> +{
> + struct iscsi_sge *bd_tbl;
> +
> + bd_tbl = (struct iscsi_sge *)qedi_conn->gen_pdu.req_bd_tbl;
> +
> + bd_tbl->sge_addr.hi =
> + (u32)((u64)qedi_conn->gen_pdu.req_dma_addr >> 32);
> + bd_tbl->sge_addr.lo = (u32)qedi_conn->gen_pdu.req_dma_addr;
> + bd_tbl->sge_len = qedi_conn->gen_pdu.req_wr_ptr -
> + qedi_conn->gen_pdu.req_buf;
> + bd_tbl->reserved0 = 0;
> + bd_tbl = (struct iscsi_sge *)qedi_conn->gen_pdu.resp_bd_tbl;
> + bd_tbl->sge_addr.hi =
> + (u32)((u64)qedi_conn->gen_pdu.resp_dma_addr >> 32);
> + bd_tbl->sge_addr.lo = (u32)qedi_conn->gen_pdu.resp_dma_addr;
> + bd_tbl->sge_len = ISCSI_DEF_MAX_RECV_SEG_LEN;
> + bd_tbl->reserved0 = 0;
> +}
> +
> +static int qedi_iscsi_send_generic_request(struct iscsi_task *task)
> +{
> + struct qedi_cmd *cmd = task->dd_data;
> + struct qedi_conn *qedi_conn = cmd->conn;
> + char *buf;
> + int data_len;
> + int rc = 0;
> +
> + qedi_iscsi_prep_generic_pdu_bd(qedi_conn);
> + switch (task->hdr->opcode & ISCSI_OPCODE_MASK) {
> + case ISCSI_OP_LOGIN:
> + qedi_send_iscsi_login(qedi_conn, task);
> + break;
> + case ISCSI_OP_NOOP_OUT:
> + data_len = qedi_conn->gen_pdu.req_buf_size;
> + buf = qedi_conn->gen_pdu.req_buf;
> + if (data_len)
> + rc = qedi_send_iscsi_nopout(qedi_conn, task,
> + buf, data_len, 1);
> + else
> + rc = qedi_send_iscsi_nopout(qedi_conn, task,
> + NULL, 0, 1);
> + break;
> + case ISCSI_OP_LOGOUT:
> + rc = qedi_send_iscsi_logout(qedi_conn, task);
> + break;
> + case ISCSI_OP_TEXT:
> + rc = qedi_send_iscsi_text(qedi_conn, task);
> + break;
> + default:
> + iscsi_conn_printk(KERN_ALERT, qedi_conn->cls_conn->dd_data,
> + "unsupported op 0x%x\n", task->hdr->opcode);
> + }
> +
> + return rc;
> +}
> +
> +static int qedi_mtask_xmit(struct iscsi_conn *conn, struct iscsi_task *task)
> +{
> + struct qedi_conn *qedi_conn = conn->dd_data;
> + struct qedi_cmd *cmd = task->dd_data;
> +
> + memset(qedi_conn->gen_pdu.req_buf, 0, ISCSI_DEF_MAX_RECV_SEG_LEN);
> +
> + qedi_conn->gen_pdu.req_buf_size = task->data_count;
> +
> + if (task->data_count) {
> + memcpy(qedi_conn->gen_pdu.req_buf, task->data,
> + task->data_count);
> + qedi_conn->gen_pdu.req_wr_ptr =
> + qedi_conn->gen_pdu.req_buf + task->data_count;
> + }
> +
> + cmd->conn = conn->dd_data;
> + cmd->scsi_cmd = NULL;
> + return qedi_iscsi_send_generic_request(task);
> +}
> +
> +static int qedi_task_xmit(struct iscsi_task *task)
> +{
> + struct iscsi_conn *conn = task->conn;
> + struct qedi_conn *qedi_conn = conn->dd_data;
> + struct qedi_cmd *cmd = task->dd_data;
> + struct scsi_cmnd *sc = task->sc;
> +
> + cmd->state = 0;
> + cmd->task = NULL;
> + cmd->use_slowpath = false;
> + cmd->conn = qedi_conn;
> + cmd->task = task;
> + cmd->io_cmd_in_list = false;
> + INIT_LIST_HEAD(&cmd->io_cmd);
> +
> + if (!sc)
> + return qedi_mtask_xmit(conn, task);
> +}
> +
> +static struct iscsi_endpoint *
> +qedi_ep_connect(struct Scsi_Host *shost, struct sockaddr *dst_addr,
> + int non_blocking)
> +{
> + struct qedi_ctx *qedi;
> + struct iscsi_endpoint *ep;
> + struct qedi_endpoint *qedi_ep;
> + struct sockaddr_in *addr;
> + struct sockaddr_in6 *addr6;
> + struct qed_dev *cdev = NULL;
> + struct qedi_uio_dev *udev = NULL;
> + struct iscsi_path path_req;
> + u32 msg_type = ISCSI_KEVENT_IF_DOWN;
> + u32 iscsi_cid = QEDI_CID_RESERVED;
> + u16 len = 0;
> + char *buf = NULL;
> + int ret;
> +
> + if (!shost) {
> + ret = -ENXIO;
> + QEDI_ERR(NULL, "shost is NULL\n");
> + return ERR_PTR(ret);
> + }
> +
> + if (do_not_recover) {
> + ret = -ENOMEM;
> + return ERR_PTR(ret);
> + }
> +
> + qedi = iscsi_host_priv(shost);
> + cdev = qedi->cdev;
> + udev = qedi->udev;
> +
> + if (test_bit(QEDI_IN_OFFLINE, &qedi->flags) ||
> + test_bit(QEDI_IN_RECOVERY, &qedi->flags)) {
> + ret = -ENOMEM;
> + return ERR_PTR(ret);
> + }
> +
> + ep = iscsi_create_endpoint(sizeof(struct qedi_endpoint));
> + if (!ep) {
> + QEDI_ERR(&qedi->dbg_ctx, "endpoint create fail\n");
> + ret = -ENOMEM;
> + return ERR_PTR(ret);
> + }
> + qedi_ep = ep->dd_data;
> + memset(qedi_ep, 0, sizeof(struct qedi_endpoint));
> + qedi_ep->state = EP_STATE_IDLE;
> + qedi_ep->iscsi_cid = (u32)-1;
> + qedi_ep->qedi = qedi;
> +
> + if (dst_addr->sa_family == AF_INET) {
> + addr = (struct sockaddr_in *)dst_addr;
> + memcpy(qedi_ep->dst_addr, &addr->sin_addr.s_addr,
> + sizeof(struct in_addr));
> + qedi_ep->dst_port = ntohs(addr->sin_port);
> + qedi_ep->ip_type = TCP_IPV4;
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
> + "dst_addr=%pI4, dst_port=%u\n",
> + qedi_ep->dst_addr, qedi_ep->dst_port);
> + } else if (dst_addr->sa_family == AF_INET6) {
> + addr6 = (struct sockaddr_in6 *)dst_addr;
> + memcpy(qedi_ep->dst_addr, &addr6->sin6_addr,
> + sizeof(struct in6_addr));
> + qedi_ep->dst_port = ntohs(addr6->sin6_port);
> + qedi_ep->ip_type = TCP_IPV6;
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
> + "dst_addr=%pI6, dst_port=%u\n",
> + qedi_ep->dst_addr, qedi_ep->dst_port);
> + } else {
> + QEDI_ERR(&qedi->dbg_ctx, "Invalid endpoint\n");
> + }
> +
> + if (atomic_read(&qedi->link_state) != QEDI_LINK_UP) {
> + QEDI_WARN(&qedi->dbg_ctx, "qedi link down\n");
> + ret = -ENXIO;
> + goto ep_conn_exit;
> + }
> +
> + ret = qedi_alloc_sq(qedi, qedi_ep);
> + if (ret)
> + goto ep_conn_exit;
> +
> + ret = qedi_ops->acquire_conn(qedi->cdev, &qedi_ep->handle,
> + &qedi_ep->fw_cid, &qedi_ep->p_doorbell);
> +
> + if (ret) {
> + QEDI_ERR(&qedi->dbg_ctx, "Could not acquire connection\n");
> + ret = -ENXIO;
> + goto ep_free_sq;
> + }
> +
> + iscsi_cid = qedi_ep->handle;
> + qedi_ep->iscsi_cid = iscsi_cid;
> +
> + init_waitqueue_head(&qedi_ep->ofld_wait);
> + init_waitqueue_head(&qedi_ep->tcp_ofld_wait);
> + qedi_ep->state = EP_STATE_OFLDCONN_START;
> + qedi->ep_tbl[iscsi_cid] = qedi_ep;
> +
> + buf = (char *)&path_req;
> + len = sizeof(path_req);
> + memset(&path_req, 0, len);
> +
> + msg_type = ISCSI_KEVENT_PATH_REQ;
> + path_req.handle = (u64)qedi_ep->iscsi_cid;
> + path_req.pmtu = qedi->ll2_mtu;
> + qedi_ep->pmtu = qedi->ll2_mtu;
> + if (qedi_ep->ip_type == TCP_IPV4) {
> + memcpy(&path_req.dst.v4_addr, &qedi_ep->dst_addr,
> + sizeof(struct in_addr));
> + path_req.ip_addr_len = 4;
> + } else {
> + memcpy(&path_req.dst.v6_addr, &qedi_ep->dst_addr,
> + sizeof(struct in6_addr));
> + path_req.ip_addr_len = 16;
> + }
> +
> + ret = iscsi_offload_mesg(shost, &qedi_iscsi_transport, msg_type, buf,
> + len);
> + if (ret) {
> + QEDI_ERR(&qedi->dbg_ctx,
> + "iscsi_offload_mesg() failed for cid=0x%x ret=%d\n",
> + iscsi_cid, ret);
> + goto ep_rel_conn;
> + }
> +
> + atomic_inc(&qedi->num_offloads);
> + return ep;
> +
> +ep_rel_conn:
> + qedi->ep_tbl[iscsi_cid] = NULL;
> + ret = qedi_ops->release_conn(qedi->cdev, qedi_ep->handle);
> + if (ret)
> + QEDI_WARN(&qedi->dbg_ctx, "release_conn returned %d\n",
> + ret);
> +ep_free_sq:
> + qedi_free_sq(qedi, qedi_ep);
> +ep_conn_exit:
> + iscsi_destroy_endpoint(ep);
> + return ERR_PTR(ret);
> +}
> +
> +static int qedi_ep_poll(struct iscsi_endpoint *ep, int timeout_ms)
> +{
> + struct qedi_endpoint *qedi_ep;
> + int ret = 0;
> +
> + if (do_not_recover)
> + return 1;
> +
> + qedi_ep = ep->dd_data;
> + if (qedi_ep->state == EP_STATE_IDLE ||
> + qedi_ep->state == EP_STATE_OFLDCONN_FAILED)
> + return -1;
> +
> + if (qedi_ep->state == EP_STATE_OFLDCONN_COMPL)
> + ret = 1;
> +
> + ret = wait_event_interruptible_timeout(qedi_ep->ofld_wait,
> + ((qedi_ep->state ==
> + EP_STATE_OFLDCONN_FAILED) ||
> + (qedi_ep->state ==
> + EP_STATE_OFLDCONN_COMPL)),
> + msecs_to_jiffies(timeout_ms));
> +
> + if (qedi_ep->state == EP_STATE_OFLDCONN_FAILED)
> + ret = -1;
> +
> + if (ret > 0)
> + return 1;
> + else if (!ret)
> + return 0;
> + else
> + return ret;
> +}
> +
> +static void qedi_cleanup_active_cmd_list(struct qedi_conn *qedi_conn)
> +{
> + struct qedi_cmd *cmd, *cmd_tmp;
> +
> + list_for_each_entry_safe(cmd, cmd_tmp, &qedi_conn->active_cmd_list,
> + io_cmd) {
> + list_del_init(&cmd->io_cmd);
> + qedi_conn->active_cmd_count--;
> + }
> +}
> +
> +static void qedi_ep_disconnect(struct iscsi_endpoint *ep)
> +{
> + struct qedi_endpoint *qedi_ep;
> + struct qedi_conn *qedi_conn = NULL;
> + struct iscsi_conn *conn = NULL;
> + struct qedi_ctx *qedi;
> + int ret = 0;
> + int wait_delay = 20 * HZ;
> + int abrt_conn = 0;
> + int count = 10;
> +
> + qedi_ep = ep->dd_data;
> + qedi = qedi_ep->qedi;
> +
> + flush_work(&qedi_ep->offload_work);
> +
> + if (qedi_ep->conn) {
> + qedi_conn = qedi_ep->conn;
> + conn = qedi_conn->cls_conn->dd_data;
> + iscsi_suspend_queue(conn);
> + abrt_conn = qedi_conn->abrt_conn;
> +
> + while (count--) {
> + if (!test_bit(QEDI_CONN_FW_CLEANUP,
> + &qedi_conn->flags)) {
> + break;
> + }
> + msleep(1000);
> + }
> +
> + if (test_bit(QEDI_IN_RECOVERY, &qedi->flags)) {
> + if (do_not_recover) {
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
> + "Do not recover cid=0x%x\n",
> + qedi_ep->iscsi_cid);
> + goto ep_exit_recover;
> + }
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
> + "Reset recovery cid=0x%x, qedi_ep=%p, state=0x%x\n",
> + qedi_ep->iscsi_cid, qedi_ep, qedi_ep->state);
> + qedi_cleanup_active_cmd_list(qedi_conn);
> + goto ep_release_conn;
> + }
> + }
> +
> + if (do_not_recover)
> + goto ep_exit_recover;
> +
> + switch (qedi_ep->state) {
> + case EP_STATE_OFLDCONN_START:
> + goto ep_release_conn;
> + case EP_STATE_OFLDCONN_FAILED:
> + break;
> + case EP_STATE_OFLDCONN_COMPL:
> + if (unlikely(!qedi_conn))
> + break;
> +
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
> + "Active cmd count=%d, abrt_conn=%d, ep state=0x%x, cid=0x%x, qedi_conn=%p\n",
> + qedi_conn->active_cmd_count, abrt_conn,
> + qedi_ep->state,
> + qedi_ep->iscsi_cid,
> + qedi_ep->conn
> + );
> +
> + if (!qedi_conn->active_cmd_count)
> + abrt_conn = 0;
> + else
> + abrt_conn = 1;
> +
> + if (abrt_conn)
> + qedi_clearsq(qedi, qedi_conn, NULL);
> + break;
> + default:
> + break;
> + }
> +
> + qedi_ep->state = EP_STATE_DISCONN_START;
> + ret = qedi_ops->destroy_conn(qedi->cdev, qedi_ep->handle, abrt_conn);
> + if (ret) {
> + QEDI_WARN(&qedi->dbg_ctx,
> + "destroy_conn failed returned %d\n", ret);
> + } else {
> + ret = wait_event_interruptible_timeout(
> + qedi_ep->tcp_ofld_wait,
> + (qedi_ep->state !=
> + EP_STATE_DISCONN_START),
> + wait_delay);
> + if ((ret <= 0) || (qedi_ep->state == EP_STATE_DISCONN_START)) {
> + QEDI_WARN(&qedi->dbg_ctx,
> + "Destroy conn timedout or interrupted, ret=%d, delay=%d, cid=0x%x\n",
> + ret, wait_delay, qedi_ep->iscsi_cid);
> + }
> + }
> +
> +ep_release_conn:
> + ret = qedi_ops->release_conn(qedi->cdev, qedi_ep->handle);
> + if (ret)
> + QEDI_WARN(&qedi->dbg_ctx,
> + "release_conn returned %d, cid=0x%x\n",
> + ret, qedi_ep->iscsi_cid);
> +ep_exit_recover:
> + qedi_ep->state = EP_STATE_IDLE;
> + qedi->ep_tbl[qedi_ep->iscsi_cid] = NULL;
> + qedi->cid_que.conn_cid_tbl[qedi_ep->iscsi_cid] = NULL;
> + qedi_free_id(&qedi->lcl_port_tbl, qedi_ep->src_port);
> + qedi_free_sq(qedi, qedi_ep);
> +
> + if (qedi_conn)
> + qedi_conn->ep = NULL;
> +
> + qedi_ep->conn = NULL;
> + qedi_ep->qedi = NULL;
> + atomic_dec(&qedi->num_offloads);
> +
> + iscsi_destroy_endpoint(ep);
> +}
> +
> +static int qedi_data_avail(struct qedi_ctx *qedi, u16 vlanid)
> +{
> + struct qed_dev *cdev = qedi->cdev;
> + struct qedi_uio_dev *udev;
> + struct qedi_uio_ctrl *uctrl;
> + struct sk_buff *skb;
> + u32 len;
> + int rc = 0;
> +
> + udev = qedi->udev;
> + if (!udev) {
> + QEDI_ERR(&qedi->dbg_ctx, "udev is NULL.\n");
> + return -EINVAL;
> + }
> +
> + uctrl = (struct qedi_uio_ctrl *)udev->uctrl;
> + if (!uctrl) {
> + QEDI_ERR(&qedi->dbg_ctx, "uctlr is NULL.\n");
> + return -EINVAL;
> + }
> +
> + len = uctrl->host_tx_pkt_len;
> + if (!len) {
> + QEDI_ERR(&qedi->dbg_ctx, "Invalid len %u\n", len);
> + return -EINVAL;
> + }
> +
> + skb = alloc_skb(len, GFP_ATOMIC);
> + if (!skb) {
> + QEDI_ERR(&qedi->dbg_ctx, "alloc_skb failed\n");
> + return -EINVAL;
> + }
> +
> + skb_put(skb, len);
> + memcpy(skb->data, udev->tx_pkt, len);
> + skb->ip_summed = CHECKSUM_NONE;
> +
> + if (vlanid)
> + __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), vlanid);
> +
> + rc = qedi_ops->ll2->start_xmit(cdev, skb);
> + if (rc) {
> + QEDI_ERR(&qedi->dbg_ctx, "ll2 start_xmit returned %d\n",
> + rc);
> + kfree_skb(skb);
> + }
> +
> + uctrl->host_tx_pkt_len = 0;
> + uctrl->hw_tx_cons++;
> +
> + return rc;
> +}
> +
> +static void qedi_offload_work(struct work_struct *work)
> +{
> + struct qedi_endpoint *qedi_ep =
> + container_of(work, struct qedi_endpoint, offload_work);
> + struct qedi_ctx *qedi;
> + int wait_delay = 20 * HZ;
> + int ret;
> +
> + qedi = qedi_ep->qedi;
> +
> + ret = qedi_iscsi_offload_conn(qedi_ep);
> + if (ret) {
> + QEDI_ERR(&qedi->dbg_ctx,
> + "offload error: iscsi_cid=%u, qedi_ep=%p, ret=%d\n",
> + qedi_ep->iscsi_cid, qedi_ep, ret);
> + qedi_ep->state = EP_STATE_OFLDCONN_FAILED;
> + return;
> + }
> +
> + ret = wait_event_interruptible_timeout(qedi_ep->tcp_ofld_wait,
> + (qedi_ep->state ==
> + EP_STATE_OFLDCONN_COMPL),
> + wait_delay);
> + if ((ret <= 0) || (qedi_ep->state != EP_STATE_OFLDCONN_COMPL)) {
> + qedi_ep->state = EP_STATE_OFLDCONN_FAILED;
> + QEDI_ERR(&qedi->dbg_ctx,
> + "Offload conn TIMEOUT iscsi_cid=%u, qedi_ep=%p\n",
> + qedi_ep->iscsi_cid, qedi_ep);
> + }
> +}
> +
> +static int qedi_set_path(struct Scsi_Host *shost, struct iscsi_path *path_data)
> +{
> + struct qedi_ctx *qedi;
> + struct qedi_endpoint *qedi_ep;
> + int ret = 0;
> + u32 iscsi_cid;
> + u16 port_id = 0;
> +
> + if (!shost) {
> + ret = -ENXIO;
> + QEDI_ERR(NULL, "shost is NULL\n");
> + return ret;
> + }
> +
> + if (strcmp(shost->hostt->proc_name, "qedi")) {
> + ret = -ENXIO;
> + QEDI_ERR(NULL, "shost %s is invalid\n",
> + shost->hostt->proc_name);
> + return ret;
> + }
> +
> + qedi = iscsi_host_priv(shost);
> + if (path_data->handle == QEDI_PATH_HANDLE) {
> + ret = qedi_data_avail(qedi, path_data->vlan_id);
> + goto set_path_exit;
> + }
> +
> + iscsi_cid = (u32)path_data->handle;
> + qedi_ep = qedi->ep_tbl[iscsi_cid];
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
> + "iscsi_cid=0x%x, qedi_ep=%p\n", iscsi_cid, qedi_ep);
> +
> + if (!is_valid_ether_addr(&path_data->mac_addr[0])) {
> + QEDI_NOTICE(&qedi->dbg_ctx, "dst mac NOT VALID\n");
> + ret = -EIO;
> + goto set_path_exit;
> + }
> +
> + ether_addr_copy(&qedi_ep->src_mac[0], &qedi->mac[0]);
> + ether_addr_copy(&qedi_ep->dst_mac[0], &path_data->mac_addr[0]);
> +
> + qedi_ep->vlan_id = path_data->vlan_id;
> + if (path_data->pmtu < DEF_PATH_MTU) {
> + qedi_ep->pmtu = qedi->ll2_mtu;
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO,
> + "MTU cannot be %u, using default MTU %u\n",
> + path_data->pmtu, qedi_ep->pmtu);
> + }
> +
> + if (path_data->pmtu != qedi->ll2_mtu) {
> + if (path_data->pmtu > JUMBO_MTU) {
> + ret = -EINVAL;
> + QEDI_ERR(NULL, "Invalid MTU %u\n", path_data->pmtu);
> + goto set_path_exit;
> + }
> +
> + qedi_reset_host_mtu(qedi, path_data->pmtu);
> + qedi_ep->pmtu = qedi->ll2_mtu;
> + }
> +
> + port_id = qedi_ep->src_port;
> + if (port_id >= QEDI_LOCAL_PORT_MIN &&
> + port_id < QEDI_LOCAL_PORT_MAX) {
> + if (qedi_alloc_id(&qedi->lcl_port_tbl, port_id))
> + port_id = 0;
> + } else {
> + port_id = 0;
> + }
> +
> + if (!port_id) {
> + port_id = qedi_alloc_new_id(&qedi->lcl_port_tbl);
> + if (port_id == QEDI_LOCAL_PORT_INVALID) {
> + QEDI_ERR(&qedi->dbg_ctx,
> + "Failed to allocate port id for iscsi_cid=0x%x\n",
> + iscsi_cid);
> + ret = -ENOMEM;
> + goto set_path_exit;
> + }
> + }
> +
> + qedi_ep->src_port = port_id;
> +
> + if (qedi_ep->ip_type == TCP_IPV4) {
> + memcpy(&qedi_ep->src_addr[0], &path_data->src.v4_addr,
> + sizeof(struct in_addr));
> + memcpy(&qedi->src_ip[0], &path_data->src.v4_addr,
> + sizeof(struct in_addr));
> + qedi->ip_type = TCP_IPV4;
> +
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
> + "src addr:port=%pI4:%u, dst addr:port=%pI4:%u\n",
> + qedi_ep->src_addr, qedi_ep->src_port,
> + qedi_ep->dst_addr, qedi_ep->dst_port);
> + } else {
> + memcpy(&qedi_ep->src_addr[0], &path_data->src.v6_addr,
> + sizeof(struct in6_addr));
> + memcpy(&qedi->src_ip[0], &path_data->src.v6_addr,
> + sizeof(struct in6_addr));
> + qedi->ip_type = TCP_IPV6;
> +
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
> + "src addr:port=%pI6:%u, dst addr:port=%pI6:%u\n",
> + qedi_ep->src_addr, qedi_ep->src_port,
> + qedi_ep->dst_addr, qedi_ep->dst_port);
> + }
> +
> + INIT_WORK(&qedi_ep->offload_work, qedi_offload_work);
> + queue_work(qedi->offload_thread, &qedi_ep->offload_work);
> +
> + ret = 0;
> +
> +set_path_exit:
> + return ret;
> +}
> +
> +static umode_t qedi_attr_is_visible(int param_type, int param)
> +{
> + switch (param_type) {
> + case ISCSI_HOST_PARAM:
> + switch (param) {
> + case ISCSI_HOST_PARAM_NETDEV_NAME:
> + case ISCSI_HOST_PARAM_HWADDRESS:
> + case ISCSI_HOST_PARAM_IPADDRESS:
> + return S_IRUGO;
> + default:
> + return 0;
> + }
> + case ISCSI_PARAM:
> + switch (param) {
> + case ISCSI_PARAM_MAX_RECV_DLENGTH:
> + case ISCSI_PARAM_MAX_XMIT_DLENGTH:
> + case ISCSI_PARAM_HDRDGST_EN:
> + case ISCSI_PARAM_DATADGST_EN:
> + case ISCSI_PARAM_CONN_ADDRESS:
> + case ISCSI_PARAM_CONN_PORT:
> + case ISCSI_PARAM_EXP_STATSN:
> + case ISCSI_PARAM_PERSISTENT_ADDRESS:
> + case ISCSI_PARAM_PERSISTENT_PORT:
> + case ISCSI_PARAM_PING_TMO:
> + case ISCSI_PARAM_RECV_TMO:
> + case ISCSI_PARAM_INITIAL_R2T_EN:
> + case ISCSI_PARAM_MAX_R2T:
> + case ISCSI_PARAM_IMM_DATA_EN:
> + case ISCSI_PARAM_FIRST_BURST:
> + case ISCSI_PARAM_MAX_BURST:
> + case ISCSI_PARAM_PDU_INORDER_EN:
> + case ISCSI_PARAM_DATASEQ_INORDER_EN:
> + case ISCSI_PARAM_ERL:
> + case ISCSI_PARAM_TARGET_NAME:
> + case ISCSI_PARAM_TPGT:
> + case ISCSI_PARAM_USERNAME:
> + case ISCSI_PARAM_PASSWORD:
> + case ISCSI_PARAM_USERNAME_IN:
> + case ISCSI_PARAM_PASSWORD_IN:
> + case ISCSI_PARAM_FAST_ABORT:
> + case ISCSI_PARAM_ABORT_TMO:
> + case ISCSI_PARAM_LU_RESET_TMO:
> + case ISCSI_PARAM_TGT_RESET_TMO:
> + case ISCSI_PARAM_IFACE_NAME:
> + case ISCSI_PARAM_INITIATOR_NAME:
> + case ISCSI_PARAM_BOOT_ROOT:
> + case ISCSI_PARAM_BOOT_NIC:
> + case ISCSI_PARAM_BOOT_TARGET:
> + return S_IRUGO;
> + default:
> + return 0;
> + }
> + }
> +
> + return 0;
> +}
> +
> +static void qedi_cleanup_task(struct iscsi_task *task)
> +{
> + if (!task->sc || task->state == ISCSI_TASK_PENDING) {
> + QEDI_INFO(NULL, QEDI_LOG_IO, "Returning ref_cnt=%d\n",
> + atomic_read(&task->refcount));
> + return;
> + }
> +
> + qedi_iscsi_unmap_sg_list(task->dd_data);
> +}
> +
> +struct iscsi_transport qedi_iscsi_transport = {
> + .owner = THIS_MODULE,
> + .name = QEDI_MODULE_NAME,
> + .caps = CAP_RECOVERY_L0 | CAP_HDRDGST | CAP_MULTI_R2T | CAP_DATADGST |
> + CAP_DATA_PATH_OFFLOAD | CAP_TEXT_NEGO,
> + .create_session = qedi_session_create,
> + .destroy_session = qedi_session_destroy,
> + .create_conn = qedi_conn_create,
> + .bind_conn = qedi_conn_bind,
> + .start_conn = qedi_conn_start,
> + .stop_conn = iscsi_conn_stop,
> + .destroy_conn = qedi_conn_destroy,
> + .set_param = iscsi_set_param,
> + .get_ep_param = qedi_ep_get_param,
> + .get_conn_param = iscsi_conn_get_param,
> + .get_session_param = iscsi_session_get_param,
> + .get_host_param = qedi_host_get_param,
> + .send_pdu = iscsi_conn_send_pdu,
> + .get_stats = qedi_conn_get_stats,
> + .xmit_task = qedi_task_xmit,
> + .cleanup_task = qedi_cleanup_task,
> + .session_recovery_timedout = iscsi_session_recovery_timedout,
> + .ep_connect = qedi_ep_connect,
> + .ep_poll = qedi_ep_poll,
> + .ep_disconnect = qedi_ep_disconnect,
> + .set_path = qedi_set_path,
> + .attr_is_visible = qedi_attr_is_visible,
> +};
> +
> +void qedi_start_conn_recovery(struct qedi_ctx *qedi,
> + struct qedi_conn *qedi_conn)
> +{
> + struct iscsi_cls_session *cls_sess;
> + struct iscsi_cls_conn *cls_conn;
> + struct iscsi_conn *conn;
> +
> + cls_conn = qedi_conn->cls_conn;
> + conn = cls_conn->dd_data;
> + cls_sess = iscsi_conn_to_session(cls_conn);
> +
> + if (iscsi_is_session_online(cls_sess)) {
> + qedi_conn->abrt_conn = 1;
> + QEDI_ERR(&qedi->dbg_ctx,
> + "Failing connection, state=0x%x, cid=0x%x\n",
> + conn->session->state, qedi_conn->iscsi_conn_id);
> + iscsi_conn_failure(qedi_conn->cls_conn->dd_data,
> + ISCSI_ERR_CONN_FAILED);
> + }
> +}
> +
> +void qedi_process_iscsi_error(struct qedi_endpoint *ep, struct async_data *data)
> +{
> + struct qedi_conn *qedi_conn;
> + struct qedi_ctx *qedi;
> + char warn_notice[] = "iscsi_warning";
> + char error_notice[] = "iscsi_error";
> + char *message;
> + int need_recovery = 0;
> + u32 err_mask = 0;
> + char msg[64];
> +
> + if (!ep)
> + return;
> +
> + qedi_conn = ep->conn;
> + if (!qedi_conn)
> + return;
> +
> + qedi = ep->qedi;
> +
> + QEDI_ERR(&qedi->dbg_ctx, "async event iscsi error:0x%x\n",
> + data->error_code);
> +
> + if (err_mask) {
> + need_recovery = 0;
> + message = warn_notice;
> + } else {
> + need_recovery = 1;
> + message = error_notice;
> + }
> +
> + switch (data->error_code) {
> + case ISCSI_STATUS_NONE:
> + strcpy(msg, "tcp_error none");
> + break;
> + case ISCSI_CONN_ERROR_TASK_CID_MISMATCH:
> + strcpy(msg, "task cid mismatch");
> + break;
> + case ISCSI_CONN_ERROR_TASK_NOT_VALID:
> + strcpy(msg, "invalid task");
> + break;
> + case ISCSI_CONN_ERROR_RQ_RING_IS_FULL:
> + strcpy(msg, "rq ring full");
> + break;
> + case ISCSI_CONN_ERROR_CMDQ_RING_IS_FULL:
> + strcpy(msg, "cmdq ring full");
> + break;
> + case ISCSI_CONN_ERROR_HQE_CACHING_FAILED:
> + strcpy(msg, "sge caching failed");
> + break;
> + case ISCSI_CONN_ERROR_HEADER_DIGEST_ERROR:
> + strcpy(msg, "hdr digest error");
> + break;
> + case ISCSI_CONN_ERROR_LOCAL_COMPLETION_ERROR:
> + strcpy(msg, "local cmpl error");
> + break;
> + case ISCSI_CONN_ERROR_DATA_OVERRUN:
> + strcpy(msg, "invalid task");
> + break;
> + case ISCSI_CONN_ERROR_OUT_OF_SGES_ERROR:
> + strcpy(msg, "out of sge error");
> + break;
> + case ISCSI_CONN_ERROR_TCP_SEG_PROC_IP_OPTIONS_ERROR:
> + strcpy(msg, "tcp seg ip options error");
> + break;
> + case ISCSI_CONN_ERROR_TCP_IP_FRAGMENT_ERROR:
> + strcpy(msg, "tcp ip fragment error");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_AHS_LEN:
> + strcpy(msg, "AHS len protocol error");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_ITT_OUT_OF_RANGE:
> + strcpy(msg, "itt out of range error");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_SEG_LEN_EXCEEDS_PDU_SIZE:
> + strcpy(msg, "data seg more than pdu size");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_INVALID_OPCODE:
> + strcpy(msg, "invalid opcode");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_INVALID_OPCODE_BEFORE_UPDATE:
> + strcpy(msg, "invalid opcode before update");
> + break;
> + case ISCSI_CONN_ERROR_UNVALID_NOPIN_DSL:
> + strcpy(msg, "unexpected opcode");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_R2T_CARRIES_NO_DATA:
> + strcpy(msg, "r2t carries no data");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_SN:
> + strcpy(msg, "data sn error");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_IN_TTT:
> + strcpy(msg, "data TTT error");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_R2T_TTT:
> + strcpy(msg, "r2t TTT error");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_R2T_BUFFER_OFFSET:
> + strcpy(msg, "buffer offset error");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_BUFFER_OFFSET_OOO:
> + strcpy(msg, "buffer offset ooo");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_R2T_SN:
> + strcpy(msg, "data seg len 0");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_0:
> + strcpy(msg, "data xer len error");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_1:
> + strcpy(msg, "data xer len1 error");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_DESIRED_DATA_TRNS_LEN_2:
> + strcpy(msg, "data xer len2 error");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_LUN:
> + strcpy(msg, "protocol lun error");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_F_BIT_ZERO:
> + strcpy(msg, "f bit zero error");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_F_BIT_ZERO_S_BIT_ONE:
> + strcpy(msg, "f bit zero s bit one error");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_EXP_STAT_SN:
> + strcpy(msg, "exp stat sn error");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_DSL_NOT_ZERO:
> + strcpy(msg, "dsl not zero error");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_INVALID_DSL:
> + strcpy(msg, "invalid dsl");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_DATA_SEG_LEN_TOO_BIG:
> + strcpy(msg, "data seg len too big");
> + break;
> + case ISCSI_CONN_ERROR_PROTOCOL_ERR_OUTSTANDING_R2T_COUNT:
> + strcpy(msg, "outstanding r2t count error");
> + break;
> + case ISCSI_CONN_ERROR_SENSE_DATA_LENGTH:
> + strcpy(msg, "sense datalen error");
> + break;
Please use an array for mapping values onto strings.
> + case ISCSI_ERROR_UNKNOWN:
> + default:
> + need_recovery = 0;
> + strcpy(msg, "unknown error");
> + break;
> + }
> + iscsi_conn_printk(KERN_ALERT,
> + qedi_conn->cls_conn->dd_data,
> + "qedi: %s - %s\n", message, msg);
> +
> + if (need_recovery)
> + qedi_start_conn_recovery(qedi_conn->qedi, qedi_conn);
> +}
> +
> +void qedi_process_tcp_error(struct qedi_endpoint *ep, struct async_data *data)
> +{
> + struct qedi_conn *qedi_conn;
> +
> + if (!ep)
> + return;
> +
> + qedi_conn = ep->conn;
> + if (!qedi_conn)
> + return;
> +
> + QEDI_ERR(&ep->qedi->dbg_ctx, "async event TCP error:0x%x\n",
> + data->error_code);
> +
> + qedi_start_conn_recovery(qedi_conn->qedi, qedi_conn);
> +}
> diff --git a/drivers/scsi/qedi/qedi_iscsi.h b/drivers/scsi/qedi/qedi_iscsi.h
> new file mode 100644
> index 0000000..6da1c90
> --- /dev/null
> +++ b/drivers/scsi/qedi/qedi_iscsi.h
> @@ -0,0 +1,228 @@
> +/*
> + * 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_ISCSI_H_
> +#define _QEDI_ISCSI_H_
> +
> +#include <linux/socket.h>
> +#include <linux/completion.h>
> +#include "qedi.h"
> +
> +#define ISCSI_MAX_SESS_PER_HBA 4096
> +
> +#define DEF_KA_TIMEOUT 7200000
> +#define DEF_KA_INTERVAL 10000
> +#define DEF_KA_MAX_PROBE_COUNT 10
> +#define DEF_TOS 0
> +#define DEF_TTL 0xfe
> +#define DEF_SND_SEQ_SCALE 0
> +#define DEF_RCV_BUF 0xffff
> +#define DEF_SND_BUF 0xffff
> +#define DEF_SEED 0
> +#define DEF_MAX_RT_TIME 8000
> +#define DEF_MAX_DA_COUNT 2
> +#define DEF_SWS_TIMER 1000
> +#define DEF_MAX_CWND 2
> +#define DEF_PATH_MTU 1500
> +#define DEF_MSS 1460
> +#define DEF_LL2_MTU 1560
> +#define JUMBO_MTU 9000
> +
> +#define MIN_MTU 576 /* rfc 793 */
> +#define IPV4_HDR_LEN 20
> +#define IPV6_HDR_LEN 40
> +#define TCP_HDR_LEN 20
> +#define TCP_OPTION_LEN 12
> +#define VLAN_LEN 4
> +
> +enum {
> + EP_STATE_IDLE = 0x0,
> + EP_STATE_ACQRCONN_START = 0x1,
> + EP_STATE_ACQRCONN_COMPL = 0x2,
> + EP_STATE_OFLDCONN_START = 0x4,
> + EP_STATE_OFLDCONN_COMPL = 0x8,
> + EP_STATE_DISCONN_START = 0x10,
> + EP_STATE_DISCONN_COMPL = 0x20,
> + EP_STATE_CLEANUP_START = 0x40,
> + EP_STATE_CLEANUP_CMPL = 0x80,
> + EP_STATE_TCP_FIN_RCVD = 0x100,
> + EP_STATE_TCP_RST_RCVD = 0x200,
> + EP_STATE_LOGOUT_SENT = 0x400,
> + EP_STATE_LOGOUT_RESP_RCVD = 0x800,
> + EP_STATE_CLEANUP_FAILED = 0x1000,
> + EP_STATE_OFLDCONN_FAILED = 0x2000,
> + EP_STATE_CONNECT_FAILED = 0x4000,
> + EP_STATE_DISCONN_TIMEDOUT = 0x8000,
> +};
> +
> +struct qedi_conn;
> +
> +struct qedi_endpoint {
> + struct qedi_ctx *qedi;
> + u32 dst_addr[4];
> + u32 src_addr[4];
> + u16 src_port;
> + u16 dst_port;
> + u16 vlan_id;
> + u16 pmtu;
> + u8 src_mac[ETH_ALEN];
> + u8 dst_mac[ETH_ALEN];
> + u8 ip_type;
> + int state;
> + wait_queue_head_t ofld_wait;
> + wait_queue_head_t tcp_ofld_wait;
> + u32 iscsi_cid;
> + /* identifier of the connection from qed */
> + u32 handle;
> + u32 fw_cid;
> + void __iomem *p_doorbell;
> +
> + /* Send queue management */
> + struct iscsi_wqe *sq;
> + dma_addr_t sq_dma;
> +
> + u16 sq_prod_idx;
> + u16 fw_sq_prod_idx;
> + u16 sq_con_idx;
> + u32 sq_mem_size;
> +
> + void *sq_pbl;
> + dma_addr_t sq_pbl_dma;
> + u32 sq_pbl_size;
> + struct qedi_conn *conn;
> + struct work_struct offload_work;
> +};
> +
> +#define QEDI_SQ_WQES_MIN 16
> +
> +struct qedi_io_bdt {
> + struct iscsi_sge *sge_tbl;
> + dma_addr_t sge_tbl_dma;
> + u16 sge_valid;
> +};
> +
> +/**
> + * struct generic_pdu_resc - login pdu resource structure
> + *
> + * @req_buf: driver buffer used to stage payload associated with
> + * the login request
> + * @req_dma_addr: dma address for iscsi login request payload buffer
> + * @req_buf_size: actual login request payload length
> + * @req_wr_ptr: pointer into login request buffer when next data is
> + * to be written
> + * @resp_hdr: iscsi header where iscsi login response header is to
> + * be recreated
> + * @resp_buf: buffer to stage login response payload
> + * @resp_dma_addr: login response payload buffer dma address
> + * @resp_buf_size: login response paylod length
> + * @resp_wr_ptr: pointer into login response buffer when next data is
> + * to be written
> + * @req_bd_tbl: iscsi login request payload BD table
> + * @req_bd_dma: login request BD table dma address
> + * @resp_bd_tbl: iscsi login response payload BD table
> + * @resp_bd_dma: login request BD table dma address
> + *
> + * following structure defines buffer info for generic pdus such as iSCSI Login,
> + * Logout and NOP
> + */
> +struct generic_pdu_resc {
> + char *req_buf;
> + dma_addr_t req_dma_addr;
> + u32 req_buf_size;
> + char *req_wr_ptr;
> + struct iscsi_hdr resp_hdr;
> + char *resp_buf;
> + dma_addr_t resp_dma_addr;
> + u32 resp_buf_size;
> + char *resp_wr_ptr;
> + char *req_bd_tbl;
> + dma_addr_t req_bd_dma;
> + char *resp_bd_tbl;
> + dma_addr_t resp_bd_dma;
> +};
> +
> +struct qedi_conn {
> + struct iscsi_cls_conn *cls_conn;
> + struct qedi_ctx *qedi;
> + struct qedi_endpoint *ep;
> + struct list_head active_cmd_list;
> + spinlock_t list_lock; /* internal conn lock */
> + u32 active_cmd_count;
> + u32 cmd_cleanup_req;
> + u32 cmd_cleanup_cmpl;
> +
> + u32 iscsi_conn_id;
> + int itt;
> + int abrt_conn;
> +#define QEDI_CID_RESERVED 0x5AFF
> + u32 fw_cid;
> + /*
> + * Buffer for login negotiation process
> + */
> + struct generic_pdu_resc gen_pdu;
> +
> + struct list_head tmf_work_list;
> + wait_queue_head_t wait_queue;
> + spinlock_t tmf_work_lock; /* tmf work lock */
> + unsigned long flags;
> +#define QEDI_CONN_FW_CLEANUP 1
> +};
> +
> +struct qedi_cmd {
> + struct list_head io_cmd;
> + bool io_cmd_in_list;
> + struct iscsi_hdr hdr;
> + struct qedi_conn *conn;
> + struct scsi_cmnd *scsi_cmd;
> + struct scatterlist *sg;
> + struct qedi_io_bdt io_tbl;
> + struct iscsi_task_context request;
> + unsigned char *sense_buffer;
> + dma_addr_t sense_buffer_dma;
> + u16 task_id;
> +
> + /* field populated for tmf work queue */
> + struct iscsi_task *task;
> + struct work_struct tmf_work;
> + int state;
> +#define CLEANUP_WAIT 1
> +#define CLEANUP_RECV 2
> +#define CLEANUP_WAIT_FAILED 3
> +#define CLEANUP_NOT_REQUIRED 4
> +#define LUN_RESET_RESPONSE_RECEIVED 5
> +#define RESPONSE_RECEIVED 6
> +
> + int type;
> +#define TYPEIO 1
> +#define TYPERESET 2
> +
> + struct qedi_work_map *list_tmf_work;
> + /* slowpath management */
> + bool use_slowpath;
> +
> + struct iscsi_tm_rsp *tmf_resp_buf;
> +};
> +
> +struct qedi_work_map {
> + struct list_head list;
> + struct qedi_cmd *qedi_cmd;
> + int rtid;
> +
> + int state;
> +#define QEDI_WORK_QUEUED 1
> +#define QEDI_WORK_SCHEDULED 2
> +#define QEDI_WORK_EXIT 3
> +
> + struct work_struct *ptr_tmf_work;
> +};
> +
> +#define qedi_set_itt(task_id, itt) ((u32)((task_id & 0xffff) | (itt << 16)))
> +#define qedi_get_itt(cqe) (cqe.iscsi_hdr.cmd.itt >> 16)
> +
> +#endif /* _QEDI_ISCSI_H_ */
> diff --git a/drivers/scsi/qedi/qedi_main.c b/drivers/scsi/qedi/qedi_main.c
> index 58ac9a2..22d19a3 100644
> --- a/drivers/scsi/qedi/qedi_main.c
> +++ b/drivers/scsi/qedi/qedi_main.c
> @@ -27,6 +27,8 @@
> #include <scsi/scsi.h>
>
> #include "qedi.h"
> +#include "qedi_gbl.h"
> +#include "qedi_iscsi.h"
>
> static uint fw_debug;
> module_param(fw_debug, uint, S_IRUGO | S_IWUSR);
> @@ -1368,6 +1370,139 @@ static int qedi_alloc_global_queues(struct qedi_ctx *qedi)
> return status;
> }
>
> +int qedi_alloc_sq(struct qedi_ctx *qedi, struct qedi_endpoint *ep)
> +{
> + int rval = 0;
> + u32 *pbl;
> + dma_addr_t page;
> + int num_pages;
> +
> + if (!ep)
> + return -EIO;
> +
> + /* Calculate appropriate queue and PBL sizes */
> + ep->sq_mem_size = QEDI_SQ_SIZE * sizeof(struct iscsi_wqe);
> + ep->sq_mem_size += QEDI_PAGE_SIZE - 1;
> +
> + ep->sq_pbl_size = (ep->sq_mem_size / QEDI_PAGE_SIZE) * sizeof(void *);
> + ep->sq_pbl_size = ep->sq_pbl_size + QEDI_PAGE_SIZE;
> +
> + ep->sq = dma_alloc_coherent(&qedi->pdev->dev, ep->sq_mem_size,
> + &ep->sq_dma, GFP_KERNEL);
> + if (!ep->sq) {
> + QEDI_WARN(&qedi->dbg_ctx,
> + "Could not allocate send queue.\n");
> + rval = -ENOMEM;
> + goto out;
> + }
> + memset(ep->sq, 0, ep->sq_mem_size);
> +
> + ep->sq_pbl = dma_alloc_coherent(&qedi->pdev->dev, ep->sq_pbl_size,
> + &ep->sq_pbl_dma, GFP_KERNEL);
> + if (!ep->sq_pbl) {
> + QEDI_WARN(&qedi->dbg_ctx,
> + "Could not allocate send queue PBL.\n");
> + rval = -ENOMEM;
> + goto out_free_sq;
> + }
> + memset(ep->sq_pbl, 0, ep->sq_pbl_size);
> +
> + /* Create PBL */
> + num_pages = ep->sq_mem_size / QEDI_PAGE_SIZE;
> + page = ep->sq_dma;
> + pbl = (u32 *)ep->sq_pbl;
> +
> + while (num_pages--) {
> + *pbl = (u32)page;
> + pbl++;
> + *pbl = (u32)((u64)page >> 32);
> + pbl++;
> + page += QEDI_PAGE_SIZE;
> + }
> +
> + return rval;
> +
> +out_free_sq:
> + dma_free_coherent(&qedi->pdev->dev, ep->sq_mem_size, ep->sq,
> + ep->sq_dma);
> +out:
> + return rval;
> +}
> +
> +void qedi_free_sq(struct qedi_ctx *qedi, struct qedi_endpoint *ep)
> +{
> + if (ep->sq_pbl)
> + dma_free_coherent(&qedi->pdev->dev, ep->sq_pbl_size, ep->sq_pbl,
> + ep->sq_pbl_dma);
> + if (ep->sq)
> + dma_free_coherent(&qedi->pdev->dev, ep->sq_mem_size, ep->sq,
> + ep->sq_dma);
> +}
> +
> +int qedi_get_task_idx(struct qedi_ctx *qedi)
> +{
> + s16 tmp_idx;
> +
> +again:
> + tmp_idx = find_first_zero_bit(qedi->task_idx_map,
> + MAX_ISCSI_TASK_ENTRIES);
> +
> + if (tmp_idx >= MAX_ISCSI_TASK_ENTRIES) {
> + QEDI_ERR(&qedi->dbg_ctx, "FW task context pool is full.\n");
> + tmp_idx = -1;
> + goto err_idx;
> + }
> +
> + if (test_and_set_bit(tmp_idx, qedi->task_idx_map))
> + goto again;
> +
> +err_idx:
> + return tmp_idx;
> +}
> +
> +void qedi_clear_task_idx(struct qedi_ctx *qedi, int idx)
> +{
> + if (!test_and_clear_bit(idx, qedi->task_idx_map)) {
> + QEDI_ERR(&qedi->dbg_ctx,
> + "FW task context, already cleared, tid=0x%x\n", idx);
> + WARN_ON(1);
> + }
> +}
> +
> +void qedi_update_itt_map(struct qedi_ctx *qedi, u32 tid, u32 proto_itt)
> +{
> + qedi->itt_map[tid].itt = proto_itt;
> +
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
> + "update itt map tid=0x%x, with proto itt=0x%x\n", tid,
> + qedi->itt_map[tid].itt);
> +}
> +
> +void qedi_get_task_tid(struct qedi_ctx *qedi, u32 itt, s16 *tid)
> +{
> + u16 i;
> +
> + for (i = 0; i < MAX_ISCSI_TASK_ENTRIES; i++) {
> + if (qedi->itt_map[i].itt == itt) {
> + *tid = i;
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
> + "Ref itt=0x%x, found at tid=0x%x\n",
> + itt, *tid);
> + return;
> + }
> + }
> +
> + WARN_ON(1);
> +}
> +
> +void qedi_get_proto_itt(struct qedi_ctx *qedi, u32 tid, u32 *proto_itt)
> +{
> + *proto_itt = qedi->itt_map[tid].itt;
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_CONN,
> + "Get itt map tid [0x%x with proto itt[0x%x]",
> + tid, *proto_itt);
> +}
> +
> static int qedi_alloc_itt(struct qedi_ctx *qedi)
> {
> qedi->itt_map = kzalloc((sizeof(struct qedi_itt_map) *
> @@ -1488,6 +1623,26 @@ static int qedi_cpu_callback(struct notifier_block *nfb,
> .notifier_call = qedi_cpu_callback,
> };
>
> +void qedi_reset_host_mtu(struct qedi_ctx *qedi, u16 mtu)
> +{
> + struct qed_ll2_params params;
> +
> + qedi_recover_all_conns(qedi);
> +
> + qedi_ops->ll2->stop(qedi->cdev);
> + qedi_ll2_free_skbs(qedi);
> +
> + QEDI_INFO(&qedi->dbg_ctx, QEDI_LOG_INFO, "old MTU %u, new MTU %u\n",
> + qedi->ll2_mtu, mtu);
> + memset(¶ms, 0, sizeof(params));
> + qedi->ll2_mtu = mtu;
> + params.mtu = qedi->ll2_mtu + IPV6_HDR_LEN + TCP_HDR_LEN;
> + params.drop_ttl0_packets = 0;
> + params.rx_vlan_stripping = 1;
> + ether_addr_copy(params.ll2_mac_address, qedi->dev_info.common.hw_mac);
> + qedi_ops->ll2->start(qedi->cdev, ¶ms);
> +}
> +
> static void __qedi_remove(struct pci_dev *pdev, int mode)
> {
> struct qedi_ctx *qedi = pci_get_drvdata(pdev);
> @@ -1852,6 +2007,13 @@ static int __init qedi_init(void)
> qedi_dbg_init("qedi");
> #endif
>
> + qedi_scsi_transport = iscsi_register_transport(&qedi_iscsi_transport);
> + if (!qedi_scsi_transport) {
> + QEDI_ERR(NULL, "Could not register qedi transport");
> + rc = -ENOMEM;
> + goto exit_qedi_init_1;
> + }
> +
> register_hotcpu_notifier(&qedi_cpu_notifier);
>
> ret = pci_register_driver(&qedi_pci_driver);
> @@ -1874,6 +2036,7 @@ static int __init qedi_init(void)
> return rc;
>
> exit_qedi_init_2:
> + iscsi_unregister_transport(&qedi_iscsi_transport);
> exit_qedi_init_1:
> #ifdef CONFIG_DEBUG_FS
> qedi_dbg_exit();
> @@ -1892,6 +2055,7 @@ static void __exit qedi_cleanup(void)
>
> pci_unregister_driver(&qedi_pci_driver);
> unregister_hotcpu_notifier(&qedi_cpu_notifier);
> + iscsi_unregister_transport(&qedi_iscsi_transport);
>
> #ifdef CONFIG_DEBUG_FS
> qedi_dbg_exit();
>
Cheers,
Hannes
--
Dr. Hannes Reinecke Teamlead Storage & Networking
hare@suse.de +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)
^ permalink raw reply
* Re: [PATCH 08/10] mm: replace __access_remote_vm() write parameter with gup_flags
From: Jan Kara @ 2016-10-19 7:59 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: linux-mm, Linus Torvalds, Jan Kara, Hugh Dickins, Dave Hansen,
Rik van Riel, Mel Gorman, Andrew Morton, adi-buildroot-devel,
ceph-devel, dri-devel, intel-gfx, kvm, linux-alpha,
linux-arm-kernel, linux-cris-kernel, linux-fbdev, linux-fsdevel,
linux-ia64, linux-kernel, linux-media, linux-mips, linux-rdma,
linux-s390, linux-samsung-soc, linux-scsi, linux-security-module,
linux-sh@
In-Reply-To: <20161013002020.3062-9-lstoakes@gmail.com>
On Thu 13-10-16 01:20:18, Lorenzo Stoakes wrote:
> This patch removes the write parameter from __access_remote_vm() and replaces it
> with a gup_flags parameter as use of this function previously _implied_
> FOLL_FORCE, whereas after this patch callers explicitly pass this flag.
>
> We make this explicit as use of FOLL_FORCE can result in surprising behaviour
> (and hence bugs) within the mm subsystem.
>
> Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>
So I'm not convinced this (and the following two patches) is actually
helping much. By grepping for FOLL_FORCE we will easily see that any caller
of access_remote_vm() gets that semantics and can thus continue search
accordingly (it is much simpler than searching for all get_user_pages()
users and extracting from parameter lists what they actually pass as
'force' argument). Sure it makes somewhat more visible to callers of
access_remote_vm() that they get FOLL_FORCE semantics but OTOH it also
opens a space for issues where a caller of access_remote_vm() actually
wants FOLL_FORCE (and currently all of them want it) and just mistakenly
does not set it. All in all I'd prefer to keep access_remote_vm() and
friends as is...
Honza
> ---
> mm/memory.c | 23 +++++++++++++++--------
> mm/nommu.c | 9 ++++++---
> 2 files changed, 21 insertions(+), 11 deletions(-)
>
> diff --git a/mm/memory.c b/mm/memory.c
> index 20a9adb..79ebed3 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -3869,14 +3869,11 @@ EXPORT_SYMBOL_GPL(generic_access_phys);
> * given task for page fault accounting.
> */
> static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
> - unsigned long addr, void *buf, int len, int write)
> + unsigned long addr, void *buf, int len, unsigned int gup_flags)
> {
> struct vm_area_struct *vma;
> void *old_buf = buf;
> - unsigned int flags = FOLL_FORCE;
> -
> - if (write)
> - flags |= FOLL_WRITE;
> + int write = gup_flags & FOLL_WRITE;
>
> down_read(&mm->mmap_sem);
> /* ignore errors, just check how much was successfully transferred */
> @@ -3886,7 +3883,7 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
> struct page *page = NULL;
>
> ret = get_user_pages_remote(tsk, mm, addr, 1,
> - flags, &page, &vma);
> + gup_flags, &page, &vma);
> if (ret <= 0) {
> #ifndef CONFIG_HAVE_IOREMAP_PROT
> break;
> @@ -3945,7 +3942,12 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
> int access_remote_vm(struct mm_struct *mm, unsigned long addr,
> void *buf, int len, int write)
> {
> - return __access_remote_vm(NULL, mm, addr, buf, len, write);
> + unsigned int flags = FOLL_FORCE;
> +
> + if (write)
> + flags |= FOLL_WRITE;
> +
> + return __access_remote_vm(NULL, mm, addr, buf, len, flags);
> }
>
> /*
> @@ -3958,12 +3960,17 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr,
> {
> struct mm_struct *mm;
> int ret;
> + unsigned int flags = FOLL_FORCE;
>
> mm = get_task_mm(tsk);
> if (!mm)
> return 0;
>
> - ret = __access_remote_vm(tsk, mm, addr, buf, len, write);
> + if (write)
> + flags |= FOLL_WRITE;
> +
> + ret = __access_remote_vm(tsk, mm, addr, buf, len, flags);
> +
> mmput(mm);
>
> return ret;
> diff --git a/mm/nommu.c b/mm/nommu.c
> index 70cb844..bde7df3 100644
> --- a/mm/nommu.c
> +++ b/mm/nommu.c
> @@ -1809,9 +1809,10 @@ void filemap_map_pages(struct fault_env *fe,
> EXPORT_SYMBOL(filemap_map_pages);
>
> static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
> - unsigned long addr, void *buf, int len, int write)
> + unsigned long addr, void *buf, int len, unsigned int gup_flags)
> {
> struct vm_area_struct *vma;
> + int write = gup_flags & FOLL_WRITE;
>
> down_read(&mm->mmap_sem);
>
> @@ -1853,7 +1854,8 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
> int access_remote_vm(struct mm_struct *mm, unsigned long addr,
> void *buf, int len, int write)
> {
> - return __access_remote_vm(NULL, mm, addr, buf, len, write);
> + return __access_remote_vm(NULL, mm, addr, buf, len,
> + write ? FOLL_WRITE : 0);
> }
>
> /*
> @@ -1871,7 +1873,8 @@ int access_process_vm(struct task_struct *tsk, unsigned long addr, void *buf, in
> if (!mm)
> return 0;
>
> - len = __access_remote_vm(tsk, mm, addr, buf, len, write);
> + len = __access_remote_vm(tsk, mm, addr, buf, len,
> + write ? FOLL_WRITE : 0);
>
> mmput(mm);
> return len;
> --
> 2.10.0
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [RFC 4/6] qedi: Add LL2 iSCSI interface for offload iSCSI.
From: Hannes Reinecke @ 2016-10-19 7:53 UTC (permalink / raw)
To: manish.rangankar, lduncan, cleech
Cc: martin.petersen, jejb, linux-scsi, netdev, Yuval.Mintz,
QLogic-Storage-Upstream, Nilesh Javali, Adheer Chandravanshi,
Chad Dupuis, Saurav Kashyap, Arun Easi
In-Reply-To: <1476853273-22960-5-git-send-email-manish.rangankar@cavium.com>
On 10/19/2016 07:01 AM, manish.rangankar@cavium.com wrote:
> From: Manish Rangankar <manish.rangankar@cavium.com>
>
> This patch adds support for iscsiuio interface using Light L2 (LL2) qed
> interface.
>
> 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>
> ---
> drivers/scsi/qedi/qedi.h | 73 +++++++++
> drivers/scsi/qedi/qedi_main.c | 357 ++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 430 insertions(+)
>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Cheers,
Hannes
--
Dr. Hannes Reinecke Teamlead Storage & Networking
hare@suse.de +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)
^ permalink raw reply
* Re: [PATCH 07/10] mm: replace get_user_pages_remote() write/force parameters with gup_flags
From: Jan Kara @ 2016-10-19 7:47 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: linux-mips, linux-fbdev, Jan Kara, kvm, linux-sh, Dave Hansen,
dri-devel, linux-mm, netdev, sparclinux, linux-ia64, linux-s390,
linux-samsung-soc, linux-scsi, linux-rdma, x86, Hugh Dickins,
linux-media, Rik van Riel, intel-gfx, adi-buildroot-devel,
ceph-devel, linux-arm-kernel, linux-cris-kernel, Linus Torvalds,
linuxppc-dev, linux-kernel, linux-security-module, linux-alpha,
lin
In-Reply-To: <20161013002020.3062-8-lstoakes@gmail.com>
On Thu 13-10-16 01:20:17, Lorenzo Stoakes wrote:
> This patch removes the write and force parameters from get_user_pages_remote()
> and replaces them with a gup_flags parameter to make the use of FOLL_FORCE
> explicit in callers as use of this flag can result in surprising behaviour (and
> hence bugs) within the mm subsystem.
>
> Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>
Looks good. You can add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
> drivers/gpu/drm/etnaviv/etnaviv_gem.c | 7 +++++--
> drivers/gpu/drm/i915/i915_gem_userptr.c | 6 +++++-
> drivers/infiniband/core/umem_odp.c | 7 +++++--
> fs/exec.c | 9 +++++++--
> include/linux/mm.h | 2 +-
> kernel/events/uprobes.c | 6 ++++--
> mm/gup.c | 22 +++++++---------------
> mm/memory.c | 6 +++++-
> security/tomoyo/domain.c | 2 +-
> 9 files changed, 40 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gem.c b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
> index 5ce3603..0370b84 100644
> --- a/drivers/gpu/drm/etnaviv/etnaviv_gem.c
> +++ b/drivers/gpu/drm/etnaviv/etnaviv_gem.c
> @@ -748,19 +748,22 @@ static struct page **etnaviv_gem_userptr_do_get_pages(
> int ret = 0, pinned, npages = etnaviv_obj->base.size >> PAGE_SHIFT;
> struct page **pvec;
> uintptr_t ptr;
> + unsigned int flags = 0;
>
> pvec = drm_malloc_ab(npages, sizeof(struct page *));
> if (!pvec)
> return ERR_PTR(-ENOMEM);
>
> + if (!etnaviv_obj->userptr.ro)
> + flags |= FOLL_WRITE;
> +
> pinned = 0;
> ptr = etnaviv_obj->userptr.ptr;
>
> down_read(&mm->mmap_sem);
> while (pinned < npages) {
> ret = get_user_pages_remote(task, mm, ptr, npages - pinned,
> - !etnaviv_obj->userptr.ro, 0,
> - pvec + pinned, NULL);
> + flags, pvec + pinned, NULL);
> if (ret < 0)
> break;
>
> diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c
> index e537930..c6f780f 100644
> --- a/drivers/gpu/drm/i915/i915_gem_userptr.c
> +++ b/drivers/gpu/drm/i915/i915_gem_userptr.c
> @@ -508,6 +508,10 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
> pvec = drm_malloc_gfp(npages, sizeof(struct page *), GFP_TEMPORARY);
> if (pvec != NULL) {
> struct mm_struct *mm = obj->userptr.mm->mm;
> + unsigned int flags = 0;
> +
> + if (!obj->userptr.read_only)
> + flags |= FOLL_WRITE;
>
> ret = -EFAULT;
> if (atomic_inc_not_zero(&mm->mm_users)) {
> @@ -517,7 +521,7 @@ __i915_gem_userptr_get_pages_worker(struct work_struct *_work)
> (work->task, mm,
> obj->userptr.ptr + pinned * PAGE_SIZE,
> npages - pinned,
> - !obj->userptr.read_only, 0,
> + flags,
> pvec + pinned, NULL);
> if (ret < 0)
> break;
> diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c
> index 75077a0..1f0fe32 100644
> --- a/drivers/infiniband/core/umem_odp.c
> +++ b/drivers/infiniband/core/umem_odp.c
> @@ -527,6 +527,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
> u64 off;
> int j, k, ret = 0, start_idx, npages = 0;
> u64 base_virt_addr;
> + unsigned int flags = 0;
>
> if (access_mask == 0)
> return -EINVAL;
> @@ -556,6 +557,9 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
> goto out_put_task;
> }
>
> + if (access_mask & ODP_WRITE_ALLOWED_BIT)
> + flags |= FOLL_WRITE;
> +
> start_idx = (user_virt - ib_umem_start(umem)) >> PAGE_SHIFT;
> k = start_idx;
>
> @@ -574,8 +578,7 @@ int ib_umem_odp_map_dma_pages(struct ib_umem *umem, u64 user_virt, u64 bcnt,
> */
> npages = get_user_pages_remote(owning_process, owning_mm,
> user_virt, gup_num_pages,
> - access_mask & ODP_WRITE_ALLOWED_BIT,
> - 0, local_page_list, NULL);
> + flags, local_page_list, NULL);
> up_read(&owning_mm->mmap_sem);
>
> if (npages < 0)
> diff --git a/fs/exec.c b/fs/exec.c
> index 6fcfb3f..4e497b9 100644
> --- a/fs/exec.c
> +++ b/fs/exec.c
> @@ -191,6 +191,7 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
> {
> struct page *page;
> int ret;
> + unsigned int gup_flags = FOLL_FORCE;
>
> #ifdef CONFIG_STACK_GROWSUP
> if (write) {
> @@ -199,12 +200,16 @@ static struct page *get_arg_page(struct linux_binprm *bprm, unsigned long pos,
> return NULL;
> }
> #endif
> +
> + if (write)
> + gup_flags |= FOLL_WRITE;
> +
> /*
> * We are doing an exec(). 'current' is the process
> * doing the exec and bprm->mm is the new process's mm.
> */
> - ret = get_user_pages_remote(current, bprm->mm, pos, 1, write,
> - 1, &page, NULL);
> + ret = get_user_pages_remote(current, bprm->mm, pos, 1, gup_flags,
> + &page, NULL);
> if (ret <= 0)
> return NULL;
>
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 686a477..2a481d3 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1276,7 +1276,7 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
> struct vm_area_struct **vmas, int *nonblocking);
> long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
> unsigned long start, unsigned long nr_pages,
> - int write, int force, struct page **pages,
> + unsigned int gup_flags, struct page **pages,
> struct vm_area_struct **vmas);
> long get_user_pages(unsigned long start, unsigned long nr_pages,
> unsigned int gup_flags, struct page **pages,
> diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> index d4129bb..f9ec9ad 100644
> --- a/kernel/events/uprobes.c
> +++ b/kernel/events/uprobes.c
> @@ -300,7 +300,8 @@ int uprobe_write_opcode(struct mm_struct *mm, unsigned long vaddr,
>
> retry:
> /* Read the page with vaddr into memory */
> - ret = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &old_page, &vma);
> + ret = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &old_page,
> + &vma);
> if (ret <= 0)
> return ret;
>
> @@ -1710,7 +1711,8 @@ static int is_trap_at_addr(struct mm_struct *mm, unsigned long vaddr)
> * but we treat this as a 'remote' access since it is
> * essentially a kernel access to the memory.
> */
> - result = get_user_pages_remote(NULL, mm, vaddr, 1, 0, 1, &page, NULL);
> + result = get_user_pages_remote(NULL, mm, vaddr, 1, FOLL_FORCE, &page,
> + NULL);
> if (result < 0)
> return result;
>
> diff --git a/mm/gup.c b/mm/gup.c
> index dc91303..0deecf3 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -905,9 +905,7 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
> * @mm: mm_struct of target mm
> * @start: starting user address
> * @nr_pages: number of pages from start to pin
> - * @write: whether pages will be written to by the caller
> - * @force: whether to force access even when user mapping is currently
> - * protected (but never forces write access to shared mapping).
> + * @gup_flags: flags modifying lookup behaviour
> * @pages: array that receives pointers to the pages pinned.
> * Should be at least nr_pages long. Or NULL, if caller
> * only intends to ensure the pages are faulted in.
> @@ -936,9 +934,9 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
> * or similar operation cannot guarantee anything stronger anyway because
> * locks can't be held over the syscall boundary.
> *
> - * If write=0, the page must not be written to. If the page is written to,
> - * set_page_dirty (or set_page_dirty_lock, as appropriate) must be called
> - * after the page is finished with, and before put_page is called.
> + * If gup_flags & FOLL_WRITE == 0, the page must not be written to. If the page
> + * is written to, set_page_dirty (or set_page_dirty_lock, as appropriate) must
> + * be called after the page is finished with, and before put_page is called.
> *
> * get_user_pages is typically used for fewer-copy IO operations, to get a
> * handle on the memory by some means other than accesses via the user virtual
> @@ -955,18 +953,12 @@ EXPORT_SYMBOL(get_user_pages_unlocked);
> */
> long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
> unsigned long start, unsigned long nr_pages,
> - int write, int force, struct page **pages,
> + unsigned int gup_flags, struct page **pages,
> struct vm_area_struct **vmas)
> {
> - unsigned int flags = FOLL_TOUCH | FOLL_REMOTE;
> -
> - if (write)
> - flags |= FOLL_WRITE;
> - if (force)
> - flags |= FOLL_FORCE;
> -
> return __get_user_pages_locked(tsk, mm, start, nr_pages, pages, vmas,
> - NULL, false, flags);
> + NULL, false,
> + gup_flags | FOLL_TOUCH | FOLL_REMOTE);
> }
> EXPORT_SYMBOL(get_user_pages_remote);
>
> diff --git a/mm/memory.c b/mm/memory.c
> index fc1987d..20a9adb 100644
> --- a/mm/memory.c
> +++ b/mm/memory.c
> @@ -3873,6 +3873,10 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
> {
> struct vm_area_struct *vma;
> void *old_buf = buf;
> + unsigned int flags = FOLL_FORCE;
> +
> + if (write)
> + flags |= FOLL_WRITE;
>
> down_read(&mm->mmap_sem);
> /* ignore errors, just check how much was successfully transferred */
> @@ -3882,7 +3886,7 @@ static int __access_remote_vm(struct task_struct *tsk, struct mm_struct *mm,
> struct page *page = NULL;
>
> ret = get_user_pages_remote(tsk, mm, addr, 1,
> - write, 1, &page, &vma);
> + flags, &page, &vma);
> if (ret <= 0) {
> #ifndef CONFIG_HAVE_IOREMAP_PROT
> break;
> diff --git a/security/tomoyo/domain.c b/security/tomoyo/domain.c
> index ade7c6c..682b73a 100644
> --- a/security/tomoyo/domain.c
> +++ b/security/tomoyo/domain.c
> @@ -881,7 +881,7 @@ bool tomoyo_dump_page(struct linux_binprm *bprm, unsigned long pos,
> * the execve().
> */
> if (get_user_pages_remote(current, bprm->mm, pos, 1,
> - 0, 1, &page, NULL) <= 0)
> + FOLL_FORCE, &page, NULL) <= 0)
> return false;
> #else
> page = bprm->page[pos / PAGE_SIZE];
> --
> 2.10.0
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* Re: [RFC 3/6] qedi: Add QLogic FastLinQ offload iSCSI driver framework.
From: Hannes Reinecke @ 2016-10-19 7:45 UTC (permalink / raw)
To: manish.rangankar, lduncan, cleech
Cc: martin.petersen, jejb, linux-scsi, netdev, Yuval.Mintz,
QLogic-Storage-Upstream, Nilesh Javali, Adheer Chandravanshi,
Chad Dupuis, Saurav Kashyap, Arun Easi
In-Reply-To: <1476853273-22960-4-git-send-email-manish.rangankar@cavium.com>
On 10/19/2016 07:01 AM, manish.rangankar@cavium.com wrote:
> From: Manish Rangankar <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 | 286 +++++++
> 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 | 1550 +++++++++++++++++++++++++++++++++++
> drivers/scsi/qedi/qedi_sysfs.c | 52 ++
> drivers/scsi/qedi/qedi_version.h | 14 +
> 14 files changed, 2508 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 5e925a2..906d05f 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -9909,6 +9909,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 bad4fae..28b4366 100644
> --- a/drivers/net/ethernet/qlogic/Kconfig
> +++ b/drivers/net/ethernet/qlogic/Kconfig
> @@ -121,16 +121,4 @@ config INFINIBAND_QEDR
> 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
Huh? You just introduce this one in patch 1/6.
Please fold them together so that this can be omitted.
> 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..0a5035e
> --- /dev/null
> +++ b/drivers/scsi/qedi/qedi.h
> @@ -0,0 +1,286 @@
> +/*
> + * 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;
> +};
> +
> +/* 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;
> +};
> +
> +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 (void *)(info->blocks[tid / info->num_tids_per_block] +
> + (tid % info->num_tids_per_block) * info->size);
> +}
> +
> +#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..2678a15
> --- /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_crit("[%s]:[%s:%d]:%d: %pV", dev_name(&qedi->pdev->dev),
> + nfunc, line, qedi->host_no, &vaf);
> + else
> + pr_crit("[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..b442a62
> --- /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>
> +
Please use kernel-doc style for comments
> +/****************************************/
> +/* 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..35ab2f9
> --- /dev/null
> +++ b/drivers/scsi/qedi/qedi_main.c
> @@ -0,0 +1,1550 @@
> +/*
> + * 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 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((void *)qedi->fp_array, 0, MIN_NUM_CPUS_MSIX(qedi) *
> + sizeof(*qedi->fp_array));
> + memset((void *)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
> + */
> + }
> +}
> +
Please check if you cannot make use of Christophs irq rework.
> +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((qedi->max_active_conns *
> + sizeof(u32)), GFP_KERNEL);
> + if (!qedi->cid_que.cid_que_base)
> + return -ENOMEM;
> +
> + qedi->cid_que.conn_cid_tbl = kmalloc((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 bool qedi_process_completions(struct qedi_fastpath *fp)
> +{
> + struct qedi_work *qedi_work = NULL;
> + 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;
> +
> + /* 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);
> +
> + /* Alloc and copy to the cqe */
> + qedi_work = kzalloc(sizeof(*qedi_work), GFP_ATOMIC);
> + if (qedi_work) {
> + INIT_LIST_HEAD(&qedi_work->list);
> + qedi_work->qedi = qedi;
> + memcpy(&qedi_work->cqe, cqe, sizeof(union iscsi_cqe));
> + qedi_work->que_idx = fp->sb_id;
> + list_add_tail(&qedi_work->list, &p->work_list);
> + } else {
> + WARN_ON(1);
> + continue;
> + }
> +
Memory allocation in an interrupt routine?
You must be kidding ...
> + 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);
> +}
> +
Again, consider using the interrupt affinity rework from Christoph Hellwig.
Cheers,
Hannes
--
Dr. Hannes Reinecke Teamlead Storage & Networking
hare@suse.de +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)
^ permalink raw reply
* Re: [PATCH 06/10] mm: replace get_user_pages() write/force parameters with gup_flags
From: Jan Kara @ 2016-10-19 7:44 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: linux-mips, linux-fbdev, Jan Kara, kvm, linux-sh, Dave Hansen,
dri-devel, linux-mm, netdev, sparclinux, linux-ia64, linux-s390,
linux-samsung-soc, linux-scsi, linux-rdma, x86, Hugh Dickins,
linux-media, Rik van Riel, intel-gfx, adi-buildroot-devel,
ceph-devel, linux-arm-kernel, linux-cris-kernel, Linus Torvalds,
linuxppc-dev, linux-kernel, linux-security-module, linux-alpha,
lin
In-Reply-To: <20161013002020.3062-7-lstoakes@gmail.com>
On Thu 13-10-16 01:20:16, Lorenzo Stoakes wrote:
> This patch removes the write and force parameters from get_user_pages() and
> replaces them with a gup_flags parameter to make the use of FOLL_FORCE explicit
> in callers as use of this flag can result in surprising behaviour (and hence
> bugs) within the mm subsystem.
>
> Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>
The patch looks good. You can add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
> arch/cris/arch-v32/drivers/cryptocop.c | 4 +---
> arch/ia64/kernel/err_inject.c | 2 +-
> arch/x86/mm/mpx.c | 5 ++---
> drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c | 7 +++++--
> drivers/gpu/drm/radeon/radeon_ttm.c | 3 ++-
> drivers/gpu/drm/via/via_dmablit.c | 4 ++--
> drivers/infiniband/core/umem.c | 6 +++++-
> drivers/infiniband/hw/mthca/mthca_memfree.c | 2 +-
> drivers/infiniband/hw/qib/qib_user_pages.c | 3 ++-
> drivers/infiniband/hw/usnic/usnic_uiom.c | 5 ++++-
> drivers/media/v4l2-core/videobuf-dma-sg.c | 7 +++++--
> drivers/misc/mic/scif/scif_rma.c | 3 +--
> drivers/misc/sgi-gru/grufault.c | 2 +-
> drivers/platform/goldfish/goldfish_pipe.c | 3 ++-
> drivers/rapidio/devices/rio_mport_cdev.c | 3 ++-
> .../vc04_services/interface/vchiq_arm/vchiq_2835_arm.c | 3 +--
> .../vc04_services/interface/vchiq_arm/vchiq_arm.c | 3 +--
> drivers/virt/fsl_hypervisor.c | 4 ++--
> include/linux/mm.h | 2 +-
> mm/gup.c | 12 +++---------
> mm/mempolicy.c | 2 +-
> mm/nommu.c | 18 ++++--------------
> 22 files changed, 49 insertions(+), 54 deletions(-)
>
> diff --git a/arch/cris/arch-v32/drivers/cryptocop.c b/arch/cris/arch-v32/drivers/cryptocop.c
> index b5698c8..099e170 100644
> --- a/arch/cris/arch-v32/drivers/cryptocop.c
> +++ b/arch/cris/arch-v32/drivers/cryptocop.c
> @@ -2722,7 +2722,6 @@ static int cryptocop_ioctl_process(struct inode *inode, struct file *filp, unsig
> err = get_user_pages((unsigned long int)(oper.indata + prev_ix),
> noinpages,
> 0, /* read access only for in data */
> - 0, /* no force */
> inpages,
> NULL);
>
> @@ -2736,8 +2735,7 @@ static int cryptocop_ioctl_process(struct inode *inode, struct file *filp, unsig
> if (oper.do_cipher){
> err = get_user_pages((unsigned long int)oper.cipher_outdata,
> nooutpages,
> - 1, /* write access for out data */
> - 0, /* no force */
> + FOLL_WRITE, /* write access for out data */
> outpages,
> NULL);
> up_read(¤t->mm->mmap_sem);
> diff --git a/arch/ia64/kernel/err_inject.c b/arch/ia64/kernel/err_inject.c
> index 09f8457..5ed0ea9 100644
> --- a/arch/ia64/kernel/err_inject.c
> +++ b/arch/ia64/kernel/err_inject.c
> @@ -142,7 +142,7 @@ store_virtual_to_phys(struct device *dev, struct device_attribute *attr,
> u64 virt_addr=simple_strtoull(buf, NULL, 16);
> int ret;
>
> - ret = get_user_pages(virt_addr, 1, VM_READ, 0, NULL, NULL);
> + ret = get_user_pages(virt_addr, 1, FOLL_WRITE, NULL, NULL);
> if (ret<=0) {
> #ifdef ERR_INJ_DEBUG
> printk("Virtual address %lx is not existing.\n",virt_addr);
> diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c
> index 8047687..e4f8009 100644
> --- a/arch/x86/mm/mpx.c
> +++ b/arch/x86/mm/mpx.c
> @@ -544,10 +544,9 @@ static int mpx_resolve_fault(long __user *addr, int write)
> {
> long gup_ret;
> int nr_pages = 1;
> - int force = 0;
>
> - gup_ret = get_user_pages((unsigned long)addr, nr_pages, write,
> - force, NULL, NULL);
> + gup_ret = get_user_pages((unsigned long)addr, nr_pages,
> + write ? FOLL_WRITE : 0, NULL, NULL);
> /*
> * get_user_pages() returns number of pages gotten.
> * 0 means we failed to fault in and get anything,
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
> index 887483b..dcaf691 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ttm.c
> @@ -555,10 +555,13 @@ struct amdgpu_ttm_tt {
> int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages)
> {
> struct amdgpu_ttm_tt *gtt = (void *)ttm;
> - int write = !(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY);
> + unsigned int flags = 0;
> unsigned pinned = 0;
> int r;
>
> + if (!(gtt->userflags & AMDGPU_GEM_USERPTR_READONLY))
> + flags |= FOLL_WRITE;
> +
> if (gtt->userflags & AMDGPU_GEM_USERPTR_ANONONLY) {
> /* check that we only use anonymous memory
> to prevent problems with writeback */
> @@ -581,7 +584,7 @@ int amdgpu_ttm_tt_get_user_pages(struct ttm_tt *ttm, struct page **pages)
> list_add(&guptask.list, >t->guptasks);
> spin_unlock(>t->guptasklock);
>
> - r = get_user_pages(userptr, num_pages, write, 0, p, NULL);
> + r = get_user_pages(userptr, num_pages, flags, p, NULL);
>
> spin_lock(>t->guptasklock);
> list_del(&guptask.list);
> diff --git a/drivers/gpu/drm/radeon/radeon_ttm.c b/drivers/gpu/drm/radeon/radeon_ttm.c
> index 4552682..3de5e6e 100644
> --- a/drivers/gpu/drm/radeon/radeon_ttm.c
> +++ b/drivers/gpu/drm/radeon/radeon_ttm.c
> @@ -566,7 +566,8 @@ static int radeon_ttm_tt_pin_userptr(struct ttm_tt *ttm)
> uint64_t userptr = gtt->userptr + pinned * PAGE_SIZE;
> struct page **pages = ttm->pages + pinned;
>
> - r = get_user_pages(userptr, num_pages, write, 0, pages, NULL);
> + r = get_user_pages(userptr, num_pages, write ? FOLL_WRITE : 0,
> + pages, NULL);
> if (r < 0)
> goto release_pages;
>
> diff --git a/drivers/gpu/drm/via/via_dmablit.c b/drivers/gpu/drm/via/via_dmablit.c
> index 7e2a12c..1a3ad76 100644
> --- a/drivers/gpu/drm/via/via_dmablit.c
> +++ b/drivers/gpu/drm/via/via_dmablit.c
> @@ -241,8 +241,8 @@ via_lock_all_dma_pages(drm_via_sg_info_t *vsg, drm_via_dmablit_t *xfer)
> down_read(¤t->mm->mmap_sem);
> ret = get_user_pages((unsigned long)xfer->mem_addr,
> vsg->num_pages,
> - (vsg->direction == DMA_FROM_DEVICE),
> - 0, vsg->pages, NULL);
> + (vsg->direction == DMA_FROM_DEVICE) ? FOLL_WRITE : 0,
> + vsg->pages, NULL);
>
> up_read(¤t->mm->mmap_sem);
> if (ret != vsg->num_pages) {
> diff --git a/drivers/infiniband/core/umem.c b/drivers/infiniband/core/umem.c
> index c68746c..224ad27 100644
> --- a/drivers/infiniband/core/umem.c
> +++ b/drivers/infiniband/core/umem.c
> @@ -94,6 +94,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
> unsigned long dma_attrs = 0;
> struct scatterlist *sg, *sg_list_start;
> int need_release = 0;
> + unsigned int gup_flags = FOLL_WRITE;
>
> if (dmasync)
> dma_attrs |= DMA_ATTR_WRITE_BARRIER;
> @@ -183,6 +184,9 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
> if (ret)
> goto out;
>
> + if (!umem->writable)
> + gup_flags |= FOLL_FORCE;
> +
> need_release = 1;
> sg_list_start = umem->sg_head.sgl;
>
> @@ -190,7 +194,7 @@ struct ib_umem *ib_umem_get(struct ib_ucontext *context, unsigned long addr,
> ret = get_user_pages(cur_base,
> min_t(unsigned long, npages,
> PAGE_SIZE / sizeof (struct page *)),
> - 1, !umem->writable, page_list, vma_list);
> + gup_flags, page_list, vma_list);
>
> if (ret < 0)
> goto out;
> diff --git a/drivers/infiniband/hw/mthca/mthca_memfree.c b/drivers/infiniband/hw/mthca/mthca_memfree.c
> index 6c00d04..c6fe89d 100644
> --- a/drivers/infiniband/hw/mthca/mthca_memfree.c
> +++ b/drivers/infiniband/hw/mthca/mthca_memfree.c
> @@ -472,7 +472,7 @@ int mthca_map_user_db(struct mthca_dev *dev, struct mthca_uar *uar,
> goto out;
> }
>
> - ret = get_user_pages(uaddr & PAGE_MASK, 1, 1, 0, pages, NULL);
> + ret = get_user_pages(uaddr & PAGE_MASK, 1, FOLL_WRITE, pages, NULL);
> if (ret < 0)
> goto out;
>
> diff --git a/drivers/infiniband/hw/qib/qib_user_pages.c b/drivers/infiniband/hw/qib/qib_user_pages.c
> index 2d2b94f..75f0862 100644
> --- a/drivers/infiniband/hw/qib/qib_user_pages.c
> +++ b/drivers/infiniband/hw/qib/qib_user_pages.c
> @@ -67,7 +67,8 @@ static int __qib_get_user_pages(unsigned long start_page, size_t num_pages,
>
> for (got = 0; got < num_pages; got += ret) {
> ret = get_user_pages(start_page + got * PAGE_SIZE,
> - num_pages - got, 1, 1,
> + num_pages - got,
> + FOLL_WRITE | FOLL_FORCE,
> p + got, NULL);
> if (ret < 0)
> goto bail_release;
> diff --git a/drivers/infiniband/hw/usnic/usnic_uiom.c b/drivers/infiniband/hw/usnic/usnic_uiom.c
> index a0b6ebe..1ccee6e 100644
> --- a/drivers/infiniband/hw/usnic/usnic_uiom.c
> +++ b/drivers/infiniband/hw/usnic/usnic_uiom.c
> @@ -111,6 +111,7 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable,
> int i;
> int flags;
> dma_addr_t pa;
> + unsigned int gup_flags;
>
> if (!can_do_mlock())
> return -EPERM;
> @@ -135,6 +136,8 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable,
>
> flags = IOMMU_READ | IOMMU_CACHE;
> flags |= (writable) ? IOMMU_WRITE : 0;
> + gup_flags = FOLL_WRITE;
> + gup_flags |= (writable) ? 0 : FOLL_FORCE;
> cur_base = addr & PAGE_MASK;
> ret = 0;
>
> @@ -142,7 +145,7 @@ static int usnic_uiom_get_pages(unsigned long addr, size_t size, int writable,
> ret = get_user_pages(cur_base,
> min_t(unsigned long, npages,
> PAGE_SIZE / sizeof(struct page *)),
> - 1, !writable, page_list, NULL);
> + gup_flags, page_list, NULL);
>
> if (ret < 0)
> goto out;
> diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c
> index f300f06..1db0af6 100644
> --- a/drivers/media/v4l2-core/videobuf-dma-sg.c
> +++ b/drivers/media/v4l2-core/videobuf-dma-sg.c
> @@ -156,6 +156,7 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
> {
> unsigned long first, last;
> int err, rw = 0;
> + unsigned int flags = FOLL_FORCE;
>
> dma->direction = direction;
> switch (dma->direction) {
> @@ -178,12 +179,14 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
> if (NULL == dma->pages)
> return -ENOMEM;
>
> + if (rw == READ)
> + flags |= FOLL_WRITE;
> +
> dprintk(1, "init user [0x%lx+0x%lx => %d pages]\n",
> data, size, dma->nr_pages);
>
> err = get_user_pages(data & PAGE_MASK, dma->nr_pages,
> - rw == READ, 1, /* force */
> - dma->pages, NULL);
> + flags, dma->pages, NULL);
>
> if (err != dma->nr_pages) {
> dma->nr_pages = (err >= 0) ? err : 0;
> diff --git a/drivers/misc/mic/scif/scif_rma.c b/drivers/misc/mic/scif/scif_rma.c
> index e0203b1..f806a44 100644
> --- a/drivers/misc/mic/scif/scif_rma.c
> +++ b/drivers/misc/mic/scif/scif_rma.c
> @@ -1396,8 +1396,7 @@ int __scif_pin_pages(void *addr, size_t len, int *out_prot,
> pinned_pages->nr_pages = get_user_pages(
> (u64)addr,
> nr_pages,
> - !!(prot & SCIF_PROT_WRITE),
> - 0,
> + (prot & SCIF_PROT_WRITE) ? FOLL_WRITE : 0,
> pinned_pages->pages,
> NULL);
> up_write(&mm->mmap_sem);
> diff --git a/drivers/misc/sgi-gru/grufault.c b/drivers/misc/sgi-gru/grufault.c
> index a2d97b9..6fb773d 100644
> --- a/drivers/misc/sgi-gru/grufault.c
> +++ b/drivers/misc/sgi-gru/grufault.c
> @@ -198,7 +198,7 @@ static int non_atomic_pte_lookup(struct vm_area_struct *vma,
> #else
> *pageshift = PAGE_SHIFT;
> #endif
> - if (get_user_pages(vaddr, 1, write, 0, &page, NULL) <= 0)
> + if (get_user_pages(vaddr, 1, write ? FOLL_WRITE : 0, &page, NULL) <= 0)
> return -EFAULT;
> *paddr = page_to_phys(page);
> put_page(page);
> diff --git a/drivers/platform/goldfish/goldfish_pipe.c b/drivers/platform/goldfish/goldfish_pipe.c
> index 07462d7..1aba2c7 100644
> --- a/drivers/platform/goldfish/goldfish_pipe.c
> +++ b/drivers/platform/goldfish/goldfish_pipe.c
> @@ -309,7 +309,8 @@ static ssize_t goldfish_pipe_read_write(struct file *filp, char __user *buffer,
> * much memory to the process.
> */
> down_read(¤t->mm->mmap_sem);
> - ret = get_user_pages(address, 1, !is_write, 0, &page, NULL);
> + ret = get_user_pages(address, 1, is_write ? 0 : FOLL_WRITE,
> + &page, NULL);
> up_read(¤t->mm->mmap_sem);
> if (ret < 0)
> break;
> diff --git a/drivers/rapidio/devices/rio_mport_cdev.c b/drivers/rapidio/devices/rio_mport_cdev.c
> index 436dfe8..9013a58 100644
> --- a/drivers/rapidio/devices/rio_mport_cdev.c
> +++ b/drivers/rapidio/devices/rio_mport_cdev.c
> @@ -892,7 +892,8 @@ rio_dma_transfer(struct file *filp, u32 transfer_mode,
> down_read(¤t->mm->mmap_sem);
> pinned = get_user_pages(
> (unsigned long)xfer->loc_addr & PAGE_MASK,
> - nr_pages, dir == DMA_FROM_DEVICE, 0,
> + nr_pages,
> + dir == DMA_FROM_DEVICE ? FOLL_WRITE : 0,
> page_list, NULL);
> up_read(¤t->mm->mmap_sem);
>
> diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
> index c29040f..1091b9f 100644
> --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
> +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_2835_arm.c
> @@ -423,8 +423,7 @@ create_pagelist(char __user *buf, size_t count, unsigned short type,
> actual_pages = get_user_pages(task, task->mm,
> (unsigned long)buf & ~(PAGE_SIZE - 1),
> num_pages,
> - (type == PAGELIST_READ) /*Write */ ,
> - 0 /*Force */ ,
> + (type == PAGELIST_READ) ? FOLL_WRITE : 0,
> pages,
> NULL /*vmas */);
> up_read(&task->mm->mmap_sem);
> diff --git a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
> index e11c0e0..7b6cd4d 100644
> --- a/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
> +++ b/drivers/staging/vc04_services/interface/vchiq_arm/vchiq_arm.c
> @@ -1477,8 +1477,7 @@ dump_phys_mem(void *virt_addr, uint32_t num_bytes)
> current->mm, /* mm */
> (unsigned long)virt_addr, /* start */
> num_pages, /* len */
> - 0, /* write */
> - 0, /* force */
> + 0, /* gup_flags */
> pages, /* pages (array of page pointers) */
> NULL); /* vmas */
> up_read(¤t->mm->mmap_sem);
> diff --git a/drivers/virt/fsl_hypervisor.c b/drivers/virt/fsl_hypervisor.c
> index 60bdad3..150ce2a 100644
> --- a/drivers/virt/fsl_hypervisor.c
> +++ b/drivers/virt/fsl_hypervisor.c
> @@ -245,8 +245,8 @@ static long ioctl_memcpy(struct fsl_hv_ioctl_memcpy __user *p)
> /* Get the physical addresses of the source buffer */
> down_read(¤t->mm->mmap_sem);
> num_pinned = get_user_pages(param.local_vaddr - lb_offset,
> - num_pages, (param.source == -1) ? READ : WRITE,
> - 0, pages, NULL);
> + num_pages, (param.source == -1) ? 0 : FOLL_WRITE,
> + pages, NULL);
> up_read(¤t->mm->mmap_sem);
>
> if (num_pinned != num_pages) {
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 5ff084f6..686a477 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1279,7 +1279,7 @@ long get_user_pages_remote(struct task_struct *tsk, struct mm_struct *mm,
> int write, int force, struct page **pages,
> struct vm_area_struct **vmas);
> long get_user_pages(unsigned long start, unsigned long nr_pages,
> - int write, int force, struct page **pages,
> + unsigned int gup_flags, struct page **pages,
> struct vm_area_struct **vmas);
> long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
> unsigned int gup_flags, struct page **pages, int *locked);
> diff --git a/mm/gup.c b/mm/gup.c
> index 7a0d033..dc91303 100644
> --- a/mm/gup.c
> +++ b/mm/gup.c
> @@ -977,18 +977,12 @@ EXPORT_SYMBOL(get_user_pages_remote);
> * obviously don't pass FOLL_REMOTE in here.
> */
> long get_user_pages(unsigned long start, unsigned long nr_pages,
> - int write, int force, struct page **pages,
> + unsigned int gup_flags, struct page **pages,
> struct vm_area_struct **vmas)
> {
> - unsigned int flags = FOLL_TOUCH;
> -
> - if (write)
> - flags |= FOLL_WRITE;
> - if (force)
> - flags |= FOLL_FORCE;
> -
> return __get_user_pages_locked(current, current->mm, start, nr_pages,
> - pages, vmas, NULL, false, flags);
> + pages, vmas, NULL, false,
> + gup_flags | FOLL_TOUCH);
> }
> EXPORT_SYMBOL(get_user_pages);
>
> diff --git a/mm/mempolicy.c b/mm/mempolicy.c
> index ad1c96a..0b859af 100644
> --- a/mm/mempolicy.c
> +++ b/mm/mempolicy.c
> @@ -850,7 +850,7 @@ static int lookup_node(unsigned long addr)
> struct page *p;
> int err;
>
> - err = get_user_pages(addr & PAGE_MASK, 1, 0, 0, &p, NULL);
> + err = get_user_pages(addr & PAGE_MASK, 1, 0, &p, NULL);
> if (err >= 0) {
> err = page_to_nid(p);
> put_page(p);
> diff --git a/mm/nommu.c b/mm/nommu.c
> index 842cfdd..70cb844 100644
> --- a/mm/nommu.c
> +++ b/mm/nommu.c
> @@ -160,18 +160,11 @@ long __get_user_pages(struct task_struct *tsk, struct mm_struct *mm,
> * - don't permit access to VMAs that don't support it, such as I/O mappings
> */
> long get_user_pages(unsigned long start, unsigned long nr_pages,
> - int write, int force, struct page **pages,
> + unsigned int gup_flags, struct page **pages,
> struct vm_area_struct **vmas)
> {
> - int flags = 0;
> -
> - if (write)
> - flags |= FOLL_WRITE;
> - if (force)
> - flags |= FOLL_FORCE;
> -
> - return __get_user_pages(current, current->mm, start, nr_pages, flags,
> - pages, vmas, NULL);
> + return __get_user_pages(current, current->mm, start, nr_pages,
> + gup_flags, pages, vmas, NULL);
> }
> EXPORT_SYMBOL(get_user_pages);
>
> @@ -179,10 +172,7 @@ long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
> unsigned int gup_flags, struct page **pages,
> int *locked)
> {
> - int write = gup_flags & FOLL_WRITE;
> - int force = gup_flags & FOLL_FORCE;
> -
> - return get_user_pages(start, nr_pages, write, force, pages, NULL);
> + return get_user_pages(start, nr_pages, gup_flags, pages, NULL);
> }
> EXPORT_SYMBOL(get_user_pages_locked);
>
> --
> 2.10.0
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* Re: [PATCH] crypto: ccm - avoid scatterlist for MAC encryption
From: Johannes Berg @ 2016-10-19 7:43 UTC (permalink / raw)
To: Herbert Xu, Ard Biesheuvel
Cc: Andy Lutomirski, Sergey Senozhatsky,
<netdev@vger.kernel.org>, David S. Miller,
<linux-wireless@vger.kernel.org>,
linux-kernel@vger.kernel.org, Jouni Malinen
In-Reply-To: <20161019033157.GA1457@gondor.apana.org.au>
On Wed, 2016-10-19 at 11:31 +0800, Herbert Xu wrote:
> On Mon, Oct 17, 2016 at 06:21:14PM +0100, Ard Biesheuvel wrote:
> >
> >
> > Annoyingly, all this complication with scatterlists etc is for
> > doing
> > asynchronous crypto via DMA capable crypto accelerators, and the
> > networking code (ipsec as well as mac80211, afaik) only allow
> > synchronous in the first place, given that they execute in softirq
> > context.
>
> I'm still thinking about the issue (in particular, whether we
> should continue to rely on the request context being SG-capable
> or allow it to be on the stack for AEAD).
:)
> But IPsec definitely supports async crypto. In fact it was the
> very first user of async crypto.
Yeah.
> mac80211 on the other hand is currently sync-only.
We could probably make mac80211 do that too, but can we guarantee in-
order processing? Anyway, it's pretty low priority, maybe never
happening, since hardly anyone really uses "software" crypto, the wifi
devices mostly have it built in anyway.
(One problem is that the skb->cb is already completely full, so we
can't stash away the AAD there)
johannes
^ permalink raw reply
* Re: [PATCH net-next 2/6] net: use core MTU range checking in wireless drivers
From: Johannes Berg @ 2016-10-19 7:38 UTC (permalink / raw)
To: Jarod Wilson, linux-kernel
Cc: netdev, linux-wireless, Maya Erez, Simon Kelley,
Stanislav Yakovlev
In-Reply-To: <20161019023333.15760-3-jarod@redhat.com>
On Tue, 2016-10-18 at 22:33 -0400, Jarod Wilson wrote:
> - set max_mtu in wil6210 driver
> - set max_mtu in atmel driver
> - set min/max_mtu in cisco airo driver, remove airo_change_mtu
> - set min/max_mtu in ipw2100/ipw2200 drivers, remove
> libipw_change_mtu
> - set min/max_mtu in p80211netdev, remove wlan_change_mtu
I guess we should do the same in net/mac80211/iface.c?
johannes
^ permalink raw reply
* Re: [PATCH 05/10] mm: replace get_vaddr_frames() write/force parameters with gup_flags
From: Jan Kara @ 2016-10-19 7:34 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: linux-mips, linux-fbdev, Jan Kara, kvm, linux-sh, Dave Hansen,
dri-devel, linux-mm, netdev, sparclinux, linux-ia64, linux-s390,
linux-samsung-soc, linux-scsi, linux-rdma, x86, Hugh Dickins,
linux-media, Rik van Riel, intel-gfx, adi-buildroot-devel,
ceph-devel, linux-arm-kernel, linux-cris-kernel, Linus Torvalds,
linuxppc-dev, linux-kernel, linux-security-module, linux-alpha,
lin
In-Reply-To: <20161013002020.3062-6-lstoakes@gmail.com>
On Thu 13-10-16 01:20:15, Lorenzo Stoakes wrote:
> This patch removes the write and force parameters from get_vaddr_frames() and
> replaces them with a gup_flags parameter to make the use of FOLL_FORCE explicit
> in callers as use of this flag can result in surprising behaviour (and hence
> bugs) within the mm subsystem.
>
> Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>
Looks good. You can add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
> ---
> drivers/gpu/drm/exynos/exynos_drm_g2d.c | 3 ++-
> drivers/media/platform/omap/omap_vout.c | 2 +-
> drivers/media/v4l2-core/videobuf2-memops.c | 6 +++++-
> include/linux/mm.h | 2 +-
> mm/frame_vector.c | 13 ++-----------
> 5 files changed, 11 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
> index aa92dec..fbd13fa 100644
> --- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
> +++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
> @@ -488,7 +488,8 @@ static dma_addr_t *g2d_userptr_get_dma_addr(struct drm_device *drm_dev,
> goto err_free;
> }
>
> - ret = get_vaddr_frames(start, npages, true, true, g2d_userptr->vec);
> + ret = get_vaddr_frames(start, npages, FOLL_FORCE | FOLL_WRITE,
> + g2d_userptr->vec);
> if (ret != npages) {
> DRM_ERROR("failed to get user pages from userptr.\n");
> if (ret < 0)
> diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c
> index e668dde..a31b95c 100644
> --- a/drivers/media/platform/omap/omap_vout.c
> +++ b/drivers/media/platform/omap/omap_vout.c
> @@ -214,7 +214,7 @@ static int omap_vout_get_userptr(struct videobuf_buffer *vb, u32 virtp,
> if (!vec)
> return -ENOMEM;
>
> - ret = get_vaddr_frames(virtp, 1, true, false, vec);
> + ret = get_vaddr_frames(virtp, 1, FOLL_WRITE, vec);
> if (ret != 1) {
> frame_vector_destroy(vec);
> return -EINVAL;
> diff --git a/drivers/media/v4l2-core/videobuf2-memops.c b/drivers/media/v4l2-core/videobuf2-memops.c
> index 3c3b517..1cd322e 100644
> --- a/drivers/media/v4l2-core/videobuf2-memops.c
> +++ b/drivers/media/v4l2-core/videobuf2-memops.c
> @@ -42,6 +42,10 @@ struct frame_vector *vb2_create_framevec(unsigned long start,
> unsigned long first, last;
> unsigned long nr;
> struct frame_vector *vec;
> + unsigned int flags = FOLL_FORCE;
> +
> + if (write)
> + flags |= FOLL_WRITE;
>
> first = start >> PAGE_SHIFT;
> last = (start + length - 1) >> PAGE_SHIFT;
> @@ -49,7 +53,7 @@ struct frame_vector *vb2_create_framevec(unsigned long start,
> vec = frame_vector_create(nr);
> if (!vec)
> return ERR_PTR(-ENOMEM);
> - ret = get_vaddr_frames(start & PAGE_MASK, nr, write, true, vec);
> + ret = get_vaddr_frames(start & PAGE_MASK, nr, flags, vec);
> if (ret < 0)
> goto out_destroy;
> /* We accept only complete set of PFNs */
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 27ab538..5ff084f6 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -1305,7 +1305,7 @@ struct frame_vector {
> struct frame_vector *frame_vector_create(unsigned int nr_frames);
> void frame_vector_destroy(struct frame_vector *vec);
> int get_vaddr_frames(unsigned long start, unsigned int nr_pfns,
> - bool write, bool force, struct frame_vector *vec);
> + unsigned int gup_flags, struct frame_vector *vec);
> void put_vaddr_frames(struct frame_vector *vec);
> int frame_vector_to_pages(struct frame_vector *vec);
> void frame_vector_to_pfns(struct frame_vector *vec);
> diff --git a/mm/frame_vector.c b/mm/frame_vector.c
> index 81b6749..db77dcb 100644
> --- a/mm/frame_vector.c
> +++ b/mm/frame_vector.c
> @@ -11,10 +11,7 @@
> * get_vaddr_frames() - map virtual addresses to pfns
> * @start: starting user address
> * @nr_frames: number of pages / pfns from start to map
> - * @write: whether pages will be written to by the caller
> - * @force: whether to force write access even if user mapping is
> - * readonly. See description of the same argument of
> - get_user_pages().
> + * @gup_flags: flags modifying lookup behaviour
> * @vec: structure which receives pages / pfns of the addresses mapped.
> * It should have space for at least nr_frames entries.
> *
> @@ -34,23 +31,17 @@
> * This function takes care of grabbing mmap_sem as necessary.
> */
> int get_vaddr_frames(unsigned long start, unsigned int nr_frames,
> - bool write, bool force, struct frame_vector *vec)
> + unsigned int gup_flags, struct frame_vector *vec)
> {
> struct mm_struct *mm = current->mm;
> struct vm_area_struct *vma;
> int ret = 0;
> int err;
> int locked;
> - unsigned int gup_flags = 0;
>
> if (nr_frames == 0)
> return 0;
>
> - if (write)
> - gup_flags |= FOLL_WRITE;
> - if (force)
> - gup_flags |= FOLL_FORCE;
> -
> if (WARN_ON_ONCE(nr_frames > vec->nr_allocated))
> nr_frames = vec->nr_allocated;
>
> --
> 2.10.0
>
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* Re: [PATCH 04/10] mm: replace get_user_pages_locked() write/force parameters with gup_flags
From: Jan Kara @ 2016-10-19 7:33 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: linux-mm, Linus Torvalds, Jan Kara, Hugh Dickins, Dave Hansen,
Rik van Riel, Mel Gorman, Andrew Morton, adi-buildroot-devel,
ceph-devel, dri-devel, intel-gfx, kvm, linux-alpha,
linux-arm-kernel, linux-cris-kernel, linux-fbdev, linux-fsdevel,
linux-ia64, linux-kernel, linux-media, linux-mips, linux-rdma,
linux-s390, linux-samsung-soc, linux-scsi, linux-security-module,
linux-sh@
In-Reply-To: <20161013002020.3062-5-lstoakes@gmail.com>
On Thu 13-10-16 01:20:14, Lorenzo Stoakes wrote:
> This patch removes the write and force parameters from get_user_pages_locked()
> and replaces them with a gup_flags parameter to make the use of FOLL_FORCE
> explicit in callers as use of this flag can result in surprising behaviour (and
> hence bugs) within the mm subsystem.
>
> Signed-off-by: Lorenzo Stoakes <lstoakes@gmail.com>
After our discussion the patch looks good to me. You can add:
Reviewed-by: Jan Kara <jack@suse.cz>
Honza
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [PATCH 04/10] mm: replace get_user_pages_locked() write/force parameters with gup_flags
From: Jan Kara @ 2016-10-19 7:32 UTC (permalink / raw)
To: Lorenzo Stoakes
Cc: Jan Kara, linux-mm, Linus Torvalds, Hugh Dickins, Dave Hansen,
Rik van Riel, Mel Gorman, Andrew Morton, adi-buildroot-devel,
ceph-devel, dri-devel, intel-gfx, kvm, linux-alpha,
linux-arm-kernel, linux-cris-kernel, linux-fbdev, linux-fsdevel,
linux-ia64, linux-kernel, linux-media, linux-mips, linux-rdma,
linux-s390, linux-samsung-soc, linux-scsi, linux-security-module,
linux-sh
In-Reply-To: <20161018135609.GA30025@lucifer>
On Tue 18-10-16 14:56:09, Lorenzo Stoakes wrote:
> On Tue, Oct 18, 2016 at 02:54:25PM +0200, Jan Kara wrote:
> > > @@ -1282,7 +1282,7 @@ long get_user_pages(unsigned long start, unsigned long nr_pages,
> > > int write, int force, struct page **pages,
> > > struct vm_area_struct **vmas);
> > > long get_user_pages_locked(unsigned long start, unsigned long nr_pages,
> > > - int write, int force, struct page **pages, int *locked);
> > > + unsigned int gup_flags, struct page **pages, int *locked);
> >
> > Hum, the prototype is inconsistent with e.g. __get_user_pages_unlocked()
> > where gup_flags come after **pages argument. Actually it makes more sense
> > to have it before **pages so that input arguments come first and output
> > arguments second but I don't care that much. But it definitely should be
> > consistent...
>
> It was difficult to decide quite how to arrange parameters as there was
> inconsitency with regards to parameter ordering already - for example
> __get_user_pages() places its flags argument before pages whereas, as you note,
> __get_user_pages_unlocked() puts them afterwards.
>
> I ended up compromising by trying to match the existing ordering of the function
> as much as I could by replacing write, force pairs with gup_flags in the same
> location (with the exception of get_user_pages_unlocked() which I felt should
> match __get_user_pages_unlocked() in signature) or if there was already a
> gup_flags parameter as in the case of __get_user_pages_unlocked() I simply
> removed the write, force pair and left the flags as the last parameter.
>
> I am happy to rearrange parameters as needed, however I am not sure if it'd be
> worthwhile for me to do so (I am keen to try to avoid adding too much noise here
> :)
>
> If we were to rearrange parameters for consistency I'd suggest adjusting
> __get_user_pages_unlocked() to put gup_flags before pages and do the same with
> get_user_pages_unlocked(), let me know what you think.
Yeah, ok. If the inconsistency is already there, just leave it for now.
Honza
--
Jan Kara <jack@suse.com>
SUSE Labs, CR
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: [RFC 1/6] qed: Add support for hardware offloaded iSCSI.
From: Hannes Reinecke @ 2016-10-19 7:31 UTC (permalink / raw)
To: manish.rangankar, lduncan, cleech
Cc: martin.petersen, jejb, linux-scsi, netdev, Yuval.Mintz,
QLogic-Storage-Upstream, Yuval Mintz, Arun Easi
In-Reply-To: <1476853273-22960-2-git-send-email-manish.rangankar@cavium.com>
On 10/19/2016 07:01 AM, manish.rangankar@cavium.com wrote:
> From: Yuval Mintz <Yuval.Mintz@qlogic.com>
>
> This adds the backbone required for the various HW initalizations
> which are necessary for the iSCSI driver (qedi) for QLogic FastLinQ
> 4xxxx line of adapters - FW notification, resource initializations, etc.
>
> Signed-off-by: Arun Easi <arun.easi@cavium.com>
> Signed-off-by: Yuval Mintz <yuval.mintz@cavium.com>
> ---
> drivers/net/ethernet/qlogic/Kconfig | 15 +
> drivers/net/ethernet/qlogic/qed/Makefile | 1 +
> drivers/net/ethernet/qlogic/qed/qed.h | 8 +-
> drivers/net/ethernet/qlogic/qed/qed_dev.c | 15 +
> drivers/net/ethernet/qlogic/qed/qed_int.h | 1 -
> drivers/net/ethernet/qlogic/qed/qed_iscsi.c | 1310 ++++++++++++++++++++++++
> drivers/net/ethernet/qlogic/qed/qed_iscsi.h | 52 +
> drivers/net/ethernet/qlogic/qed/qed_l2.c | 1 -
> drivers/net/ethernet/qlogic/qed/qed_ll2.c | 35 +-
> drivers/net/ethernet/qlogic/qed/qed_main.c | 2 -
> drivers/net/ethernet/qlogic/qed/qed_mcp.h | 6 -
> drivers/net/ethernet/qlogic/qed/qed_reg_addr.h | 2 +
> drivers/net/ethernet/qlogic/qed/qed_spq.c | 15 +
> include/linux/qed/qed_if.h | 2 +
> include/linux/qed/qed_iscsi_if.h | 249 +++++
> 15 files changed, 1692 insertions(+), 22 deletions(-)
> create mode 100644 drivers/net/ethernet/qlogic/qed/qed_iscsi.c
> create mode 100644 drivers/net/ethernet/qlogic/qed/qed_iscsi.h
> create mode 100644 include/linux/qed/qed_iscsi_if.h
>
> diff --git a/drivers/net/ethernet/qlogic/Kconfig b/drivers/net/ethernet/qlogic/Kconfig
> index 0df1391f9..bad4fae 100644
> --- a/drivers/net/ethernet/qlogic/Kconfig
> +++ b/drivers/net/ethernet/qlogic/Kconfig
> @@ -118,4 +118,19 @@ config INFINIBAND_QEDR
> for QLogic QED. This would be replaced by the 'real' option
> once the QEDR driver is added [+relocated].
>
> +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/net/ethernet/qlogic/qed/Makefile b/drivers/net/ethernet/qlogic/qed/Makefile
> index cda0af7..b76669c 100644
> --- a/drivers/net/ethernet/qlogic/qed/Makefile
> +++ b/drivers/net/ethernet/qlogic/qed/Makefile
> @@ -6,3 +6,4 @@ qed-y := qed_cxt.o qed_dev.o qed_hw.o qed_init_fw_funcs.o qed_init_ops.o \
> qed-$(CONFIG_QED_SRIOV) += qed_sriov.o qed_vf.o
> qed-$(CONFIG_QED_LL2) += qed_ll2.o
> qed-$(CONFIG_INFINIBAND_QEDR) += qed_roce.o
> +qed-$(CONFIG_QED_ISCSI) += qed_iscsi.o
> diff --git a/drivers/net/ethernet/qlogic/qed/qed.h b/drivers/net/ethernet/qlogic/qed/qed.h
> index 653bb57..a61b1c0 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed.h
> +++ b/drivers/net/ethernet/qlogic/qed/qed.h
> @@ -35,6 +35,7 @@
>
> #define QED_WFQ_UNIT 100
>
> +#define ISCSI_BDQ_ID(_port_id) (_port_id)
> #define QED_WID_SIZE (1024)
> #define QED_PF_DEMS_SIZE (4)
>
> @@ -167,6 +168,7 @@ enum QED_RESOURCES {
> QED_ILT,
> QED_LL2_QUEUE,
> QED_RDMA_STATS_QUEUE,
> + QED_CMDQS_CQS,
> QED_MAX_RESC,
> };
>
> @@ -379,6 +381,7 @@ struct qed_hwfn {
> bool using_ll2;
> struct qed_ll2_info *p_ll2_info;
> struct qed_rdma_info *p_rdma_info;
> + struct qed_iscsi_info *p_iscsi_info;
> struct qed_pf_params pf_params;
>
> bool b_rdma_enabled_in_prs;
> @@ -578,6 +581,8 @@ struct qed_dev {
> /* Linux specific here */
> struct qede_dev *edev;
> struct pci_dev *pdev;
> + u32 flags;
> +#define QED_FLAG_STORAGE_STARTED (BIT(0))
> int msg_enable;
>
> struct pci_params pci_params;
> @@ -591,6 +596,7 @@ struct qed_dev {
> union {
> struct qed_common_cb_ops *common;
> struct qed_eth_cb_ops *eth;
> + struct qed_iscsi_cb_ops *iscsi;
> } protocol_ops;
> void *ops_cookie;
>
> @@ -600,7 +606,7 @@ struct qed_dev {
> struct qed_cb_ll2_info *ll2;
> u8 ll2_mac_address[ETH_ALEN];
> #endif
> -
> + DECLARE_HASHTABLE(connections, 10);
> const struct firmware *firmware;
>
> u32 rdma_max_sge;
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_dev.c b/drivers/net/ethernet/qlogic/qed/qed_dev.c
> index 754f6a9..a4234c0 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_dev.c
> +++ b/drivers/net/ethernet/qlogic/qed/qed_dev.c
> @@ -29,6 +29,7 @@
> #include "qed_hw.h"
> #include "qed_init_ops.h"
> #include "qed_int.h"
> +#include "qed_iscsi.h"
> #include "qed_ll2.h"
> #include "qed_mcp.h"
> #include "qed_reg_addr.h"
> @@ -155,6 +156,9 @@ void qed_resc_free(struct qed_dev *cdev)
> #ifdef CONFIG_QED_LL2
> qed_ll2_free(p_hwfn, p_hwfn->p_ll2_info);
> #endif
> + if (IS_ENABLED(CONFIG_QEDI) &&
> + p_hwfn->hw_info.personality == QED_PCI_ISCSI)
> + qed_iscsi_free(p_hwfn, p_hwfn->p_iscsi_info);
> qed_iov_free(p_hwfn);
> qed_dmae_info_free(p_hwfn);
> qed_dcbx_info_free(p_hwfn, p_hwfn->p_dcbx_info);
> @@ -411,6 +415,7 @@ int qed_qm_reconf(struct qed_hwfn *p_hwfn, struct qed_ptt *p_ptt)
>
> int qed_resc_alloc(struct qed_dev *cdev)
> {
> + struct qed_iscsi_info *p_iscsi_info;
> #ifdef CONFIG_QED_LL2
> struct qed_ll2_info *p_ll2_info;
> #endif
> @@ -532,6 +537,13 @@ int qed_resc_alloc(struct qed_dev *cdev)
> p_hwfn->p_ll2_info = p_ll2_info;
> }
> #endif
> + if (IS_ENABLED(CONFIG_QEDI) &&
> + p_hwfn->hw_info.personality == QED_PCI_ISCSI) {
> + p_iscsi_info = qed_iscsi_alloc(p_hwfn);
> + if (!p_iscsi_info)
> + goto alloc_no_mem;
> + p_hwfn->p_iscsi_info = p_iscsi_info;
> + }
>
> /* DMA info initialization */
> rc = qed_dmae_info_alloc(p_hwfn);
> @@ -585,6 +597,9 @@ void qed_resc_setup(struct qed_dev *cdev)
> if (p_hwfn->using_ll2)
> qed_ll2_setup(p_hwfn, p_hwfn->p_ll2_info);
> #endif
> + if (IS_ENABLED(CONFIG_QEDI) &&
> + p_hwfn->hw_info.personality == QED_PCI_ISCSI)
> + qed_iscsi_setup(p_hwfn, p_hwfn->p_iscsi_info);
> }
> }
>
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_int.h b/drivers/net/ethernet/qlogic/qed/qed_int.h
> index 0948be6..cc28066 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_int.h
> +++ b/drivers/net/ethernet/qlogic/qed/qed_int.h
> @@ -218,7 +218,6 @@ struct qed_igu_info {
> u16 free_blks;
> };
>
> -/* TODO Names of function may change... */
> void qed_int_igu_init_pure_rt(struct qed_hwfn *p_hwfn,
> struct qed_ptt *p_ptt,
> bool b_set,
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.c b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
> new file mode 100644
> index 0000000..cb22dad
> --- /dev/null
> +++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.c
> @@ -0,0 +1,1310 @@
> +/* QLogic qed NIC Driver
Shouldn't that be qedi iSCSI Driver?
> + * Copyright (c) 2015 QLogic Corporation
> + *
> + * 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/types.h>
> +#include <asm/byteorder.h>
> +#include <asm/param.h>
> +#include <linux/delay.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/etherdevice.h>
> +#include <linux/interrupt.h>
> +#include <linux/kernel.h>
> +#include <linux/log2.h>
> +#include <linux/module.h>
> +#include <linux/pci.h>
> +#include <linux/slab.h>
> +#include <linux/stddef.h>
> +#include <linux/string.h>
> +#include <linux/version.h>
> +#include <linux/workqueue.h>
> +#include <linux/errno.h>
> +#include <linux/list.h>
> +#include <linux/spinlock.h>
> +#include <linux/qed/qed_iscsi_if.h>
> +#include "qed.h"
> +#include "qed_cxt.h"
> +#include "qed_dev_api.h"
> +#include "qed_hsi.h"
> +#include "qed_hw.h"
> +#include "qed_int.h"
> +#include "qed_iscsi.h"
> +#include "qed_ll2.h"
> +#include "qed_mcp.h"
> +#include "qed_sp.h"
> +#include "qed_sriov.h"
> +#include "qed_reg_addr.h"
> +
> +struct qed_iscsi_conn {
> + struct list_head list_entry;
> + bool free_on_delete;
> +
> + u16 conn_id;
> + u32 icid;
> + u32 fw_cid;
> +
> + u8 layer_code;
> + u8 offl_flags;
> + u8 connect_mode;
> + u32 initial_ack;
> + dma_addr_t sq_pbl_addr;
> + struct qed_chain r2tq;
> + struct qed_chain xhq;
> + struct qed_chain uhq;
> +
> + struct tcp_upload_params *tcp_upload_params_virt_addr;
> + dma_addr_t tcp_upload_params_phys_addr;
> + struct scsi_terminate_extra_params *queue_cnts_virt_addr;
> + dma_addr_t queue_cnts_phys_addr;
> + dma_addr_t syn_phy_addr;
> +
> + u16 syn_ip_payload_length;
> + u8 local_mac[6];
> + u8 remote_mac[6];
> + u16 vlan_id;
> + u8 tcp_flags;
> + u8 ip_version;
> + u32 remote_ip[4];
> + u32 local_ip[4];
> + u8 ka_max_probe_cnt;
> + u8 dup_ack_theshold;
> + u32 rcv_next;
> + u32 snd_una;
> + u32 snd_next;
> + u32 snd_max;
> + u32 snd_wnd;
> + u32 rcv_wnd;
> + u32 snd_wl1;
> + u32 cwnd;
> + u32 ss_thresh;
> + u16 srtt;
> + u16 rtt_var;
> + u32 ts_time;
> + u32 ts_recent;
> + u32 ts_recent_age;
> + u32 total_rt;
> + u32 ka_timeout_delta;
> + u32 rt_timeout_delta;
> + u8 dup_ack_cnt;
> + u8 snd_wnd_probe_cnt;
> + u8 ka_probe_cnt;
> + u8 rt_cnt;
> + u32 flow_label;
> + u32 ka_timeout;
> + u32 ka_interval;
> + u32 max_rt_time;
> + u32 initial_rcv_wnd;
> + u8 ttl;
> + u8 tos_or_tc;
> + u16 remote_port;
> + u16 local_port;
> + u16 mss;
> + u8 snd_wnd_scale;
> + u8 rcv_wnd_scale;
> + u32 ts_ticks_per_second;
> + u16 da_timeout_value;
> + u8 ack_frequency;
> +
> + u8 update_flag;
> + u8 default_cq;
> + u32 max_seq_size;
> + u32 max_recv_pdu_length;
> + u32 max_send_pdu_length;
> + u32 first_seq_length;
> + u32 exp_stat_sn;
> + u32 stat_sn;
> + u16 physical_q0;
> + u16 physical_q1;
> + u8 abortive_dsconnect;
> +};
> +
> +static int
> +qed_sp_iscsi_func_start(struct qed_hwfn *p_hwfn,
> + enum spq_mode comp_mode,
> + struct qed_spq_comp_cb *p_comp_addr,
> + void *event_context, iscsi_event_cb_t async_event_cb)
> +{
> + struct iscsi_init_ramrod_params *p_ramrod = NULL;
> + struct scsi_init_func_queues *p_queue = NULL;
> + struct qed_iscsi_pf_params *p_params = NULL;
> + struct iscsi_spe_func_init *p_init = NULL;
> + struct qed_spq_entry *p_ent = NULL;
> + struct qed_sp_init_data init_data;
> + int rc = 0;
> + u32 dval;
> + u16 val;
> + u8 i;
> +
> + /* Get SPQ entry */
> + memset(&init_data, 0, sizeof(init_data));
> + init_data.cid = qed_spq_get_cid(p_hwfn);
> + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
> + init_data.comp_mode = comp_mode;
> + init_data.p_comp_data = p_comp_addr;
> +
> + rc = qed_sp_init_request(p_hwfn, &p_ent,
> + ISCSI_RAMROD_CMD_ID_INIT_FUNC,
> + PROTOCOLID_ISCSI, &init_data);
> + if (rc)
> + return rc;
> +
> + p_ramrod = &p_ent->ramrod.iscsi_init;
> + p_init = &p_ramrod->iscsi_init_spe;
> + p_params = &p_hwfn->pf_params.iscsi_pf_params;
> + p_queue = &p_init->q_params;
> +
> + SET_FIELD(p_init->hdr.flags,
> + ISCSI_SLOW_PATH_HDR_LAYER_CODE, ISCSI_SLOW_PATH_LAYER_CODE);
> + p_init->hdr.op_code = ISCSI_RAMROD_CMD_ID_INIT_FUNC;
> +
> + val = p_params->half_way_close_timeout;
> + p_init->half_way_close_timeout = cpu_to_le16(val);
> + p_init->num_sq_pages_in_ring = p_params->num_sq_pages_in_ring;
> + p_init->num_r2tq_pages_in_ring = p_params->num_r2tq_pages_in_ring;
> + p_init->num_uhq_pages_in_ring = p_params->num_uhq_pages_in_ring;
> + p_init->func_params.log_page_size = p_params->log_page_size;
> + val = p_params->num_tasks;
> + p_init->func_params.num_tasks = cpu_to_le16(val);
> + p_init->debug_mode.flags = p_params->debug_mode;
> +
> + DMA_REGPAIR_LE(p_queue->glbl_q_params_addr,
> + p_params->glbl_q_params_addr);
> +
> + val = p_params->cq_num_entries;
> + p_queue->cq_num_entries = cpu_to_le16(val);
> + val = p_params->cmdq_num_entries;
> + p_queue->cmdq_num_entries = cpu_to_le16(val);
> + p_queue->num_queues = p_params->num_queues;
> + dval = (u8)p_hwfn->hw_info.resc_start[QED_CMDQS_CQS];
> + p_queue->queue_relative_offset = (u8)dval;
> + p_queue->cq_sb_pi = p_params->gl_rq_pi;
> + p_queue->cmdq_sb_pi = p_params->gl_cmd_pi;
> +
> + for (i = 0; i < p_params->num_queues; i++) {
> + val = p_hwfn->sbs_info[i]->igu_sb_id;
> + p_queue->cq_cmdq_sb_num_arr[i] = cpu_to_le16(val);
> + }
> +
> + p_queue->bdq_resource_id = ISCSI_BDQ_ID(p_hwfn->port_id);
> +
> + DMA_REGPAIR_LE(p_queue->bdq_pbl_base_address[BDQ_ID_RQ],
> + p_params->bdq_pbl_base_addr[BDQ_ID_RQ]);
> + p_queue->bdq_pbl_num_entries[BDQ_ID_RQ] =
> + p_params->bdq_pbl_num_entries[BDQ_ID_RQ];
> + val = p_params->bdq_xoff_threshold[BDQ_ID_RQ];
> + p_queue->bdq_xoff_threshold[BDQ_ID_RQ] = cpu_to_le16(val);
> + val = p_params->bdq_xon_threshold[BDQ_ID_RQ];
> + p_queue->bdq_xon_threshold[BDQ_ID_RQ] = cpu_to_le16(val);
> +
> + DMA_REGPAIR_LE(p_queue->bdq_pbl_base_address[BDQ_ID_IMM_DATA],
> + p_params->bdq_pbl_base_addr[BDQ_ID_IMM_DATA]);
> + p_queue->bdq_pbl_num_entries[BDQ_ID_IMM_DATA] =
> + p_params->bdq_pbl_num_entries[BDQ_ID_IMM_DATA];
> + val = p_params->bdq_xoff_threshold[BDQ_ID_IMM_DATA];
> + p_queue->bdq_xoff_threshold[BDQ_ID_IMM_DATA] = cpu_to_le16(val);
> + val = p_params->bdq_xon_threshold[BDQ_ID_IMM_DATA];
> + p_queue->bdq_xon_threshold[BDQ_ID_IMM_DATA] = cpu_to_le16(val);
> + val = p_params->rq_buffer_size;
> + p_queue->rq_buffer_size = cpu_to_le16(val);
> + if (p_params->is_target) {
> + SET_FIELD(p_queue->q_validity,
> + SCSI_INIT_FUNC_QUEUES_RQ_VALID, 1);
> + if (p_queue->bdq_pbl_num_entries[BDQ_ID_IMM_DATA])
> + SET_FIELD(p_queue->q_validity,
> + SCSI_INIT_FUNC_QUEUES_IMM_DATA_VALID, 1);
> + SET_FIELD(p_queue->q_validity,
> + SCSI_INIT_FUNC_QUEUES_CMD_VALID, 1);
> + } else {
> + SET_FIELD(p_queue->q_validity,
> + SCSI_INIT_FUNC_QUEUES_RQ_VALID, 1);
> + }
> + p_ramrod->tcp_init.two_msl_timer = cpu_to_le32(p_params->two_msl_timer);
> + val = p_params->tx_sws_timer;
> + p_ramrod->tcp_init.tx_sws_timer = cpu_to_le16(val);
> + p_ramrod->tcp_init.maxfinrt = p_params->max_fin_rt;
> +
> + p_hwfn->p_iscsi_info->event_context = event_context;
> + p_hwfn->p_iscsi_info->event_cb = async_event_cb;
> +
> + return qed_spq_post(p_hwfn, p_ent, NULL);
> +}
> +
> +static int qed_sp_iscsi_conn_offload(struct qed_hwfn *p_hwfn,
> + struct qed_iscsi_conn *p_conn,
> + enum spq_mode comp_mode,
> + struct qed_spq_comp_cb *p_comp_addr)
> +{
> + struct iscsi_spe_conn_offload *p_ramrod = NULL;
> + struct tcp_offload_params_opt2 *p_tcp2 = NULL;
> + struct tcp_offload_params *p_tcp = NULL;
> + struct qed_spq_entry *p_ent = NULL;
> + struct qed_sp_init_data init_data;
> + union qed_qm_pq_params pq_params;
> + u16 pq0_id = 0, pq1_id = 0;
> + dma_addr_t r2tq_pbl_addr;
> + dma_addr_t xhq_pbl_addr;
> + dma_addr_t uhq_pbl_addr;
> + int rc = 0;
> + u32 dval;
> + u16 wval;
> + u8 ucval;
> + u8 i;
> +
> + /* Get SPQ entry */
> + memset(&init_data, 0, sizeof(init_data));
> + init_data.cid = p_conn->icid;
> + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
> + init_data.comp_mode = comp_mode;
> + init_data.p_comp_data = p_comp_addr;
> +
> + rc = qed_sp_init_request(p_hwfn, &p_ent,
> + ISCSI_RAMROD_CMD_ID_OFFLOAD_CONN,
> + PROTOCOLID_ISCSI, &init_data);
> + if (rc)
> + return rc;
> +
> + p_ramrod = &p_ent->ramrod.iscsi_conn_offload;
> +
> + /* Transmission PQ is the first of the PF */
> + memset(&pq_params, 0, sizeof(pq_params));
> + pq0_id = qed_get_qm_pq(p_hwfn, PROTOCOLID_ISCSI, &pq_params);
> + p_conn->physical_q0 = cpu_to_le16(pq0_id);
> + p_ramrod->iscsi.physical_q0 = cpu_to_le16(pq0_id);
> +
> + /* iSCSI Pure-ACK PQ */
> + pq_params.iscsi.q_idx = 1;
> + pq1_id = qed_get_qm_pq(p_hwfn, PROTOCOLID_ISCSI, &pq_params);
> + p_conn->physical_q1 = cpu_to_le16(pq1_id);
> + p_ramrod->iscsi.physical_q1 = cpu_to_le16(pq1_id);
> +
> + p_ramrod->hdr.op_code = ISCSI_RAMROD_CMD_ID_OFFLOAD_CONN;
> + SET_FIELD(p_ramrod->hdr.flags, ISCSI_SLOW_PATH_HDR_LAYER_CODE,
> + p_conn->layer_code);
> +
> + p_ramrod->conn_id = cpu_to_le16(p_conn->conn_id);
> + p_ramrod->fw_cid = cpu_to_le32(p_conn->icid);
> +
> + DMA_REGPAIR_LE(p_ramrod->iscsi.sq_pbl_addr, p_conn->sq_pbl_addr);
> +
> + r2tq_pbl_addr = qed_chain_get_pbl_phys(&p_conn->r2tq);
> + DMA_REGPAIR_LE(p_ramrod->iscsi.r2tq_pbl_addr, r2tq_pbl_addr);
> +
> + xhq_pbl_addr = qed_chain_get_pbl_phys(&p_conn->xhq);
> + DMA_REGPAIR_LE(p_ramrod->iscsi.xhq_pbl_addr, xhq_pbl_addr);
> +
> + uhq_pbl_addr = qed_chain_get_pbl_phys(&p_conn->uhq);
> + DMA_REGPAIR_LE(p_ramrod->iscsi.uhq_pbl_addr, uhq_pbl_addr);
> +
> + p_ramrod->iscsi.initial_ack = cpu_to_le32(p_conn->initial_ack);
> + p_ramrod->iscsi.flags = p_conn->offl_flags;
> + p_ramrod->iscsi.default_cq = p_conn->default_cq;
> + p_ramrod->iscsi.stat_sn = cpu_to_le32(p_conn->stat_sn);
> +
> + if (!GET_FIELD(p_ramrod->iscsi.flags,
> + ISCSI_CONN_OFFLOAD_PARAMS_TCP_ON_CHIP_1B)) {
> + p_tcp = &p_ramrod->tcp;
> + ucval = p_conn->local_mac[1];
> + ((u8 *)(&p_tcp->local_mac_addr_hi))[0] = ucval;
> + ucval = p_conn->local_mac[0];
> + ((u8 *)(&p_tcp->local_mac_addr_hi))[1] = ucval;
> + ucval = p_conn->local_mac[3];
> + ((u8 *)(&p_tcp->local_mac_addr_mid))[0] = ucval;
> + ucval = p_conn->local_mac[2];
> + ((u8 *)(&p_tcp->local_mac_addr_mid))[1] = ucval;
> + ucval = p_conn->local_mac[5];
> + ((u8 *)(&p_tcp->local_mac_addr_lo))[0] = ucval;
> + ucval = p_conn->local_mac[4];
> + ((u8 *)(&p_tcp->local_mac_addr_lo))[1] = ucval;
> + ucval = p_conn->remote_mac[1];
> + ((u8 *)(&p_tcp->remote_mac_addr_hi))[0] = ucval;
> + ucval = p_conn->remote_mac[0];
> + ((u8 *)(&p_tcp->remote_mac_addr_hi))[1] = ucval;
> + ucval = p_conn->remote_mac[3];
> + ((u8 *)(&p_tcp->remote_mac_addr_mid))[0] = ucval;
> + ucval = p_conn->remote_mac[2];
> + ((u8 *)(&p_tcp->remote_mac_addr_mid))[1] = ucval;
> + ucval = p_conn->remote_mac[5];
> + ((u8 *)(&p_tcp->remote_mac_addr_lo))[0] = ucval;
> + ucval = p_conn->remote_mac[4];
> + ((u8 *)(&p_tcp->remote_mac_addr_lo))[1] = ucval;
> +
This looks terribly like endianness swapping. You sure this is
applicable for all architecture and endianness settings?
And wouldn't it be better to use one of the get_unaligned_XXX functions
here?
> + p_tcp->vlan_id = cpu_to_le16(p_conn->vlan_id);
> +
> + p_tcp->flags = p_conn->tcp_flags;
> + p_tcp->ip_version = p_conn->ip_version;
> + for (i = 0; i < 4; i++) {
> + dval = p_conn->remote_ip[i];
> + p_tcp->remote_ip[i] = cpu_to_le32(dval);
> + dval = p_conn->local_ip[i];
> + p_tcp->local_ip[i] = cpu_to_le32(dval);
> + }
> + p_tcp->ka_max_probe_cnt = p_conn->ka_max_probe_cnt;
> + p_tcp->dup_ack_theshold = p_conn->dup_ack_theshold;
> +
> + p_tcp->rcv_next = cpu_to_le32(p_conn->rcv_next);
> + p_tcp->snd_una = cpu_to_le32(p_conn->snd_una);
> + p_tcp->snd_next = cpu_to_le32(p_conn->snd_next);
> + p_tcp->snd_max = cpu_to_le32(p_conn->snd_max);
> + p_tcp->snd_wnd = cpu_to_le32(p_conn->snd_wnd);
> + p_tcp->rcv_wnd = cpu_to_le32(p_conn->rcv_wnd);
> + p_tcp->snd_wl1 = cpu_to_le32(p_conn->snd_wl1);
> + p_tcp->cwnd = cpu_to_le32(p_conn->cwnd);
> + p_tcp->ss_thresh = cpu_to_le32(p_conn->ss_thresh);
> + p_tcp->srtt = cpu_to_le16(p_conn->srtt);
> + p_tcp->rtt_var = cpu_to_le16(p_conn->rtt_var);
> + p_tcp->ts_time = cpu_to_le32(p_conn->ts_time);
> + p_tcp->ts_recent = cpu_to_le32(p_conn->ts_recent);
> + p_tcp->ts_recent_age = cpu_to_le32(p_conn->ts_recent_age);
> + p_tcp->total_rt = cpu_to_le32(p_conn->total_rt);
> + dval = p_conn->ka_timeout_delta;
> + p_tcp->ka_timeout_delta = cpu_to_le32(dval);
> + dval = p_conn->rt_timeout_delta;
> + p_tcp->rt_timeout_delta = cpu_to_le32(dval);
> + p_tcp->dup_ack_cnt = p_conn->dup_ack_cnt;
> + p_tcp->snd_wnd_probe_cnt = p_conn->snd_wnd_probe_cnt;
> + p_tcp->ka_probe_cnt = p_conn->ka_probe_cnt;
> + p_tcp->rt_cnt = p_conn->rt_cnt;
> + p_tcp->flow_label = cpu_to_le32(p_conn->flow_label);
> + p_tcp->ka_timeout = cpu_to_le32(p_conn->ka_timeout);
> + p_tcp->ka_interval = cpu_to_le32(p_conn->ka_interval);
> + p_tcp->max_rt_time = cpu_to_le32(p_conn->max_rt_time);
> + dval = p_conn->initial_rcv_wnd;
> + p_tcp->initial_rcv_wnd = cpu_to_le32(dval);
> + p_tcp->ttl = p_conn->ttl;
> + p_tcp->tos_or_tc = p_conn->tos_or_tc;
> + p_tcp->remote_port = cpu_to_le16(p_conn->remote_port);
> + p_tcp->local_port = cpu_to_le16(p_conn->local_port);
> + p_tcp->mss = cpu_to_le16(p_conn->mss);
> + p_tcp->snd_wnd_scale = p_conn->snd_wnd_scale;
> + p_tcp->rcv_wnd_scale = p_conn->rcv_wnd_scale;
> + dval = p_conn->ts_ticks_per_second;
> + p_tcp->ts_ticks_per_second = cpu_to_le32(dval);
> + wval = p_conn->da_timeout_value;
> + p_tcp->da_timeout_value = cpu_to_le16(wval);
> + p_tcp->ack_frequency = p_conn->ack_frequency;
> + p_tcp->connect_mode = p_conn->connect_mode;
> + } else {
> + p_tcp2 =
> + &((struct iscsi_spe_conn_offload_option2 *)p_ramrod)->tcp;
> + ucval = p_conn->local_mac[1];
> + ((u8 *)(&p_tcp2->local_mac_addr_hi))[0] = ucval;
> + ucval = p_conn->local_mac[0];
> + ((u8 *)(&p_tcp2->local_mac_addr_hi))[1] = ucval;
> + ucval = p_conn->local_mac[3];
> + ((u8 *)(&p_tcp2->local_mac_addr_mid))[0] = ucval;
> + ucval = p_conn->local_mac[2];
> + ((u8 *)(&p_tcp2->local_mac_addr_mid))[1] = ucval;
> + ucval = p_conn->local_mac[5];
> + ((u8 *)(&p_tcp2->local_mac_addr_lo))[0] = ucval;
> + ucval = p_conn->local_mac[4];
> + ((u8 *)(&p_tcp2->local_mac_addr_lo))[1] = ucval;
> +
> + ucval = p_conn->remote_mac[1];
> + ((u8 *)(&p_tcp2->remote_mac_addr_hi))[0] = ucval;
> + ucval = p_conn->remote_mac[0];
> + ((u8 *)(&p_tcp2->remote_mac_addr_hi))[1] = ucval;
> + ucval = p_conn->remote_mac[3];
> + ((u8 *)(&p_tcp2->remote_mac_addr_mid))[0] = ucval;
> + ucval = p_conn->remote_mac[2];
> + ((u8 *)(&p_tcp2->remote_mac_addr_mid))[1] = ucval;
> + ucval = p_conn->remote_mac[5];
> + ((u8 *)(&p_tcp2->remote_mac_addr_lo))[0] = ucval;
> + ucval = p_conn->remote_mac[4];
> + ((u8 *)(&p_tcp2->remote_mac_addr_lo))[1] = ucval;
> +
Same here.
> + p_tcp2->vlan_id = cpu_to_le16(p_conn->vlan_id);
> + p_tcp2->flags = p_conn->tcp_flags;
> +
> + p_tcp2->ip_version = p_conn->ip_version;
> + for (i = 0; i < 4; i++) {
> + dval = p_conn->remote_ip[i];
> + p_tcp2->remote_ip[i] = cpu_to_le32(dval);
> + dval = p_conn->local_ip[i];
> + p_tcp2->local_ip[i] = cpu_to_le32(dval);
> + }
> +
> + p_tcp2->flow_label = cpu_to_le32(p_conn->flow_label);
> + p_tcp2->ttl = p_conn->ttl;
> + p_tcp2->tos_or_tc = p_conn->tos_or_tc;
> + p_tcp2->remote_port = cpu_to_le16(p_conn->remote_port);
> + p_tcp2->local_port = cpu_to_le16(p_conn->local_port);
> + p_tcp2->mss = cpu_to_le16(p_conn->mss);
> + p_tcp2->rcv_wnd_scale = p_conn->rcv_wnd_scale;
> + p_tcp2->connect_mode = p_conn->connect_mode;
> + wval = p_conn->syn_ip_payload_length;
> + p_tcp2->syn_ip_payload_length = cpu_to_le16(wval);
> + p_tcp2->syn_phy_addr_lo = DMA_LO_LE(p_conn->syn_phy_addr);
> + p_tcp2->syn_phy_addr_hi = DMA_HI_LE(p_conn->syn_phy_addr);
> + }
> +
> + return qed_spq_post(p_hwfn, p_ent, NULL);
> +}
> +
> +static int qed_sp_iscsi_conn_update(struct qed_hwfn *p_hwfn,
> + struct qed_iscsi_conn *p_conn,
> + enum spq_mode comp_mode,
> + struct qed_spq_comp_cb *p_comp_addr)
> +{
> + struct iscsi_conn_update_ramrod_params *p_ramrod = NULL;
> + struct qed_spq_entry *p_ent = NULL;
> + struct qed_sp_init_data init_data;
> + int rc = -EINVAL;
> + u32 dval;
> +
> + /* Get SPQ entry */
> + memset(&init_data, 0, sizeof(init_data));
> + init_data.cid = p_conn->icid;
> + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
> + init_data.comp_mode = comp_mode;
> + init_data.p_comp_data = p_comp_addr;
> +
> + rc = qed_sp_init_request(p_hwfn, &p_ent,
> + ISCSI_RAMROD_CMD_ID_UPDATE_CONN,
> + PROTOCOLID_ISCSI, &init_data);
> + if (rc)
> + return rc;
> +
> + p_ramrod = &p_ent->ramrod.iscsi_conn_update;
> + p_ramrod->hdr.op_code = ISCSI_RAMROD_CMD_ID_UPDATE_CONN;
> + SET_FIELD(p_ramrod->hdr.flags,
> + ISCSI_SLOW_PATH_HDR_LAYER_CODE, p_conn->layer_code);
> +
> + p_ramrod->conn_id = cpu_to_le16(p_conn->conn_id);
> + p_ramrod->fw_cid = cpu_to_le32(p_conn->icid);
> + p_ramrod->flags = p_conn->update_flag;
> + p_ramrod->max_seq_size = cpu_to_le32(p_conn->max_seq_size);
> + dval = p_conn->max_recv_pdu_length;
> + p_ramrod->max_recv_pdu_length = cpu_to_le32(dval);
> + dval = p_conn->max_send_pdu_length;
> + p_ramrod->max_send_pdu_length = cpu_to_le32(dval);
> + dval = p_conn->first_seq_length;
> + p_ramrod->first_seq_length = cpu_to_le32(dval);
> + p_ramrod->exp_stat_sn = cpu_to_le32(p_conn->exp_stat_sn);
> +
> + return qed_spq_post(p_hwfn, p_ent, NULL);
> +}
> +
> +static int qed_sp_iscsi_conn_terminate(struct qed_hwfn *p_hwfn,
> + struct qed_iscsi_conn *p_conn,
> + enum spq_mode comp_mode,
> + struct qed_spq_comp_cb *p_comp_addr)
> +{
> + struct iscsi_spe_conn_termination *p_ramrod = NULL;
> + struct qed_spq_entry *p_ent = NULL;
> + struct qed_sp_init_data init_data;
> + int rc = -EINVAL;
> +
> + /* Get SPQ entry */
> + memset(&init_data, 0, sizeof(init_data));
> + init_data.cid = p_conn->icid;
> + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
> + init_data.comp_mode = comp_mode;
> + init_data.p_comp_data = p_comp_addr;
> +
> + rc = qed_sp_init_request(p_hwfn, &p_ent,
> + ISCSI_RAMROD_CMD_ID_TERMINATION_CONN,
> + PROTOCOLID_ISCSI, &init_data);
> + if (rc)
> + return rc;
> +
> + p_ramrod = &p_ent->ramrod.iscsi_conn_terminate;
> + p_ramrod->hdr.op_code = ISCSI_RAMROD_CMD_ID_TERMINATION_CONN;
> + SET_FIELD(p_ramrod->hdr.flags,
> + ISCSI_SLOW_PATH_HDR_LAYER_CODE, p_conn->layer_code);
> +
> + p_ramrod->conn_id = cpu_to_le16(p_conn->conn_id);
> + p_ramrod->fw_cid = cpu_to_le32(p_conn->icid);
> + p_ramrod->abortive = p_conn->abortive_dsconnect;
> +
> + DMA_REGPAIR_LE(p_ramrod->query_params_addr,
> + p_conn->tcp_upload_params_phys_addr);
> + DMA_REGPAIR_LE(p_ramrod->queue_cnts_addr, p_conn->queue_cnts_phys_addr);
> +
> + return qed_spq_post(p_hwfn, p_ent, NULL);
> +}
> +
> +static int qed_sp_iscsi_conn_clear_sq(struct qed_hwfn *p_hwfn,
> + struct qed_iscsi_conn *p_conn,
> + enum spq_mode comp_mode,
> + struct qed_spq_comp_cb *p_comp_addr)
> +{
> + struct iscsi_slow_path_hdr *p_ramrod = NULL;
> + struct qed_spq_entry *p_ent = NULL;
> + struct qed_sp_init_data init_data;
> + int rc = -EINVAL;
> +
> + /* Get SPQ entry */
> + memset(&init_data, 0, sizeof(init_data));
> + init_data.cid = p_conn->icid;
> + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
> + init_data.comp_mode = comp_mode;
> + init_data.p_comp_data = p_comp_addr;
> +
> + rc = qed_sp_init_request(p_hwfn, &p_ent,
> + ISCSI_RAMROD_CMD_ID_CLEAR_SQ,
> + PROTOCOLID_ISCSI, &init_data);
> + if (rc)
> + return rc;
> +
> + p_ramrod = &p_ent->ramrod.iscsi_empty;
> + p_ramrod->op_code = ISCSI_RAMROD_CMD_ID_CLEAR_SQ;
> + SET_FIELD(p_ramrod->flags,
> + ISCSI_SLOW_PATH_HDR_LAYER_CODE, p_conn->layer_code);
> +
> + return qed_spq_post(p_hwfn, p_ent, NULL);
> +}
> +
> +static int qed_sp_iscsi_func_stop(struct qed_hwfn *p_hwfn,
> + enum spq_mode comp_mode,
> + struct qed_spq_comp_cb *p_comp_addr)
> +{
> + struct iscsi_spe_func_dstry *p_ramrod = NULL;
> + struct qed_spq_entry *p_ent = NULL;
> + struct qed_sp_init_data init_data;
> + int rc = 0;
> +
> + /* Get SPQ entry */
> + memset(&init_data, 0, sizeof(init_data));
> + init_data.cid = qed_spq_get_cid(p_hwfn);
> + init_data.opaque_fid = p_hwfn->hw_info.opaque_fid;
> + init_data.comp_mode = comp_mode;
> + init_data.p_comp_data = p_comp_addr;
> +
> + rc = qed_sp_init_request(p_hwfn, &p_ent,
> + ISCSI_RAMROD_CMD_ID_DESTROY_FUNC,
> + PROTOCOLID_ISCSI, &init_data);
> + if (rc)
> + return rc;
> +
> + p_ramrod = &p_ent->ramrod.iscsi_destroy;
> + p_ramrod->hdr.op_code = ISCSI_RAMROD_CMD_ID_DESTROY_FUNC;
> +
> + return qed_spq_post(p_hwfn, p_ent, NULL);
> +}
> +
> +static void __iomem *qed_iscsi_get_db_addr(struct qed_hwfn *p_hwfn, u32 cid)
> +{
> + return (u8 __iomem *)p_hwfn->doorbells +
> + qed_db_addr(cid, DQ_DEMS_LEGACY);
> +}
> +
> +static void __iomem *qed_iscsi_get_primary_bdq_prod(struct qed_hwfn *p_hwfn,
> + u8 bdq_id)
> +{
> + u8 bdq_function_id = ISCSI_BDQ_ID(p_hwfn->port_id);
> +
> + return (u8 __iomem *)p_hwfn->regview + GTT_BAR0_MAP_REG_MSDM_RAM +
> + MSTORM_SCSI_BDQ_EXT_PROD_OFFSET(bdq_function_id,
> + bdq_id);
> +}
> +
> +static void __iomem *qed_iscsi_get_secondary_bdq_prod(struct qed_hwfn *p_hwfn,
> + u8 bdq_id)
> +{
> + u8 bdq_function_id = ISCSI_BDQ_ID(p_hwfn->port_id);
> +
> + return (u8 __iomem *)p_hwfn->regview + GTT_BAR0_MAP_REG_TSDM_RAM +
> + TSTORM_SCSI_BDQ_EXT_PROD_OFFSET(bdq_function_id,
> + bdq_id);
> +}
> +
> +static int qed_iscsi_setup_connection(struct qed_hwfn *p_hwfn,
> + struct qed_iscsi_conn *p_conn)
> +{
> + if (!p_conn->queue_cnts_virt_addr)
> + goto nomem;
> + memset(p_conn->queue_cnts_virt_addr, 0,
> + sizeof(*p_conn->queue_cnts_virt_addr));
> +
> + if (!p_conn->tcp_upload_params_virt_addr)
> + goto nomem;
> + memset(p_conn->tcp_upload_params_virt_addr, 0,
> + sizeof(*p_conn->tcp_upload_params_virt_addr));
> +
> + if (!p_conn->r2tq.p_virt_addr)
> + goto nomem;
> + qed_chain_pbl_zero_mem(&p_conn->r2tq);
> +
> + if (!p_conn->uhq.p_virt_addr)
> + goto nomem;
> + qed_chain_pbl_zero_mem(&p_conn->uhq);
> +
> + if (!p_conn->xhq.p_virt_addr)
> + goto nomem;
> + qed_chain_pbl_zero_mem(&p_conn->xhq);
> +
> + return 0;
> +nomem:
> + return -ENOMEM;
> +}
> +
> +static int qed_iscsi_allocate_connection(struct qed_hwfn *p_hwfn,
> + struct qed_iscsi_conn **p_out_conn)
> +{
> + u16 uhq_num_elements = 0, xhq_num_elements = 0, r2tq_num_elements = 0;
> + struct scsi_terminate_extra_params *p_q_cnts = NULL;
> + struct qed_iscsi_pf_params *p_params = NULL;
> + struct tcp_upload_params *p_tcp = NULL;
> + struct qed_iscsi_conn *p_conn = NULL;
> + int rc = 0;
> +
> + /* Try finding a free connection that can be used */
> + spin_lock_bh(&p_hwfn->p_iscsi_info->lock);
> + if (!list_empty(&p_hwfn->p_iscsi_info->free_list))
> + p_conn = list_first_entry(&p_hwfn->p_iscsi_info->free_list,
> + struct qed_iscsi_conn, list_entry);
> + if (p_conn) {
> + list_del(&p_conn->list_entry);
> + spin_unlock_bh(&p_hwfn->p_iscsi_info->lock);
> + *p_out_conn = p_conn;
> + return 0;
> + }
> + spin_unlock_bh(&p_hwfn->p_iscsi_info->lock);
> +
> + /* Need to allocate a new connection */
> + p_params = &p_hwfn->pf_params.iscsi_pf_params;
> +
> + p_conn = kzalloc(sizeof(*p_conn), GFP_KERNEL);
> + if (!p_conn)
> + return -ENOMEM;
> +
> + p_q_cnts = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev,
> + sizeof(*p_q_cnts),
> + &p_conn->queue_cnts_phys_addr,
> + GFP_KERNEL);
> + if (!p_q_cnts)
> + goto nomem_queue_cnts_param;
> + p_conn->queue_cnts_virt_addr = p_q_cnts;
> +
> + p_tcp = dma_alloc_coherent(&p_hwfn->cdev->pdev->dev,
> + sizeof(*p_tcp),
> + &p_conn->tcp_upload_params_phys_addr,
> + GFP_KERNEL);
> + if (!p_tcp)
> + goto nomem_upload_param;
> + p_conn->tcp_upload_params_virt_addr = p_tcp;
> +
> + r2tq_num_elements = p_params->num_r2tq_pages_in_ring *
> + QED_CHAIN_PAGE_SIZE / 0x80;
> + rc = qed_chain_alloc(p_hwfn->cdev,
> + QED_CHAIN_USE_TO_CONSUME_PRODUCE,
> + QED_CHAIN_MODE_PBL,
> + QED_CHAIN_CNT_TYPE_U16,
> + r2tq_num_elements, 0x80, &p_conn->r2tq);
> + if (rc)
> + goto nomem_r2tq;
> +
> + uhq_num_elements = p_params->num_uhq_pages_in_ring *
> + QED_CHAIN_PAGE_SIZE / sizeof(struct iscsi_uhqe);
> + rc = qed_chain_alloc(p_hwfn->cdev,
> + QED_CHAIN_USE_TO_CONSUME_PRODUCE,
> + QED_CHAIN_MODE_PBL,
> + QED_CHAIN_CNT_TYPE_U16,
> + uhq_num_elements,
> + sizeof(struct iscsi_uhqe), &p_conn->uhq);
> + if (rc)
> + goto nomem_uhq;
> +
> + xhq_num_elements = uhq_num_elements;
> + rc = qed_chain_alloc(p_hwfn->cdev,
> + QED_CHAIN_USE_TO_CONSUME_PRODUCE,
> + QED_CHAIN_MODE_PBL,
> + QED_CHAIN_CNT_TYPE_U16,
> + xhq_num_elements,
> + sizeof(struct iscsi_xhqe), &p_conn->xhq);
> + if (rc)
> + goto nomem;
> +
> + p_conn->free_on_delete = true;
> + *p_out_conn = p_conn;
> + return 0;
> +
> +nomem:
> + qed_chain_free(p_hwfn->cdev, &p_conn->uhq);
> +nomem_uhq:
> + qed_chain_free(p_hwfn->cdev, &p_conn->r2tq);
> +nomem_r2tq:
> + dma_free_coherent(&p_hwfn->cdev->pdev->dev,
> + sizeof(struct tcp_upload_params),
> + p_conn->tcp_upload_params_virt_addr,
> + p_conn->tcp_upload_params_phys_addr);
> +nomem_upload_param:
> + dma_free_coherent(&p_hwfn->cdev->pdev->dev,
> + sizeof(struct scsi_terminate_extra_params),
> + p_conn->queue_cnts_virt_addr,
> + p_conn->queue_cnts_phys_addr);
> +nomem_queue_cnts_param:
> + kfree(p_conn);
> +
> + return -ENOMEM;
> +}
> +
> +static int qed_iscsi_acquire_connection(struct qed_hwfn *p_hwfn,
> + struct qed_iscsi_conn *p_in_conn,
> + struct qed_iscsi_conn **p_out_conn)
> +{
> + struct qed_iscsi_conn *p_conn = NULL;
> + int rc = 0;
> + u32 icid;
> +
> + spin_lock_bh(&p_hwfn->p_iscsi_info->lock);
> + rc = qed_cxt_acquire_cid(p_hwfn, PROTOCOLID_ISCSI, &icid);
> + spin_unlock_bh(&p_hwfn->p_iscsi_info->lock);
> + if (rc)
> + return rc;
> +
> + /* Use input connection or allocate a new one */
> + if (p_in_conn)
> + p_conn = p_in_conn;
> + else
> + rc = qed_iscsi_allocate_connection(p_hwfn, &p_conn);
> +
> + if (!rc)
> + rc = qed_iscsi_setup_connection(p_hwfn, p_conn);
> +
> + if (rc) {
> + spin_lock_bh(&p_hwfn->p_iscsi_info->lock);
> + qed_cxt_release_cid(p_hwfn, icid);
> + spin_unlock_bh(&p_hwfn->p_iscsi_info->lock);
> + return rc;
> + }
> +
> + p_conn->icid = icid;
> + p_conn->conn_id = (u16)icid;
> + p_conn->fw_cid = (p_hwfn->hw_info.opaque_fid << 16) | icid;
> +
> + *p_out_conn = p_conn;
> +
> + return rc;
> +}
> +
> +static void qed_iscsi_release_connection(struct qed_hwfn *p_hwfn,
> + struct qed_iscsi_conn *p_conn)
> +{
> + spin_lock_bh(&p_hwfn->p_iscsi_info->lock);
> + list_add_tail(&p_conn->list_entry, &p_hwfn->p_iscsi_info->free_list);
> + qed_cxt_release_cid(p_hwfn, p_conn->icid);
> + spin_unlock_bh(&p_hwfn->p_iscsi_info->lock);
> +}
> +
> +struct qed_iscsi_info *qed_iscsi_alloc(struct qed_hwfn *p_hwfn)
> +{
> + struct qed_iscsi_info *p_iscsi_info;
> +
> + p_iscsi_info = kzalloc(sizeof(*p_iscsi_info), GFP_KERNEL);
> + if (!p_iscsi_info) {
> + DP_NOTICE(p_hwfn, "Failed to allocate qed_iscsi_info'\n");
> + return NULL;
> + }
> +
> + INIT_LIST_HEAD(&p_iscsi_info->free_list);
> + return p_iscsi_info;
> +}
> +
> +void qed_iscsi_setup(struct qed_hwfn *p_hwfn,
> + struct qed_iscsi_info *p_iscsi_info)
> +{
> + spin_lock_init(&p_iscsi_info->lock);
> +}
> +
> +void qed_iscsi_free(struct qed_hwfn *p_hwfn,
> + struct qed_iscsi_info *p_iscsi_info)
> +{
> + kfree(p_iscsi_info);
> +}
> +
> +static void _qed_iscsi_get_tstats(struct qed_hwfn *p_hwfn,
> + struct qed_ptt *p_ptt,
> + struct qed_iscsi_stats *p_stats)
> +{
> + struct tstorm_iscsi_stats_drv tstats;
> + u32 tstats_addr;
> +
> + memset(&tstats, 0, sizeof(tstats));
> + tstats_addr = BAR0_MAP_REG_TSDM_RAM +
> + TSTORM_ISCSI_RX_STATS_OFFSET(p_hwfn->rel_pf_id);
> + qed_memcpy_from(p_hwfn, p_ptt, &tstats, tstats_addr, sizeof(tstats));
> +
> + p_stats->iscsi_rx_bytes_cnt =
> + HILO_64_REGPAIR(tstats.iscsi_rx_bytes_cnt);
> + p_stats->iscsi_rx_packet_cnt =
> + HILO_64_REGPAIR(tstats.iscsi_rx_packet_cnt);
> + p_stats->iscsi_cmdq_threshold_cnt =
> + le32_to_cpu(tstats.iscsi_cmdq_threshold_cnt);
> + p_stats->iscsi_rq_threshold_cnt =
> + le32_to_cpu(tstats.iscsi_rq_threshold_cnt);
> + p_stats->iscsi_immq_threshold_cnt =
> + le32_to_cpu(tstats.iscsi_immq_threshold_cnt);
> +}
> +
> +static void _qed_iscsi_get_mstats(struct qed_hwfn *p_hwfn,
> + struct qed_ptt *p_ptt,
> + struct qed_iscsi_stats *p_stats)
> +{
> + struct mstorm_iscsi_stats_drv mstats;
> + u32 mstats_addr;
> +
> + memset(&mstats, 0, sizeof(mstats));
> + mstats_addr = BAR0_MAP_REG_MSDM_RAM +
> + MSTORM_ISCSI_RX_STATS_OFFSET(p_hwfn->rel_pf_id);
> + qed_memcpy_from(p_hwfn, p_ptt, &mstats, mstats_addr, sizeof(mstats));
> +
> + p_stats->iscsi_rx_dropped_pdus_task_not_valid =
> + HILO_64_REGPAIR(mstats.iscsi_rx_dropped_pdus_task_not_valid);
> +}
> +
> +static void _qed_iscsi_get_ustats(struct qed_hwfn *p_hwfn,
> + struct qed_ptt *p_ptt,
> + struct qed_iscsi_stats *p_stats)
> +{
> + struct ustorm_iscsi_stats_drv ustats;
> + u32 ustats_addr;
> +
> + memset(&ustats, 0, sizeof(ustats));
> + ustats_addr = BAR0_MAP_REG_USDM_RAM +
> + USTORM_ISCSI_RX_STATS_OFFSET(p_hwfn->rel_pf_id);
> + qed_memcpy_from(p_hwfn, p_ptt, &ustats, ustats_addr, sizeof(ustats));
> +
> + p_stats->iscsi_rx_data_pdu_cnt =
> + HILO_64_REGPAIR(ustats.iscsi_rx_data_pdu_cnt);
> + p_stats->iscsi_rx_r2t_pdu_cnt =
> + HILO_64_REGPAIR(ustats.iscsi_rx_r2t_pdu_cnt);
> + p_stats->iscsi_rx_total_pdu_cnt =
> + HILO_64_REGPAIR(ustats.iscsi_rx_total_pdu_cnt);
> +}
> +
> +static void _qed_iscsi_get_xstats(struct qed_hwfn *p_hwfn,
> + struct qed_ptt *p_ptt,
> + struct qed_iscsi_stats *p_stats)
> +{
> + struct xstorm_iscsi_stats_drv xstats;
> + u32 xstats_addr;
> +
> + memset(&xstats, 0, sizeof(xstats));
> + xstats_addr = BAR0_MAP_REG_XSDM_RAM +
> + XSTORM_ISCSI_TX_STATS_OFFSET(p_hwfn->rel_pf_id);
> + qed_memcpy_from(p_hwfn, p_ptt, &xstats, xstats_addr, sizeof(xstats));
> +
> + p_stats->iscsi_tx_go_to_slow_start_event_cnt =
> + HILO_64_REGPAIR(xstats.iscsi_tx_go_to_slow_start_event_cnt);
> + p_stats->iscsi_tx_fast_retransmit_event_cnt =
> + HILO_64_REGPAIR(xstats.iscsi_tx_fast_retransmit_event_cnt);
> +}
> +
> +static void _qed_iscsi_get_ystats(struct qed_hwfn *p_hwfn,
> + struct qed_ptt *p_ptt,
> + struct qed_iscsi_stats *p_stats)
> +{
> + struct ystorm_iscsi_stats_drv ystats;
> + u32 ystats_addr;
> +
> + memset(&ystats, 0, sizeof(ystats));
> + ystats_addr = BAR0_MAP_REG_YSDM_RAM +
> + YSTORM_ISCSI_TX_STATS_OFFSET(p_hwfn->rel_pf_id);
> + qed_memcpy_from(p_hwfn, p_ptt, &ystats, ystats_addr, sizeof(ystats));
> +
> + p_stats->iscsi_tx_data_pdu_cnt =
> + HILO_64_REGPAIR(ystats.iscsi_tx_data_pdu_cnt);
> + p_stats->iscsi_tx_r2t_pdu_cnt =
> + HILO_64_REGPAIR(ystats.iscsi_tx_r2t_pdu_cnt);
> + p_stats->iscsi_tx_total_pdu_cnt =
> + HILO_64_REGPAIR(ystats.iscsi_tx_total_pdu_cnt);
> +}
> +
> +static void _qed_iscsi_get_pstats(struct qed_hwfn *p_hwfn,
> + struct qed_ptt *p_ptt,
> + struct qed_iscsi_stats *p_stats)
> +{
> + struct pstorm_iscsi_stats_drv pstats;
> + u32 pstats_addr;
> +
> + memset(&pstats, 0, sizeof(pstats));
> + pstats_addr = BAR0_MAP_REG_PSDM_RAM +
> + PSTORM_ISCSI_TX_STATS_OFFSET(p_hwfn->rel_pf_id);
> + qed_memcpy_from(p_hwfn, p_ptt, &pstats, pstats_addr, sizeof(pstats));
> +
> + p_stats->iscsi_tx_bytes_cnt =
> + HILO_64_REGPAIR(pstats.iscsi_tx_bytes_cnt);
> + p_stats->iscsi_tx_packet_cnt =
> + HILO_64_REGPAIR(pstats.iscsi_tx_packet_cnt);
> +}
> +
> +static int qed_iscsi_get_stats(struct qed_hwfn *p_hwfn,
> + struct qed_iscsi_stats *stats)
> +{
> + struct qed_ptt *p_ptt;
> +
> + memset(stats, 0, sizeof(*stats));
> +
> + p_ptt = qed_ptt_acquire(p_hwfn);
> + if (!p_ptt) {
> + DP_ERR(p_hwfn, "Failed to acquire ptt\n");
> + return -EAGAIN;
> + }
> +
> + _qed_iscsi_get_tstats(p_hwfn, p_ptt, stats);
> + _qed_iscsi_get_mstats(p_hwfn, p_ptt, stats);
> + _qed_iscsi_get_ustats(p_hwfn, p_ptt, stats);
> +
> + _qed_iscsi_get_xstats(p_hwfn, p_ptt, stats);
> + _qed_iscsi_get_ystats(p_hwfn, p_ptt, stats);
> + _qed_iscsi_get_pstats(p_hwfn, p_ptt, stats);
> +
> + qed_ptt_release(p_hwfn, p_ptt);
> +
> + return 0;
> +}
> +
> +struct qed_hash_iscsi_con {
> + struct hlist_node node;
> + struct qed_iscsi_conn *con;
> +};
> +
> +static int qed_fill_iscsi_dev_info(struct qed_dev *cdev,
> + struct qed_dev_iscsi_info *info)
> +{
> + struct qed_hwfn *hwfn = QED_LEADING_HWFN(cdev);
> +
> + int rc;
> +
> + memset(info, 0, sizeof(*info));
> + rc = qed_fill_dev_info(cdev, &info->common);
> +
> + info->primary_dbq_rq_addr =
> + qed_iscsi_get_primary_bdq_prod(hwfn, BDQ_ID_RQ);
> + info->secondary_bdq_rq_addr =
> + qed_iscsi_get_secondary_bdq_prod(hwfn, BDQ_ID_RQ);
> +
> + return rc;
> +}
> +
> +static void qed_register_iscsi_ops(struct qed_dev *cdev,
> + struct qed_iscsi_cb_ops *ops, void *cookie)
> +{
> + cdev->protocol_ops.iscsi = ops;
> + cdev->ops_cookie = cookie;
> +}
> +
> +static struct qed_hash_iscsi_con *qed_iscsi_get_hash(struct qed_dev *cdev,
> + u32 handle)
> +{
> + struct qed_hash_iscsi_con *hash_con = NULL;
> +
> + if (!(cdev->flags & QED_FLAG_STORAGE_STARTED))
> + return NULL;
> +
> + hash_for_each_possible(cdev->connections, hash_con, node, handle) {
> + if (hash_con->con->icid == handle)
> + break;
> + }
> +
> + if (!hash_con || (hash_con->con->icid != handle))
> + return NULL;
> +
> + return hash_con;
> +}
> +
> +static int qed_iscsi_stop(struct qed_dev *cdev)
> +{
> + int rc;
> +
> + if (!(cdev->flags & QED_FLAG_STORAGE_STARTED)) {
> + DP_NOTICE(cdev, "iscsi already stopped\n");
> + return 0;
> + }
> +
> + if (!hash_empty(cdev->connections)) {
> + DP_NOTICE(cdev,
> + "Can't stop iscsi - not all connections were returned\n");
> + return -EINVAL;
> + }
> +
> + /* Stop the iscsi */
> + rc = qed_sp_iscsi_func_stop(QED_LEADING_HWFN(cdev),
> + QED_SPQ_MODE_EBLOCK, NULL);
> + cdev->flags &= ~QED_FLAG_STORAGE_STARTED;
> +
> + return rc;
> +}
> +
> +static int qed_iscsi_start(struct qed_dev *cdev,
> + struct qed_iscsi_tid *tasks,
> + void *event_context,
> + iscsi_event_cb_t async_event_cb)
> +{
> + int rc;
> +
> + if (cdev->flags & QED_FLAG_STORAGE_STARTED) {
> + DP_NOTICE(cdev, "iscsi already started;\n");
> + return 0;
> + }
> +
> + rc = qed_sp_iscsi_func_start(QED_LEADING_HWFN(cdev),
> + QED_SPQ_MODE_EBLOCK, NULL, event_context,
> + async_event_cb);
> + if (rc) {
> + DP_NOTICE(cdev, "Failed to start iscsi\n");
> + return rc;
> + }
> +
> + cdev->flags |= QED_FLAG_STORAGE_STARTED;
> + hash_init(cdev->connections);
> +
> + if (tasks) {
> + struct qed_tid_mem *tid_info = kzalloc(sizeof(*tid_info),
> + GFP_KERNEL);
> +
> + if (!tid_info) {
> + DP_NOTICE(cdev,
> + "Failed to allocate tasks information\n");
> + qed_iscsi_stop(cdev);
> + return -ENOMEM;
> + }
> +
> + rc = qed_cxt_get_tid_mem_info(QED_LEADING_HWFN(cdev),
> + tid_info);
> + if (rc) {
> + DP_NOTICE(cdev, "Failed to gather task information\n");
> + qed_iscsi_stop(cdev);
> + kfree(tid_info);
> + return rc;
> + }
> +
> + /* Fill task information */
> + tasks->size = tid_info->tid_size;
> + tasks->num_tids_per_block = tid_info->num_tids_per_block;
> + memcpy(tasks->blocks, tid_info->blocks, MAX_TID_BLOCKS);
> +
> + kfree(tid_info);
> + }
> +
> + return 0;
> +}
> +
> +static int qed_iscsi_acquire_conn(struct qed_dev *cdev,
> + u32 *handle,
> + u32 *fw_cid, void __iomem **p_doorbell)
> +{
> + struct qed_hash_iscsi_con *hash_con;
> + int rc;
> +
> + /* Allocate a hashed connection */
> + hash_con = kzalloc(sizeof(*hash_con), GFP_ATOMIC);
> + if (!hash_con) {
> + DP_NOTICE(cdev, "Failed to allocate hashed connection\n");
> + return -ENOMEM;
> + }
> +
> + /* Acquire the connection */
> + rc = qed_iscsi_acquire_connection(QED_LEADING_HWFN(cdev), NULL,
> + &hash_con->con);
> + if (rc) {
> + DP_NOTICE(cdev, "Failed to acquire Connection\n");
> + kfree(hash_con);
> + return rc;
> + }
> +
> + /* Added the connection to hash table */
> + *handle = hash_con->con->icid;
> + *fw_cid = hash_con->con->fw_cid;
> + hash_add(cdev->connections, &hash_con->node, *handle);
> +
> + if (p_doorbell)
> + *p_doorbell = qed_iscsi_get_db_addr(QED_LEADING_HWFN(cdev),
> + *handle);
> +
> + return 0;
> +}
> +
> +static int qed_iscsi_release_conn(struct qed_dev *cdev, u32 handle)
> +{
> + struct qed_hash_iscsi_con *hash_con;
> +
> + hash_con = qed_iscsi_get_hash(cdev, handle);
> + if (!hash_con) {
> + DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
> + handle);
> + return -EINVAL;
> + }
> +
> + hlist_del(&hash_con->node);
> + qed_iscsi_release_connection(QED_LEADING_HWFN(cdev), hash_con->con);
> + kfree(hash_con);
> +
> + return 0;
> +}
> +
> +static int qed_iscsi_offload_conn(struct qed_dev *cdev,
> + u32 handle,
> + struct qed_iscsi_params_offload *conn_info)
> +{
> + struct qed_hash_iscsi_con *hash_con;
> + struct qed_iscsi_conn *con;
> +
> + hash_con = qed_iscsi_get_hash(cdev, handle);
> + if (!hash_con) {
> + DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
> + handle);
> + return -EINVAL;
> + }
> +
> + /* Update the connection with information from the params */
> + con = hash_con->con;
> +
> + ether_addr_copy(con->local_mac, conn_info->src.mac);
> + ether_addr_copy(con->remote_mac, conn_info->dst.mac);
> + memcpy(con->local_ip, conn_info->src.ip, sizeof(con->local_ip));
> + memcpy(con->remote_ip, conn_info->dst.ip, sizeof(con->remote_ip));
> + con->local_port = conn_info->src.port;
> + con->remote_port = conn_info->dst.port;
> +
> + con->layer_code = conn_info->layer_code;
> + con->sq_pbl_addr = conn_info->sq_pbl_addr;
> + con->initial_ack = conn_info->initial_ack;
> + con->vlan_id = conn_info->vlan_id;
> + con->tcp_flags = conn_info->tcp_flags;
> + con->ip_version = conn_info->ip_version;
> + con->default_cq = conn_info->default_cq;
> + con->ka_max_probe_cnt = conn_info->ka_max_probe_cnt;
> + con->dup_ack_theshold = conn_info->dup_ack_theshold;
> + con->rcv_next = conn_info->rcv_next;
> + con->snd_una = conn_info->snd_una;
> + con->snd_next = conn_info->snd_next;
> + con->snd_max = conn_info->snd_max;
> + con->snd_wnd = conn_info->snd_wnd;
> + con->rcv_wnd = conn_info->rcv_wnd;
> + con->snd_wl1 = conn_info->snd_wl1;
> + con->cwnd = conn_info->cwnd;
> + con->ss_thresh = conn_info->ss_thresh;
> + con->srtt = conn_info->srtt;
> + con->rtt_var = conn_info->rtt_var;
> + con->ts_time = conn_info->ts_time;
> + con->ts_recent = conn_info->ts_recent;
> + con->ts_recent_age = conn_info->ts_recent_age;
> + con->total_rt = conn_info->total_rt;
> + con->ka_timeout_delta = conn_info->ka_timeout_delta;
> + con->rt_timeout_delta = conn_info->rt_timeout_delta;
> + con->dup_ack_cnt = conn_info->dup_ack_cnt;
> + con->snd_wnd_probe_cnt = conn_info->snd_wnd_probe_cnt;
> + con->ka_probe_cnt = conn_info->ka_probe_cnt;
> + con->rt_cnt = conn_info->rt_cnt;
> + con->flow_label = conn_info->flow_label;
> + con->ka_timeout = conn_info->ka_timeout;
> + con->ka_interval = conn_info->ka_interval;
> + con->max_rt_time = conn_info->max_rt_time;
> + con->initial_rcv_wnd = conn_info->initial_rcv_wnd;
> + con->ttl = conn_info->ttl;
> + con->tos_or_tc = conn_info->tos_or_tc;
> + con->remote_port = conn_info->remote_port;
> + con->local_port = conn_info->local_port;
> + con->mss = conn_info->mss;
> + con->snd_wnd_scale = conn_info->snd_wnd_scale;
> + con->rcv_wnd_scale = conn_info->rcv_wnd_scale;
> + con->ts_ticks_per_second = conn_info->ts_ticks_per_second;
> + con->da_timeout_value = conn_info->da_timeout_value;
> + con->ack_frequency = conn_info->ack_frequency;
> +
> + /* Set default values on other connection fields */
> + con->offl_flags = 0x1;
> +
> + return qed_sp_iscsi_conn_offload(QED_LEADING_HWFN(cdev), con,
> + QED_SPQ_MODE_EBLOCK, NULL);
> +}
> +
> +static int qed_iscsi_update_conn(struct qed_dev *cdev,
> + u32 handle,
> + struct qed_iscsi_params_update *conn_info)
> +{
> + struct qed_hash_iscsi_con *hash_con;
> + struct qed_iscsi_conn *con;
> +
> + hash_con = qed_iscsi_get_hash(cdev, handle);
> + if (!hash_con) {
> + DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
> + handle);
> + return -EINVAL;
> + }
> +
> + /* Update the connection with information from the params */
> + con = hash_con->con;
> + con->update_flag = conn_info->update_flag;
> + con->max_seq_size = conn_info->max_seq_size;
> + con->max_recv_pdu_length = conn_info->max_recv_pdu_length;
> + con->max_send_pdu_length = conn_info->max_send_pdu_length;
> + con->first_seq_length = conn_info->first_seq_length;
> + con->exp_stat_sn = conn_info->exp_stat_sn;
> +
> + return qed_sp_iscsi_conn_update(QED_LEADING_HWFN(cdev), con,
> + QED_SPQ_MODE_EBLOCK, NULL);
> +}
> +
> +static int qed_iscsi_clear_conn_sq(struct qed_dev *cdev, u32 handle)
> +{
> + struct qed_hash_iscsi_con *hash_con;
> +
> + hash_con = qed_iscsi_get_hash(cdev, handle);
> + if (!hash_con) {
> + DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
> + handle);
> + return -EINVAL;
> + }
> +
> + return qed_sp_iscsi_conn_clear_sq(QED_LEADING_HWFN(cdev),
> + hash_con->con,
> + QED_SPQ_MODE_EBLOCK, NULL);
> +}
> +
> +static int qed_iscsi_destroy_conn(struct qed_dev *cdev,
> + u32 handle, u8 abrt_conn)
> +{
> + struct qed_hash_iscsi_con *hash_con;
> +
> + hash_con = qed_iscsi_get_hash(cdev, handle);
> + if (!hash_con) {
> + DP_NOTICE(cdev, "Failed to find connection for handle %d\n",
> + handle);
> + return -EINVAL;
> + }
> +
> + hash_con->con->abortive_dsconnect = abrt_conn;
> +
> + return qed_sp_iscsi_conn_terminate(QED_LEADING_HWFN(cdev),
> + hash_con->con,
> + QED_SPQ_MODE_EBLOCK, NULL);
> +}
> +
> +static int qed_iscsi_stats(struct qed_dev *cdev, struct qed_iscsi_stats *stats)
> +{
> + return qed_iscsi_get_stats(QED_LEADING_HWFN(cdev), stats);
> +}
> +
> +static const struct qed_iscsi_ops qed_iscsi_ops_pass = {
> + .common = &qed_common_ops_pass,
> + .ll2 = &qed_ll2_ops_pass,
> + .fill_dev_info = &qed_fill_iscsi_dev_info,
> + .register_ops = &qed_register_iscsi_ops,
> + .start = &qed_iscsi_start,
> + .stop = &qed_iscsi_stop,
> + .acquire_conn = &qed_iscsi_acquire_conn,
> + .release_conn = &qed_iscsi_release_conn,
> + .offload_conn = &qed_iscsi_offload_conn,
> + .update_conn = &qed_iscsi_update_conn,
> + .destroy_conn = &qed_iscsi_destroy_conn,
> + .clear_sq = &qed_iscsi_clear_conn_sq,
> + .get_stats = &qed_iscsi_stats,
> +};
> +
> +const struct qed_iscsi_ops *qed_get_iscsi_ops()
> +{
> + return &qed_iscsi_ops_pass;
> +}
> +EXPORT_SYMBOL(qed_get_iscsi_ops);
> +
> +void qed_put_iscsi_ops(void)
> +{
> +}
> +EXPORT_SYMBOL(qed_put_iscsi_ops);
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_iscsi.h b/drivers/net/ethernet/qlogic/qed/qed_iscsi.h
> new file mode 100644
> index 0000000..269848c
> --- /dev/null
> +++ b/drivers/net/ethernet/qlogic/qed/qed_iscsi.h
> @@ -0,0 +1,52 @@
> +/* QLogic qed NIC Driver
> + * Copyright (c) 2015 QLogic Corporation
> + *
> + * 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 _QED_ISCSI_H
> +#define _QED_ISCSI_H
> +#include <linux/types.h>
> +#include <linux/list.h>
> +#include <linux/slab.h>
> +#include <linux/spinlock.h>
> +#include <linux/qed/tcp_common.h>
> +#include <linux/qed/qed_iscsi_if.h>
> +#include <linux/qed/qed_chain.h>
> +#include "qed.h"
> +#include "qed_hsi.h"
> +#include "qed_mcp.h"
> +#include "qed_sp.h"
> +
> +struct qed_iscsi_info {
> + spinlock_t lock;
> + struct list_head free_list;
> + u16 max_num_outstanding_tasks;
> + void *event_context;
> + iscsi_event_cb_t event_cb;
> +};
> +
> +#ifdef CONFIG_QED_LL2
> +extern const struct qed_ll2_ops qed_ll2_ops_pass;
> +#endif
> +
> +#if IS_ENABLED(CONFIG_QEDI)
> +struct qed_iscsi_info *qed_iscsi_alloc(struct qed_hwfn *p_hwfn);
> +
> +void qed_iscsi_setup(struct qed_hwfn *p_hwfn,
> + struct qed_iscsi_info *p_iscsi_info);
> +
> +void qed_iscsi_free(struct qed_hwfn *p_hwfn,
> + struct qed_iscsi_info *p_iscsi_info);
> +#else /* IS_ENABLED(CONFIG_QEDI) */
> +static inline struct qed_iscsi_info *qed_iscsi_alloc(
> + struct qed_hwfn *p_hwfn) { return NULL; }
> +static inline void qed_iscsi_setup(struct qed_hwfn *p_hwfn,
> + struct qed_iscsi_info *p_iscsi_info) {}
> +static inline void qed_iscsi_free(struct qed_hwfn *p_hwfn,
> + struct qed_iscsi_info *p_iscsi_info) {}
> +#endif /* IS_ENABLED(CONFIG_QEDI) */
> +
> +#endif
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_l2.c b/drivers/net/ethernet/qlogic/qed/qed_l2.c
> index ddd410a..07e2f77 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_l2.c
> +++ b/drivers/net/ethernet/qlogic/qed/qed_l2.c
> @@ -2187,6 +2187,5 @@ const struct qed_eth_ops *qed_get_eth_ops(void)
>
> void qed_put_eth_ops(void)
> {
> - /* TODO - reference count for module? */
> }
> EXPORT_SYMBOL(qed_put_eth_ops);
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_ll2.c b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
> index a6db107..e67f3c9 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_ll2.c
> +++ b/drivers/net/ethernet/qlogic/qed/qed_ll2.c
> @@ -299,6 +299,7 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle)
> p_tx->cur_completing_bd_idx = 1;
> b_last_frag = p_tx->cur_completing_bd_idx == p_pkt->bd_used;
> tx_frag = p_pkt->bds_set[0].tx_frag;
> +#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
> if (p_ll2_conn->gsi_enable)
> qed_ll2b_release_tx_gsi_packet(p_hwfn,
> p_ll2_conn->my_id,
> @@ -307,6 +308,7 @@ static void qed_ll2_txq_flush(struct qed_hwfn *p_hwfn, u8 connection_handle)
> b_last_frag,
> b_last_packet);
> else
> +#endif
> qed_ll2b_complete_tx_packet(p_hwfn,
> p_ll2_conn->my_id,
> p_pkt->cookie,
Huh? What is that doing here?
> @@ -367,6 +369,7 @@ static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
>
> spin_unlock_irqrestore(&p_tx->lock, flags);
> tx_frag = p_pkt->bds_set[0].tx_frag;
> +#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
> if (p_ll2_conn->gsi_enable)
> qed_ll2b_complete_tx_gsi_packet(p_hwfn,
> p_ll2_conn->my_id,
> @@ -374,6 +377,7 @@ static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
> tx_frag,
> b_last_frag, !num_bds);
> else
> +#endif
> qed_ll2b_complete_tx_packet(p_hwfn,
> p_ll2_conn->my_id,
> p_pkt->cookie,
> @@ -421,6 +425,7 @@ static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
> "Mismatch between active_descq and the LL2 Rx chain\n");
> list_add_tail(&p_pkt->list_entry, &p_rx->free_descq);
>
> +#if IS_ENABLED(CONFIG_INFINIBAND_QEDR)
> spin_unlock_irqrestore(&p_rx->lock, lock_flags);
> qed_ll2b_complete_rx_gsi_packet(p_hwfn,
> p_ll2_info->my_id,
> @@ -433,6 +438,7 @@ static int qed_ll2_txq_completion(struct qed_hwfn *p_hwfn, void *p_cookie)
> src_mac_addrhi,
> src_mac_addrlo, b_last_cqe);
> spin_lock_irqsave(&p_rx->lock, lock_flags);
> +#endif
>
> return 0;
> }
> @@ -1516,11 +1522,12 @@ static void qed_ll2_register_cb_ops(struct qed_dev *cdev,
>
> static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
> {
> - struct qed_ll2_info ll2_info;
> + struct qed_ll2_info *ll2_info;
> struct qed_ll2_buffer *buffer;
> enum qed_ll2_conn_type conn_type;
> struct qed_ptt *p_ptt;
> int rc, i;
> + u8 gsi_enable = 1;
>
> /* Initialize LL2 locks & lists */
> INIT_LIST_HEAD(&cdev->ll2->list);
> @@ -1552,6 +1559,7 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
> switch (QED_LEADING_HWFN(cdev)->hw_info.personality) {
> case QED_PCI_ISCSI:
> conn_type = QED_LL2_TYPE_ISCSI;
> + gsi_enable = 0;
> break;
> case QED_PCI_ETH_ROCE:
> conn_type = QED_LL2_TYPE_ROCE;
> @@ -1561,18 +1569,23 @@ static int qed_ll2_start(struct qed_dev *cdev, struct qed_ll2_params *params)
> }
>
> /* Prepare the temporary ll2 information */
> - memset(&ll2_info, 0, sizeof(ll2_info));
> - ll2_info.conn_type = conn_type;
> - ll2_info.mtu = params->mtu;
> - ll2_info.rx_drop_ttl0_flg = params->drop_ttl0_packets;
> - ll2_info.rx_vlan_removal_en = params->rx_vlan_stripping;
> - ll2_info.tx_tc = 0;
> - ll2_info.tx_dest = CORE_TX_DEST_NW;
> - ll2_info.gsi_enable = 1;
> -
> - rc = qed_ll2_acquire_connection(QED_LEADING_HWFN(cdev), &ll2_info,
> + ll2_info = kzalloc(sizeof(*ll2_info), GFP_KERNEL);
> + if (!ll2_info) {
> + DP_INFO(cdev, "Failed to allocate LL2 info buffer\n");
> + goto fail;
> + }
> + ll2_info->conn_type = conn_type;
> + ll2_info->mtu = params->mtu;
> + ll2_info->rx_drop_ttl0_flg = params->drop_ttl0_packets;
> + ll2_info->rx_vlan_removal_en = params->rx_vlan_stripping;
> + ll2_info->tx_tc = 0;
> + ll2_info->tx_dest = CORE_TX_DEST_NW;
> + ll2_info->gsi_enable = gsi_enable;
> +
> + rc = qed_ll2_acquire_connection(QED_LEADING_HWFN(cdev), ll2_info,
> QED_LL2_RX_SIZE, QED_LL2_TX_SIZE,
> &cdev->ll2->handle);
> + kfree(ll2_info);
> if (rc) {
> DP_INFO(cdev, "Failed to acquire LL2 connection\n");
> goto fail;
Where is the benefit of this hunk? And is it related to iSCSI?
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_main.c b/drivers/net/ethernet/qlogic/qed/qed_main.c
> index 4ee3151..a01ad9d 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_main.c
> +++ b/drivers/net/ethernet/qlogic/qed/qed_main.c
> @@ -1239,7 +1239,6 @@ static void qed_fill_link(struct qed_hwfn *hwfn,
> if (link.link_up)
> if_link->link_up = true;
>
> - /* TODO - at the moment assume supported and advertised speed equal */
> if_link->supported_caps = QED_LM_FIBRE_BIT;
> if (params.speed.autoneg)
> if_link->supported_caps |= QED_LM_Autoneg_BIT;
> @@ -1294,7 +1293,6 @@ static void qed_fill_link(struct qed_hwfn *hwfn,
> if (link.link_up)
> if_link->speed = link.speed;
>
> - /* TODO - fill duplex properly */
> if_link->duplex = DUPLEX_FULL;
> qed_mcp_get_media_type(hwfn->cdev, &media_type);
> if_link->port = qed_get_port_type(media_type);
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_mcp.h b/drivers/net/ethernet/qlogic/qed/qed_mcp.h
> index dff520e..2e5f51b 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_mcp.h
> +++ b/drivers/net/ethernet/qlogic/qed/qed_mcp.h
> @@ -314,9 +314,6 @@ int qed_mcp_bist_clock_test(struct qed_hwfn *p_hwfn,
>
> /* Using hwfn number (and not pf_num) is required since in CMT mode,
> * same pf_num may be used by two different hwfn
> - * TODO - this shouldn't really be in .h file, but until all fields
> - * required during hw-init will be placed in their correct place in shmem
> - * we need it in qed_dev.c [for readin the nvram reflection in shmem].
> */
> #define MCP_PF_ID_BY_REL(p_hwfn, rel_pfid) (QED_IS_BB((p_hwfn)->cdev) ? \
> ((rel_pfid) | \
> @@ -324,9 +321,6 @@ int qed_mcp_bist_clock_test(struct qed_hwfn *p_hwfn,
> rel_pfid)
> #define MCP_PF_ID(p_hwfn) MCP_PF_ID_BY_REL(p_hwfn, (p_hwfn)->rel_pf_id)
>
> -/* TODO - this is only correct as long as only BB is supported, and
> - * no port-swapping is implemented; Afterwards we'll need to fix it.
> - */
> #define MFW_PORT(_p_hwfn) ((_p_hwfn)->abs_pf_id % \
> ((_p_hwfn)->cdev->num_ports_in_engines * 2))
> struct qed_mcp_info {
Please split off the patch and use a separate one to remove all the TODO
entries. They do not relate to the iSCSI offload bit.
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
> index b414a05..9754420 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
> +++ b/drivers/net/ethernet/qlogic/qed/qed_reg_addr.h
> @@ -82,6 +82,8 @@
> 0x1c80000UL
> #define BAR0_MAP_REG_XSDM_RAM \
> 0x1e00000UL
> +#define BAR0_MAP_REG_YSDM_RAM \
> + 0x1e80000UL
> #define NIG_REG_RX_LLH_BRB_GATE_DNTFWD_PERPF \
> 0x5011f4UL
> #define PRS_REG_SEARCH_TCP \
> diff --git a/drivers/net/ethernet/qlogic/qed/qed_spq.c b/drivers/net/ethernet/qlogic/qed/qed_spq.c
> index caff415..d3fa578 100644
> --- a/drivers/net/ethernet/qlogic/qed/qed_spq.c
> +++ b/drivers/net/ethernet/qlogic/qed/qed_spq.c
> @@ -24,6 +24,7 @@
> #include "qed_hsi.h"
> #include "qed_hw.h"
> #include "qed_int.h"
> +#include "qed_iscsi.h"
> #include "qed_mcp.h"
> #include "qed_reg_addr.h"
> #include "qed_sp.h"
> @@ -249,6 +250,20 @@ static int qed_spq_hw_post(struct qed_hwfn *p_hwfn,
> return qed_sriov_eqe_event(p_hwfn,
> p_eqe->opcode,
> p_eqe->echo, &p_eqe->data);
> + case PROTOCOLID_ISCSI:
> + if (!IS_ENABLED(CONFIG_QEDI))
> + return -EINVAL;
> +
> + if (p_hwfn->p_iscsi_info->event_cb) {
> + struct qed_iscsi_info *p_iscsi = p_hwfn->p_iscsi_info;
> +
> + return p_iscsi->event_cb(p_iscsi->event_context,
> + p_eqe->opcode, &p_eqe->data);
> + } else {
> + DP_NOTICE(p_hwfn,
> + "iSCSI async completion is not set\n");
> + return -EINVAL;
> + }
> default:
> DP_NOTICE(p_hwfn,
> "Unknown Async completion for protocol: %d\n",
> diff --git a/include/linux/qed/qed_if.h b/include/linux/qed/qed_if.h
> index f9ae903..c0c9fa8 100644
> --- a/include/linux/qed/qed_if.h
> +++ b/include/linux/qed/qed_if.h
> @@ -165,6 +165,7 @@ struct qed_iscsi_pf_params {
> u32 max_cwnd;
> u16 cq_num_entries;
> u16 cmdq_num_entries;
> + u32 two_msl_timer;
> u16 dup_ack_threshold;
> u16 tx_sws_timer;
> u16 min_rto;
> @@ -271,6 +272,7 @@ struct qed_dev_info {
> enum qed_sb_type {
> QED_SB_TYPE_L2_QUEUE,
> QED_SB_TYPE_CNQ,
> + QED_SB_TYPE_STORAGE,
> };
>
> enum qed_protocol {
> diff --git a/include/linux/qed/qed_iscsi_if.h b/include/linux/qed/qed_iscsi_if.h
> new file mode 100644
> index 0000000..6735ee5
> --- /dev/null
> +++ b/include/linux/qed/qed_iscsi_if.h
> @@ -0,0 +1,249 @@
> +/* QLogic qed NIC Driver
Again, this is the iSCSI driver, is it not?
> + * Copyright (c) 2015 QLogic Corporation
> + *
And you _might_ want to check the copyright, seeing that it's being
posted from the cavium.com domain ...
Cheers,
Hannes
--
Dr. Hannes Reinecke Teamlead Storage & Networking
hare@suse.de +49 911 74053 688
SUSE LINUX GmbH, Maxfeldstr. 5, 90409 Nürnberg
GF: F. Imendörffer, J. Smithard, J. Guild, D. Upmanyu, G. Norton
HRB 21284 (AG Nürnberg)
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox