--- /dev/null
+From 1ed9ec9b08addbd8d3e36d5f4a652d8590a6ddb7 Mon Sep 17 00:00:00 2001
+From: Daniel Mack <daniel@zonque.org>
+Date: Sat, 20 Jun 2020 21:39:25 +0200
+Subject: dsa: Allow forwarding of redirected IGMP traffic
+
+From: Daniel Mack <daniel@zonque.org>
+
+commit 1ed9ec9b08addbd8d3e36d5f4a652d8590a6ddb7 upstream.
+
+The driver for Marvell switches puts all ports in IGMP snooping mode
+which results in all IGMP/MLD frames that ingress on the ports to be
+forwarded to the CPU only.
+
+The bridge code in the kernel can then interpret these frames and act
+upon them, for instance by updating the mdb in the switch to reflect
+multicast memberships of stations connected to the ports. However,
+the IGMP/MLD frames must then also be forwarded to other ports of the
+bridge so external IGMP queriers can track membership reports, and
+external multicast clients can receive query reports from foreign IGMP
+queriers.
+
+Currently, this is impossible as the EDSA tagger sets offload_fwd_mark
+on the skb when it unwraps the tagged frames, and that will make the
+switchdev layer prevent the skb from egressing on any other port of
+the same switch.
+
+To fix that, look at the To_CPU code in the DSA header and make
+forwarding of the frame possible for trapped IGMP packets.
+
+Introduce some #defines for the frame types to make the code a bit more
+comprehensive.
+
+This was tested on a Marvell 88E6352 variant.
+
+Signed-off-by: Daniel Mack <daniel@zonque.org>
+Reviewed-by: Andrew Lunn <andrew@lunn.ch>
+Tested-by: Andrew Lunn <andrew@lunn.ch>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Cc: DENG Qingfang <dqfext@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ net/dsa/tag_edsa.c | 37 ++++++++++++++++++++++++++++++++++---
+ 1 file changed, 34 insertions(+), 3 deletions(-)
+
+--- a/net/dsa/tag_edsa.c
++++ b/net/dsa/tag_edsa.c
+@@ -17,6 +17,16 @@
+ #define DSA_HLEN 4
+ #define EDSA_HLEN 8
+
++#define FRAME_TYPE_TO_CPU 0x00
++#define FRAME_TYPE_FORWARD 0x03
++
++#define TO_CPU_CODE_MGMT_TRAP 0x00
++#define TO_CPU_CODE_FRAME2REG 0x01
++#define TO_CPU_CODE_IGMP_MLD_TRAP 0x02
++#define TO_CPU_CODE_POLICY_TRAP 0x03
++#define TO_CPU_CODE_ARP_MIRROR 0x04
++#define TO_CPU_CODE_POLICY_MIRROR 0x05
++
+ static struct sk_buff *edsa_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+ struct dsa_port *dp = dsa_slave_to_port(dev);
+@@ -81,6 +91,8 @@ static struct sk_buff *edsa_rcv(struct s
+ struct packet_type *pt)
+ {
+ u8 *edsa_header;
++ int frame_type;
++ int code;
+ int source_device;
+ int source_port;
+
+@@ -95,8 +107,29 @@ static struct sk_buff *edsa_rcv(struct s
+ /*
+ * Check that frame type is either TO_CPU or FORWARD.
+ */
+- if ((edsa_header[0] & 0xc0) != 0x00 && (edsa_header[0] & 0xc0) != 0xc0)
++ frame_type = edsa_header[0] >> 6;
++
++ switch (frame_type) {
++ case FRAME_TYPE_TO_CPU:
++ code = (edsa_header[1] & 0x6) | ((edsa_header[2] >> 4) & 1);
++
++ /*
++ * Mark the frame to never egress on any port of the same switch
++ * unless it's a trapped IGMP/MLD packet, in which case the
++ * bridge might want to forward it.
++ */
++ if (code != TO_CPU_CODE_IGMP_MLD_TRAP)
++ skb->offload_fwd_mark = 1;
++
++ break;
++
++ case FRAME_TYPE_FORWARD:
++ skb->offload_fwd_mark = 1;
++ break;
++
++ default:
+ return NULL;
++ }
+
+ /*
+ * Determine source device and port.
+@@ -160,8 +193,6 @@ static struct sk_buff *edsa_rcv(struct s
+ 2 * ETH_ALEN);
+ }
+
+- skb->offload_fwd_mark = 1;
+-
+ return skb;
+ }
+
--- /dev/null
+From cd4ed6b470f1569692b5d0d295b207f870570829 Mon Sep 17 00:00:00 2001
+From: Quinn Tran <quinn.tran@cavium.com>
+Date: Fri, 31 Aug 2018 11:24:31 -0700
+Subject: scsi: qla2xxx: Move rport registration out of internal work_list
+
+From: Quinn Tran <quinn.tran@cavium.com>
+
+commit cd4ed6b470f1569692b5d0d295b207f870570829 upstream.
+
+Currently, the rport registration is being called from a single work element
+that is used to process QLA internal "work_list". This work_list is meant for
+quick and simple task (ie no sleep). The Rport registration process sometime
+can be delayed by upper layer. This causes back pressure with the internal
+queue where other jobs are unable to move forward.
+
+This patch will schedule the registration process with a new work element
+(fc_port.reg_work). While the RPort is being registered, the current state of
+the fcport will not move forward until the registration is done. If the state
+of the fabric has changed, a new field/next_disc_state will record the next
+action on whether to 'DELETE' or 'Reverify the session/ADISC'.
+
+Signed-off-by: Quinn Tran <quinn.tran@cavium.com>
+Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Zhengyuan Liu <liuzhengyuan@kylinos.cn>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/scsi/qla2xxx/qla_def.h | 6 +-
+ drivers/scsi/qla2xxx/qla_gbl.h | 5 +-
+ drivers/scsi/qla2xxx/qla_init.c | 66 ++++++++++++++++++++++++++----
+ drivers/scsi/qla2xxx/qla_os.c | 26 +++++++----
+ drivers/scsi/qla2xxx/qla_target.c | 83 ++++++++++++++++++++++++++++++--------
+ 5 files changed, 147 insertions(+), 39 deletions(-)
+
+--- a/drivers/scsi/qla2xxx/qla_def.h
++++ b/drivers/scsi/qla2xxx/qla_def.h
+@@ -2375,11 +2375,13 @@ typedef struct fc_port {
+ unsigned long expires;
+ struct list_head del_list_entry;
+ struct work_struct free_work;
+-
++ struct work_struct reg_work;
++ uint64_t jiffies_at_registration;
+ struct qlt_plogi_ack_t *plogi_link[QLT_PLOGI_LINK_MAX];
+
+ uint16_t tgt_id;
+ uint16_t old_tgt_id;
++ uint16_t sec_since_registration;
+
+ uint8_t fcp_prio;
+
+@@ -2412,6 +2414,7 @@ typedef struct fc_port {
+ struct qla_tgt_sess *tgt_session;
+ struct ct_sns_desc ct_desc;
+ enum discovery_state disc_state;
++ enum discovery_state next_disc_state;
+ enum login_state fw_login_state;
+ unsigned long dm_login_expire;
+ unsigned long plogi_nack_done_deadline;
+@@ -3222,7 +3225,6 @@ enum qla_work_type {
+ QLA_EVT_GPDB,
+ QLA_EVT_PRLI,
+ QLA_EVT_GPSC,
+- QLA_EVT_UPD_FCPORT,
+ QLA_EVT_GNL,
+ QLA_EVT_NACK,
+ QLA_EVT_RELOGIN,
+--- a/drivers/scsi/qla2xxx/qla_gbl.h
++++ b/drivers/scsi/qla2xxx/qla_gbl.h
+@@ -54,7 +54,7 @@ extern void qla2x00_abort_isp_cleanup(sc
+ extern void qla2x00_quiesce_io(scsi_qla_host_t *);
+
+ extern void qla2x00_update_fcport(scsi_qla_host_t *, fc_port_t *);
+-
++void qla_register_fcport_fn(struct work_struct *);
+ extern void qla2x00_alloc_fw_dump(scsi_qla_host_t *);
+ extern void qla2x00_try_to_stop_firmware(scsi_qla_host_t *);
+
+@@ -109,6 +109,7 @@ int qla24xx_post_newsess_work(struct scs
+ int qla24xx_fcport_handle_login(struct scsi_qla_host *, fc_port_t *);
+ int qla24xx_detect_sfp(scsi_qla_host_t *vha);
+ int qla24xx_post_gpdb_work(struct scsi_qla_host *, fc_port_t *, u8);
++
+ void qla2x00_async_prlo_done(struct scsi_qla_host *, fc_port_t *,
+ uint16_t *);
+ extern int qla2x00_post_async_prlo_work(struct scsi_qla_host *, fc_port_t *,
+@@ -208,7 +209,7 @@ extern void qla2x00_disable_board_on_pci
+ extern void qla2x00_sp_compl(void *, int);
+ extern void qla2xxx_qpair_sp_free_dma(void *);
+ extern void qla2xxx_qpair_sp_compl(void *, int);
+-extern int qla24xx_post_upd_fcport_work(struct scsi_qla_host *, fc_port_t *);
++extern void qla24xx_sched_upd_fcport(fc_port_t *);
+ void qla2x00_handle_login_done_event(struct scsi_qla_host *, fc_port_t *,
+ uint16_t *);
+ int qla24xx_post_gnl_work(struct scsi_qla_host *, fc_port_t *);
+--- a/drivers/scsi/qla2xxx/qla_init.c
++++ b/drivers/scsi/qla2xxx/qla_init.c
+@@ -1204,11 +1204,7 @@ void __qla24xx_handle_gpdb_event(scsi_ql
+ vha->fcport_count++;
+ ea->fcport->login_succ = 1;
+
+- ql_dbg(ql_dbg_disc, vha, 0x20d6,
+- "%s %d %8phC post upd_fcport fcp_cnt %d\n",
+- __func__, __LINE__, ea->fcport->port_name,
+- vha->fcport_count);
+- qla24xx_post_upd_fcport_work(vha, ea->fcport);
++ qla24xx_sched_upd_fcport(ea->fcport);
+ } else if (ea->fcport->login_succ) {
+ /*
+ * We have an existing session. A late RSCN delivery
+@@ -1326,6 +1322,7 @@ int qla24xx_fcport_handle_login(struct s
+ {
+ u16 data[2];
+ u64 wwn;
++ u16 sec;
+
+ ql_dbg(ql_dbg_disc, vha, 0x20d8,
+ "%s %8phC DS %d LS %d P %d fl %x confl %p rscn %d|%d login %d retry %d lid %d scan %d\n",
+@@ -1457,6 +1454,22 @@ int qla24xx_fcport_handle_login(struct s
+ qla24xx_post_prli_work(vha, fcport);
+ break;
+
++ case DSC_UPD_FCPORT:
++ sec = jiffies_to_msecs(jiffies -
++ fcport->jiffies_at_registration)/1000;
++ if (fcport->sec_since_registration < sec && sec &&
++ !(sec % 60)) {
++ fcport->sec_since_registration = sec;
++ ql_dbg(ql_dbg_disc, fcport->vha, 0xffff,
++ "%s %8phC - Slow Rport registration(%d Sec)\n",
++ __func__, fcport->port_name, sec);
++ }
++
++ if (fcport->next_disc_state != DSC_DELETE_PEND)
++ fcport->next_disc_state = DSC_ADISC;
++ set_bit(RELOGIN_NEEDED, &vha->dpc_flags);
++ break;
++
+ default:
+ break;
+ }
+@@ -1572,8 +1585,10 @@ void qla2x00_fcport_event_handler(scsi_q
+ case RSCN_PORT_ADDR:
+ fcport = qla2x00_find_fcport_by_nportid
+ (vha, &ea->id, 1);
+- if (fcport)
++ if (fcport) {
+ fcport->scan_needed = 1;
++ fcport->rscn_gen++;
++ }
+
+ spin_lock_irqsave(&vha->work_lock, flags);
+ if (vha->scan.scan_flags == 0) {
+@@ -4741,6 +4756,7 @@ qla2x00_alloc_fcport(scsi_qla_host_t *vh
+ return NULL;
+ }
+ INIT_WORK(&fcport->del_work, qla24xx_delete_sess_fn);
++ INIT_WORK(&fcport->reg_work, qla_register_fcport_fn);
+ INIT_LIST_HEAD(&fcport->gnl_entry);
+ INIT_LIST_HEAD(&fcport->list);
+
+@@ -5221,13 +5237,15 @@ qla2x00_reg_remote_port(scsi_qla_host_t
+ void
+ qla2x00_update_fcport(scsi_qla_host_t *vha, fc_port_t *fcport)
+ {
+- fcport->vha = vha;
+-
+ if (IS_SW_RESV_ADDR(fcport->d_id))
+ return;
+
++ ql_dbg(ql_dbg_disc, vha, 0x20ef, "%s %8phC\n",
++ __func__, fcport->port_name);
++
++ fcport->disc_state = DSC_UPD_FCPORT;
++ fcport->login_retry = vha->hw->login_retry_count;
+ fcport->flags &= ~(FCF_LOGIN_NEEDED | FCF_ASYNC_SENT);
+- fcport->disc_state = DSC_LOGIN_COMPLETE;
+ fcport->deleted = 0;
+ fcport->logout_on_delete = 1;
+ fcport->login_retry = vha->hw->login_retry_count;
+@@ -5289,6 +5307,36 @@ qla2x00_update_fcport(scsi_qla_host_t *v
+ }
+ }
+ qla2x00_set_fcport_state(fcport, FCS_ONLINE);
++
++ fcport->disc_state = DSC_LOGIN_COMPLETE;
++}
++
++void qla_register_fcport_fn(struct work_struct *work)
++{
++ fc_port_t *fcport = container_of(work, struct fc_port, reg_work);
++ u32 rscn_gen = fcport->rscn_gen;
++ u16 data[2];
++
++ if (IS_SW_RESV_ADDR(fcport->d_id))
++ return;
++
++ qla2x00_update_fcport(fcport->vha, fcport);
++
++ if (rscn_gen != fcport->rscn_gen) {
++ /* RSCN(s) came in while registration */
++ switch (fcport->next_disc_state) {
++ case DSC_DELETE_PEND:
++ qlt_schedule_sess_for_deletion(fcport);
++ break;
++ case DSC_ADISC:
++ data[0] = data[1] = 0;
++ qla2x00_post_async_adisc_work(fcport->vha, fcport,
++ data);
++ break;
++ default:
++ break;
++ }
++ }
+ }
+
+ /*
+--- a/drivers/scsi/qla2xxx/qla_os.c
++++ b/drivers/scsi/qla2xxx/qla_os.c
+@@ -4792,16 +4792,25 @@ qlafx00_post_aenfx_work(struct scsi_qla_
+ return qla2x00_post_work(vha, e);
+ }
+
+-int qla24xx_post_upd_fcport_work(struct scsi_qla_host *vha, fc_port_t *fcport)
++void qla24xx_sched_upd_fcport(fc_port_t *fcport)
+ {
+- struct qla_work_evt *e;
++ unsigned long flags;
+
+- e = qla2x00_alloc_work(vha, QLA_EVT_UPD_FCPORT);
+- if (!e)
+- return QLA_FUNCTION_FAILED;
++ if (IS_SW_RESV_ADDR(fcport->d_id))
++ return;
+
+- e->u.fcport.fcport = fcport;
+- return qla2x00_post_work(vha, e);
++ spin_lock_irqsave(&fcport->vha->work_lock, flags);
++ if (fcport->disc_state == DSC_UPD_FCPORT) {
++ spin_unlock_irqrestore(&fcport->vha->work_lock, flags);
++ return;
++ }
++ fcport->jiffies_at_registration = jiffies;
++ fcport->sec_since_registration = 0;
++ fcport->next_disc_state = DSC_DELETED;
++ fcport->disc_state = DSC_UPD_FCPORT;
++ spin_unlock_irqrestore(&fcport->vha->work_lock, flags);
++
++ queue_work(system_unbound_wq, &fcport->reg_work);
+ }
+
+ static
+@@ -5057,9 +5066,6 @@ qla2x00_do_work(struct scsi_qla_host *vh
+ case QLA_EVT_GPSC:
+ qla24xx_async_gpsc(vha, e->u.fcport.fcport);
+ break;
+- case QLA_EVT_UPD_FCPORT:
+- qla2x00_update_fcport(vha, e->u.fcport.fcport);
+- break;
+ case QLA_EVT_GNL:
+ qla24xx_async_gnl(vha, e->u.fcport.fcport);
+ break;
+--- a/drivers/scsi/qla2xxx/qla_target.c
++++ b/drivers/scsi/qla2xxx/qla_target.c
+@@ -600,14 +600,7 @@ void qla2x00_async_nack_sp_done(void *s,
+ sp->fcport->login_succ = 1;
+
+ vha->fcport_count++;
+-
+- ql_dbg(ql_dbg_disc, vha, 0x20f3,
+- "%s %d %8phC post upd_fcport fcp_cnt %d\n",
+- __func__, __LINE__,
+- sp->fcport->port_name,
+- vha->fcport_count);
+- sp->fcport->disc_state = DSC_UPD_FCPORT;
+- qla24xx_post_upd_fcport_work(vha, sp->fcport);
++ qla24xx_sched_upd_fcport(sp->fcport);
+ } else {
+ sp->fcport->login_retry = 0;
+ sp->fcport->disc_state = DSC_LOGIN_COMPLETE;
+@@ -1227,11 +1220,12 @@ void qlt_schedule_sess_for_deletion(stru
+ {
+ struct qla_tgt *tgt = sess->tgt;
+ unsigned long flags;
++ u16 sec;
+
+- if (sess->disc_state == DSC_DELETE_PEND)
++ switch (sess->disc_state) {
++ case DSC_DELETE_PEND:
+ return;
+-
+- if (sess->disc_state == DSC_DELETED) {
++ case DSC_DELETED:
+ if (tgt && tgt->tgt_stop && (tgt->sess_count == 0))
+ wake_up_all(&tgt->waitQ);
+ if (sess->vha->fcport_count == 0)
+@@ -1240,6 +1234,24 @@ void qlt_schedule_sess_for_deletion(stru
+ if (!sess->plogi_link[QLT_PLOGI_LINK_SAME_WWN] &&
+ !sess->plogi_link[QLT_PLOGI_LINK_CONFLICT])
+ return;
++ break;
++ case DSC_UPD_FCPORT:
++ /*
++ * This port is not done reporting to upper layer.
++ * let it finish
++ */
++ sess->next_disc_state = DSC_DELETE_PEND;
++ sec = jiffies_to_msecs(jiffies -
++ sess->jiffies_at_registration)/1000;
++ if (sess->sec_since_registration < sec && sec && !(sec % 5)) {
++ sess->sec_since_registration = sec;
++ ql_dbg(ql_dbg_disc, sess->vha, 0xffff,
++ "%s %8phC : Slow Rport registration(%d Sec)\n",
++ __func__, sess->port_name, sec);
++ }
++ return;
++ default:
++ break;
+ }
+
+ if (sess->deleted == QLA_SESS_DELETED)
+@@ -4749,6 +4761,32 @@ static int qlt_handle_login(struct scsi_
+ goto out;
+ }
+
++ if (sess->disc_state == DSC_UPD_FCPORT) {
++ u16 sec;
++
++ /*
++ * Remote port registration is still going on from
++ * previous login. Allow it to finish before we
++ * accept the new login.
++ */
++ sess->next_disc_state = DSC_DELETE_PEND;
++ sec = jiffies_to_msecs(jiffies -
++ sess->jiffies_at_registration) / 1000;
++ if (sess->sec_since_registration < sec && sec &&
++ !(sec % 5)) {
++ sess->sec_since_registration = sec;
++ ql_dbg(ql_dbg_disc, vha, 0xffff,
++ "%s %8phC - Slow Rport registration (%d Sec)\n",
++ __func__, sess->port_name, sec);
++ }
++
++ if (!conflict_sess)
++ kmem_cache_free(qla_tgt_plogi_cachep, pla);
++
++ qlt_send_term_imm_notif(vha, iocb, 1);
++ goto out;
++ }
++
+ qlt_plogi_ack_link(vha, pla, sess, QLT_PLOGI_LINK_SAME_WWN);
+ sess->d_id = port_id;
+ sess->login_gen++;
+@@ -4908,6 +4946,7 @@ static int qlt_24xx_handle_els(struct sc
+
+ if (sess != NULL) {
+ bool delete = false;
++ int sec;
+ spin_lock_irqsave(&tgt->ha->tgt.sess_lock, flags);
+ switch (sess->fw_login_state) {
+ case DSC_LS_PLOGI_PEND:
+@@ -4920,9 +4959,24 @@ static int qlt_24xx_handle_els(struct sc
+ }
+
+ switch (sess->disc_state) {
++ case DSC_UPD_FCPORT:
++ spin_unlock_irqrestore(&tgt->ha->tgt.sess_lock,
++ flags);
++
++ sec = jiffies_to_msecs(jiffies -
++ sess->jiffies_at_registration)/1000;
++ if (sess->sec_since_registration < sec && sec &&
++ !(sec % 5)) {
++ sess->sec_since_registration = sec;
++ ql_dbg(ql_dbg_disc, sess->vha, 0xffff,
++ "%s %8phC : Slow Rport registration(%d Sec)\n",
++ __func__, sess->port_name, sec);
++ }
++ qlt_send_term_imm_notif(vha, iocb, 1);
++ return 0;
++
+ case DSC_LOGIN_PEND:
+ case DSC_GPDB:
+- case DSC_UPD_FCPORT:
+ case DSC_LOGIN_COMPLETE:
+ case DSC_ADISC:
+ delete = false;
+@@ -5959,10 +6013,7 @@ static fc_port_t *qlt_get_port_database(
+ case MODE_DUAL:
+ if (newfcport) {
+ if (!IS_IIDMA_CAPABLE(vha->hw) || !vha->hw->flags.gpsc_supported) {
+- ql_dbg(ql_dbg_disc, vha, 0x20fe,
+- "%s %d %8phC post upd_fcport fcp_cnt %d\n",
+- __func__, __LINE__, fcport->port_name, vha->fcport_count);
+- qla24xx_post_upd_fcport_work(vha, fcport);
++ qla24xx_sched_upd_fcport(fcport);
+ } else {
+ ql_dbg(ql_dbg_disc, vha, 0x20ff,
+ "%s %d %8phC post gpsc fcp_cnt %d\n",
--- /dev/null
+From 0aca77843e2803bf4fab1598b7891c56c16be979 Mon Sep 17 00:00:00 2001
+From: Quinn Tran <quinn.tran@cavium.com>
+Date: Tue, 4 Sep 2018 14:19:16 -0700
+Subject: scsi: qla2xxx: Reduce holding sess_lock to prevent CPU lock-up
+
+From: Quinn Tran <quinn.tran@cavium.com>
+
+commit 0aca77843e2803bf4fab1598b7891c56c16be979 upstream.
+
+- Reduce sess_lock holding to prevent CPU Lock up. sess_lock was held across
+ fc_port registration and deletion. These calls can be blocked by upper
+ layer. Sess_lock is also being accessed by interrupt thread.
+
+- Reduce number of loops in processing work_list to prevent kernel complaint
+ of CPU lockup or holding sess_lock.
+
+Reported-by: Zhengyuan Liu <liuzhengyuan@kylinos.cn>
+Tested-by: Zhengyuan Liu <liuzhengyuan@kylinos.cn>
+Fixes: 9ba1cb25c151 ("scsi: qla2xxx: Remove all rports if fabric scan retry fails")
+Link: https://lore.kernel.org/linux-scsi/D01377DD-2E86-427B-BA0C-8D7649E37870@oracle.com/T/#t
+Signed-off-by: Quinn Tran <quinn.tran@cavium.com>
+Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/scsi/qla2xxx/qla_def.h | 2 +-
+ drivers/scsi/qla2xxx/qla_gs.c | 18 ++++++++++++------
+ drivers/scsi/qla2xxx/qla_init.c | 33 +++++++++++++++++----------------
+ drivers/scsi/qla2xxx/qla_os.c | 3 +--
+ drivers/scsi/qla2xxx/qla_target.c | 2 ++
+ 5 files changed, 33 insertions(+), 25 deletions(-)
+
+--- a/drivers/scsi/qla2xxx/qla_def.h
++++ b/drivers/scsi/qla2xxx/qla_def.h
+@@ -262,8 +262,8 @@ struct name_list_extended {
+ struct get_name_list_extended *l;
+ dma_addr_t ldma;
+ struct list_head fcports;
+- spinlock_t fcports_lock;
+ u32 size;
++ u8 sent;
+ };
+ /*
+ * Timeout timer counts in seconds
+--- a/drivers/scsi/qla2xxx/qla_gs.c
++++ b/drivers/scsi/qla2xxx/qla_gs.c
+@@ -4018,11 +4018,10 @@ void qla24xx_async_gnnft_done(scsi_qla_h
+ if ((qla_dual_mode_enabled(vha) ||
+ qla_ini_mode_enabled(vha)) &&
+ atomic_read(&fcport->state) == FCS_ONLINE) {
+- qla2x00_mark_device_lost(vha, fcport,
+- ql2xplogiabsentdevice, 0);
++ if (fcport->loop_id != FC_NO_LOOP_ID) {
++ if (fcport->flags & FCF_FCP2_DEVICE)
++ fcport->logout_on_delete = 0;
+
+- if (fcport->loop_id != FC_NO_LOOP_ID &&
+- (fcport->flags & FCF_FCP2_DEVICE) == 0) {
+ ql_dbg(ql_dbg_disc, vha, 0x20f0,
+ "%s %d %8phC post del sess\n",
+ __func__, __LINE__,
+@@ -4261,12 +4260,13 @@ static void qla2x00_async_gpnft_gnnft_sp
+
+ sp->rc = res;
+ rc = qla2x00_post_nvme_gpnft_done_work(vha, sp, QLA_EVT_GPNFT);
+- if (!rc) {
++ if (rc) {
+ qla24xx_sp_unmap(vha, sp);
+ set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
+ set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+ return;
+ }
++ return;
+ }
+
+ if (cmd == GPN_FT_CMD) {
+@@ -4316,6 +4316,8 @@ static int qla24xx_async_gnnft(scsi_qla_
+ vha->scan.scan_flags &= ~SF_SCANNING;
+ spin_unlock_irqrestore(&vha->work_lock, flags);
+ WARN_ON(1);
++ set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
++ set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+ goto done_free_sp;
+ }
+
+@@ -4349,8 +4351,12 @@ static int qla24xx_async_gnnft(scsi_qla_
+ sp->done = qla2x00_async_gpnft_gnnft_sp_done;
+
+ rval = qla2x00_start_sp(sp);
+- if (rval != QLA_SUCCESS)
++ if (rval != QLA_SUCCESS) {
++ spin_lock_irqsave(&vha->work_lock, flags);
++ vha->scan.scan_flags &= ~SF_SCANNING;
++ spin_unlock_irqrestore(&vha->work_lock, flags);
+ goto done_free_sp;
++ }
+
+ ql_dbg(ql_dbg_disc, vha, 0xffff,
+ "Async-%s hdl=%x FC4Type %x.\n", sp->name,
+--- a/drivers/scsi/qla2xxx/qla_init.c
++++ b/drivers/scsi/qla2xxx/qla_init.c
+@@ -800,6 +800,7 @@ qla24xx_async_gnl_sp_done(void *s, int r
+ if (res == QLA_FUNCTION_TIMEOUT)
+ return;
+
++ sp->fcport->flags &= ~(FCF_ASYNC_SENT|FCF_ASYNC_ACTIVE);
+ memset(&ea, 0, sizeof(ea));
+ ea.sp = sp;
+ ea.rc = res;
+@@ -827,25 +828,24 @@ qla24xx_async_gnl_sp_done(void *s, int r
+ (loop_id & 0x7fff));
+ }
+
+- spin_lock_irqsave(&vha->gnl.fcports_lock, flags);
++ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
+
+ INIT_LIST_HEAD(&h);
+ fcport = tf = NULL;
+ if (!list_empty(&vha->gnl.fcports))
+ list_splice_init(&vha->gnl.fcports, &h);
++ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
+
+ list_for_each_entry_safe(fcport, tf, &h, gnl_entry) {
+ list_del_init(&fcport->gnl_entry);
+- spin_lock(&vha->hw->tgt.sess_lock);
++ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
+ fcport->flags &= ~(FCF_ASYNC_SENT | FCF_ASYNC_ACTIVE);
+- spin_unlock(&vha->hw->tgt.sess_lock);
++ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
+ ea.fcport = fcport;
+
+ qla2x00_fcport_event_handler(vha, &ea);
+ }
+- spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags);
+
+- spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
+ /* create new fcport if fw has knowledge of new sessions */
+ for (i = 0; i < n; i++) {
+ port_id_t id;
+@@ -878,6 +878,8 @@ qla24xx_async_gnl_sp_done(void *s, int r
+ }
+ }
+
++ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
++ vha->gnl.sent = 0;
+ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
+
+ sp->free(sp);
+@@ -897,27 +899,24 @@ int qla24xx_async_gnl(struct scsi_qla_ho
+ ql_dbg(ql_dbg_disc, vha, 0x20d9,
+ "Async-gnlist WWPN %8phC \n", fcport->port_name);
+
+- spin_lock_irqsave(&vha->gnl.fcports_lock, flags);
+- if (!list_empty(&fcport->gnl_entry)) {
+- spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags);
+- rval = QLA_SUCCESS;
+- goto done;
+- }
+-
+- spin_lock(&vha->hw->tgt.sess_lock);
++ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
++ fcport->flags |= FCF_ASYNC_SENT;
+ fcport->disc_state = DSC_GNL;
+ fcport->last_rscn_gen = fcport->rscn_gen;
+ fcport->last_login_gen = fcport->login_gen;
+- spin_unlock(&vha->hw->tgt.sess_lock);
+
+ list_add_tail(&fcport->gnl_entry, &vha->gnl.fcports);
+- spin_unlock_irqrestore(&vha->gnl.fcports_lock, flags);
++ if (vha->gnl.sent) {
++ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
++ return QLA_SUCCESS;
++ }
++ vha->gnl.sent = 1;
++ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
+
+ sp = qla2x00_get_sp(vha, fcport, GFP_KERNEL);
+ if (!sp)
+ goto done;
+
+- fcport->flags |= FCF_ASYNC_SENT;
+ sp->type = SRB_MB_IOCB;
+ sp->name = "gnlist";
+ sp->gen1 = fcport->rscn_gen;
+@@ -1204,7 +1203,9 @@ void __qla24xx_handle_gpdb_event(scsi_ql
+ vha->fcport_count++;
+ ea->fcport->login_succ = 1;
+
++ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
+ qla24xx_sched_upd_fcport(ea->fcport);
++ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
+ } else if (ea->fcport->login_succ) {
+ /*
+ * We have an existing session. A late RSCN delivery
+--- a/drivers/scsi/qla2xxx/qla_os.c
++++ b/drivers/scsi/qla2xxx/qla_os.c
+@@ -2719,7 +2719,7 @@ static void qla2x00_iocb_work_fn(struct
+ struct scsi_qla_host, iocb_work);
+ struct qla_hw_data *ha = vha->hw;
+ struct scsi_qla_host *base_vha = pci_get_drvdata(ha->pdev);
+- int i = 20;
++ int i = 2;
+ unsigned long flags;
+
+ if (test_bit(UNLOADING, &base_vha->dpc_flags))
+@@ -4606,7 +4606,6 @@ struct scsi_qla_host *qla2x00_create_hos
+
+ spin_lock_init(&vha->work_lock);
+ spin_lock_init(&vha->cmd_list_lock);
+- spin_lock_init(&vha->gnl.fcports_lock);
+ init_waitqueue_head(&vha->fcport_waitQ);
+ init_waitqueue_head(&vha->vref_waitq);
+
+--- a/drivers/scsi/qla2xxx/qla_target.c
++++ b/drivers/scsi/qla2xxx/qla_target.c
+@@ -600,7 +600,9 @@ void qla2x00_async_nack_sp_done(void *s,
+ sp->fcport->login_succ = 1;
+
+ vha->fcport_count++;
++ spin_unlock_irqrestore(&vha->hw->tgt.sess_lock, flags);
+ qla24xx_sched_upd_fcport(sp->fcport);
++ spin_lock_irqsave(&vha->hw->tgt.sess_lock, flags);
+ } else {
+ sp->fcport->login_retry = 0;
+ sp->fcport->disc_state = DSC_LOGIN_COMPLETE;
--- /dev/null
+From cb873ba4002095d1e2fc60521bc4d860c7b72b92 Mon Sep 17 00:00:00 2001
+From: Quinn Tran <quinn.tran@cavium.com>
+Date: Fri, 31 Aug 2018 11:24:29 -0700
+Subject: scsi: qla2xxx: Update rscn_rcvd field to more meaningful scan_needed
+
+From: Quinn Tran <quinn.tran@cavium.com>
+
+commit cb873ba4002095d1e2fc60521bc4d860c7b72b92 upstream.
+
+Rename rscn_rcvd field to scan_needed to be more meaningful.
+
+Signed-off-by: Quinn Tran <quinn.tran@cavium.com>
+Signed-off-by: Himanshu Madhani <himanshu.madhani@cavium.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Zhengyuan Liu <liuzhengyuan@kylinos.cn>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/scsi/qla2xxx/qla_def.h | 2 +-
+ drivers/scsi/qla2xxx/qla_gs.c | 12 ++++++------
+ drivers/scsi/qla2xxx/qla_init.c | 2 +-
+ 3 files changed, 8 insertions(+), 8 deletions(-)
+
+--- a/drivers/scsi/qla2xxx/qla_def.h
++++ b/drivers/scsi/qla2xxx/qla_def.h
+@@ -2351,7 +2351,7 @@ typedef struct fc_port {
+ unsigned int login_succ:1;
+ unsigned int query:1;
+ unsigned int id_changed:1;
+- unsigned int rscn_rcvd:1;
++ unsigned int scan_needed:1;
+
+ struct work_struct nvme_del_work;
+ struct completion nvme_del_done;
+--- a/drivers/scsi/qla2xxx/qla_gs.c
++++ b/drivers/scsi/qla2xxx/qla_gs.c
+@@ -3973,7 +3973,7 @@ void qla24xx_async_gnnft_done(scsi_qla_h
+ list_for_each_entry(fcport, &vha->vp_fcports, list) {
+ if (memcmp(rp->port_name, fcport->port_name, WWN_SIZE))
+ continue;
+- fcport->rscn_rcvd = 0;
++ fcport->scan_needed = 0;
+ fcport->scan_state = QLA_FCPORT_FOUND;
+ found = true;
+ /*
+@@ -4009,12 +4009,12 @@ void qla24xx_async_gnnft_done(scsi_qla_h
+ */
+ list_for_each_entry(fcport, &vha->vp_fcports, list) {
+ if ((fcport->flags & FCF_FABRIC_DEVICE) == 0) {
+- fcport->rscn_rcvd = 0;
++ fcport->scan_needed = 0;
+ continue;
+ }
+
+ if (fcport->scan_state != QLA_FCPORT_FOUND) {
+- fcport->rscn_rcvd = 0;
++ fcport->scan_needed = 0;
+ if ((qla_dual_mode_enabled(vha) ||
+ qla_ini_mode_enabled(vha)) &&
+ atomic_read(&fcport->state) == FCS_ONLINE) {
+@@ -4033,7 +4033,7 @@ void qla24xx_async_gnnft_done(scsi_qla_h
+ }
+ }
+ } else {
+- if (fcport->rscn_rcvd ||
++ if (fcport->scan_needed ||
+ fcport->disc_state != DSC_LOGIN_COMPLETE) {
+ if (fcport->login_retry == 0) {
+ fcport->login_retry =
+@@ -4043,7 +4043,7 @@ void qla24xx_async_gnnft_done(scsi_qla_h
+ fcport->port_name, fcport->loop_id,
+ fcport->login_retry);
+ }
+- fcport->rscn_rcvd = 0;
++ fcport->scan_needed = 0;
+ qla24xx_fcport_handle_login(vha, fcport);
+ }
+ }
+@@ -4058,7 +4058,7 @@ out:
+
+ if (recheck) {
+ list_for_each_entry(fcport, &vha->vp_fcports, list) {
+- if (fcport->rscn_rcvd) {
++ if (fcport->scan_needed) {
+ set_bit(LOCAL_LOOP_UPDATE, &vha->dpc_flags);
+ set_bit(LOOP_RESYNC_NEEDED, &vha->dpc_flags);
+ break;
+--- a/drivers/scsi/qla2xxx/qla_init.c
++++ b/drivers/scsi/qla2xxx/qla_init.c
+@@ -1573,7 +1573,7 @@ void qla2x00_fcport_event_handler(scsi_q
+ fcport = qla2x00_find_fcport_by_nportid
+ (vha, &ea->id, 1);
+ if (fcport)
+- fcport->rscn_rcvd = 1;
++ fcport->scan_needed = 1;
+
+ spin_lock_irqsave(&vha->work_lock, flags);
+ if (vha->scan.scan_flags == 0) {
--- /dev/null
+dsa-allow-forwarding-of-redirected-igmp-traffic.patch
+scsi-qla2xxx-update-rscn_rcvd-field-to-more-meaningful-scan_needed.patch
+scsi-qla2xxx-move-rport-registration-out-of-internal-work_list.patch
+scsi-qla2xxx-reduce-holding-sess_lock-to-prevent-cpu-lock-up.patch