X-Git-Url: http://ftp.safe.ca/?a=blobdiff_plain;f=drivers%2Fscsi%2Flpfc%2Flpfc_els.c;h=2a40a6eabf4d3a55708d5ceb93494f07a9daaef7;hb=318ae2edc3b29216abd8a2510f3f80b764f06858;hp=2c034a554c88c9848ef08da69f2eb00674d39247;hpb=04c684968487eb4f98728363a97b8da48f3bb958;p=safe%2Fjmp%2Flinux-2.6 diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c index 2c034a5..2a40a6e 100644 --- a/drivers/scsi/lpfc/lpfc_els.c +++ b/drivers/scsi/lpfc/lpfc_els.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2008 Emulex. All rights reserved. * + * Copyright (C) 2004-2009 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -50,9 +50,6 @@ static int lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint8_t retry); static int lpfc_issue_fabric_iocb(struct lpfc_hba *phba, struct lpfc_iocbq *iocb); -static void lpfc_register_new_vport(struct lpfc_hba *phba, - struct lpfc_vport *vport, - struct lpfc_nodelist *ndlp); static int lpfc_max_els_tries = 3; @@ -146,7 +143,7 @@ lpfc_els_chk_latt(struct lpfc_vport *vport) * Pointer to the newly allocated/prepared els iocb data structure * NULL - when els iocb data structure allocation/preparation failed **/ -static struct lpfc_iocbq * +struct lpfc_iocbq * lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, uint16_t cmdSize, uint8_t retry, struct lpfc_nodelist *ndlp, uint32_t did, @@ -168,6 +165,32 @@ lpfc_prep_els_iocb(struct lpfc_vport *vport, uint8_t expectRsp, if (elsiocb == NULL) return NULL; + /* + * If this command is for fabric controller and HBA running + * in FIP mode send FLOGI, FDISC and LOGO as FIP frames. + */ + if ((did == Fabric_DID) && + (phba->hba_flag & HBA_FIP_SUPPORT) && + ((elscmd == ELS_CMD_FLOGI) || + (elscmd == ELS_CMD_FDISC) || + (elscmd == ELS_CMD_LOGO))) + switch (elscmd) { + case ELS_CMD_FLOGI: + elsiocb->iocb_flag |= ((ELS_ID_FLOGI << LPFC_FIP_ELS_ID_SHIFT) + & LPFC_FIP_ELS_ID_MASK); + break; + case ELS_CMD_FDISC: + elsiocb->iocb_flag |= ((ELS_ID_FDISC << LPFC_FIP_ELS_ID_SHIFT) + & LPFC_FIP_ELS_ID_MASK); + break; + case ELS_CMD_LOGO: + elsiocb->iocb_flag |= ((ELS_ID_LOGO << LPFC_FIP_ELS_ID_SHIFT) + & LPFC_FIP_ELS_ID_MASK); + break; + } + else + elsiocb->iocb_flag &= ~LPFC_FIP_ELS_ID_MASK; + icmd = &elsiocb->iocb; /* fill in BDEs for command */ @@ -388,6 +411,75 @@ fail: } /** + * lpfc_issue_reg_vfi - Register VFI for this vport's fabric login + * @vport: pointer to a host virtual N_Port data structure. + * + * This routine issues a REG_VFI mailbox for the vfi, vpi, fcfi triplet for + * the @vport. This mailbox command is necessary for FCoE only. + * + * Return code + * 0 - successfully issued REG_VFI for @vport + * A failure code otherwise. + **/ +static int +lpfc_issue_reg_vfi(struct lpfc_vport *vport) +{ + struct lpfc_hba *phba = vport->phba; + LPFC_MBOXQ_t *mboxq; + struct lpfc_nodelist *ndlp; + struct serv_parm *sp; + struct lpfc_dmabuf *dmabuf; + int rc = 0; + + sp = &phba->fc_fabparam; + ndlp = lpfc_findnode_did(vport, Fabric_DID); + if (!ndlp || !NLP_CHK_NODE_ACT(ndlp)) { + rc = -ENODEV; + goto fail; + } + + dmabuf = kzalloc(sizeof(struct lpfc_dmabuf), GFP_KERNEL); + if (!dmabuf) { + rc = -ENOMEM; + goto fail; + } + dmabuf->virt = lpfc_mbuf_alloc(phba, MEM_PRI, &dmabuf->phys); + if (!dmabuf->virt) { + rc = -ENOMEM; + goto fail_free_dmabuf; + } + mboxq = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mboxq) { + rc = -ENOMEM; + goto fail_free_coherent; + } + vport->port_state = LPFC_FABRIC_CFG_LINK; + memcpy(dmabuf->virt, &phba->fc_fabparam, sizeof(vport->fc_sparam)); + lpfc_reg_vfi(mboxq, vport, dmabuf->phys); + mboxq->mbox_cmpl = lpfc_mbx_cmpl_reg_vfi; + mboxq->vport = vport; + mboxq->context1 = dmabuf; + rc = lpfc_sli_issue_mbox(phba, mboxq, MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + rc = -ENXIO; + goto fail_free_mbox; + } + return 0; + +fail_free_mbox: + mempool_free(mboxq, phba->mbox_mem_pool); +fail_free_coherent: + lpfc_mbuf_free(phba, dmabuf->virt, dmabuf->phys); +fail_free_dmabuf: + kfree(dmabuf); +fail: + lpfc_vport_set_state(vport, FC_VPORT_FAILED); + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0289 Issue Register VFI failed: Err %d\n", rc); + return rc; +} + +/** * lpfc_cmpl_els_flogi_fabric - Completion function for flogi to a fabric port * @vport: pointer to a host virtual N_Port data structure. * @ndlp: pointer to a node-list data structure. @@ -497,19 +589,38 @@ lpfc_cmpl_els_flogi_fabric(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; spin_unlock_irq(shost->host_lock); } + /* + * If VPI is unreged, driver need to do INIT_VPI + * before re-registering + */ + if (phba->sli_rev == LPFC_SLI_REV4) { + spin_lock_irq(shost->host_lock); + vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; + spin_unlock_irq(shost->host_lock); + } } - lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE); - - if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED && - vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) { - lpfc_register_new_vport(phba, vport, ndlp); - return 0; + if (phba->sli_rev < LPFC_SLI_REV4) { + lpfc_nlp_set_state(vport, ndlp, NLP_STE_REG_LOGIN_ISSUE); + if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED && + vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) + lpfc_register_new_vport(phba, vport, ndlp); + else + lpfc_issue_fabric_reglogin(vport); + } else { + ndlp->nlp_type |= NLP_FABRIC; + lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); + if ((!(vport->fc_flag & FC_VPORT_NEEDS_REG_VPI)) && + (vport->vpi_state & LPFC_VPI_REGISTERED)) { + lpfc_start_fdiscs(phba); + lpfc_do_scr_ns_plogi(phba, vport); + } else if (vport->fc_flag & FC_VFI_REGISTERED) + lpfc_issue_init_vpi(vport); + else + lpfc_issue_reg_vfi(vport); } - lpfc_issue_fabric_reglogin(vport); return 0; } - /** * lpfc_cmpl_els_flogi_nport - Completion function for flogi to an N_Port * @vport: pointer to a host virtual N_Port data structure. @@ -702,6 +813,9 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp->ulpTimeout); goto flogifail; } + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_VPORT_CVL_RCVD; + spin_unlock_irq(shost->host_lock); /* * The FLogI succeeded. Sync the data for the CPU before @@ -713,7 +827,7 @@ lpfc_cmpl_els_flogi(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, /* FLOGI completes successfully */ lpfc_printf_vlog(vport, KERN_INFO, LOG_ELS, - "0101 FLOGI completes sucessfully " + "0101 FLOGI completes successfully " "Data: x%x x%x x%x x%x\n", irsp->un.ulpWord[4], sp->cmn.e_d_tov, sp->cmn.w2.r_a_tov, sp->cmn.edtovResolution); @@ -817,9 +931,14 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (sp->cmn.fcphHigh < FC_PH3) sp->cmn.fcphHigh = FC_PH3; - if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { + if (phba->sli_rev == LPFC_SLI_REV4) { + elsiocb->iocb.ulpCt_h = ((SLI4_CT_FCFI >> 1) & 1); + elsiocb->iocb.ulpCt_l = (SLI4_CT_FCFI & 1); + /* FLOGI needs to be 3 for WQE FCFI */ + /* Set the fcfi to the fcfi we registered with */ + elsiocb->iocb.ulpContext = phba->fcf.fcfi; + } else if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { sp->cmn.request_multiple_Nport = 1; - /* For FLOGI, Let FLOGI rsp set the NPortID for VPI 0 */ icmd->ulpCt_h = 1; icmd->ulpCt_l = 0; @@ -862,7 +981,7 @@ lpfc_issue_els_flogi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, * function returns, it does not guarantee all the IOCBs are actually aborted. * * Return code - * 0 - Sucessfully issued abort iocb on all outstanding flogis (Always 0) + * 0 - Successfully issued abort iocb on all outstanding flogis (Always 0) **/ int lpfc_els_abort_flogi(struct lpfc_hba *phba) @@ -932,6 +1051,8 @@ lpfc_initial_flogi(struct lpfc_vport *vport) if (!ndlp) return 0; lpfc_nlp_init(vport, ndlp, Fabric_DID); + /* Set the node type */ + ndlp->nlp_type |= NLP_FABRIC; /* Put ndlp onto node list */ lpfc_enqueue_node(vport, ndlp); } else if (!NLP_CHK_NODE_ACT(ndlp)) { @@ -1604,7 +1725,8 @@ lpfc_adisc_done(struct lpfc_vport *vport) * and continue discovery. */ if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && - !(vport->fc_flag & FC_RSCN_MODE)) { + !(vport->fc_flag & FC_RSCN_MODE) && + (phba->sli_rev < LPFC_SLI_REV4)) { lpfc_issue_reg_vpi(phba, vport); return; } @@ -2355,6 +2477,7 @@ lpfc_els_retry_delay_handler(struct lpfc_nodelist *ndlp) */ del_timer_sync(&ndlp->nlp_delayfunc); retry = ndlp->nlp_retry; + ndlp->nlp_retry = 0; switch (cmd) { case ELS_CMD_FLOGI: @@ -2609,17 +2732,21 @@ lpfc_els_retry(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (did == FDMI_DID) retry = 1; - if ((cmd == ELS_CMD_FLOGI) && + if (((cmd == ELS_CMD_FLOGI) || (cmd == ELS_CMD_FDISC)) && (phba->fc_topology != TOPOLOGY_LOOP) && !lpfc_error_lost_link(irsp)) { /* FLOGI retry policy */ retry = 1; - maxretry = 48; - if (cmdiocb->retry >= 32) + /* retry forever */ + maxretry = 0; + if (cmdiocb->retry >= 100) + delay = 5000; + else if (cmdiocb->retry >= 32) delay = 1000; } - if ((++cmdiocb->retry) >= maxretry) { + cmdiocb->retry++; + if (maxretry && (cmdiocb->retry >= maxretry)) { phba->fc_stat.elsRetryExceeded++; retry = 0; } @@ -2937,6 +3064,14 @@ lpfc_mbx_cmpl_dflt_rpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; + /* + * This routine is used to register and unregister in previous SLI + * modes. + */ + if ((pmb->u.mb.mbxCommand == MBX_UNREG_LOGIN) && + (phba->sli_rev == LPFC_SLI_REV4)) + lpfc_sli4_free_rpi(phba, pmb->u.mb.un.varUnregLogin.rpi); + pmb->context1 = NULL; lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); @@ -2994,7 +3129,7 @@ lpfc_cmpl_els_rsp(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, if (ndlp && NLP_CHK_NODE_ACT(ndlp) && (*((uint32_t *) (pcmd)) == ELS_CMD_LS_RJT)) { /* A LS_RJT associated with Default RPI cleanup has its own - * seperate code path. + * separate code path. */ if (!(ndlp->nlp_flag & NLP_RM_DFLT_RPI)) ls_rjt = 1; @@ -3816,7 +3951,9 @@ lpfc_rscn_payload_check(struct lpfc_vport *vport, uint32_t did) payload_len -= sizeof(uint32_t); switch (rscn_did.un.b.resv & RSCN_ADDRESS_FORMAT_MASK) { case RSCN_ADDRESS_FORMAT_PORT: - if (ns_did.un.word == rscn_did.un.word) + if ((ns_did.un.b.domain == rscn_did.un.b.domain) + && (ns_did.un.b.area == rscn_did.un.b.area) + && (ns_did.un.b.id == rscn_did.un.b.id)) goto return_did_out; break; case RSCN_ADDRESS_FORMAT_AREA: @@ -4017,8 +4154,8 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, spin_lock_irq(shost->host_lock); if (vport->fc_rscn_flush) { /* Another thread is walking fc_rscn_id_list on this vport */ - spin_unlock_irq(shost->host_lock); vport->fc_flag |= FC_RSCN_DISCOVERY; + spin_unlock_irq(shost->host_lock); /* Send back ACC */ lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); return 0; @@ -4026,7 +4163,7 @@ lpfc_els_rcv_rscn(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, /* Indicate we are walking fc_rscn_id_list on this vport */ vport->fc_rscn_flush = 1; spin_unlock_irq(shost->host_lock); - /* Get the array count after sucessfully have the token */ + /* Get the array count after successfully have the token */ rscn_cnt = vport->fc_rscn_id_cnt; /* If we are already processing an RSCN, save the received * RSCN payload buffer, cmdiocb->context2 to process later. @@ -4260,7 +4397,7 @@ lpfc_els_rcv_flogi(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, did = Fabric_DID; - if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3))) { + if ((lpfc_check_sparm(vport, ndlp, sp, CLASS3, 1))) { /* For a FLOGI we accept, then if our portname is greater * then the remote portname we initiate Nport login. */ @@ -4396,6 +4533,29 @@ lpfc_els_rcv_lirr(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, } /** + * lpfc_els_rcv_rrq - Process an unsolicited rrq iocb + * @vport: pointer to a host virtual N_Port data structure. + * @cmdiocb: pointer to lpfc command iocb data structure. + * @ndlp: pointer to a node-list data structure. + * + * This routine processes a Reinstate Recovery Qualifier (RRQ) IOCB + * received as an ELS unsolicited event. A request to RRQ shall only + * be accepted if the Originator Nx_Port N_Port_ID or the Responder + * Nx_Port N_Port_ID of the target Exchange is the same as the + * N_Port_ID of the Nx_Port that makes the request. If the RRQ is + * not accepted, an LS_RJT with reason code "Unable to perform + * command request" and reason code explanation "Invalid Originator + * S_ID" shall be returned. For now, we just unconditionally accept + * RRQ from the target. + **/ +static void +lpfc_els_rcv_rrq(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, + struct lpfc_nodelist *ndlp) +{ + lpfc_els_rsp_acc(vport, ELS_CMD_ACC, cmdiocb, ndlp, NULL); +} + +/** * lpfc_els_rsp_rps_acc - Completion callbk func for MBX_READ_LNK_STAT mbox cmd * @phba: pointer to lpfc hba data structure. * @pmb: pointer to the driver internal queue element for mailbox command. @@ -4857,7 +5017,10 @@ lpfc_els_rcv_fan(struct lpfc_vport *vport, struct lpfc_iocbq *cmdiocb, } else { /* FAN verified - skip FLOGI */ vport->fc_myDID = vport->fc_prevDID; - lpfc_issue_fabric_reglogin(vport); + if (phba->sli_rev < LPFC_SLI_REV4) + lpfc_issue_fabric_reglogin(vport); + else + lpfc_issue_reg_vfi(vport); } } return 0; @@ -5286,7 +5449,7 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (lpfc_els_chk_latt(vport)) goto dropit; - /* Ignore traffic recevied during vport shutdown. */ + /* Ignore traffic received during vport shutdown. */ if (vport->load_flag & FC_UNLOADING) goto dropit; @@ -5508,6 +5671,16 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, if (newnode) lpfc_nlp_put(ndlp); break; + case ELS_CMD_RRQ: + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, + "RCV RRQ: did:x%x/ste:x%x flg:x%x", + did, vport->port_state, ndlp->nlp_flag); + + phba->fc_stat.elsRcvRRQ++; + lpfc_els_rcv_rrq(vport, elsiocb, ndlp); + if (newnode) + lpfc_nlp_put(ndlp); + break; default: lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_UNSOL, "RCV ELS cmd: cmd:x%x did:x%x/ste:x%x", @@ -5540,11 +5713,10 @@ lpfc_els_unsol_buffer(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, dropit: if (vport && !(vport->load_flag & FC_UNLOADING)) - lpfc_printf_log(phba, KERN_ERR, LOG_ELS, - "(%d):0111 Dropping received ELS cmd " + lpfc_printf_vlog(vport, KERN_ERR, LOG_ELS, + "0111 Dropping received ELS cmd " "Data: x%x x%x x%x\n", - vport->vpi, icmd->ulpStatus, - icmd->un.ulpWord[4], icmd->ulpTimeout); + icmd->ulpStatus, icmd->un.ulpWord[4], icmd->ulpTimeout); phba->fc_stat.elsRcvDrop++; } @@ -5561,7 +5733,7 @@ dropit: * NULL - No vport with the matching @vpi found * Otherwise - Address to the vport with the matching @vpi. **/ -static struct lpfc_vport * +struct lpfc_vport * lpfc_find_vport_by_vpid(struct lpfc_hba *phba, uint16_t vpi) { struct lpfc_vport *vport; @@ -5620,10 +5792,9 @@ lpfc_els_unsol_event(struct lpfc_hba *phba, struct lpfc_sli_ring *pring, icmd->ulpCommand == CMD_IOCB_RCV_SEQ64_CX)) { if (icmd->unsli3.rcvsli3.vpi == 0xffff) vport = phba->pport; - else { - uint16_t vpi = icmd->unsli3.rcvsli3.vpi; - vport = lpfc_find_vport_by_vpid(phba, vpi); - } + else + vport = lpfc_find_vport_by_vpid(phba, + icmd->unsli3.rcvsli3.vpi - phba->vpi_base); } /* If there are no BDEs associated * with this IOCB, there is nothing to do. @@ -5756,6 +5927,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; MAILBOX_t *mb = &pmb->u.mb; + int rc; spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI; @@ -5777,6 +5949,26 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) spin_unlock_irq(shost->host_lock); lpfc_can_disctmo(vport); break; + /* If reg_vpi fail with invalid VPI status, re-init VPI */ + case 0x20: + spin_lock_irq(shost->host_lock); + vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + spin_unlock_irq(shost->host_lock); + lpfc_init_vpi(phba, pmb, vport->vpi); + pmb->vport = vport; + pmb->mbox_cmpl = lpfc_init_vpi_cmpl; + rc = lpfc_sli_issue_mbox(phba, pmb, + MBX_NOWAIT); + if (rc == MBX_NOT_FINISHED) { + lpfc_printf_vlog(vport, + KERN_ERR, LOG_MBOX, + "2732 Failed to issue INIT_VPI" + " mailbox command\n"); + } else { + lpfc_nlp_put(ndlp); + return; + } + default: /* Try to recover from this error */ lpfc_mbx_unreg_vpi(vport); @@ -5789,11 +5981,18 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_initial_fdisc(vport); break; } - } else { - if (vport == phba->pport) - lpfc_issue_fabric_reglogin(vport); - else + spin_lock_irq(shost->host_lock); + vport->vpi_state |= LPFC_VPI_REGISTERED; + spin_unlock_irq(shost->host_lock); + if (vport == phba->pport) { + if (phba->sli_rev < LPFC_SLI_REV4) + lpfc_issue_fabric_reglogin(vport); + else { + lpfc_start_fdiscs(phba); + lpfc_do_scr_ns_plogi(phba, vport); + } + } else lpfc_do_scr_ns_plogi(phba, vport); } @@ -5815,7 +6014,7 @@ lpfc_cmpl_reg_new_vport(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) * This routine registers the @vport as a new virtual port with a HBA. * It is done through a registering vpi mailbox command. **/ -static void +void lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { @@ -5824,7 +6023,7 @@ lpfc_register_new_vport(struct lpfc_hba *phba, struct lpfc_vport *vport, mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (mbox) { - lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, mbox); + lpfc_reg_vpi(vport, mbox); mbox->vport = vport; mbox->context2 = lpfc_nlp_get(ndlp); mbox->mbox_cmpl = lpfc_cmpl_reg_new_vport; @@ -5856,6 +6055,78 @@ mbox_err_exit: } /** + * lpfc_retry_pport_discovery - Start timer to retry FLOGI. + * @phba: pointer to lpfc hba data structure. + * + * This routine abort all pending discovery commands and + * start a timer to retry FLOGI for the physical port + * discovery. + **/ +void +lpfc_retry_pport_discovery(struct lpfc_hba *phba) +{ + struct lpfc_vport **vports; + struct lpfc_nodelist *ndlp; + struct Scsi_Host *shost; + int i; + uint32_t link_state; + + /* Treat this failure as linkdown for all vports */ + link_state = phba->link_state; + lpfc_linkdown(phba); + phba->link_state = link_state; + + vports = lpfc_create_vport_work_array(phba); + + if (vports) { + for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) { + ndlp = lpfc_findnode_did(vports[i], Fabric_DID); + if (ndlp) + lpfc_cancel_retry_delay_tmo(vports[i], ndlp); + lpfc_els_flush_cmd(vports[i]); + } + lpfc_destroy_vport_work_array(phba, vports); + } + + /* If fabric require FLOGI, then re-instantiate physical login */ + ndlp = lpfc_findnode_did(phba->pport, Fabric_DID); + if (!ndlp) + return; + + + shost = lpfc_shost_from_vport(phba->pport); + mod_timer(&ndlp->nlp_delayfunc, jiffies + HZ); + spin_lock_irq(shost->host_lock); + ndlp->nlp_flag |= NLP_DELAY_TMO; + spin_unlock_irq(shost->host_lock); + ndlp->nlp_last_elscmd = ELS_CMD_FLOGI; + phba->pport->port_state = LPFC_FLOGI; + return; +} + +/** + * lpfc_fabric_login_reqd - Check if FLOGI required. + * @phba: pointer to lpfc hba data structure. + * @cmdiocb: pointer to FDISC command iocb. + * @rspiocb: pointer to FDISC response iocb. + * + * This routine checks if a FLOGI is reguired for FDISC + * to succeed. + **/ +static int +lpfc_fabric_login_reqd(struct lpfc_hba *phba, + struct lpfc_iocbq *cmdiocb, + struct lpfc_iocbq *rspiocb) +{ + + if ((rspiocb->iocb.ulpStatus != IOSTAT_FABRIC_RJT) || + (rspiocb->iocb.un.ulpWord[4] != RJT_LOGIN_REQUIRED)) + return 0; + else + return 1; +} + +/** * lpfc_cmpl_els_fdisc - Completion function for fdisc iocb command * @phba: pointer to lpfc hba data structure. * @cmdiocb: pointer to lpfc command iocb data structure. @@ -5904,6 +6175,12 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp->ulpStatus, irsp->un.ulpWord[4], vport->fc_prevDID); if (irsp->ulpStatus) { + + if (lpfc_fabric_login_reqd(phba, cmdiocb, rspiocb)) { + lpfc_retry_pport_discovery(phba); + goto out; + } + /* Check for retry */ if (lpfc_els_retry(phba, cmdiocb, rspiocb)) goto out; @@ -5913,12 +6190,8 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, irsp->ulpStatus, irsp->un.ulpWord[4]); goto fdisc_failed; } - if (vport->fc_vport->vport_state == FC_VPORT_INITIALIZING) - lpfc_vport_set_state(vport, FC_VPORT_FAILED); - lpfc_nlp_put(ndlp); - /* giving up on FDISC. Cancel discovery timer */ - lpfc_can_disctmo(vport); spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_VPORT_CVL_RCVD; vport->fc_flag |= FC_FABRIC; if (vport->phba->fc_topology == TOPOLOGY_LOOP) vport->fc_flag |= FC_PUBLIC_LOOP; @@ -5946,10 +6219,13 @@ lpfc_cmpl_els_fdisc(struct lpfc_hba *phba, struct lpfc_iocbq *cmdiocb, lpfc_mbx_unreg_vpi(vport); spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + vport->fc_flag |= FC_VPORT_NEEDS_INIT_VPI; spin_unlock_irq(shost->host_lock); } - if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) + if (vport->fc_flag & FC_VPORT_NEEDS_INIT_VPI) + lpfc_issue_init_vpi(vport); + else if (vport->fc_flag & FC_VPORT_NEEDS_REG_VPI) lpfc_register_new_vport(phba, vport, ndlp); else lpfc_do_scr_ns_plogi(phba, vport); @@ -5996,6 +6272,7 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int did = ndlp->nlp_DID; int rc; + vport->port_state = LPFC_FDISC; cmdsize = (sizeof(uint32_t) + sizeof(struct serv_parm)); elsiocb = lpfc_prep_els_iocb(vport, 1, cmdsize, retry, ndlp, did, ELS_CMD_FDISC); @@ -6010,9 +6287,17 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, icmd->un.elsreq64.myID = 0; icmd->un.elsreq64.fl = 1; - /* For FDISC, Let FDISC rsp set the NPortID for this VPI */ - icmd->ulpCt_h = 1; - icmd->ulpCt_l = 0; + if (phba->sli_rev == LPFC_SLI_REV4) { + /* FDISC needs to be 1 for WQE VPI */ + elsiocb->iocb.ulpCt_h = (SLI4_CT_VPI >> 1) & 1; + elsiocb->iocb.ulpCt_l = SLI4_CT_VPI & 1 ; + /* Set the ulpContext to the vpi */ + elsiocb->iocb.ulpContext = vport->vpi + phba->vpi_base; + } else { + /* For FDISC, Let FDISC rsp set the NPortID for this VPI */ + icmd->ulpCt_h = 1; + icmd->ulpCt_l = 0; + } pcmd = (uint8_t *) (((struct lpfc_dmabuf *) elsiocb->context2)->virt); *((uint32_t *) (pcmd)) = ELS_CMD_FDISC; @@ -6053,7 +6338,6 @@ lpfc_issue_els_fdisc(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, return 1; } lpfc_vport_set_state(vport, FC_VPORT_INITIALIZING); - vport->port_state = LPFC_FDISC; return 0; } @@ -6496,3 +6780,38 @@ void lpfc_fabric_abort_hba(struct lpfc_hba *phba) lpfc_sli_cancel_iocbs(phba, &completions, IOSTAT_LOCAL_REJECT, IOERR_SLI_ABORTED); } + +/** + * lpfc_sli4_els_xri_aborted - Slow-path process of els xri abort + * @phba: pointer to lpfc hba data structure. + * @axri: pointer to the els xri abort wcqe structure. + * + * This routine is invoked by the worker thread to process a SLI4 slow-path + * ELS aborted xri. + **/ +void +lpfc_sli4_els_xri_aborted(struct lpfc_hba *phba, + struct sli4_wcqe_xri_aborted *axri) +{ + uint16_t xri = bf_get(lpfc_wcqe_xa_xri, axri); + struct lpfc_sglq *sglq_entry = NULL, *sglq_next = NULL; + unsigned long iflag = 0; + + spin_lock_irqsave(&phba->sli4_hba.abts_sgl_list_lock, iflag); + list_for_each_entry_safe(sglq_entry, sglq_next, + &phba->sli4_hba.lpfc_abts_els_sgl_list, list) { + if (sglq_entry->sli4_xritag == xri) { + list_del(&sglq_entry->list); + spin_unlock_irqrestore( + &phba->sli4_hba.abts_sgl_list_lock, + iflag); + spin_lock_irqsave(&phba->hbalock, iflag); + + list_add_tail(&sglq_entry->list, + &phba->sli4_hba.lpfc_sgl_list); + spin_unlock_irqrestore(&phba->hbalock, iflag); + return; + } + } + spin_unlock_irqrestore(&phba->sli4_hba.abts_sgl_list_lock, iflag); +}