X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fscsi%2Flpfc%2Flpfc_hbadisc.c;fp=drivers%2Fscsi%2Flpfc%2Flpfc_hbadisc.c;h=c39564e85e944f62ebed5d8b3d41a6f75daf4ff7;hb=97bf2856c6014879bd04983a3e9dfcdac1e7fe85;hp=a1f751e79405fee9fdc32db86bfc47bd7dcdcd31;hpb=76828883507a47dae78837ab5dec5a5b4513c667;p=linux-2.6.git diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index a1f751e79..c39564e85 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -1,7 +1,7 @@ /******************************************************************* * This file is part of the Emulex Linux Device Driver for * * Fibre Channel Host Bus Adapters. * - * Copyright (C) 2004-2005 Emulex. All rights reserved. * + * Copyright (C) 2004-2006 Emulex. All rights reserved. * * EMULEX and SLI are trademarks of Emulex. * * www.emulex.com * * Portions Copyright (C) 2004-2005 Christoph Hellwig * @@ -56,18 +56,63 @@ static uint8_t lpfcAlpaArray[] = { static void lpfc_disc_timeout_handler(struct lpfc_hba *); -static void -lpfc_process_nodev_timeout(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) +void +lpfc_terminate_rport_io(struct fc_rport *rport) { - int warn_on = 0; + struct lpfc_rport_data *rdata; + struct lpfc_nodelist * ndlp; + struct lpfc_hba *phba; + + rdata = rport->dd_data; + ndlp = rdata->pnode; + + if (!ndlp) { + if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) + printk(KERN_ERR "Cannot find remote node" + " to terminate I/O Data x%x\n", + rport->port_id); + return; + } + + phba = ndlp->nlp_phba; spin_lock_irq(phba->host->host_lock); - if (!(ndlp->nlp_flag & NLP_NODEV_TMO)) { - spin_unlock_irq(phba->host->host_lock); + if (ndlp->nlp_sid != NLP_NO_SID) { + lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring], + ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT); + } + spin_unlock_irq(phba->host->host_lock); + + return; +} + +/* + * This function will be called when dev_loss_tmo fire. + */ +void +lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) +{ + struct lpfc_rport_data *rdata; + struct lpfc_nodelist * ndlp; + uint8_t *name; + int warn_on = 0; + struct lpfc_hba *phba; + + rdata = rport->dd_data; + ndlp = rdata->pnode; + + if (!ndlp) { + if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) + printk(KERN_ERR "Cannot find remote node" + " for rport in dev_loss_tmo_callbk x%x\n", + rport->port_id); return; } - ndlp->nlp_flag &= ~NLP_NODEV_TMO; + name = (uint8_t *)&ndlp->nlp_portname; + phba = ndlp->nlp_phba; + + spin_lock_irq(phba->host->host_lock); if (ndlp->nlp_sid != NLP_NO_SID) { warn_on = 1; @@ -75,23 +120,39 @@ lpfc_process_nodev_timeout(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring], ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT); } + if (phba->fc_flag & FC_UNLOADING) + warn_on = 0; + spin_unlock_irq(phba->host->host_lock); if (warn_on) { lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "%d:0203 Nodev timeout on NPort x%x " - "Data: x%x x%x x%x\n", - phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag, + "%d:0203 Devloss timeout on " + "WWPN %x:%x:%x:%x:%x:%x:%x:%x " + "NPort x%x Data: x%x x%x x%x\n", + phba->brd_no, + *name, *(name+1), *(name+2), *(name+3), + *(name+4), *(name+5), *(name+6), *(name+7), + ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); } else { lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, - "%d:0204 Nodev timeout on NPort x%x " - "Data: x%x x%x x%x\n", - phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag, + "%d:0204 Devloss timeout on " + "WWPN %x:%x:%x:%x:%x:%x:%x:%x " + "NPort x%x Data: x%x x%x x%x\n", + phba->brd_no, + *name, *(name+1), *(name+2), *(name+3), + *(name+4), *(name+5), *(name+6), *(name+7), + ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); } - lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RM); + ndlp->rport = NULL; + rdata->pnode = NULL; + + if (!(phba->fc_flag & FC_UNLOADING)) + lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RM); + return; } @@ -108,23 +169,42 @@ lpfc_work_list_done(struct lpfc_hba * phba) evt_listp); spin_unlock_irq(phba->host->host_lock); free_evt = 1; - switch(evtp->evt) { - case LPFC_EVT_NODEV_TMO: - ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1); - lpfc_process_nodev_timeout(phba, ndlp); - free_evt = 0; - break; + switch (evtp->evt) { case LPFC_EVT_ELS_RETRY: ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1); lpfc_els_retry_delay_handler(ndlp); free_evt = 0; break; case LPFC_EVT_ONLINE: - *(int *)(evtp->evt_arg1) = lpfc_online(phba); + if (phba->hba_state < LPFC_LINK_DOWN) + *(int *)(evtp->evt_arg1) = lpfc_online(phba); + else + *(int *)(evtp->evt_arg1) = 0; complete((struct completion *)(evtp->evt_arg2)); break; case LPFC_EVT_OFFLINE: - *(int *)(evtp->evt_arg1) = lpfc_offline(phba); + if (phba->hba_state >= LPFC_LINK_DOWN) + lpfc_offline(phba); + lpfc_sli_brdrestart(phba); + *(int *)(evtp->evt_arg1) = + lpfc_sli_brdready(phba,HS_FFRDY | HS_MBRDY); + complete((struct completion *)(evtp->evt_arg2)); + break; + case LPFC_EVT_WARM_START: + if (phba->hba_state >= LPFC_LINK_DOWN) + lpfc_offline(phba); + lpfc_reset_barrier(phba); + lpfc_sli_brdreset(phba); + lpfc_hba_down_post(phba); + *(int *)(evtp->evt_arg1) = + lpfc_sli_brdready(phba, HS_MBRDY); + complete((struct completion *)(evtp->evt_arg2)); + break; + case LPFC_EVT_KILL: + if (phba->hba_state >= LPFC_LINK_DOWN) + lpfc_offline(phba); + *(int *)(evtp->evt_arg1) + = (phba->stopped) ? 0 : lpfc_sli_brdkill(phba); complete((struct completion *)(evtp->evt_arg2)); break; } @@ -151,13 +231,13 @@ lpfc_work_done(struct lpfc_hba * phba) work_hba_events=phba->work_hba_events; spin_unlock_irq(phba->host->host_lock); - if(ha_copy & HA_ERATT) + if (ha_copy & HA_ERATT) lpfc_handle_eratt(phba); - if(ha_copy & HA_MBATT) + if (ha_copy & HA_MBATT) lpfc_sli_handle_mb_event(phba); - if(ha_copy & HA_LATT) + if (ha_copy & HA_LATT) lpfc_handle_latt(phba); if (work_hba_events & WORKER_DISC_TMO) @@ -225,7 +305,7 @@ lpfc_do_work(void *p) { struct lpfc_hba *phba = p; int rc; - DECLARE_WAIT_QUEUE_HEAD(work_waitq); + DECLARE_WAIT_QUEUE_HEAD_ONSTACK(work_waitq); set_user_nice(current, -20); phba->work_wait = &work_waitq; @@ -269,8 +349,8 @@ lpfc_workq_post_event(struct lpfc_hba * phba, void *arg1, void *arg2, evtp->evt_arg2 = arg2; evtp->evt = evt; - list_add_tail(&evtp->evt_listp, &phba->work_list); spin_lock_irq(phba->host->host_lock); + list_add_tail(&evtp->evt_listp, &phba->work_list); if (phba->work_wait) wake_up(phba->work_wait); spin_unlock_irq(phba->host->host_lock); @@ -283,16 +363,23 @@ lpfc_linkdown(struct lpfc_hba * phba) { struct lpfc_sli *psli; struct lpfc_nodelist *ndlp, *next_ndlp; - struct list_head *listp; - struct list_head *node_list[7]; + struct list_head *listp, *node_list[7]; LPFC_MBOXQ_t *mb; int rc, i; psli = &phba->sli; + /* sysfs or selective reset may call this routine to clean up */ + if (phba->hba_state >= LPFC_LINK_DOWN) { + if (phba->hba_state == LPFC_LINK_DOWN) + return 0; - spin_lock_irq(phba->host->host_lock); - phba->hba_state = LPFC_LINK_DOWN; - spin_unlock_irq(phba->host->host_lock); + spin_lock_irq(phba->host->host_lock); + phba->hba_state = LPFC_LINK_DOWN; + spin_unlock_irq(phba->host->host_lock); + } + + fc_host_post_event(phba->host, fc_get_event_number(), + FCH_EVT_LINKDOWN, 0); /* Clean up any firmware default rpi's */ if ((mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) { @@ -324,33 +411,10 @@ lpfc_linkdown(struct lpfc_hba * phba) continue; list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) { - /* Fabric nodes are not handled thru state machine for - link down */ - if (ndlp->nlp_type & NLP_FABRIC) { - /* Remove ALL Fabric nodes except Fabric_DID */ - if (ndlp->nlp_DID != Fabric_DID) { - /* Take it off current list and free */ - lpfc_nlp_list(phba, ndlp, - NLP_NO_LIST); - } - } - else { - - rc = lpfc_disc_state_machine(phba, ndlp, NULL, - NLP_EVT_DEVICE_RECOVERY); - - /* Check config parameter use-adisc or FCP-2 */ - if ((rc != NLP_STE_FREED_NODE) && - (phba->cfg_use_adisc == 0) && - !(ndlp->nlp_fcp_info & - NLP_FCP_2_DEVICE)) { - /* We know we will have to relogin, so - * unreglogin the rpi right now to fail - * any outstanding I/Os quickly. - */ - lpfc_unreg_rpi(phba, ndlp); - } - } + + rc = lpfc_disc_state_machine(phba, ndlp, NULL, + NLP_EVT_DEVICE_RECOVERY); + } } @@ -384,13 +448,18 @@ lpfc_linkdown(struct lpfc_hba * phba) lpfc_can_disctmo(phba); /* Must process IOCBs on all rings to handle ABORTed I/Os */ - return (0); + return 0; } static int lpfc_linkup(struct lpfc_hba * phba) { struct lpfc_nodelist *ndlp, *next_ndlp; + struct list_head *listp, *node_list[7]; + int i; + + fc_host_post_event(phba->host, fc_get_event_number(), + FCH_EVT_LINKUP, 0); spin_lock_irq(phba->host->host_lock); phba->hba_state = LPFC_LINK_UP; @@ -401,14 +470,33 @@ lpfc_linkup(struct lpfc_hba * phba) spin_unlock_irq(phba->host->host_lock); - /* - * Clean up old Fabric NLP_FABRIC logins. - */ - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpunmap_list, - nlp_listp) { - if (ndlp->nlp_DID == Fabric_DID) { - /* Take it off current list and free */ - lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + node_list[0] = &phba->fc_plogi_list; + node_list[1] = &phba->fc_adisc_list; + node_list[2] = &phba->fc_reglogin_list; + node_list[3] = &phba->fc_prli_list; + node_list[4] = &phba->fc_nlpunmap_list; + node_list[5] = &phba->fc_nlpmap_list; + node_list[6] = &phba->fc_npr_list; + for (i = 0; i < 7; i++) { + listp = node_list[i]; + if (list_empty(listp)) + continue; + + list_for_each_entry_safe(ndlp, next_ndlp, listp, nlp_listp) { + if (phba->fc_flag & FC_LBIT) { + if (ndlp->nlp_type & NLP_FABRIC) { + /* On Linkup its safe to clean up the + * ndlp from Fabric connections. + */ + lpfc_nlp_list(phba, ndlp, + NLP_UNUSED_LIST); + } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { + /* Fail outstanding IO now since device + * is marked for PLOGI. + */ + lpfc_unreg_rpi(phba, ndlp); + } + } } } @@ -437,7 +525,7 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) psli = &phba->sli; mb = &pmb->mb; /* Since we don't do discovery right now, turn these off here */ - psli->ring[psli->ip_ring].flag &= ~LPFC_STOP_IOCB_EVENT; + psli->ring[psli->extra_ring].flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[psli->fcp_ring].flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[psli->next_ring].flag &= ~LPFC_STOP_IOCB_EVENT; @@ -462,7 +550,7 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) lpfc_els_disc_plogi(phba); } - if(!phba->num_disc_nodes) { + if (!phba->num_disc_nodes) { spin_lock_irq(phba->host->host_lock); phba->fc_flag &= ~FC_NDISC_ACTIVE; spin_unlock_irq(phba->host->host_lock); @@ -504,80 +592,59 @@ out: } static void -lpfc_mbx_cmpl_config_link(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) +lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { - struct lpfc_sli *psli; - MAILBOX_t *mb; - - psli = &phba->sli; - mb = &pmb->mb; - /* Check for error */ - if (mb->mbxStatus) { - /* CONFIG_LINK mbox error state */ - lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, - "%d:0306 CONFIG_LINK mbxStatus error x%x " - "HBA state x%x\n", - phba->brd_no, mb->mbxStatus, phba->hba_state); + struct lpfc_sli *psli = &phba->sli; + int rc; - lpfc_linkdown(phba); - phba->hba_state = LPFC_HBA_ERROR; + if (pmb->mb.mbxStatus) goto out; - } - if (phba->hba_state == LPFC_LOCAL_CFG_LINK) { - if (phba->fc_topology == TOPOLOGY_LOOP) { - /* If we are public loop and L bit was set */ - if ((phba->fc_flag & FC_PUBLIC_LOOP) && - !(phba->fc_flag & FC_LBIT)) { - /* Need to wait for FAN - use discovery timer - * for timeout. hba_state is identically - * LPFC_LOCAL_CFG_LINK while waiting for FAN - */ - lpfc_set_disctmo(phba); - mempool_free( pmb, phba->mbox_mem_pool); - return; - } + mempool_free(pmb, phba->mbox_mem_pool); + + if (phba->fc_topology == TOPOLOGY_LOOP && + phba->fc_flag & FC_PUBLIC_LOOP && + !(phba->fc_flag & FC_LBIT)) { + /* Need to wait for FAN - use discovery timer + * for timeout. hba_state is identically + * LPFC_LOCAL_CFG_LINK while waiting for FAN + */ + lpfc_set_disctmo(phba); + return; } - /* Start discovery by sending a FLOGI hba_state is identically - * LPFC_FLOGI while waiting for FLOGI cmpl - */ - phba->hba_state = LPFC_FLOGI; - lpfc_set_disctmo(phba); - lpfc_initial_flogi(phba); - mempool_free( pmb, phba->mbox_mem_pool); - return; - } - if (phba->hba_state == LPFC_FABRIC_CFG_LINK) { - mempool_free( pmb, phba->mbox_mem_pool); - return; - } + /* Start discovery by sending a FLOGI. hba_state is identically + * LPFC_FLOGI while waiting for FLOGI cmpl + */ + phba->hba_state = LPFC_FLOGI; + lpfc_set_disctmo(phba); + lpfc_initial_flogi(phba); + return; out: - /* CONFIG_LINK bad hba state */ - lpfc_printf_log(phba, - KERN_ERR, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + "%d:0306 CONFIG_LINK mbxStatus error x%x " + "HBA state x%x\n", + phba->brd_no, pmb->mb.mbxStatus, phba->hba_state); + + lpfc_linkdown(phba); + + phba->hba_state = LPFC_HBA_ERROR; + + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, "%d:0200 CONFIG_LINK bad hba state x%x\n", phba->brd_no, phba->hba_state); - if (phba->hba_state != LPFC_CLEAR_LA) { - lpfc_clear_la(phba, pmb); - pmb->mbox_cmpl = lpfc_mbx_cmpl_clear_la; - if (lpfc_sli_issue_mbox(phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB)) - == MBX_NOT_FINISHED) { - mempool_free( pmb, phba->mbox_mem_pool); - lpfc_disc_flush_list(phba); - psli->ring[(psli->ip_ring)].flag &= - ~LPFC_STOP_IOCB_EVENT; - psli->ring[(psli->fcp_ring)].flag &= - ~LPFC_STOP_IOCB_EVENT; - psli->ring[(psli->next_ring)].flag &= - ~LPFC_STOP_IOCB_EVENT; - phba->hba_state = LPFC_HBA_READY; - } - } else { - mempool_free( pmb, phba->mbox_mem_pool); + lpfc_clear_la(phba, pmb); + pmb->mbox_cmpl = lpfc_mbx_cmpl_clear_la; + rc = lpfc_sli_issue_mbox(phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB)); + if (rc == MBX_NOT_FINISHED) { + mempool_free(pmb, phba->mbox_mem_pool); + lpfc_disc_flush_list(phba); + psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; + psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; + psli->ring[(psli->next_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; + phba->hba_state = LPFC_HBA_READY; } return; } @@ -605,6 +672,10 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) memcpy((uint8_t *) & phba->fc_sparam, (uint8_t *) mp->virt, sizeof (struct serv_parm)); + if (phba->cfg_soft_wwnn) + u64_to_wwn(phba->cfg_soft_wwnn, phba->fc_sparam.nodeName.u.wwn); + if (phba->cfg_soft_wwpn) + u64_to_wwn(phba->cfg_soft_wwpn, phba->fc_sparam.portName.u.wwn); memcpy((uint8_t *) & phba->fc_nodename, (uint8_t *) & phba->fc_sparam.nodeName, sizeof (struct lpfc_name)); @@ -627,7 +698,7 @@ out: == MBX_NOT_FINISHED) { mempool_free( pmb, phba->mbox_mem_pool); lpfc_disc_flush_list(phba); - psli->ring[(psli->ip_ring)].flag &= + psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; @@ -646,11 +717,14 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) { int i; LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox; + struct lpfc_dmabuf *mp; + int rc; + sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); spin_lock_irq(phba->host->host_lock); - switch(la->UlnkSpeed) { + switch (la->UlnkSpeed) { case LA_1GHZ_LINK: phba->fc_linkspeed = LA_1GHZ_LINK; break; @@ -724,16 +798,27 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) if (sparam_mbox) { lpfc_read_sparam(phba, sparam_mbox); sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam; - lpfc_sli_issue_mbox(phba, sparam_mbox, + rc = lpfc_sli_issue_mbox(phba, sparam_mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); + if (rc == MBX_NOT_FINISHED) { + mp = (struct lpfc_dmabuf *) sparam_mbox->context1; + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + mempool_free(sparam_mbox, phba->mbox_mem_pool); + if (cfglink_mbox) + mempool_free(cfglink_mbox, phba->mbox_mem_pool); + return; + } } if (cfglink_mbox) { phba->hba_state = LPFC_LOCAL_CFG_LINK; lpfc_config_link(phba, cfglink_mbox); - cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_config_link; - lpfc_sli_issue_mbox(phba, cfglink_mbox, + cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link; + rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); + if (rc == MBX_NOT_FINISHED) + mempool_free(cfglink_mbox, phba->mbox_mem_pool); } } @@ -784,6 +869,13 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) memcpy(&phba->alpa_map[0], mp->virt, 128); + spin_lock_irq(phba->host->host_lock); + if (la->pb) + phba->fc_flag |= FC_BYPASSED_MODE; + else + phba->fc_flag &= ~FC_BYPASSED_MODE; + spin_unlock_irq(phba->host->host_lock); + if (((phba->fc_eventTag + 1) < la->eventTag) || (phba->fc_eventTag == la->eventTag)) { phba->fc_stat.LinkMultiEvent++; @@ -904,32 +996,36 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) */ lpfc_issue_els_scr(phba, SCR_DID, 0); - /* Allocate a new node instance. If the pool is empty, just - * start the discovery process and skip the Nameserver login - * process. This is attempted again later on. Otherwise, issue - * a Port Login (PLOGI) to the NameServer - */ - if ((ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL)) - == 0) { - lpfc_disc_start(phba); - } else { - lpfc_nlp_init(phba, ndlp, NameServer_DID); - ndlp->nlp_type |= NLP_FABRIC; - ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; - lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST); - lpfc_issue_els_plogi(phba, ndlp, 0); - if (phba->cfg_fdmi_on) { - if ((ndlp_fdmi = mempool_alloc( - phba->nlp_mem_pool, - GFP_KERNEL))) { - lpfc_nlp_init(phba, ndlp_fdmi, - FDMI_DID); - ndlp_fdmi->nlp_type |= NLP_FABRIC; - ndlp_fdmi->nlp_state = - NLP_STE_PLOGI_ISSUE; - lpfc_issue_els_plogi(phba, ndlp_fdmi, - 0); - } + ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, NameServer_DID); + if (!ndlp) { + /* Allocate a new node instance. If the pool is empty, + * start the discovery process and skip the Nameserver + * login process. This is attempted again later on. + * Otherwise, issue a Port Login (PLOGI) to NameServer. + */ + ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC); + if (!ndlp) { + lpfc_disc_start(phba); + lpfc_mbuf_free(phba, mp->virt, mp->phys); + kfree(mp); + mempool_free( pmb, phba->mbox_mem_pool); + return; + } else { + lpfc_nlp_init(phba, ndlp, NameServer_DID); + ndlp->nlp_type |= NLP_FABRIC; + } + } + ndlp->nlp_state = NLP_STE_PLOGI_ISSUE; + lpfc_nlp_list(phba, ndlp, NLP_PLOGI_LIST); + lpfc_issue_els_plogi(phba, NameServer_DID, 0); + if (phba->cfg_fdmi_on) { + ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool, + GFP_KERNEL); + if (ndlp_fdmi) { + lpfc_nlp_init(phba, ndlp_fdmi, FDMI_DID); + ndlp_fdmi->nlp_type |= NLP_FABRIC; + ndlp_fdmi->nlp_state = NLP_STE_PLOGI_ISSUE; + lpfc_issue_els_plogi(phba, FDMI_DID, 0); } } } @@ -937,7 +1033,6 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free( pmb, phba->mbox_mem_pool); - return; } @@ -988,6 +1083,7 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RNN_ID); lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RSNN_NN); lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RFT_ID); + lpfc_ns_cmd(phba, ndlp, SLI_CTNS_RFF_ID); } phba->fc_ns_retry = 0; @@ -1028,10 +1124,6 @@ lpfc_register_remote_port(struct lpfc_hba * phba, /* initialize static port data */ rport->maxframe_size = ndlp->nlp_maxframe; rport->supported_classes = ndlp->nlp_class_sup; - if ((rport->scsi_target_id != -1) && - (rport->scsi_target_id < MAX_FCP_TARGET)) { - ndlp->nlp_sid = rport->scsi_target_id; - } rdata = rport->dd_data; rdata->pnode = ndlp; @@ -1044,6 +1136,10 @@ lpfc_register_remote_port(struct lpfc_hba * phba, if (rport_ids.roles != FC_RPORT_ROLE_UNKNOWN) fc_remote_port_rolechg(rport, rport_ids.roles); + if ((rport->scsi_target_id != -1) && + (rport->scsi_target_id < LPFC_MAX_TARGET)) { + ndlp->nlp_sid = rport->scsi_target_id; + } return; } @@ -1055,8 +1151,11 @@ lpfc_unregister_remote_port(struct lpfc_hba * phba, struct fc_rport *rport = ndlp->rport; struct lpfc_rport_data *rdata = rport->dd_data; - ndlp->rport = NULL; - rdata->pnode = NULL; + if (rport->scsi_target_id == -1) { + ndlp->rport = NULL; + rdata->pnode = NULL; + } + fc_remote_port_delete(rport); return; @@ -1070,12 +1169,12 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) psli = &phba->sli; /* Sanity check to ensure we are not moving to / from the same list */ - if ((nlp->nlp_flag & NLP_LIST_MASK) == list) { + if ((nlp->nlp_flag & NLP_LIST_MASK) == list) if (list != NLP_NO_LIST) - return(0); - } + return 0; - switch(nlp->nlp_flag & NLP_LIST_MASK) { + spin_lock_irq(phba->host->host_lock); + switch (nlp->nlp_flag & NLP_LIST_MASK) { case NLP_NO_LIST: /* Not on any list */ break; case NLP_UNUSED_LIST: @@ -1101,10 +1200,8 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) case NLP_UNMAPPED_LIST: phba->fc_unmap_cnt--; list_del(&nlp->nlp_listp); - spin_lock_irq(phba->host->host_lock); nlp->nlp_flag &= ~NLP_TGT_NO_SCSIID; nlp->nlp_type &= ~NLP_FC_NODE; - spin_unlock_irq(phba->host->host_lock); phba->nport_event_cnt++; if (nlp->rport) rport_del = unmapped; @@ -1122,19 +1219,14 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) /* Stop delay tmo if taking node off NPR list */ if ((nlp->nlp_flag & NLP_DELAY_TMO) && (list != NLP_NPR_LIST)) { - spin_lock_irq(phba->host->host_lock); - nlp->nlp_flag &= ~NLP_DELAY_TMO; spin_unlock_irq(phba->host->host_lock); - del_timer_sync(&nlp->nlp_delayfunc); - if (!list_empty(&nlp->els_retry_evt.evt_listp)) - list_del_init(&nlp->els_retry_evt.evt_listp); + lpfc_cancel_retry_delay_tmo(phba, nlp); + spin_lock_irq(phba->host->host_lock); } break; } - spin_lock_irq(phba->host->host_lock); nlp->nlp_flag &= ~NLP_LIST_MASK; - spin_unlock_irq(phba->host->host_lock); /* Add NPort to list */ lpfc_printf_log(phba, @@ -1144,48 +1236,40 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) phba->brd_no, nlp->nlp_DID, list, nlp->nlp_flag); - switch(list) { + switch (list) { case NLP_NO_LIST: /* No list, just remove it */ + spin_unlock_irq(phba->host->host_lock); lpfc_nlp_remove(phba, nlp); + spin_lock_irq(phba->host->host_lock); /* as node removed - stop further transport calls */ rport_del = none; break; case NLP_UNUSED_LIST: - spin_lock_irq(phba->host->host_lock); nlp->nlp_flag |= list; - spin_unlock_irq(phba->host->host_lock); /* Put it at the end of the unused list */ list_add_tail(&nlp->nlp_listp, &phba->fc_unused_list); phba->fc_unused_cnt++; break; case NLP_PLOGI_LIST: - spin_lock_irq(phba->host->host_lock); nlp->nlp_flag |= list; - spin_unlock_irq(phba->host->host_lock); /* Put it at the end of the plogi list */ list_add_tail(&nlp->nlp_listp, &phba->fc_plogi_list); phba->fc_plogi_cnt++; break; case NLP_ADISC_LIST: - spin_lock_irq(phba->host->host_lock); nlp->nlp_flag |= list; - spin_unlock_irq(phba->host->host_lock); /* Put it at the end of the adisc list */ list_add_tail(&nlp->nlp_listp, &phba->fc_adisc_list); phba->fc_adisc_cnt++; break; case NLP_REGLOGIN_LIST: - spin_lock_irq(phba->host->host_lock); nlp->nlp_flag |= list; - spin_unlock_irq(phba->host->host_lock); /* Put it at the end of the reglogin list */ list_add_tail(&nlp->nlp_listp, &phba->fc_reglogin_list); phba->fc_reglogin_cnt++; break; case NLP_PRLI_LIST: - spin_lock_irq(phba->host->host_lock); nlp->nlp_flag |= list; - spin_unlock_irq(phba->host->host_lock); /* Put it at the end of the prli list */ list_add_tail(&nlp->nlp_listp, &phba->fc_prli_list); phba->fc_prli_cnt++; @@ -1194,73 +1278,37 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) rport_add = unmapped; /* ensure all vestiges of "mapped" significance are gone */ nlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); - spin_lock_irq(phba->host->host_lock); nlp->nlp_flag |= list; - spin_unlock_irq(phba->host->host_lock); /* Put it at the end of the unmap list */ list_add_tail(&nlp->nlp_listp, &phba->fc_nlpunmap_list); phba->fc_unmap_cnt++; phba->nport_event_cnt++; - /* stop nodev tmo if running */ - if (nlp->nlp_flag & NLP_NODEV_TMO) { - spin_lock_irq(phba->host->host_lock); - nlp->nlp_flag &= ~NLP_NODEV_TMO; - spin_unlock_irq(phba->host->host_lock); - del_timer_sync(&nlp->nlp_tmofunc); - if (!list_empty(&nlp->nodev_timeout_evt.evt_listp)) - list_del_init(&nlp->nodev_timeout_evt. - evt_listp); - - } + nlp->nlp_flag &= ~NLP_NODEV_REMOVE; nlp->nlp_type |= NLP_FC_NODE; break; case NLP_MAPPED_LIST: rport_add = mapped; - spin_lock_irq(phba->host->host_lock); nlp->nlp_flag |= list; - spin_unlock_irq(phba->host->host_lock); /* Put it at the end of the map list */ list_add_tail(&nlp->nlp_listp, &phba->fc_nlpmap_list); phba->fc_map_cnt++; phba->nport_event_cnt++; - /* stop nodev tmo if running */ - if (nlp->nlp_flag & NLP_NODEV_TMO) { - nlp->nlp_flag &= ~NLP_NODEV_TMO; - del_timer_sync(&nlp->nlp_tmofunc); - if (!list_empty(&nlp->nodev_timeout_evt.evt_listp)) - list_del_init(&nlp->nodev_timeout_evt. - evt_listp); - - } + nlp->nlp_flag &= ~NLP_NODEV_REMOVE; break; case NLP_NPR_LIST: - spin_lock_irq(phba->host->host_lock); nlp->nlp_flag |= list; - spin_unlock_irq(phba->host->host_lock); /* Put it at the end of the npr list */ list_add_tail(&nlp->nlp_listp, &phba->fc_npr_list); phba->fc_npr_cnt++; - /* - * Sanity check for Fabric entity. - * Set nodev_tmo for NPR state, for Fabric use 1 sec. - */ - if (nlp->nlp_type & NLP_FABRIC) { - mod_timer(&nlp->nlp_tmofunc, jiffies + HZ); - } - else { - mod_timer(&nlp->nlp_tmofunc, - jiffies + HZ * phba->cfg_nodev_tmo); - } - spin_lock_irq(phba->host->host_lock); - nlp->nlp_flag |= NLP_NODEV_TMO; nlp->nlp_flag &= ~NLP_RCV_PLOGI; - spin_unlock_irq(phba->host->host_lock); break; case NLP_JUST_DQ: break; } + spin_unlock_irq(phba->host->host_lock); + /* * We make all the calls into the transport after we have * moved the node between lists. This so that we don't @@ -1282,7 +1330,8 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) * already. If we have, and it's a scsi entity, be * sure to unblock any attached scsi devices */ - if (!nlp->rport) + if ((!nlp->rport) || (nlp->rport->port_state == + FC_PORTSTATE_BLOCKED)) lpfc_register_remote_port(phba, nlp); /* @@ -1294,7 +1343,7 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) if ((rport_add == mapped) && ((!nlp->rport) || (nlp->rport->scsi_target_id == -1) || - (nlp->rport->scsi_target_id >= MAX_FCP_TARGET))) { + (nlp->rport->scsi_target_id >= LPFC_MAX_TARGET))) { nlp->nlp_state = NLP_STE_UNMAPPED_NODE; spin_lock_irq(phba->host->host_lock); nlp->nlp_flag |= NLP_TGT_NO_SCSIID; @@ -1303,7 +1352,7 @@ lpfc_nlp_list(struct lpfc_hba * phba, struct lpfc_nodelist * nlp, int list) } } } - return (0); + return 0; } /* @@ -1314,7 +1363,15 @@ lpfc_set_disctmo(struct lpfc_hba * phba) { uint32_t tmo; - tmo = ((phba->fc_ratov * 2) + 1); + if (phba->hba_state == LPFC_LOCAL_CFG_LINK) { + /* For FAN, timeout should be greater then edtov */ + tmo = (((phba->fc_edtov + 999) / 1000) + 1); + } else { + /* Normal discovery timeout should be > then ELS/CT timeout + * FC spec states we need 3 * ratov for CT requests + */ + tmo = ((phba->fc_ratov * 3) + 3); + } mod_timer(&phba->fc_disctmo, jiffies + HZ * tmo); spin_lock_irq(phba->host->host_lock); @@ -1354,7 +1411,7 @@ lpfc_can_disctmo(struct lpfc_hba * phba) phba->brd_no, phba->hba_state, phba->fc_flag, phba->fc_plogi_cnt, phba->fc_adisc_cnt); - return (0); + return 0; } /* @@ -1375,27 +1432,29 @@ lpfc_check_sli_ndlp(struct lpfc_hba * phba, switch (icmd->ulpCommand) { case CMD_GEN_REQUEST64_CR: if (icmd->ulpContext == (volatile ushort)ndlp->nlp_rpi) - return (1); + return 1; case CMD_ELS_REQUEST64_CR: + if (icmd->un.elsreq64.remoteID == ndlp->nlp_DID) + return 1; case CMD_XMIT_ELS_RSP64_CX: if (iocb->context1 == (uint8_t *) ndlp) - return (1); + return 1; } - } else if (pring->ringno == psli->ip_ring) { + } else if (pring->ringno == psli->extra_ring) { } else if (pring->ringno == psli->fcp_ring) { /* Skip match check if waiting to relogin to FCP target */ if ((ndlp->nlp_type & NLP_FCP_TARGET) && (ndlp->nlp_flag & NLP_DELAY_TMO)) { - return (0); + return 0; } if (icmd->ulpContext == (volatile ushort)ndlp->nlp_rpi) { - return (1); + return 1; } } else if (pring->ringno == psli->next_ring) { } - return (0); + return 0; } /* @@ -1456,7 +1515,7 @@ lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) } } - return (0); + return 0; } /* @@ -1528,6 +1587,8 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; } } + + spin_lock_irq(phba->host->host_lock); list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) && (ndlp == (struct lpfc_nodelist *) mb->context2)) { @@ -1540,23 +1601,22 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) mempool_free(mb, phba->mbox_mem_pool); } } + spin_unlock_irq(phba->host->host_lock); lpfc_els_abort(phba,ndlp,0); spin_lock_irq(phba->host->host_lock); - ndlp->nlp_flag &= ~(NLP_NODEV_TMO|NLP_DELAY_TMO); + ndlp->nlp_flag &= ~NLP_DELAY_TMO; spin_unlock_irq(phba->host->host_lock); - del_timer_sync(&ndlp->nlp_tmofunc); + ndlp->nlp_last_elscmd = 0; del_timer_sync(&ndlp->nlp_delayfunc); - if (!list_empty(&ndlp->nodev_timeout_evt.evt_listp)) - list_del_init(&ndlp->nodev_timeout_evt.evt_listp); if (!list_empty(&ndlp->els_retry_evt.evt_listp)) list_del_init(&ndlp->els_retry_evt.evt_listp); lpfc_unreg_rpi(phba, ndlp); - return (0); + return 0; } /* @@ -1567,36 +1627,20 @@ lpfc_freenode(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) int lpfc_nlp_remove(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) { - if (ndlp->nlp_flag & NLP_NODEV_TMO) { - spin_lock_irq(phba->host->host_lock); - ndlp->nlp_flag &= ~NLP_NODEV_TMO; - spin_unlock_irq(phba->host->host_lock); - del_timer_sync(&ndlp->nlp_tmofunc); - if (!list_empty(&ndlp->nodev_timeout_evt.evt_listp)) - list_del_init(&ndlp->nodev_timeout_evt.evt_listp); - - } - if (ndlp->nlp_flag & NLP_DELAY_TMO) { - spin_lock_irq(phba->host->host_lock); - ndlp->nlp_flag &= ~NLP_DELAY_TMO; - spin_unlock_irq(phba->host->host_lock); - del_timer_sync(&ndlp->nlp_delayfunc); - if (!list_empty(&ndlp->els_retry_evt.evt_listp)) - list_del_init(&ndlp->els_retry_evt.evt_listp); + lpfc_cancel_retry_delay_tmo(phba, ndlp); } if (ndlp->nlp_disc_refcnt) { spin_lock_irq(phba->host->host_lock); ndlp->nlp_flag |= NLP_DELAY_REMOVE; spin_unlock_irq(phba->host->host_lock); - } - else { + } else { lpfc_freenode(phba, ndlp); mempool_free( ndlp, phba->nlp_mem_pool); } - return(0); + return 0; } static int @@ -1607,20 +1651,20 @@ lpfc_matchdid(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint32_t did) D_ID matchdid; if (did == Bcast_DID) - return (0); + return 0; if (ndlp->nlp_DID == 0) { - return (0); + return 0; } /* First check for Direct match */ if (ndlp->nlp_DID == did) - return (1); + return 1; /* Next check for area/domain identically equals 0 match */ mydid.un.word = phba->fc_myDID; if ((mydid.un.b.domain == 0) && (mydid.un.b.area == 0)) { - return (0); + return 0; } matchdid.un.word = did; @@ -1631,9 +1675,9 @@ lpfc_matchdid(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint32_t did) if ((ndlpdid.un.b.domain == 0) && (ndlpdid.un.b.area == 0)) { if (ndlpdid.un.b.id) - return (1); + return 1; } - return (0); + return 0; } matchdid.un.word = ndlp->nlp_DID; @@ -1642,201 +1686,64 @@ lpfc_matchdid(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint32_t did) if ((matchdid.un.b.domain == 0) && (matchdid.un.b.area == 0)) { if (matchdid.un.b.id) - return (1); + return 1; } } } - return (0); + return 0; } /* Search for a nodelist entry on a specific list */ struct lpfc_nodelist * lpfc_findnode_did(struct lpfc_hba * phba, uint32_t order, uint32_t did) { - struct lpfc_nodelist *ndlp, *next_ndlp; + struct lpfc_nodelist *ndlp; + struct list_head *lists[]={&phba->fc_nlpunmap_list, + &phba->fc_nlpmap_list, + &phba->fc_plogi_list, + &phba->fc_adisc_list, + &phba->fc_reglogin_list, + &phba->fc_prli_list, + &phba->fc_npr_list, + &phba->fc_unused_list}; + uint32_t search[]={NLP_SEARCH_UNMAPPED, + NLP_SEARCH_MAPPED, + NLP_SEARCH_PLOGI, + NLP_SEARCH_ADISC, + NLP_SEARCH_REGLOGIN, + NLP_SEARCH_PRLI, + NLP_SEARCH_NPR, + NLP_SEARCH_UNUSED}; + int i; uint32_t data1; - if (order & NLP_SEARCH_UNMAPPED) { - list_for_each_entry_safe(ndlp, next_ndlp, - &phba->fc_nlpunmap_list, nlp_listp) { - if (lpfc_matchdid(phba, ndlp, did)) { - data1 = (((uint32_t) ndlp->nlp_state << 24) | - ((uint32_t) ndlp->nlp_xri << 16) | - ((uint32_t) ndlp->nlp_type << 8) | - ((uint32_t) ndlp->nlp_rpi & 0xff)); - /* FIND node DID unmapped */ - lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0929 FIND node DID unmapped" - " Data: x%p x%x x%x x%x\n", - phba->brd_no, - ndlp, ndlp->nlp_DID, - ndlp->nlp_flag, data1); - return (ndlp); - } - } - } - - if (order & NLP_SEARCH_MAPPED) { - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nlpmap_list, - nlp_listp) { - if (lpfc_matchdid(phba, ndlp, did)) { - - data1 = (((uint32_t) ndlp->nlp_state << 24) | - ((uint32_t) ndlp->nlp_xri << 16) | - ((uint32_t) ndlp->nlp_type << 8) | - ((uint32_t) ndlp->nlp_rpi & 0xff)); - /* FIND node DID mapped */ - lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0930 FIND node DID mapped " - "Data: x%p x%x x%x x%x\n", - phba->brd_no, - ndlp, ndlp->nlp_DID, - ndlp->nlp_flag, data1); - return (ndlp); - } - } - } - - if (order & NLP_SEARCH_PLOGI) { - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_plogi_list, - nlp_listp) { - if (lpfc_matchdid(phba, ndlp, did)) { - - data1 = (((uint32_t) ndlp->nlp_state << 24) | - ((uint32_t) ndlp->nlp_xri << 16) | - ((uint32_t) ndlp->nlp_type << 8) | - ((uint32_t) ndlp->nlp_rpi & 0xff)); - /* LOG change to PLOGI */ - /* FIND node DID plogi */ - lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0908 FIND node DID plogi " - "Data: x%p x%x x%x x%x\n", - phba->brd_no, - ndlp, ndlp->nlp_DID, - ndlp->nlp_flag, data1); - return (ndlp); - } - } - } - - if (order & NLP_SEARCH_ADISC) { - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list, - nlp_listp) { - if (lpfc_matchdid(phba, ndlp, did)) { - - data1 = (((uint32_t) ndlp->nlp_state << 24) | - ((uint32_t) ndlp->nlp_xri << 16) | - ((uint32_t) ndlp->nlp_type << 8) | - ((uint32_t) ndlp->nlp_rpi & 0xff)); - /* LOG change to ADISC */ - /* FIND node DID adisc */ - lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0931 FIND node DID adisc " - "Data: x%p x%x x%x x%x\n", - phba->brd_no, - ndlp, ndlp->nlp_DID, - ndlp->nlp_flag, data1); - return (ndlp); - } - } - } - - if (order & NLP_SEARCH_REGLOGIN) { - list_for_each_entry_safe(ndlp, next_ndlp, - &phba->fc_reglogin_list, nlp_listp) { + spin_lock_irq(phba->host->host_lock); + for (i = 0; i < ARRAY_SIZE(lists); i++ ) { + if (!(order & search[i])) + continue; + list_for_each_entry(ndlp, lists[i], nlp_listp) { if (lpfc_matchdid(phba, ndlp, did)) { - data1 = (((uint32_t) ndlp->nlp_state << 24) | ((uint32_t) ndlp->nlp_xri << 16) | ((uint32_t) ndlp->nlp_type << 8) | ((uint32_t) ndlp->nlp_rpi & 0xff)); - /* LOG change to REGLOGIN */ - /* FIND node DID reglogin */ lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0931 FIND node DID reglogin" + "%d:0929 FIND node DID " " Data: x%p x%x x%x x%x\n", phba->brd_no, ndlp, ndlp->nlp_DID, ndlp->nlp_flag, data1); - return (ndlp); - } - } - } - - if (order & NLP_SEARCH_PRLI) { - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_prli_list, - nlp_listp) { - if (lpfc_matchdid(phba, ndlp, did)) { - - data1 = (((uint32_t) ndlp->nlp_state << 24) | - ((uint32_t) ndlp->nlp_xri << 16) | - ((uint32_t) ndlp->nlp_type << 8) | - ((uint32_t) ndlp->nlp_rpi & 0xff)); - /* LOG change to PRLI */ - /* FIND node DID prli */ - lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0931 FIND node DID prli " - "Data: x%p x%x x%x x%x\n", - phba->brd_no, - ndlp, ndlp->nlp_DID, - ndlp->nlp_flag, data1); - return (ndlp); - } - } - } - - if (order & NLP_SEARCH_NPR) { - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list, - nlp_listp) { - if (lpfc_matchdid(phba, ndlp, did)) { - - data1 = (((uint32_t) ndlp->nlp_state << 24) | - ((uint32_t) ndlp->nlp_xri << 16) | - ((uint32_t) ndlp->nlp_type << 8) | - ((uint32_t) ndlp->nlp_rpi & 0xff)); - /* LOG change to NPR */ - /* FIND node DID npr */ - lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0931 FIND node DID npr " - "Data: x%p x%x x%x x%x\n", - phba->brd_no, - ndlp, ndlp->nlp_DID, - ndlp->nlp_flag, data1); - return (ndlp); - } - } - } - - if (order & NLP_SEARCH_UNUSED) { - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_adisc_list, - nlp_listp) { - if (lpfc_matchdid(phba, ndlp, did)) { - - data1 = (((uint32_t) ndlp->nlp_state << 24) | - ((uint32_t) ndlp->nlp_xri << 16) | - ((uint32_t) ndlp->nlp_type << 8) | - ((uint32_t) ndlp->nlp_rpi & 0xff)); - /* LOG change to UNUSED */ - /* FIND node DID unused */ - lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0931 FIND node DID unused " - "Data: x%p x%x x%x x%x\n", - phba->brd_no, - ndlp, ndlp->nlp_DID, - ndlp->nlp_flag, data1); - return (ndlp); + spin_unlock_irq(phba->host->host_lock); + return ndlp; } } } + spin_unlock_irq(phba->host->host_lock); /* FIND node did NOT FOUND */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_NODE, + lpfc_printf_log(phba, KERN_INFO, LOG_NODE, "%d:0932 FIND node did x%x NOT FOUND Data: x%x\n", phba->brd_no, did, order); - - /* no match found */ return NULL; } @@ -1846,8 +1753,9 @@ lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did) struct lpfc_nodelist *ndlp; uint32_t flg; - if ((ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did)) == 0) { - if ((phba->hba_state == LPFC_HBA_READY) && + ndlp = lpfc_findnode_did(phba, NLP_SEARCH_ALL, did); + if (!ndlp) { + if ((phba->fc_flag & FC_RSCN_MODE) && ((lpfc_rscn_payload_check(phba, did) == 0))) return NULL; ndlp = (struct lpfc_nodelist *) @@ -1860,22 +1768,21 @@ lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did) ndlp->nlp_flag |= NLP_NPR_2B_DISC; return ndlp; } - if ((phba->hba_state == LPFC_HBA_READY) && - (phba->fc_flag & FC_RSCN_MODE)) { + if (phba->fc_flag & FC_RSCN_MODE) { if (lpfc_rscn_payload_check(phba, did)) { ndlp->nlp_flag |= NLP_NPR_2B_DISC; - } - else { - ndlp->nlp_flag &= ~NLP_NPR_2B_DISC; + + /* Since this node is marked for discovery, + * delay timeout is not needed. + */ + if (ndlp->nlp_flag & NLP_DELAY_TMO) + lpfc_cancel_retry_delay_tmo(phba, ndlp); + } else ndlp = NULL; - } - } - else { + } else { flg = ndlp->nlp_flag & NLP_LIST_MASK; - if ((flg == NLP_ADISC_LIST) || - (flg == NLP_PLOGI_LIST)) { + if ((flg == NLP_ADISC_LIST) || (flg == NLP_PLOGI_LIST)) return NULL; - } ndlp->nlp_state = NLP_STE_NPR_NODE; lpfc_nlp_list(phba, ndlp, NLP_NPR_LIST); ndlp->nlp_flag |= NLP_NPR_2B_DISC; @@ -1998,7 +1905,7 @@ lpfc_disc_start(struct lpfc_hba * phba) if (rc == MBX_NOT_FINISHED) { mempool_free( mbox, phba->mbox_mem_pool); lpfc_disc_flush_list(phba); - psli->ring[(psli->ip_ring)].flag &= + psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; @@ -2023,8 +1930,7 @@ lpfc_disc_start(struct lpfc_hba * phba) spin_lock_irq(phba->host->host_lock); phba->fc_flag &= ~FC_RSCN_MODE; spin_unlock_irq(phba->host->host_lock); - } - else + } else lpfc_els_handle_rscn(phba); } } @@ -2174,7 +2080,7 @@ static void lpfc_disc_timeout_handler(struct lpfc_hba *phba) { struct lpfc_sli *psli; - struct lpfc_nodelist *ndlp; + struct lpfc_nodelist *ndlp, *next_ndlp; LPFC_MBOXQ_t *clearlambox, *initlinkmbox; int rc, clrlaerr = 0; @@ -2201,10 +2107,19 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) "%d:0221 FAN timeout\n", phba->brd_no); - /* Forget about FAN, Start discovery by sending a FLOGI - * hba_state is identically LPFC_FLOGI while waiting for FLOGI - * cmpl - */ + /* Start discovery by sending FLOGI, clean up old rpis */ + list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_npr_list, + nlp_listp) { + if (ndlp->nlp_type & NLP_FABRIC) { + /* Clean up the ndlp on Fabric connections */ + lpfc_nlp_list(phba, ndlp, NLP_NO_LIST); + } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { + /* Fail outstanding IO now since device + * is marked for PLOGI. + */ + lpfc_unreg_rpi(phba, ndlp); + } + } phba->hba_state = LPFC_FLOGI; lpfc_set_disctmo(phba); lpfc_initial_flogi(phba); @@ -2292,7 +2207,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) initlinkmbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!initlinkmbox) { lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "%d:0226 Device Discovery " + "%d:0206 Device Discovery " "completion error\n", phba->brd_no); phba->hba_state = LPFC_HBA_ERROR; @@ -2322,7 +2237,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) if (!clearlambox) { clrlaerr = 1; lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "%d:0226 Device Discovery " + "%d:0207 Device Discovery " "completion error\n", phba->brd_no); phba->hba_state = LPFC_HBA_ERROR; @@ -2369,7 +2284,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) if (clrlaerr) { lpfc_disc_flush_list(phba); - psli->ring[(psli->ip_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; + psli->ring[(psli->extra_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[(psli->fcp_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[(psli->next_ring)].flag &= ~LPFC_STOP_IOCB_EVENT; phba->hba_state = LPFC_HBA_READY; @@ -2378,34 +2293,6 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) return; } -static void -lpfc_nodev_timeout(unsigned long ptr) -{ - struct lpfc_hba *phba; - struct lpfc_nodelist *ndlp; - unsigned long iflag; - struct lpfc_work_evt *evtp; - - ndlp = (struct lpfc_nodelist *)ptr; - phba = ndlp->nlp_phba; - evtp = &ndlp->nodev_timeout_evt; - spin_lock_irqsave(phba->host->host_lock, iflag); - - if (!list_empty(&evtp->evt_listp)) { - spin_unlock_irqrestore(phba->host->host_lock, iflag); - return; - } - evtp->evt_arg1 = ndlp; - evtp->evt = LPFC_EVT_NODEV_TMO; - list_add_tail(&evtp->evt_listp, &phba->work_list); - if (phba->work_wait) - wake_up(phba->work_wait); - - spin_unlock_irqrestore(phba->host->host_lock, iflag); - return; -} - - /* * This routine handles processing a NameServer REG_LOGIN mailbox * command upon completion. It is setup in the LPFC_MBOXQ @@ -2470,11 +2357,57 @@ lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi) &phba->fc_reglogin_list}; int i; + spin_lock_irq(phba->host->host_lock); for (i = 0; i < ARRAY_SIZE(lists); i++ ) list_for_each_entry(ndlp, lists[i], nlp_listp) - if (ndlp->nlp_rpi == rpi) - return (ndlp); + if (ndlp->nlp_rpi == rpi) { + spin_unlock_irq(phba->host->host_lock); + return ndlp; + } + spin_unlock_irq(phba->host->host_lock); + return NULL; +} +/* + * This routine looks up the ndlp lists + * for the given WWPN. If WWPN found + * it return the node list pointer + * else return NULL. + */ +struct lpfc_nodelist * +lpfc_findnode_wwpn(struct lpfc_hba * phba, uint32_t order, + struct lpfc_name * wwpn) +{ + struct lpfc_nodelist *ndlp; + struct list_head * lists[]={&phba->fc_nlpunmap_list, + &phba->fc_nlpmap_list, + &phba->fc_npr_list, + &phba->fc_plogi_list, + &phba->fc_adisc_list, + &phba->fc_reglogin_list, + &phba->fc_prli_list}; + uint32_t search[]={NLP_SEARCH_UNMAPPED, + NLP_SEARCH_MAPPED, + NLP_SEARCH_NPR, + NLP_SEARCH_PLOGI, + NLP_SEARCH_ADISC, + NLP_SEARCH_REGLOGIN, + NLP_SEARCH_PRLI}; + int i; + + spin_lock_irq(phba->host->host_lock); + for (i = 0; i < ARRAY_SIZE(lists); i++ ) { + if (!(order & search[i])) + continue; + list_for_each_entry(ndlp, lists[i], nlp_listp) { + if (memcmp(&ndlp->nlp_portname, wwpn, + sizeof(struct lpfc_name)) == 0) { + spin_unlock_irq(phba->host->host_lock); + return ndlp; + } + } + } + spin_unlock_irq(phba->host->host_lock); return NULL; } @@ -2483,11 +2416,7 @@ lpfc_nlp_init(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp, uint32_t did) { memset(ndlp, 0, sizeof (struct lpfc_nodelist)); - INIT_LIST_HEAD(&ndlp->nodev_timeout_evt.evt_listp); INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); - init_timer(&ndlp->nlp_tmofunc); - ndlp->nlp_tmofunc.function = lpfc_nodev_timeout; - ndlp->nlp_tmofunc.data = (unsigned long)ndlp; init_timer(&ndlp->nlp_delayfunc); ndlp->nlp_delayfunc.function = lpfc_els_retry_delay; ndlp->nlp_delayfunc.data = (unsigned long)ndlp;