]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
4.19-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 17 Sep 2020 14:43:36 +0000 (16:43 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 17 Sep 2020 14:43:36 +0000 (16:43 +0200)
added patches:
dsa-allow-forwarding-of-redirected-igmp-traffic.patch
scsi-qla2xxx-move-rport-registration-out-of-internal-work_list.patch
scsi-qla2xxx-reduce-holding-sess_lock-to-prevent-cpu-lock-up.patch
scsi-qla2xxx-update-rscn_rcvd-field-to-more-meaningful-scan_needed.patch

queue-4.19/dsa-allow-forwarding-of-redirected-igmp-traffic.patch [new file with mode: 0644]
queue-4.19/scsi-qla2xxx-move-rport-registration-out-of-internal-work_list.patch [new file with mode: 0644]
queue-4.19/scsi-qla2xxx-reduce-holding-sess_lock-to-prevent-cpu-lock-up.patch [new file with mode: 0644]
queue-4.19/scsi-qla2xxx-update-rscn_rcvd-field-to-more-meaningful-scan_needed.patch [new file with mode: 0644]
queue-4.19/series [new file with mode: 0644]

diff --git a/queue-4.19/dsa-allow-forwarding-of-redirected-igmp-traffic.patch b/queue-4.19/dsa-allow-forwarding-of-redirected-igmp-traffic.patch
new file mode 100644 (file)
index 0000000..0bfeca7
--- /dev/null
@@ -0,0 +1,113 @@
+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;
+ }
diff --git a/queue-4.19/scsi-qla2xxx-move-rport-registration-out-of-internal-work_list.patch b/queue-4.19/scsi-qla2xxx-move-rport-registration-out-of-internal-work_list.patch
new file mode 100644 (file)
index 0000000..0525a8d
--- /dev/null
@@ -0,0 +1,401 @@
+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",
diff --git a/queue-4.19/scsi-qla2xxx-reduce-holding-sess_lock-to-prevent-cpu-lock-up.patch b/queue-4.19/scsi-qla2xxx-reduce-holding-sess_lock-to-prevent-cpu-lock-up.patch
new file mode 100644 (file)
index 0000000..a4a3e08
--- /dev/null
@@ -0,0 +1,226 @@
+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;
diff --git a/queue-4.19/scsi-qla2xxx-update-rscn_rcvd-field-to-more-meaningful-scan_needed.patch b/queue-4.19/scsi-qla2xxx-update-rscn_rcvd-field-to-more-meaningful-scan_needed.patch
new file mode 100644 (file)
index 0000000..40faf54
--- /dev/null
@@ -0,0 +1,98 @@
+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) {
diff --git a/queue-4.19/series b/queue-4.19/series
new file mode 100644 (file)
index 0000000..fa17740
--- /dev/null
@@ -0,0 +1,4 @@
+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