diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_els.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_els.c | 154 |
1 files changed, 114 insertions, 40 deletions
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index b73612d4fc5..813eeca7ce1 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -109,9 +109,10 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, /* fill in BDEs for command */ /* Allocate buffer for command payload */ - if (((pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL)) == 0) || - ((pcmd->virt = lpfc_mbuf_alloc(phba, - MEM_PRI, &(pcmd->phys))) == 0)) { + pcmd = kmalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (pcmd) + pcmd->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pcmd->phys); + if (!pcmd || !pcmd->virt) { kfree(pcmd); lpfc_sli_release_iocbq(phba, elsiocb); @@ -126,7 +127,7 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, if (prsp) prsp->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &prsp->phys); - if (prsp == 0 || prsp->virt == 0) { + if (!prsp || !prsp->virt) { kfree(prsp); lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); kfree(pcmd); @@ -143,7 +144,7 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, if (pbuflist) pbuflist->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &pbuflist->phys); - if (pbuflist == 0 || pbuflist->virt == 0) { + if (!pbuflist || !pbuflist->virt) { lpfc_sli_release_iocbq(phba, elsiocb); lpfc_mbuf_free(phba, pcmd->virt, pcmd->phys); lpfc_mbuf_free(phba, prsp->virt, prsp->phys); @@ -234,15 +235,20 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport) struct lpfc_nodelist *ndlp; struct serv_parm *sp; int rc; + int err = 0; sp = &phba->fc_fabparam; ndlp = lpfc_findnode_did(vport, Fabric_DID); - if (!ndlp) + if (!ndlp) { + err = 1; goto fail; + } mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) + if (!mbox) { + err = 2; goto fail; + } vport->port_state = LPFC_FABRIC_CFG_LINK; lpfc_config_link(phba, mbox); @@ -250,24 +256,32 @@ lpfc_issue_fabric_reglogin(struct lpfc_vport *vport) mbox->vport = vport; rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) + if (rc == MBX_NOT_FINISHED) { + err = 3; goto fail_free_mbox; + } mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!mbox) + if (!mbox) { + err = 4; goto fail; + } rc = lpfc_reg_login(phba, vport->vpi, Fabric_DID, (uint8_t *)sp, mbox, 0); - if (rc) + if (rc) { + err = 5; goto fail_free_mbox; + } mbox->mbox_cmpl = lpfc_mbx_cmpl_fabric_reg_login; mbox->vport = vport; mbox->context2 = lpfc_nlp_get(ndlp); rc = lpfc_sli_issue_mbox(phba, mbox, MBX_NOWAIT); - if (rc == MBX_NOT_FINISHED) + if (rc == MBX_NOT_FINISHED) { + err = 6; goto fail_issue_reg_login; + } return 0; @@ -282,7 +296,7 @@ fail_free_mbox: fail: lpfc_vport_set_state(vport, FC_VPORT_FAILED); lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, - "0249 Cannot issue Register Fabric login\n"); + "0249 Cannot issue Register Fabric login: Err %d\n", err); return -ENXIO; } @@ -684,6 +698,9 @@ lpfc_initial_flogi(struct lpfc_vport *vport) struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp; + vport->port_state = LPFC_FLOGI; + lpfc_set_disctmo(vport); + /* First look for the Fabric ndlp */ ndlp = lpfc_findnode_did(vport, Fabric_DID); if (!ndlp) { @@ -694,6 +711,12 @@ lpfc_initial_flogi(struct lpfc_vport *vport) lpfc_nlp_init(vport, ndlp, Fabric_DID); } else { lpfc_dequeue_node(vport, ndlp); + + /* If we go thru this path, Fabric_DID ndlp is in the process + * of being removed. We need to bump the reference count by 1 + * so it stays around all through this link up period. + */ + lpfc_nlp_get(ndlp); } if (lpfc_issue_els_flogi(vport, ndlp, 0)) { lpfc_nlp_put(ndlp); @@ -932,6 +955,7 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) struct lpfc_hba *phba = vport->phba; struct serv_parm *sp; IOCB_t *icmd; + struct lpfc_nodelist *ndlp; struct lpfc_iocbq *elsiocb; struct lpfc_sli_ring *pring; struct lpfc_sli *psli; @@ -942,8 +966,11 @@ lpfc_issue_els_plogi(struct lpfc_vport *vport, uint32_t did, uint8_t retry) psli = &phba->sli; pring = &psli->ring[LPFC_ELS_RING]; /* ELS ring */ + ndlp = lpfc_findnode_did(vport, did); + /* If ndlp if not NULL, we will bump the reference count on it */ + cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm)); - elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, NULL, did, + elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did, ELS_CMD_PLOGI); if (!elsiocb) return 1; @@ -1412,6 +1439,13 @@ lpfc_issue_els_logo(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, psli = &phba->sli; pring = &psli->ring[LPFC_ELS_RING]; + spin_lock_irq(shost->host_lock); + if (ndlp->nlp_flag & NLP_LOGO_SND) { + spin_unlock_irq(shost->host_lock); + return 0; + } + spin_unlock_irq(shost->host_lock); + cmdsize = (2 * sizeof(uint32_t)) + sizeof(struct lpfc_name); elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, ndlp->nlp_DID, ELS_CMD_LOGO); @@ -1758,6 +1792,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, uint32_t *elscmd; struct ls_rjt stat; int retry = 0, maxretry = lpfc_max_els_tries, delay = 0; + int logerr = 0; uint32_t cmd = 0; uint32_t did; @@ -1814,6 +1849,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, break; case IOERR_NO_RESOURCES: + logerr = 1; /* HBA out of resources */ retry = 1; if (cmdiocb->retry > 100) delay = 100; @@ -1842,6 +1878,7 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, case IOSTAT_NPORT_BSY: case IOSTAT_FABRIC_BSY: + logerr = 1; /* Fabric / Remote NPort out of resources */ retry = 1; break; @@ -1922,6 +1959,15 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (did == FDMI_DID) retry = 1; + if ((cmd == ELS_CMD_FLOGI) && + (phba->fc_topology != TOPOLOGY_LOOP)) { + /* FLOGI retry policy */ + retry = 1; + maxretry = 48; + if (cmdiocb->retry >= 32) + delay = 1000; + } + if ((++cmdiocb->retry) >= maxretry) { phba->fc_stat.elsRetryExceeded++; retry = 0; @@ -2005,11 +2051,20 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } } /* No retry ELS command <elsCmd> to remote NPORT <did> */ - lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + if (logerr) { + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0137 No retry ELS command x%x to remote " + "NPORT x%x: Out of Resources: Error:x%x/%x\n", + cmd, did, irsp->ulpStatus, + irsp->un.ulpWord[4]); + } + else { + lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, "0108 No retry ELS command x%x to remote " "NPORT x%x Retried:%d Error:x%x/%x\n", cmd, did, cmdiocb->retry, irsp->ulpStatus, irsp->un.ulpWord[4]); + } return 0; } @@ -2089,6 +2144,12 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) kfree(mp); mempool_free(pmb, phba->mbox_mem_pool); lpfc_nlp_put(ndlp); + + /* This is the end of the default RPI cleanup logic for this + * ndlp. If no other discovery threads are using this ndlp. + * we should free all resources associated with it. + */ + lpfc_nlp_not_used(ndlp); return; } @@ -2118,6 +2179,9 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, } mempool_free(mbox, phba->mbox_mem_pool); } + if (ndlp && (ndlp->nlp_flag & NLP_RM_DFLT_RPI)) + if (lpfc_nlp_not_used(ndlp)) + ndlp = NULL; goto out; } @@ -2153,15 +2217,22 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, != MBX_NOT_FINISHED) { goto out; } - lpfc_nlp_put(ndlp); - /* NOTE: we should have messages for unsuccessful - reglogin */ + + /* ELS rsp: Cannot issue reg_login for <NPortid> */ + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0138 ELS rsp: Cannot issue reg_login for x%x " + "Data: x%x x%x x%x\n", + ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, + ndlp->nlp_rpi); + + if (lpfc_nlp_not_used(ndlp)) + ndlp = NULL; } else { /* Do not drop node for lpfc_els_abort'ed ELS cmds */ if (!lpfc_error_lost_link(irsp) && ndlp->nlp_flag & NLP_ACC_REGLOGIN) { - lpfc_drop_node(vport, ndlp); - ndlp = NULL; + if (lpfc_nlp_not_used(ndlp)) + ndlp = NULL; } } mp = (struct lpfc_dmabuf *) mbox->context1; @@ -2350,10 +2421,14 @@ lpfc_els_rsp_reject(struct lpfc_vport *vport, uint32_t rejectError, /* If the node is in the UNUSED state, and we are sending * a reject, we are done with it. Release driver reference * count here. The outstanding els will release its reference on - * completion and the node can be freed then. + * completion, as long as the ndlp stays in the UNUSED list, + * and the node can be freed then. */ - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) + if ((ndlp->nlp_state == NLP_STE_UNUSED_NODE) && + !(ndlp->nlp_flag & NLP_DELAYED_RM)) { + ndlp->nlp_flag |= NLP_DELAYED_RM; lpfc_nlp_put(ndlp); + } if (rc == IOCB_ERROR) { lpfc_els_free_iocb(phba, elsiocb); @@ -3466,8 +3541,6 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, } } - vport->port_state = LPFC_FLOGI; - lpfc_set_disctmo(vport); lpfc_initial_flogi(vport); return 0; } @@ -3747,11 +3820,11 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, goto dropit; lpfc_nlp_init(vport, ndlp, did); + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); newnode = 1; if ((did & Fabric_DID_MASK) == Fabric_DID_MASK) { ndlp->nlp_type |= NLP_FABRIC; } - lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); } phba->fc_stat.elsRcvFrame++; @@ -3791,8 +3864,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvFLOGI++; lpfc_els_rcv_flogi(vport, elsiocb, ndlp); - if (newnode) - lpfc_drop_node(vport, ndlp); + if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM))) + lpfc_nlp_put(ndlp); break; case ELS_CMD_LOGO: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -3821,8 +3894,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, case ELS_CMD_RSCN: phba->fc_stat.elsRcvRSCN++; lpfc_els_rcv_rscn(vport, elsiocb, ndlp); - if (newnode) - lpfc_drop_node(vport, ndlp); + if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM))) + lpfc_nlp_put(ndlp); break; case ELS_CMD_ADISC: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -3893,8 +3966,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvLIRR++; lpfc_els_rcv_lirr(vport, elsiocb, ndlp); - if (newnode) - lpfc_drop_node(vport, ndlp); + if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM))) + lpfc_nlp_put(ndlp); break; case ELS_CMD_RPS: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -3903,8 +3976,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvRPS++; lpfc_els_rcv_rps(vport, elsiocb, ndlp); - if (newnode) - lpfc_drop_node(vport, ndlp); + if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM))) + lpfc_nlp_put(ndlp); break; case ELS_CMD_RPL: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -3913,8 +3986,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvRPL++; lpfc_els_rcv_rpl(vport, elsiocb, ndlp); - if (newnode) - lpfc_drop_node(vport, ndlp); + if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM))) + lpfc_nlp_put(ndlp); break; case ELS_CMD_RNID: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -3923,8 +3996,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, phba->fc_stat.elsRcvRNID++; lpfc_els_rcv_rnid(vport, elsiocb, ndlp); - if (newnode) - lpfc_drop_node(vport, ndlp); + if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM))) + lpfc_nlp_put(ndlp); break; default: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, @@ -3938,8 +4011,8 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, "0115 Unknown ELS command x%x " "received from NPORT x%x\n", cmd, did); - if (newnode) - lpfc_drop_node(vport, ndlp); + if (newnode && (!(ndlp->nlp_flag & NLP_DELAYED_RM))) + lpfc_nlp_put(ndlp); break; } @@ -3955,10 +4028,11 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, return; dropit: - lpfc_printf_log(phba, KERN_ERR, LOG_ELS, + if (vport && !(vport->load_flag & FC_UNLOADING)) + lpfc_printf_log(phba, KERN_ERR, LOG_ELS, "(%d):0111 Dropping received ELS cmd " "Data: x%x x%x x%x\n", - vport ? vport->vpi : 0xffff, icmd->ulpStatus, + vport->vpi, icmd->ulpStatus, icmd->un.ulpWord[4], icmd->ulpTimeout); phba->fc_stat.elsRcvDrop++; } |