scsi: lpfc: Reset link or adapter instead of doing infinite nameserver PLOGI retry
authorJames Smart <jsmart2021@gmail.com>
Tue, 23 Oct 2018 20:41:04 +0000 (13:41 -0700)
committerMartin K. Petersen <martin.petersen@oracle.com>
Wed, 7 Nov 2018 01:42:50 +0000 (20:42 -0500)
Currently, PLOGI failures are infinitely delayed/retried.  There have
been some fabric situations where the PLOGI's were to the nameserver
and it stopped responding. The retries would never clear up.  A better
resolution in this situation is to retry a couple of times, then drop
the link and reinit. This brings back connectivity to the nameserver.

Signed-off-by: Dick Kennedy <dick.kennedy@broadcom.com>
Signed-off-by: James Smart <jsmart2021@gmail.com>
Reviewed-by: Hannes Reinecke <hare@suse.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/scsi/lpfc/lpfc_crtn.h
drivers/scsi/lpfc/lpfc_els.c

index e011365..e9b297a 100644 (file)
@@ -380,6 +380,7 @@ void lpfc_nvmet_buf_free(struct lpfc_hba *phba, void *virtp, dma_addr_t dma);
 
 void lpfc_in_buf_free(struct lpfc_hba *, struct lpfc_dmabuf *);
 void lpfc_rq_buf_free(struct lpfc_hba *phba, struct lpfc_dmabuf *mp);
+int lpfc_link_reset(struct lpfc_vport *vport);
 
 /* Function prototypes. */
 const char* lpfc_info(struct Scsi_Host *);
index 8160a5e..e3e8519 100644 (file)
@@ -3241,6 +3241,62 @@ lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp)
        return;
 }
 
+/**
+ * lpfc_link_reset - Issue link reset
+ * @vport: pointer to a virtual N_Port data structure.
+ *
+ * This routine performs link reset by sending INIT_LINK mailbox command.
+ * For SLI-3 adapter, link attention interrupt is enabled before issuing
+ * INIT_LINK mailbox command.
+ *
+ * Return code
+ *   0 - Link reset initiated successfully
+ *   1 - Failed to initiate link reset
+ **/
+int
+lpfc_link_reset(struct lpfc_vport *vport)
+{
+       struct lpfc_hba *phba = vport->phba;
+       LPFC_MBOXQ_t *mbox;
+       uint32_t control;
+       int rc;
+
+       lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS,
+                        "2851 Attempt link reset\n");
+       mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
+       if (!mbox) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+                               "2852 Failed to allocate mbox memory");
+               return 1;
+       }
+
+       /* Enable Link attention interrupts */
+       if (phba->sli_rev <= LPFC_SLI_REV3) {
+               spin_lock_irq(&phba->hbalock);
+               phba->sli.sli_flag |= LPFC_PROCESS_LA;
+               control = readl(phba->HCregaddr);
+               control |= HC_LAINT_ENA;
+               writel(control, phba->HCregaddr);
+               readl(phba->HCregaddr); /* flush */
+               spin_unlock_irq(&phba->hbalock);
+       }
+
+       lpfc_init_link(phba, mbox, phba->cfg_topology,
+                      phba->cfg_link_speed);
+       mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl;
+       mbox->vport = vport;
+       rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT);
+       if ((rc != MBX_BUSY) && (rc != MBX_SUCCESS)) {
+               lpfc_printf_log(phba, KERN_ERR, LOG_MBOX,
+                               "2853 Failed to issue INIT_LINK "
+                               "mbox command, rc:x%x\n", rc);
+               mempool_free(mbox, phba->mbox_mem_pool);
+               return 1;
+       }
+
+       return 0;
+}
+
 /**
  * lpfc_els_retry - Make retry decision on an els command iocb
  * @phba: pointer to lpfc hba data structure.
@@ -3277,6 +3333,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
        int logerr = 0;
        uint32_t cmd = 0;
        uint32_t did;
+       int link_reset = 0, rc;
 
 
        /* Note: context2 may be 0 for internal driver abort
@@ -3358,7 +3415,6 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        retry = 1;
                        break;
 
-               case IOERR_SEQUENCE_TIMEOUT:
                case IOERR_INVALID_RPI:
                        if (cmd == ELS_CMD_PLOGI &&
                            did == NameServer_DID) {
@@ -3369,6 +3425,18 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                        }
                        retry = 1;
                        break;
+
+               case IOERR_SEQUENCE_TIMEOUT:
+                       if (cmd == ELS_CMD_PLOGI &&
+                           did == NameServer_DID &&
+                           (cmdiocb->retry + 1) == maxretry) {
+                               /* Reset the Link */
+                               link_reset = 1;
+                               break;
+                       }
+                       retry = 1;
+                       delay = 100;
+                       break;
                }
                break;
 
@@ -3525,6 +3593,19 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb,
                break;
        }
 
+       if (link_reset) {
+               rc = lpfc_link_reset(vport);
+               if (rc) {
+                       /* Do not give up. Retry PLOGI one more time and attempt
+                        * link reset if PLOGI fails again.
+                        */
+                       retry = 1;
+                       delay = 100;
+                       goto out_retry;
+               }
+               return 1;
+       }
+
        if (did == FDMI_DID)
                retry = 1;