From 2e0fef85e098f6794956b8b80b111179fbb4cbb7 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sun, 17 Jun 2007 19:56:36 -0500 Subject: [SCSI] lpfc: NPIV: split ports The driver is reorganized to separate the handling of the adapter from the handling of the FC port. Adapter handling includes submissions of command requests, receiving responses, and managing adapter resources. The FC port includes the discovery engine, login handling, and the mapping of a Scsi_Host on the "port". Although not a large functional change, as it touches core structures and functions, resulting in a large text delta. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_hbadisc.c | 1245 +++++++++++++++++++++----------------- 1 file changed, 680 insertions(+), 565 deletions(-) (limited to 'drivers/scsi/lpfc/lpfc_hbadisc.c') diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 61caa8d379e2..dee875ee6165 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -54,7 +54,7 @@ static uint8_t lpfcAlpaArray[] = { 0x10, 0x0F, 0x08, 0x04, 0x02, 0x01 }; -static void lpfc_disc_timeout_handler(struct lpfc_hba *); +static void lpfc_disc_timeout_handler(struct lpfc_vport *); void lpfc_terminate_rport_io(struct fc_rport *rport) @@ -74,14 +74,12 @@ lpfc_terminate_rport_io(struct fc_rport *rport) return; } - phba = ndlp->nlp_phba; + phba = ndlp->vport->phba; - spin_lock_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; } @@ -97,6 +95,7 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) uint8_t *name; int warn_on = 0; struct lpfc_hba *phba; + struct lpfc_vport *vport; rdata = rport->dd_data; ndlp = rdata->pnode; @@ -113,9 +112,8 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) return; name = (uint8_t *)&ndlp->nlp_portname; - phba = ndlp->nlp_phba; - - spin_lock_irq(phba->host->host_lock); + vport = ndlp->vport; + phba = vport->phba; if (ndlp->nlp_sid != NLP_NO_SID) { warn_on = 1; @@ -123,11 +121,9 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) 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) + if (vport->load_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 Devloss timeout on " @@ -150,11 +146,11 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) ndlp->nlp_state, ndlp->nlp_rpi); } - if (!(phba->fc_flag & FC_UNLOADING) && + if (!(vport->load_flag & FC_UNLOADING) && !(ndlp->nlp_flag & NLP_DELAY_TMO) && !(ndlp->nlp_flag & NLP_NPR_2B_DISC) && (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) - lpfc_disc_state_machine(phba, ndlp, NULL, NLP_EVT_DEVICE_RM); + lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); else { rdata->pnode = NULL; ndlp->rport = NULL; @@ -166,33 +162,33 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) } static void -lpfc_work_list_done(struct lpfc_hba * phba) +lpfc_work_list_done(struct lpfc_hba *phba) { struct lpfc_work_evt *evtp = NULL; struct lpfc_nodelist *ndlp; int free_evt; - spin_lock_irq(phba->host->host_lock); - while(!list_empty(&phba->work_list)) { + spin_lock_irq(&phba->hbalock); + while (!list_empty(&phba->work_list)) { list_remove_head((&phba->work_list), evtp, typeof(*evtp), evt_listp); - spin_unlock_irq(phba->host->host_lock); + spin_unlock_irq(&phba->hbalock); free_evt = 1; switch (evtp->evt) { case LPFC_EVT_ELS_RETRY: - ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1); + ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1); lpfc_els_retry_delay_handler(ndlp); free_evt = 0; break; case LPFC_EVT_ONLINE: - if (phba->hba_state < LPFC_LINK_DOWN) - *(int *)(evtp->evt_arg1) = lpfc_online(phba); + if (phba->link_state < LPFC_LINK_DOWN) + *(int *) (evtp->evt_arg1) = lpfc_online(phba); else - *(int *)(evtp->evt_arg1) = 0; + *(int *) (evtp->evt_arg1) = 0; complete((struct completion *)(evtp->evt_arg2)); break; case LPFC_EVT_OFFLINE_PREP: - if (phba->hba_state >= LPFC_LINK_DOWN) + if (phba->link_state >= LPFC_LINK_DOWN) lpfc_offline_prep(phba); *(int *)(evtp->evt_arg1) = 0; complete((struct completion *)(evtp->evt_arg2)); @@ -218,33 +214,32 @@ lpfc_work_list_done(struct lpfc_hba * phba) case LPFC_EVT_KILL: lpfc_offline(phba); *(int *)(evtp->evt_arg1) - = (phba->stopped) ? 0 : lpfc_sli_brdkill(phba); + = (phba->pport->stopped) + ? 0 : lpfc_sli_brdkill(phba); lpfc_unblock_mgmt_io(phba); complete((struct completion *)(evtp->evt_arg2)); break; } if (free_evt) kfree(evtp); - spin_lock_irq(phba->host->host_lock); + spin_lock_irq(&phba->hbalock); } - spin_unlock_irq(phba->host->host_lock); + spin_unlock_irq(&phba->hbalock); } static void -lpfc_work_done(struct lpfc_hba * phba) +lpfc_work_done(struct lpfc_hba *phba) { struct lpfc_sli_ring *pring; int i; - uint32_t ha_copy; - uint32_t control; - uint32_t work_hba_events; + uint32_t ha_copy, control, work_port_events; + struct lpfc_vport *vport; - spin_lock_irq(phba->host->host_lock); + spin_lock_irq(&phba->hbalock); ha_copy = phba->work_ha; phba->work_ha = 0; - work_hba_events=phba->work_hba_events; - spin_unlock_irq(phba->host->host_lock); + spin_unlock_irq(&phba->hbalock); if (ha_copy & HA_ERATT) lpfc_handle_eratt(phba); @@ -255,21 +250,25 @@ lpfc_work_done(struct lpfc_hba * phba) if (ha_copy & HA_LATT) lpfc_handle_latt(phba); - if (work_hba_events & WORKER_DISC_TMO) - lpfc_disc_timeout_handler(phba); + vport = phba->pport; - if (work_hba_events & WORKER_ELS_TMO) - lpfc_els_timeout_handler(phba); + work_port_events = vport->work_port_events; - if (work_hba_events & WORKER_MBOX_TMO) + if (work_port_events & WORKER_DISC_TMO) + lpfc_disc_timeout_handler(vport); + + if (work_port_events & WORKER_ELS_TMO) + lpfc_els_timeout_handler(vport); + + if (work_port_events & WORKER_MBOX_TMO) lpfc_mbox_timeout_handler(phba); - if (work_hba_events & WORKER_FDMI_TMO) - lpfc_fdmi_tmo_handler(phba); + if (work_port_events & WORKER_FDMI_TMO) + lpfc_fdmi_timeout_handler(vport); - spin_lock_irq(phba->host->host_lock); - phba->work_hba_events &= ~work_hba_events; - spin_unlock_irq(phba->host->host_lock); + spin_lock_irq(&phba->hbalock); + vport->work_port_events &= ~work_port_events; + spin_unlock_irq(&phba->hbalock); for (i = 0; i < phba->sli.num_rings; i++, ha_copy >>= 4) { pring = &phba->sli.ring[i]; @@ -286,33 +285,37 @@ lpfc_work_done(struct lpfc_hba * phba) /* * Turn on Ring interrupts */ - spin_lock_irq(phba->host->host_lock); + spin_lock_irq(&phba->hbalock); control = readl(phba->HCregaddr); control |= (HC_R0INT_ENA << i); writel(control, phba->HCregaddr); readl(phba->HCregaddr); /* flush */ - spin_unlock_irq(phba->host->host_lock); + spin_unlock_irq(&phba->hbalock); } } - lpfc_work_list_done (phba); - + lpfc_work_list_done(phba); } static int -check_work_wait_done(struct lpfc_hba *phba) { +check_work_wait_done(struct lpfc_hba *phba) +{ + struct lpfc_vport *vport = phba->pport; + int rc = 0; + + + if (!vport) + return 0; + spin_lock_irq(&phba->hbalock); - spin_lock_irq(phba->host->host_lock); if (phba->work_ha || - phba->work_hba_events || + vport->work_port_events || (!list_empty(&phba->work_list)) || - kthread_should_stop()) { - spin_unlock_irq(phba->host->host_lock); - return 1; - } else { - spin_unlock_irq(phba->host->host_lock); - return 0; - } + kthread_should_stop()) + rc = 1; + + spin_unlock_irq(&phba->hbalock); + return rc; } int @@ -347,7 +350,7 @@ lpfc_do_work(void *p) * embedding it in the IOCB. */ int -lpfc_workq_post_event(struct lpfc_hba * phba, void *arg1, void *arg2, +lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2, uint32_t evt) { struct lpfc_work_evt *evtp; @@ -364,11 +367,11 @@ lpfc_workq_post_event(struct lpfc_hba * phba, void *arg1, void *arg2, evtp->evt_arg2 = arg2; evtp->evt = evt; - spin_lock_irq(phba->host->host_lock); + spin_lock_irq(&phba->hbalock); 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); + spin_unlock_irq(&phba->hbalock); return 1; } @@ -376,75 +379,77 @@ lpfc_workq_post_event(struct lpfc_hba * phba, void *arg1, void *arg2, int lpfc_linkdown(struct lpfc_hba *phba) { - struct lpfc_sli *psli; + struct lpfc_vport *vport = phba->pport; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct lpfc_sli *psli; struct lpfc_nodelist *ndlp, *next_ndlp; LPFC_MBOXQ_t *mb; int rc; 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); + if (phba->link_state == LPFC_LINK_DOWN) { + return 0; } + spin_lock_irq(&phba->hbalock); + if (phba->link_state > LPFC_LINK_DOWN) + phba->link_state = LPFC_LINK_DOWN; + spin_unlock_irq(&phba->hbalock); - fc_host_post_event(phba->host, fc_get_event_number(), - FCH_EVT_LINKDOWN, 0); + fc_host_post_event(shost, 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))) { + mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (mb) { lpfc_unreg_did(phba, 0xffffffff, mb); - mb->mbox_cmpl=lpfc_sli_def_mbox_cmpl; + mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; if (lpfc_sli_issue_mbox(phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB)) == MBX_NOT_FINISHED) { - mempool_free( mb, phba->mbox_mem_pool); + mempool_free(mb, phba->mbox_mem_pool); } } /* Cleanup any outstanding RSCN activity */ - lpfc_els_flush_rscn(phba); + lpfc_els_flush_rscn(vport); /* Cleanup any outstanding ELS commands */ - lpfc_els_flush_cmd(phba); + lpfc_els_flush_cmd(vport); /* * Issue a LINK DOWN event to all nodes. */ - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) { - /* free any ndlp's on unused list */ + list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { + /* free any ndlp's on unused state */ if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) - lpfc_drop_node(phba, ndlp); + lpfc_drop_node(vport, ndlp); else /* otherwise, force node recovery. */ - rc = lpfc_disc_state_machine(phba, ndlp, NULL, + rc = lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RECOVERY); } /* Setup myDID for link up if we are in pt2pt mode */ - if (phba->fc_flag & FC_PT2PT) { - phba->fc_myDID = 0; - if ((mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) { + if (vport->fc_flag & FC_PT2PT) { + vport->fc_myDID = 0; + mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (mb) { lpfc_config_link(phba, mb); mb->mbox_cmpl=lpfc_sli_def_mbox_cmpl; - if (lpfc_sli_issue_mbox - (phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB)) + if (lpfc_sli_issue_mbox(phba, mb, + (MBX_NOWAIT | MBX_STOP_IOCB)) == MBX_NOT_FINISHED) { - mempool_free( mb, phba->mbox_mem_pool); + mempool_free(mb, phba->mbox_mem_pool); } } - spin_lock_irq(phba->host->host_lock); - phba->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI); - spin_unlock_irq(phba->host->host_lock); + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI); + spin_unlock_irq(shost->host_lock); } - spin_lock_irq(phba->host->host_lock); - phba->fc_flag &= ~FC_LBIT; - spin_unlock_irq(phba->host->host_lock); + + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_LBIT; + spin_unlock_irq(shost->host_lock); /* Turn off discovery timer if its running */ - lpfc_can_disctmo(phba); + lpfc_can_disctmo(vport); /* Must process IOCBs on all rings to handle ABORTed I/Os */ return 0; @@ -453,46 +458,47 @@ lpfc_linkdown(struct lpfc_hba *phba) static int lpfc_linkup(struct lpfc_hba *phba) { + struct lpfc_vport *vport = phba->pport; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp, *next_ndlp; - fc_host_post_event(phba->host, fc_get_event_number(), - FCH_EVT_LINKUP, 0); + fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKUP, 0); - spin_lock_irq(phba->host->host_lock); - phba->hba_state = LPFC_LINK_UP; - phba->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | FC_ABORT_DISCOVERY | - FC_RSCN_MODE | FC_NLP_MORE | FC_RSCN_DISCOVERY); - phba->fc_flag |= FC_NDISC_ACTIVE; - phba->fc_ns_retry = 0; - spin_unlock_irq(phba->host->host_lock); + spin_lock_irq(shost->host_lock); + phba->link_state = LPFC_LINK_UP; + vport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | FC_ABORT_DISCOVERY | + FC_RSCN_MODE | FC_NLP_MORE | FC_RSCN_DISCOVERY); + vport->fc_flag |= FC_NDISC_ACTIVE; + vport->fc_ns_retry = 0; + spin_unlock_irq(shost->host_lock); - if (phba->fc_flag & FC_LBIT) { - list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) { + if (vport->fc_flag & FC_LBIT) { + list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { if (ndlp->nlp_state != NLP_STE_UNUSED_NODE) { if (ndlp->nlp_type & NLP_FABRIC) { /* * On Linkup its safe to clean up the * ndlp from Fabric connections. */ - lpfc_nlp_set_state(phba, ndlp, + lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNUSED_NODE); } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { /* * Fail outstanding IO now since * device is marked for PLOGI. */ - lpfc_unreg_rpi(phba, ndlp); + lpfc_unreg_rpi(vport, ndlp); } } } } - /* free any ndlp's on unused list */ - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, + /* free any ndlp's in unused state */ + list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) - lpfc_drop_node(phba, ndlp); + lpfc_drop_node(vport, ndlp); } return 0; @@ -505,14 +511,14 @@ lpfc_linkup(struct lpfc_hba *phba) * handed off to the SLI layer. */ void -lpfc_mbx_cmpl_clear_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) +lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { - struct lpfc_sli *psli; - MAILBOX_t *mb; + struct lpfc_vport *vport = pmb->vport; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct lpfc_sli *psli = &phba->sli; + MAILBOX_t *mb = &pmb->mb; uint32_t control; - psli = &phba->sli; - mb = &pmb->mb; /* Since we don't do discovery right now, turn these off here */ psli->ring[psli->extra_ring].flag &= ~LPFC_STOP_IOCB_EVENT; psli->ring[psli->fcp_ring].flag &= ~LPFC_STOP_IOCB_EVENT; @@ -520,32 +526,33 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) /* Check for error */ if ((mb->mbxStatus) && (mb->mbxStatus != 0x1601)) { - /* CLEAR_LA mbox error state */ + /* CLEAR_LA mbox error state */ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, "%d:0320 CLEAR_LA mbxStatus error x%x hba " "state x%x\n", - phba->brd_no, mb->mbxStatus, phba->hba_state); + phba->brd_no, mb->mbxStatus, vport->port_state); - phba->hba_state = LPFC_HBA_ERROR; + phba->link_state = LPFC_HBA_ERROR; goto out; } - if (phba->fc_flag & FC_ABORT_DISCOVERY) + if (vport->fc_flag & FC_ABORT_DISCOVERY) goto out; - phba->num_disc_nodes = 0; - /* go thru NPR list and issue ELS PLOGIs */ - if (phba->fc_npr_cnt) { - lpfc_els_disc_plogi(phba); - } + vport->num_disc_nodes = 0; + /* go thru NPR nodes and issue ELS PLOGIs */ + if (vport->fc_npr_cnt) + lpfc_els_disc_plogi(vport); - 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); + if (!vport->num_disc_nodes) { + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_NDISC_ACTIVE; + spin_unlock_irq(shost->host_lock); } - phba->hba_state = LPFC_HBA_READY; + printk(KERN_ERR "%s (%d): vport ready\n", + __FUNCTION__, __LINE__); + vport->port_state = LPFC_VPORT_READY; out: /* Device Discovery completes */ @@ -555,34 +562,34 @@ out: "%d:0225 Device Discovery completes\n", phba->brd_no); - mempool_free( pmb, phba->mbox_mem_pool); + mempool_free(pmb, phba->mbox_mem_pool); - spin_lock_irq(phba->host->host_lock); - phba->fc_flag &= ~FC_ABORT_DISCOVERY; - if (phba->fc_flag & FC_ESTABLISH_LINK) { - phba->fc_flag &= ~FC_ESTABLISH_LINK; - } - spin_unlock_irq(phba->host->host_lock); + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~(FC_ABORT_DISCOVERY | FC_ESTABLISH_LINK); + spin_unlock_irq(shost->host_lock); del_timer_sync(&phba->fc_estabtmo); - lpfc_can_disctmo(phba); + lpfc_can_disctmo(vport); /* turn on Link Attention interrupts */ - spin_lock_irq(phba->host->host_lock); + + spin_lock_irq(&phba->hbalock); psli->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->host->host_lock); + spin_unlock_irq(&phba->hbalock); return; } + static void lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { + struct lpfc_vport *vport = pmb->vport; struct lpfc_sli *psli = &phba->sli; int rc; @@ -592,58 +599,64 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) mempool_free(pmb, phba->mbox_mem_pool); if (phba->fc_topology == TOPOLOGY_LOOP && - phba->fc_flag & FC_PUBLIC_LOOP && - !(phba->fc_flag & FC_LBIT)) { + vport->fc_flag & FC_PUBLIC_LOOP && + !(vport->fc_flag & FC_LBIT)) { /* Need to wait for FAN - use discovery timer - * for timeout. hba_state is identically + * for timeout. port_state is identically * LPFC_LOCAL_CFG_LINK while waiting for FAN */ - lpfc_set_disctmo(phba); + lpfc_set_disctmo(vport); return; } - /* Start discovery by sending a FLOGI. hba_state is identically + /* Start discovery by sending a FLOGI. port_state is identically * LPFC_FLOGI while waiting for FLOGI cmpl */ - phba->hba_state = LPFC_FLOGI; - lpfc_set_disctmo(phba); - lpfc_initial_flogi(phba); + vport->port_state = LPFC_FLOGI; + lpfc_set_disctmo(vport); + lpfc_initial_flogi(vport); return; out: 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); + phba->brd_no, pmb->mb.mbxStatus, vport->port_state); lpfc_linkdown(phba); - phba->hba_state = LPFC_HBA_ERROR; + phba->link_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); + phba->brd_no, vport->port_state); lpfc_clear_la(phba, pmb); + printk(KERN_ERR "%s (%d): do clear_la\n", + __FUNCTION__, __LINE__); pmb->mbox_cmpl = lpfc_mbx_cmpl_clear_la; + pmb->vport = vport; 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); + lpfc_disc_flush_list(vport); 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; + printk(KERN_ERR "%s (%d): vport ready\n", + __FUNCTION__, __LINE__); + vport->port_state = LPFC_VPORT_READY; } return; } static void -lpfc_mbx_cmpl_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) +lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { struct lpfc_sli *psli = &phba->sli; MAILBOX_t *mb = &pmb->mb; struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) pmb->context1; + struct lpfc_vport *vport = pmb->vport; /* Check for error */ @@ -652,67 +665,78 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, "%d:0319 READ_SPARAM mbxStatus error x%x " "hba state x%x>\n", - phba->brd_no, mb->mbxStatus, phba->hba_state); + phba->brd_no, mb->mbxStatus, vport->port_state); lpfc_linkdown(phba); - phba->hba_state = LPFC_HBA_ERROR; + phba->link_state = LPFC_HBA_ERROR; goto out; } - memcpy((uint8_t *) & phba->fc_sparam, (uint8_t *) mp->virt, + memcpy((uint8_t *) &vport->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); + u64_to_wwn(phba->cfg_soft_wwnn, + vport->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, + u64_to_wwn(phba->cfg_soft_wwpn, + vport->fc_sparam.portName.u.wwn); + memcpy((uint8_t *) &vport->fc_nodename, + (uint8_t *) &vport->fc_sparam.nodeName, sizeof (struct lpfc_name)); - memcpy((uint8_t *) & phba->fc_portname, - (uint8_t *) & phba->fc_sparam.portName, + memcpy((uint8_t *) &vport->fc_portname, + (uint8_t *) &vport->fc_sparam.portName, sizeof (struct lpfc_name)); lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); - mempool_free( pmb, phba->mbox_mem_pool); + mempool_free(pmb, phba->mbox_mem_pool); return; out: pmb->context1 = NULL; lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); - if (phba->hba_state != LPFC_CLEAR_LA) { + if (phba->link_state != LPFC_CLEAR_LA) { + struct lpfc_sli_ring *extra_ring = + &psli->ring[psli->extra_ring]; + struct lpfc_sli_ring *fcp_ring = &psli->ring[psli->fcp_ring]; + struct lpfc_sli_ring *next_ring = &psli->ring[psli->next_ring]; + lpfc_clear_la(phba, pmb); + printk(KERN_ERR "%s (%d): do clear_la\n", + __FUNCTION__, __LINE__); pmb->mbox_cmpl = lpfc_mbx_cmpl_clear_la; + pmb->vport = vport; 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->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; + mempool_free(pmb, phba->mbox_mem_pool); + lpfc_disc_flush_list(vport); + extra_ring->flag &= ~LPFC_STOP_IOCB_EVENT; + fcp_ring->flag &= ~LPFC_STOP_IOCB_EVENT; + next_ring->flag &= ~LPFC_STOP_IOCB_EVENT; + printk(KERN_ERR "%s (%d): vport ready\n", + __FUNCTION__, __LINE__); + vport->port_state = LPFC_VPORT_READY; } } else { - mempool_free( pmb, phba->mbox_mem_pool); + mempool_free(pmb, phba->mbox_mem_pool); } return; } static void -lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) +lpfc_mbx_process_link_up(struct lpfc_vport *vport, READ_LA_VAR *la) { - int i; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct lpfc_hba *phba = vport->phba; LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox; + int i; 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); + spin_lock_irq(shost->host_lock); switch (la->UlnkSpeed) { case LA_1GHZ_LINK: phba->fc_linkspeed = LA_1GHZ_LINK; @@ -737,9 +761,9 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) /* Get Loop Map information */ if (la->il) - phba->fc_flag |= FC_LBIT; + vport->fc_flag |= FC_LBIT; - phba->fc_myDID = la->granted_AL_PA; + vport->fc_myDID = la->granted_AL_PA; i = la->un.lilpBde64.tus.f.bdeSize; if (i == 0) { @@ -781,14 +805,15 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) } } } else { - phba->fc_myDID = phba->fc_pref_DID; - phba->fc_flag |= FC_LBIT; + vport->fc_myDID = phba->fc_pref_DID; + vport->fc_flag |= FC_LBIT; } - spin_unlock_irq(phba->host->host_lock); + spin_unlock_irq(shost->host_lock); lpfc_linkup(phba); if (sparam_mbox) { lpfc_read_sparam(phba, sparam_mbox); + sparam_mbox->vport = vport; sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam; rc = lpfc_sli_issue_mbox(phba, sparam_mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); @@ -804,8 +829,9 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) } if (cfglink_mbox) { - phba->hba_state = LPFC_LOCAL_CFG_LINK; + vport->port_state = LPFC_LOCAL_CFG_LINK; lpfc_config_link(phba, cfglink_mbox); + cfglink_mbox->vport = vport; cfglink_mbox->mbox_cmpl = lpfc_mbx_cmpl_local_config_link; rc = lpfc_sli_issue_mbox(phba, cfglink_mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); @@ -815,20 +841,21 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) } static void -lpfc_mbx_issue_link_down(struct lpfc_hba *phba) { +lpfc_mbx_issue_link_down(struct lpfc_hba *phba) +{ uint32_t control; struct lpfc_sli *psli = &phba->sli; lpfc_linkdown(phba); /* turn on Link Attention interrupts - no CLEAR_LA needed */ - spin_lock_irq(phba->host->host_lock); + spin_lock_irq(&phba->hbalock); psli->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->host->host_lock); + spin_unlock_irq(&phba->hbalock); } /* @@ -838,8 +865,10 @@ lpfc_mbx_issue_link_down(struct lpfc_hba *phba) { * handed off to the SLI layer. */ void -lpfc_mbx_cmpl_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) +lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { + struct lpfc_vport *vport = pmb->vport; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); READ_LA_VAR *la; MAILBOX_t *mb = &pmb->mb; struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); @@ -851,9 +880,9 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) LOG_LINK_EVENT, "%d:1307 READ_LA mbox error x%x state x%x\n", phba->brd_no, - mb->mbxStatus, phba->hba_state); + mb->mbxStatus, vport->port_state); lpfc_mbx_issue_link_down(phba); - phba->hba_state = LPFC_HBA_ERROR; + phba->link_state = LPFC_HBA_ERROR; goto lpfc_mbx_cmpl_read_la_free_mbuf; } @@ -861,27 +890,26 @@ 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); + spin_lock_irq(shost->host_lock); if (la->pb) - phba->fc_flag |= FC_BYPASSED_MODE; + vport->fc_flag |= FC_BYPASSED_MODE; else - phba->fc_flag &= ~FC_BYPASSED_MODE; - spin_unlock_irq(phba->host->host_lock); + vport->fc_flag &= ~FC_BYPASSED_MODE; + spin_unlock_irq(shost->host_lock); if (((phba->fc_eventTag + 1) < la->eventTag) || (phba->fc_eventTag == la->eventTag)) { phba->fc_stat.LinkMultiEvent++; - if (la->attType == AT_LINK_UP) { + if (la->attType == AT_LINK_UP) if (phba->fc_eventTag != 0) lpfc_linkdown(phba); } - } phba->fc_eventTag = la->eventTag; if (la->attType == AT_LINK_UP) { phba->fc_stat.LinkUp++; - if (phba->fc_flag & FC_LOOPBACK_MODE) { + if (phba->link_flag & LS_LOOPBACK_MODE) { lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, "%d:1306 Link Up Event in loop back mode " "x%x received Data: x%x x%x x%x x%x\n", @@ -896,14 +924,14 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) la->granted_AL_PA, la->UlnkSpeed, phba->alpa_map[0]); } - lpfc_mbx_process_link_up(phba, la); + lpfc_mbx_process_link_up(vport, la); } else { phba->fc_stat.LinkDown++; lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, "%d:1305 Link Down Event x%x received " "Data: x%x x%x x%x\n", phba->brd_no, la->eventTag, phba->fc_eventTag, - phba->hba_state, phba->fc_flag); + phba->pport->port_state, vport->fc_flag); lpfc_mbx_issue_link_down(phba); } @@ -921,26 +949,20 @@ lpfc_mbx_cmpl_read_la_free_mbuf: * handed off to the SLI layer. */ void -lpfc_mbx_cmpl_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) +lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { - struct lpfc_sli *psli; - MAILBOX_t *mb; - struct lpfc_dmabuf *mp; - struct lpfc_nodelist *ndlp; - - psli = &phba->sli; - mb = &pmb->mb; + struct lpfc_vport *vport = pmb->vport; + struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) pmb->context1; + struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; - ndlp = (struct lpfc_nodelist *) pmb->context2; - mp = (struct lpfc_dmabuf *) (pmb->context1); pmb->context1 = NULL; /* Good status, call state machine */ - lpfc_disc_state_machine(phba, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN); + lpfc_disc_state_machine(vport, ndlp, pmb, NLP_EVT_CMPL_REG_LOGIN); lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); - mempool_free( pmb, phba->mbox_mem_pool); + mempool_free(pmb, phba->mbox_mem_pool); lpfc_nlp_put(ndlp); return; @@ -953,20 +975,13 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) * handed off to the SLI layer. */ void -lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) +lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { - struct lpfc_sli *psli; - MAILBOX_t *mb; - struct lpfc_dmabuf *mp; - struct lpfc_nodelist *ndlp; - struct lpfc_nodelist *ndlp_fdmi; - - - psli = &phba->sli; - mb = &pmb->mb; - + struct lpfc_vport *vport = pmb->vport; + MAILBOX_t *mb = &pmb->mb; + struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); + struct lpfc_nodelist *ndlp, *ndlp_fdmi; ndlp = (struct lpfc_nodelist *) pmb->context2; - mp = (struct lpfc_dmabuf *) (pmb->context1); pmb->context1 = NULL; pmb->context2 = NULL; @@ -978,57 +993,59 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) lpfc_nlp_put(ndlp); /* FLOGI failed, so just use loop map to make discovery list */ - lpfc_disc_list_loopmap(phba); + lpfc_disc_list_loopmap(vport); /* Start discovery */ - lpfc_disc_start(phba); + lpfc_disc_start(vport); return; } ndlp->nlp_rpi = mb->un.varWords[0]; ndlp->nlp_type |= NLP_FABRIC; - lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE); + lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); lpfc_nlp_put(ndlp); /* Drop the reference from the mbox */ - if (phba->hba_state == LPFC_FABRIC_CFG_LINK) { + if (vport->port_state == LPFC_FABRIC_CFG_LINK) { /* This NPort has been assigned an NPort_ID by the fabric as a * result of the completed fabric login. Issue a State Change * Registration (SCR) ELS request to the fabric controller * (SCR_DID) so that this NPort gets RSCN events from the * fabric. */ - lpfc_issue_els_scr(phba, SCR_DID, 0); + lpfc_issue_els_scr(vport, SCR_DID, 0); - ndlp = lpfc_findnode_did(phba, NameServer_DID); + ndlp = lpfc_findnode_did(vport, NameServer_DID); if (!ndlp) { - /* Allocate a new node instance. If the pool is empty, + /* 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. + * Otherwise, issue a Port Login (PLOGI) to + * the NameServer */ - ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_ATOMIC); + ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); if (!ndlp) { - lpfc_disc_start(phba); + lpfc_disc_start(vport); 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); + lpfc_nlp_init(vport, ndlp, NameServer_DID); ndlp->nlp_type |= NLP_FABRIC; } } - lpfc_nlp_set_state(phba, ndlp, NLP_STE_PLOGI_ISSUE); - lpfc_issue_els_plogi(phba, NameServer_DID, 0); + + lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); + lpfc_issue_els_plogi(vport, NameServer_DID, 0); if (phba->cfg_fdmi_on) { ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool, - GFP_KERNEL); + GFP_KERNEL); if (ndlp_fdmi) { - lpfc_nlp_init(phba, ndlp_fdmi, FDMI_DID); + lpfc_nlp_init(vport, 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); + lpfc_issue_els_plogi(vport, FDMI_DID, 0); } } } @@ -1046,32 +1063,28 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) * handed off to the SLI layer. */ void -lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) +lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { - struct lpfc_sli *psli; - MAILBOX_t *mb; - struct lpfc_dmabuf *mp; - struct lpfc_nodelist *ndlp; - - psli = &phba->sli; - mb = &pmb->mb; - - ndlp = (struct lpfc_nodelist *) pmb->context2; - mp = (struct lpfc_dmabuf *) (pmb->context1); + MAILBOX_t *mb = &pmb->mb; + struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); + struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; + struct lpfc_vport *vport = pmb->vport; if (mb->mbxStatus) { lpfc_nlp_put(ndlp); lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free(pmb, phba->mbox_mem_pool); - lpfc_drop_node(phba, ndlp); + lpfc_drop_node(vport, ndlp); - /* RegLogin failed, so just use loop map to make discovery - list */ - lpfc_disc_list_loopmap(phba); + /* + * RegLogin failed, so just use loop map to make discovery + * list + */ + lpfc_disc_list_loopmap(vport); /* Start discovery */ - lpfc_disc_start(phba); + lpfc_disc_start(vport); return; } @@ -1079,37 +1092,39 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) ndlp->nlp_rpi = mb->un.varWords[0]; ndlp->nlp_type |= NLP_FABRIC; - lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE); + lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - if (phba->hba_state < LPFC_HBA_READY) { - /* Link up discovery requires Fabrib registration. */ - 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); + if (vport->port_state < LPFC_VPORT_READY) { + /* Link up discovery requires Fabric registration. */ + lpfc_ns_cmd(vport, ndlp, SLI_CTNS_RNN_ID); + lpfc_ns_cmd(vport, ndlp, SLI_CTNS_RSNN_NN); + lpfc_ns_cmd(vport, ndlp, SLI_CTNS_RFT_ID); + lpfc_ns_cmd(vport, ndlp, SLI_CTNS_RFF_ID); } - phba->fc_ns_retry = 0; + vport->fc_ns_retry = 0; /* Good status, issue CT Request to NameServer */ - if (lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT)) { + if (lpfc_ns_cmd(vport, ndlp, SLI_CTNS_GID_FT)) { /* Cannot issue NameServer Query, so finish up discovery */ - lpfc_disc_start(phba); + lpfc_disc_start(vport); } lpfc_nlp_put(ndlp); lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); - mempool_free( pmb, phba->mbox_mem_pool); + mempool_free(pmb, phba->mbox_mem_pool); return; } static void -lpfc_register_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) +lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { - struct fc_rport *rport; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct fc_rport *rport; struct lpfc_rport_data *rdata; struct fc_rport_identifiers rport_ids; + struct lpfc_hba *phba = vport->phba; /* Remote port has reappeared. Re-register w/ FC transport */ rport_ids.node_name = wwn_to_u64(ndlp->nlp_nodename.u.wwn); @@ -1128,7 +1143,7 @@ lpfc_register_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) *(struct lpfc_rport_data **) ndlp->rport->dd_data) { lpfc_nlp_put(ndlp); } - ndlp->rport = rport = fc_remote_port_add(phba->host, 0, &rport_ids); + ndlp->rport = rport = fc_remote_port_add(shost, 0, &rport_ids); if (!rport || !get_device(&rport->dev)) { dev_printk(KERN_WARNING, &phba->pcidev->dev, "Warning: fc_remote_port_add failed\n"); @@ -1159,7 +1174,7 @@ lpfc_register_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) } static void -lpfc_unregister_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) +lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp) { struct fc_rport *rport = ndlp->rport; struct lpfc_rport_data *rdata = rport->dd_data; @@ -1177,42 +1192,46 @@ lpfc_unregister_remote_port(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) } static void -lpfc_nlp_counters(struct lpfc_hba *phba, int state, int count) +lpfc_nlp_counters(struct lpfc_vport *vport, int state, int count) { - spin_lock_irq(phba->host->host_lock); + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + + spin_lock_irq(shost->host_lock); switch (state) { case NLP_STE_UNUSED_NODE: - phba->fc_unused_cnt += count; + vport->fc_unused_cnt += count; break; case NLP_STE_PLOGI_ISSUE: - phba->fc_plogi_cnt += count; + vport->fc_plogi_cnt += count; break; case NLP_STE_ADISC_ISSUE: - phba->fc_adisc_cnt += count; + vport->fc_adisc_cnt += count; break; case NLP_STE_REG_LOGIN_ISSUE: - phba->fc_reglogin_cnt += count; + vport->fc_reglogin_cnt += count; break; case NLP_STE_PRLI_ISSUE: - phba->fc_prli_cnt += count; + vport->fc_prli_cnt += count; break; case NLP_STE_UNMAPPED_NODE: - phba->fc_unmap_cnt += count; + vport->fc_unmap_cnt += count; break; case NLP_STE_MAPPED_NODE: - phba->fc_map_cnt += count; + vport->fc_map_cnt += count; break; case NLP_STE_NPR_NODE: - phba->fc_npr_cnt += count; + vport->fc_npr_cnt += count; break; } - spin_unlock_irq(phba->host->host_lock); + spin_unlock_irq(shost->host_lock); } static void -lpfc_nlp_state_cleanup(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, +lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, int old_state, int new_state) { + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + if (new_state == NLP_STE_UNMAPPED_NODE) { ndlp->nlp_type &= ~(NLP_FCP_TARGET | NLP_FCP_INITIATOR); ndlp->nlp_flag &= ~NLP_NODEV_REMOVE; @@ -1226,19 +1245,19 @@ lpfc_nlp_state_cleanup(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, /* Transport interface */ if (ndlp->rport && (old_state == NLP_STE_MAPPED_NODE || old_state == NLP_STE_UNMAPPED_NODE)) { - phba->nport_event_cnt++; - lpfc_unregister_remote_port(phba, ndlp); + vport->phba->nport_event_cnt++; + lpfc_unregister_remote_port(ndlp); } if (new_state == NLP_STE_MAPPED_NODE || new_state == NLP_STE_UNMAPPED_NODE) { - phba->nport_event_cnt++; + vport->phba->nport_event_cnt++; /* * Tell the fc transport about the port, if we haven't * already. If we have, and it's a scsi entity, be * sure to unblock any attached scsi devices */ - lpfc_register_remote_port(phba, ndlp); + lpfc_register_remote_port(vport, ndlp); } /* @@ -1251,10 +1270,10 @@ lpfc_nlp_state_cleanup(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, (!ndlp->rport || ndlp->rport->scsi_target_id == -1 || ndlp->rport->scsi_target_id >= LPFC_MAX_TARGET)) { - spin_lock_irq(phba->host->host_lock); + spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_TGT_NO_SCSIID; - spin_unlock_irq(phba->host->host_lock); - lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE); + spin_unlock_irq(shost->host_lock); + lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); } } @@ -1280,61 +1299,67 @@ lpfc_nlp_state_name(char *buffer, size_t size, int state) } void -lpfc_nlp_set_state(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, int state) +lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + int state) { + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); int old_state = ndlp->nlp_state; char name1[16], name2[16]; - lpfc_printf_log(phba, KERN_INFO, LOG_NODE, + lpfc_printf_log(vport->phba, KERN_INFO, LOG_NODE, "%d:0904 NPort state transition x%06x, %s -> %s\n", - phba->brd_no, + vport->phba->brd_no, ndlp->nlp_DID, lpfc_nlp_state_name(name1, sizeof(name1), old_state), lpfc_nlp_state_name(name2, sizeof(name2), state)); if (old_state == NLP_STE_NPR_NODE && (ndlp->nlp_flag & NLP_DELAY_TMO) != 0 && state != NLP_STE_NPR_NODE) - lpfc_cancel_retry_delay_tmo(phba, ndlp); + lpfc_cancel_retry_delay_tmo(vport, ndlp); if (old_state == NLP_STE_UNMAPPED_NODE) { ndlp->nlp_flag &= ~NLP_TGT_NO_SCSIID; ndlp->nlp_type &= ~NLP_FC_NODE; } if (list_empty(&ndlp->nlp_listp)) { - spin_lock_irq(phba->host->host_lock); - list_add_tail(&ndlp->nlp_listp, &phba->fc_nodes); - spin_unlock_irq(phba->host->host_lock); + spin_lock_irq(shost->host_lock); + list_add_tail(&ndlp->nlp_listp, &vport->fc_nodes); + spin_unlock_irq(shost->host_lock); } else if (old_state) - lpfc_nlp_counters(phba, old_state, -1); + lpfc_nlp_counters(vport, old_state, -1); ndlp->nlp_state = state; - lpfc_nlp_counters(phba, state, 1); - lpfc_nlp_state_cleanup(phba, ndlp, old_state, state); + lpfc_nlp_counters(vport, state, 1); + lpfc_nlp_state_cleanup(vport, ndlp, old_state, state); } void -lpfc_dequeue_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) +lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0) - lpfc_cancel_retry_delay_tmo(phba, ndlp); + lpfc_cancel_retry_delay_tmo(vport, ndlp); if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) - lpfc_nlp_counters(phba, ndlp->nlp_state, -1); - spin_lock_irq(phba->host->host_lock); + lpfc_nlp_counters(vport, ndlp->nlp_state, -1); + spin_lock_irq(shost->host_lock); list_del_init(&ndlp->nlp_listp); - spin_unlock_irq(phba->host->host_lock); - lpfc_nlp_state_cleanup(phba, ndlp, ndlp->nlp_state, 0); + spin_unlock_irq(shost->host_lock); + lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, 0); } void -lpfc_drop_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) +lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + if ((ndlp->nlp_flag & NLP_DELAY_TMO) != 0) - lpfc_cancel_retry_delay_tmo(phba, ndlp); + lpfc_cancel_retry_delay_tmo(vport, ndlp); if (ndlp->nlp_state && !list_empty(&ndlp->nlp_listp)) - lpfc_nlp_counters(phba, ndlp->nlp_state, -1); - spin_lock_irq(phba->host->host_lock); + lpfc_nlp_counters(vport, ndlp->nlp_state, -1); + spin_lock_irq(shost->host_lock); list_del_init(&ndlp->nlp_listp); - spin_unlock_irq(phba->host->host_lock); + spin_unlock_irq(shost->host_lock); lpfc_nlp_put(ndlp); } @@ -1342,11 +1367,13 @@ lpfc_drop_node(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) * Start / ReStart rescue timer for Discovery / RSCN handling */ void -lpfc_set_disctmo(struct lpfc_hba * phba) +lpfc_set_disctmo(struct lpfc_vport *vport) { + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct lpfc_hba *phba = vport->phba; uint32_t tmo; - if (phba->hba_state == LPFC_LOCAL_CFG_LINK) { + if (vport->port_state == LPFC_LOCAL_CFG_LINK) { /* For FAN, timeout should be greater then edtov */ tmo = (((phba->fc_edtov + 999) / 1000) + 1); } else { @@ -1356,18 +1383,18 @@ lpfc_set_disctmo(struct lpfc_hba * phba) tmo = ((phba->fc_ratov * 3) + 3); } - mod_timer(&phba->fc_disctmo, jiffies + HZ * tmo); - spin_lock_irq(phba->host->host_lock); - phba->fc_flag |= FC_DISC_TMO; - spin_unlock_irq(phba->host->host_lock); + mod_timer(&vport->fc_disctmo, jiffies + HZ * tmo); + spin_lock_irq(shost->host_lock); + vport->fc_flag |= FC_DISC_TMO; + spin_unlock_irq(shost->host_lock); /* Start Discovery Timer state */ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, "%d:0247 Start Discovery Timer state x%x " "Data: x%x x%lx x%x x%x\n", - phba->brd_no, - phba->hba_state, tmo, (unsigned long)&phba->fc_disctmo, - phba->fc_plogi_cnt, phba->fc_adisc_cnt); + phba->brd_no, vport->port_state, tmo, + (unsigned long)&vport->fc_disctmo, vport->fc_plogi_cnt, + vport->fc_adisc_cnt); return; } @@ -1376,23 +1403,29 @@ lpfc_set_disctmo(struct lpfc_hba * phba) * Cancel rescue timer for Discovery / RSCN handling */ int -lpfc_can_disctmo(struct lpfc_hba * phba) +lpfc_can_disctmo(struct lpfc_vport *vport) { + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct lpfc_hba *phba = vport->phba; + unsigned long iflags; + /* Turn off discovery timer if its running */ - if (phba->fc_flag & FC_DISC_TMO) { - spin_lock_irq(phba->host->host_lock); - phba->fc_flag &= ~FC_DISC_TMO; - spin_unlock_irq(phba->host->host_lock); - del_timer_sync(&phba->fc_disctmo); - phba->work_hba_events &= ~WORKER_DISC_TMO; + if (vport->fc_flag & FC_DISC_TMO) { + spin_lock_irqsave(shost->host_lock, iflags); + vport->fc_flag &= ~FC_DISC_TMO; + spin_unlock_irqrestore(shost->host_lock, iflags); + del_timer_sync(&vport->fc_disctmo); + spin_lock_irqsave(&vport->work_port_lock, iflags); + vport->work_port_events &= ~WORKER_DISC_TMO; + spin_unlock_irqrestore(&vport->work_port_lock, iflags); } /* Cancel Discovery Timer state */ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, "%d:0248 Cancel Discovery Timer state x%x " "Data: x%x x%x x%x\n", - phba->brd_no, phba->hba_state, phba->fc_flag, - phba->fc_plogi_cnt, phba->fc_adisc_cnt); + phba->brd_no, vport->port_state, vport->fc_flag, + vport->fc_plogi_cnt, vport->fc_adisc_cnt); return 0; } @@ -1402,15 +1435,13 @@ lpfc_can_disctmo(struct lpfc_hba * phba) * Return true if iocb matches the specified nport */ int -lpfc_check_sli_ndlp(struct lpfc_hba * phba, - struct lpfc_sli_ring * pring, - struct lpfc_iocbq * iocb, struct lpfc_nodelist * ndlp) +lpfc_check_sli_ndlp(struct lpfc_hba *phba, + struct lpfc_sli_ring *pring, + struct lpfc_iocbq *iocb, + struct lpfc_nodelist *ndlp) { - struct lpfc_sli *psli; - IOCB_t *icmd; - - psli = &phba->sli; - icmd = &iocb->iocb; + struct lpfc_sli *psli = &phba->sli; + IOCB_t *icmd = &iocb->iocb; if (pring->ringno == LPFC_ELS_RING) { switch (icmd->ulpCommand) { case CMD_GEN_REQUEST64_CR: @@ -1445,7 +1476,7 @@ lpfc_check_sli_ndlp(struct lpfc_hba * phba, * associated with nlp_rpi in the LPFC_NODELIST entry. */ static int -lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) +lpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) { LIST_HEAD(completions); struct lpfc_sli *psli; @@ -1465,9 +1496,9 @@ lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) for (i = 0; i < psli->num_rings; i++) { pring = &psli->ring[i]; - spin_lock_irq(phba->host->host_lock); + spin_lock_irq(&phba->hbalock); list_for_each_entry_safe(iocb, next_iocb, &pring->txq, - list) { + list) { /* * Check to see if iocb matches the nport we are * looking for @@ -1481,8 +1512,7 @@ lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) pring->txq_cnt--; } } - spin_unlock_irq(phba->host->host_lock); - + spin_unlock_irq(&phba->hbalock); } } @@ -1490,13 +1520,14 @@ lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) iocb = list_get_first(&completions, struct lpfc_iocbq, list); list_del(&iocb->list); - if (iocb->iocb_cmpl) { + if (!iocb->iocb_cmpl) + lpfc_sli_release_iocbq(phba, iocb); + else { icmd = &iocb->iocb; icmd->ulpStatus = IOSTAT_LOCAL_REJECT; icmd->un.ulpWord[4] = IOERR_SLI_ABORTED; - (iocb->iocb_cmpl) (phba, iocb, iocb); - } else - lpfc_sli_release_iocbq(phba, iocb); + (iocb->iocb_cmpl)(phba, iocb, iocb); + } } return 0; @@ -1512,19 +1543,21 @@ lpfc_no_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) * we are waiting to PLOGI back to the remote NPort. */ int -lpfc_unreg_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) +lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { - LPFC_MBOXQ_t *mbox; + struct lpfc_hba *phba = vport->phba; + LPFC_MBOXQ_t *mbox; int rc; if (ndlp->nlp_rpi) { - if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) { + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (mbox) { lpfc_unreg_login(phba, ndlp->nlp_rpi, mbox); mbox->mbox_cmpl=lpfc_sli_def_mbox_cmpl; rc = lpfc_sli_issue_mbox (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); if (rc == MBX_NOT_FINISHED) - mempool_free( mbox, phba->mbox_mem_pool); + mempool_free(mbox, phba->mbox_mem_pool); } lpfc_no_rpi(phba, ndlp); ndlp->nlp_rpi = 0; @@ -1538,10 +1571,11 @@ lpfc_unreg_rpi(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) * so it can be freed. */ static int -lpfc_cleanup_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) +lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { - LPFC_MBOXQ_t *mb; - LPFC_MBOXQ_t *nextmb; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct lpfc_hba *phba = vport->phba; + LPFC_MBOXQ_t *mb, *nextmb; struct lpfc_dmabuf *mp; /* Cleanup node for NPort */ @@ -1551,7 +1585,7 @@ lpfc_cleanup_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); - lpfc_dequeue_node(phba, ndlp); + lpfc_dequeue_node(vport, ndlp); /* cleanup any ndlp on mbox q waiting for reglogin cmpl */ if ((mb = phba->sli.mbox_active)) { @@ -1562,13 +1596,13 @@ lpfc_cleanup_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) } } - spin_lock_irq(phba->host->host_lock); + spin_lock_irq(&phba->hbalock); list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) && (ndlp == (struct lpfc_nodelist *) mb->context2)) { mp = (struct lpfc_dmabuf *) (mb->context1); if (mp) { - lpfc_mbuf_free(phba, mp->virt, mp->phys); + __lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); } list_del(&mb->list); @@ -1576,12 +1610,12 @@ lpfc_cleanup_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) lpfc_nlp_put(ndlp); } } - spin_unlock_irq(phba->host->host_lock); + spin_unlock_irq(&phba->hbalock); lpfc_els_abort(phba,ndlp); - spin_lock_irq(phba->host->host_lock); + spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~NLP_DELAY_TMO; - spin_unlock_irq(phba->host->host_lock); + spin_unlock_irq(shost->host_lock); ndlp->nlp_last_elscmd = 0; del_timer_sync(&ndlp->nlp_delayfunc); @@ -1589,7 +1623,7 @@ lpfc_cleanup_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) if (!list_empty(&ndlp->els_retry_evt.evt_listp)) list_del_init(&ndlp->els_retry_evt.evt_listp); - lpfc_unreg_rpi(phba, ndlp); + lpfc_unreg_rpi(vport, ndlp); return 0; } @@ -1600,17 +1634,22 @@ lpfc_cleanup_node(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) * machine, defer the free till we reach the end of the state machine. */ static void -lpfc_nlp_remove(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) +lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) { struct lpfc_rport_data *rdata; if (ndlp->nlp_flag & NLP_DELAY_TMO) { - lpfc_cancel_retry_delay_tmo(phba, ndlp); + lpfc_cancel_retry_delay_tmo(vport, ndlp); } - lpfc_cleanup_node(phba, ndlp); + lpfc_cleanup_node(vport, ndlp); - if ((ndlp->rport) && !(phba->fc_flag & FC_UNLOADING)) { + /* + * We should never get here with a non-NULL ndlp->rport. But + * if we do, drop the reference to the rport. That seems the + * intelligent thing to do. + */ + if (ndlp->rport && !(vport->load_flag & FC_UNLOADING)) { put_device(&ndlp->rport->dev); rdata = ndlp->rport->dd_data; rdata->pnode = NULL; @@ -1619,11 +1658,10 @@ lpfc_nlp_remove(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) } static int -lpfc_matchdid(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did) +lpfc_matchdid(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + uint32_t did) { - D_ID mydid; - D_ID ndlpdid; - D_ID matchdid; + D_ID mydid, ndlpdid, matchdid; if (did == Bcast_DID) return 0; @@ -1637,7 +1675,7 @@ lpfc_matchdid(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did) return 1; /* Next check for area/domain identically equals 0 match */ - mydid.un.word = phba->fc_myDID; + mydid.un.word = vport->fc_myDID; if ((mydid.un.b.domain == 0) && (mydid.un.b.area == 0)) { return 0; } @@ -1669,15 +1707,15 @@ lpfc_matchdid(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did) } /* Search for a nodelist entry */ -struct lpfc_nodelist * -lpfc_findnode_did(struct lpfc_hba *phba, uint32_t did) +static struct lpfc_nodelist * +__lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) { + struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp; uint32_t data1; - spin_lock_irq(phba->host->host_lock); - list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) { - if (lpfc_matchdid(phba, ndlp, did)) { + list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { + if (lpfc_matchdid(vport, ndlp, did)) { data1 = (((uint32_t) ndlp->nlp_state << 24) | ((uint32_t) ndlp->nlp_xri << 16) | ((uint32_t) ndlp->nlp_type << 8) | @@ -1688,11 +1726,9 @@ lpfc_findnode_did(struct lpfc_hba *phba, uint32_t did) phba->brd_no, ndlp, ndlp->nlp_DID, ndlp->nlp_flag, data1); - 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, @@ -1702,68 +1738,85 @@ lpfc_findnode_did(struct lpfc_hba *phba, uint32_t did) } struct lpfc_nodelist * -lpfc_setup_disc_node(struct lpfc_hba * phba, uint32_t did) +lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) +{ + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct lpfc_nodelist *ndlp; + + spin_lock_irq(shost->host_lock); + ndlp = __lpfc_findnode_did(vport, did); + spin_unlock_irq(shost->host_lock); + return ndlp; +} + +struct lpfc_nodelist * +lpfc_setup_disc_node(struct lpfc_vport *vport, uint32_t did) { + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp; - ndlp = lpfc_findnode_did(phba, did); + ndlp = lpfc_findnode_did(vport, did); if (!ndlp) { - if ((phba->fc_flag & FC_RSCN_MODE) && - ((lpfc_rscn_payload_check(phba, did) == 0))) + if ((vport->fc_flag & FC_RSCN_MODE) != 0 && + lpfc_rscn_payload_check(vport, did) == 0) return NULL; ndlp = (struct lpfc_nodelist *) - mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); + mempool_alloc(vport->phba->nlp_mem_pool, GFP_KERNEL); if (!ndlp) return NULL; - lpfc_nlp_init(phba, ndlp, did); - lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); + lpfc_nlp_init(vport, ndlp, did); + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; + spin_unlock_irq(shost->host_lock); return ndlp; } - if (phba->fc_flag & FC_RSCN_MODE) { - if (lpfc_rscn_payload_check(phba, did)) { + if (vport->fc_flag & FC_RSCN_MODE) { + if (lpfc_rscn_payload_check(vport, did)) { + spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; + spin_unlock_irq(shost->host_lock); /* 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); + lpfc_cancel_retry_delay_tmo(vport, ndlp); } else ndlp = NULL; } else { if (ndlp->nlp_state == NLP_STE_ADISC_ISSUE || ndlp->nlp_state == NLP_STE_PLOGI_ISSUE) return NULL; - lpfc_nlp_set_state(phba, ndlp, NLP_STE_NPR_NODE); + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + spin_lock_irq(shost->host_lock); ndlp->nlp_flag |= NLP_NPR_2B_DISC; + spin_unlock_irq(shost->host_lock); } return ndlp; } /* Build a list of nodes to discover based on the loopmap */ void -lpfc_disc_list_loopmap(struct lpfc_hba * phba) +lpfc_disc_list_loopmap(struct lpfc_vport *vport) { + struct lpfc_hba *phba = vport->phba; int j; uint32_t alpa, index; - if (phba->hba_state <= LPFC_LINK_DOWN) { + if (!lpfc_is_link_up(phba)) return; - } - if (phba->fc_topology != TOPOLOGY_LOOP) { + + if (phba->fc_topology != TOPOLOGY_LOOP) return; - } /* Check for loop map present or not */ if (phba->alpa_map[0]) { for (j = 1; j <= phba->alpa_map[0]; j++) { alpa = phba->alpa_map[j]; - - if (((phba->fc_myDID & 0xff) == alpa) || (alpa == 0)) { + if (((vport->fc_myDID & 0xff) == alpa) || (alpa == 0)) continue; - } - lpfc_setup_disc_node(phba, alpa); + lpfc_setup_disc_node(vport, alpa); } } else { /* No alpamap, so try all alpa's */ @@ -1776,113 +1829,139 @@ lpfc_disc_list_loopmap(struct lpfc_hba * phba) else index = FC_MAXLOOP - j - 1; alpa = lpfcAlpaArray[index]; - if ((phba->fc_myDID & 0xff) == alpa) { + if ((vport->fc_myDID & 0xff) == alpa) continue; - } - - lpfc_setup_disc_node(phba, alpa); + lpfc_setup_disc_node(vport, alpa); } } return; } -/* Start Link up / RSCN discovery on NPR list */ void -lpfc_disc_start(struct lpfc_hba * phba) +lpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport) { - struct lpfc_sli *psli; LPFC_MBOXQ_t *mbox; + struct lpfc_sli *psli = &phba->sli; + struct lpfc_sli_ring *extra_ring = &psli->ring[psli->extra_ring]; + struct lpfc_sli_ring *fcp_ring = &psli->ring[psli->fcp_ring]; + struct lpfc_sli_ring *next_ring = &psli->ring[psli->next_ring]; + int rc; + + /* Link up discovery */ + if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL)) != NULL) { + phba->link_state = LPFC_CLEAR_LA; + lpfc_clear_la(phba, mbox); + mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la; + mbox->vport = vport; + rc = lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT | + MBX_STOP_IOCB)); + if (rc == MBX_NOT_FINISHED) { + mempool_free(mbox, phba->mbox_mem_pool); + lpfc_disc_flush_list(vport); + extra_ring->flag &= ~LPFC_STOP_IOCB_EVENT; + fcp_ring->flag &= ~LPFC_STOP_IOCB_EVENT; + next_ring->flag &= ~LPFC_STOP_IOCB_EVENT; + vport->port_state = LPFC_VPORT_READY; + } + } +} + +/* Start Link up / RSCN discovery on NPR nodes */ +void +lpfc_disc_start(struct lpfc_vport *vport) +{ + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct lpfc_hba *phba = vport->phba; struct lpfc_nodelist *ndlp, *next_ndlp; uint32_t num_sent; uint32_t clear_la_pending; int did_changed; - int rc; - - psli = &phba->sli; - if (phba->hba_state <= LPFC_LINK_DOWN) { + if (!lpfc_is_link_up(phba)) return; - } - if (phba->hba_state == LPFC_CLEAR_LA) + + if (phba->link_state == LPFC_CLEAR_LA) clear_la_pending = 1; else clear_la_pending = 0; - if (phba->hba_state < LPFC_HBA_READY) { - phba->hba_state = LPFC_DISC_AUTH; - } - lpfc_set_disctmo(phba); + if (vport->port_state < LPFC_VPORT_READY) + vport->port_state = LPFC_DISC_AUTH; - if (phba->fc_prevDID == phba->fc_myDID) { + lpfc_set_disctmo(vport); + + if (vport->fc_prevDID == vport->fc_myDID) did_changed = 0; - } else { + else did_changed = 1; - } - phba->fc_prevDID = phba->fc_myDID; - phba->num_disc_nodes = 0; + + vport->fc_prevDID = vport->fc_myDID; + vport->num_disc_nodes = 0; /* Start Discovery state */ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, "%d:0202 Start Discovery hba state x%x " "Data: x%x x%x x%x\n", - phba->brd_no, phba->hba_state, phba->fc_flag, - phba->fc_plogi_cnt, phba->fc_adisc_cnt); + phba->brd_no, vport->port_state, vport->fc_flag, + vport->fc_plogi_cnt, vport->fc_adisc_cnt); /* If our did changed, we MUST do PLOGI */ - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, nlp_listp) { + list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { if (ndlp->nlp_state == NLP_STE_NPR_NODE && (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 && did_changed) { - spin_lock_irq(phba->host->host_lock); + spin_lock_irq(shost->host_lock); ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(phba->host->host_lock); + spin_unlock_irq(shost->host_lock); } } /* First do ADISCs - if any */ - num_sent = lpfc_els_disc_adisc(phba); + num_sent = lpfc_els_disc_adisc(vport); if (num_sent) return; - if ((phba->hba_state < LPFC_HBA_READY) && (!clear_la_pending)) { + if (vport->port_state < LPFC_VPORT_READY && !clear_la_pending) { + if (vport->port_type == LPFC_PHYSICAL_PORT) { /* If we get here, there is nothing to ADISC */ - if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL))) { - phba->hba_state = LPFC_CLEAR_LA; - lpfc_clear_la(phba, mbox); - mbox->mbox_cmpl = lpfc_mbx_cmpl_clear_la; - rc = lpfc_sli_issue_mbox(phba, mbox, - (MBX_NOWAIT | MBX_STOP_IOCB)); - if (rc == MBX_NOT_FINISHED) { - mempool_free( mbox, 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; + printk(KERN_ERR "%s (%d): do clear_la\n", + __FUNCTION__, __LINE__); + lpfc_issue_clear_la(phba, vport); + } else if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) { + + vport->num_disc_nodes = 0; + /* go thru NPR nodes and issue ELS PLOGIs */ + if (vport->fc_npr_cnt) + lpfc_els_disc_plogi(vport); + + if (!vport->num_disc_nodes) { + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_NDISC_ACTIVE; + spin_unlock_irq(shost->host_lock); } + printk(KERN_ERR "%s (%d): vport ready\n", + __FUNCTION__, __LINE__); + vport->port_state = LPFC_VPORT_READY; } } else { /* Next do PLOGIs - if any */ - num_sent = lpfc_els_disc_plogi(phba); + num_sent = lpfc_els_disc_plogi(vport); if (num_sent) return; - if (phba->fc_flag & FC_RSCN_MODE) { + if (vport->fc_flag & FC_RSCN_MODE) { /* Check to see if more RSCNs came in while we * were processing this one. */ - if ((phba->fc_rscn_id_cnt == 0) && - (!(phba->fc_flag & FC_RSCN_DISCOVERY))) { - spin_lock_irq(phba->host->host_lock); - phba->fc_flag &= ~FC_RSCN_MODE; - spin_unlock_irq(phba->host->host_lock); + if ((vport->fc_rscn_id_cnt == 0) && + (!(vport->fc_flag & FC_RSCN_DISCOVERY))) { + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_RSCN_MODE; + spin_unlock_irq(shost->host_lock); } else - lpfc_els_handle_rscn(phba); + lpfc_els_handle_rscn(vport); } } return; @@ -1893,7 +1972,7 @@ lpfc_disc_start(struct lpfc_hba * phba) * ring the match the sppecified nodelist. */ static void -lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) +lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) { LIST_HEAD(completions); struct lpfc_sli *psli; @@ -1907,7 +1986,7 @@ lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) /* Error matching iocb on txq or txcmplq * First check the txq. */ - spin_lock_irq(phba->host->host_lock); + spin_lock_irq(&phba->hbalock); list_for_each_entry_safe(iocb, next_iocb, &pring->txq, list) { if (iocb->context1 != ndlp) { continue; @@ -1927,36 +2006,36 @@ lpfc_free_tx(struct lpfc_hba * phba, struct lpfc_nodelist * ndlp) continue; } icmd = &iocb->iocb; - if ((icmd->ulpCommand == CMD_ELS_REQUEST64_CR) || - (icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX)) { + if (icmd->ulpCommand == CMD_ELS_REQUEST64_CR || + icmd->ulpCommand == CMD_XMIT_ELS_RSP64_CX) { lpfc_sli_issue_abort_iotag(phba, pring, iocb); } } - spin_unlock_irq(phba->host->host_lock); + spin_unlock_irq(&phba->hbalock); while (!list_empty(&completions)) { iocb = list_get_first(&completions, struct lpfc_iocbq, list); list_del(&iocb->list); - if (iocb->iocb_cmpl) { + if (!iocb->iocb_cmpl) + lpfc_sli_release_iocbq(phba, iocb); + else { icmd = &iocb->iocb; icmd->ulpStatus = IOSTAT_LOCAL_REJECT; icmd->un.ulpWord[4] = IOERR_SLI_ABORTED; (iocb->iocb_cmpl) (phba, iocb, iocb); - } else - lpfc_sli_release_iocbq(phba, iocb); + } } - - return; } void -lpfc_disc_flush_list(struct lpfc_hba * phba) +lpfc_disc_flush_list(struct lpfc_vport *vport) { struct lpfc_nodelist *ndlp, *next_ndlp; + struct lpfc_hba *phba = vport->phba; - if (phba->fc_plogi_cnt || phba->fc_adisc_cnt) { - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, + if (vport->fc_plogi_cnt || vport->fc_adisc_cnt) { + list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { if (ndlp->nlp_state == NLP_STE_PLOGI_ISSUE || ndlp->nlp_state == NLP_STE_ADISC_ISSUE) { @@ -1985,47 +2064,51 @@ lpfc_disc_flush_list(struct lpfc_hba * phba) void lpfc_disc_timeout(unsigned long ptr) { - struct lpfc_hba *phba = (struct lpfc_hba *)ptr; + struct lpfc_vport *vport = (struct lpfc_vport *) ptr; + struct lpfc_hba *phba = vport->phba; unsigned long flags = 0; if (unlikely(!phba)) return; - spin_lock_irqsave(phba->host->host_lock, flags); - if (!(phba->work_hba_events & WORKER_DISC_TMO)) { - phba->work_hba_events |= WORKER_DISC_TMO; + if ((vport->work_port_events & WORKER_DISC_TMO) == 0) { + spin_lock_irqsave(&vport->work_port_lock, flags); + vport->work_port_events |= WORKER_DISC_TMO; + spin_unlock_irqrestore(&vport->work_port_lock, flags); + if (phba->work_wait) wake_up(phba->work_wait); } - spin_unlock_irqrestore(phba->host->host_lock, flags); return; } static void -lpfc_disc_timeout_handler(struct lpfc_hba *phba) +lpfc_disc_timeout_handler(struct lpfc_vport *vport) { - struct lpfc_sli *psli; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct lpfc_hba *phba = vport->phba; + struct lpfc_sli *psli = &phba->sli; struct lpfc_nodelist *ndlp, *next_ndlp; - LPFC_MBOXQ_t *clearlambox, *initlinkmbox; + LPFC_MBOXQ_t *clearlambox, *initlinkmbox; int rc, clrlaerr = 0; - if (unlikely(!phba)) + if (!(vport->fc_flag & FC_DISC_TMO)) return; - if (!(phba->fc_flag & FC_DISC_TMO)) - return; - - psli = &phba->sli; - spin_lock_irq(phba->host->host_lock); - phba->fc_flag &= ~FC_DISC_TMO; - spin_unlock_irq(phba->host->host_lock); + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_DISC_TMO; + spin_unlock_irq(shost->host_lock); - switch (phba->hba_state) { + printk(KERN_ERR "%s (%d): link_state = %d, port_state = %d\n", + __FUNCTION__, __LINE__, phba->link_state, vport->port_state); + switch (vport->port_state) { case LPFC_LOCAL_CFG_LINK: - /* hba_state is identically LPFC_LOCAL_CFG_LINK while waiting for FAN */ - /* FAN timeout */ + /* port_state is identically LPFC_LOCAL_CFG_LINK while waiting for + * FAN + */ + /* FAN timeout */ lpfc_printf_log(phba, KERN_WARNING, LOG_DISCOVERY, @@ -2033,27 +2116,27 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) phba->brd_no); /* Start discovery by sending FLOGI, clean up old rpis */ - list_for_each_entry_safe(ndlp, next_ndlp, &phba->fc_nodes, + list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { if (ndlp->nlp_state != NLP_STE_NPR_NODE) continue; if (ndlp->nlp_type & NLP_FABRIC) { /* Clean up the ndlp on Fabric connections */ - lpfc_drop_node(phba, ndlp); + lpfc_drop_node(vport, ndlp); } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { /* Fail outstanding IO now since device * is marked for PLOGI. */ - lpfc_unreg_rpi(phba, ndlp); + lpfc_unreg_rpi(vport, ndlp); } } - phba->hba_state = LPFC_FLOGI; - lpfc_set_disctmo(phba); - lpfc_initial_flogi(phba); + vport->port_state = LPFC_FLOGI; + lpfc_set_disctmo(vport); + lpfc_initial_flogi(vport); break; case LPFC_FLOGI: - /* hba_state is identically LPFC_FLOGI while waiting for FLOGI cmpl */ + /* port_state is identically LPFC_FLOGI while waiting for FLOGI cmpl */ /* Initial FLOGI timeout */ lpfc_printf_log(phba, KERN_ERR, @@ -2066,10 +2149,10 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) */ /* FLOGI failed, so just use loop map to make discovery list */ - lpfc_disc_list_loopmap(phba); + lpfc_disc_list_loopmap(vport); /* Start discovery */ - lpfc_disc_start(phba); + lpfc_disc_start(vport); break; case LPFC_FABRIC_CFG_LINK: @@ -2080,11 +2163,11 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) "login\n", phba->brd_no); /* Next look for NameServer ndlp */ - ndlp = lpfc_findnode_did(phba, NameServer_DID); + ndlp = lpfc_findnode_did(vport, NameServer_DID); if (ndlp) lpfc_nlp_put(ndlp); /* Start discovery */ - lpfc_disc_start(phba); + lpfc_disc_start(vport); break; case LPFC_NS_QRY: @@ -2093,17 +2176,17 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) "%d:0224 NameServer Query timeout " "Data: x%x x%x\n", phba->brd_no, - phba->fc_ns_retry, LPFC_MAX_NS_RETRY); + vport->fc_ns_retry, LPFC_MAX_NS_RETRY); - ndlp = lpfc_findnode_did(phba, NameServer_DID); + ndlp = lpfc_findnode_did(vport, NameServer_DID); if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { - if (phba->fc_ns_retry < LPFC_MAX_NS_RETRY) { + if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) { /* Try it one more time */ - rc = lpfc_ns_cmd(phba, ndlp, SLI_CTNS_GID_FT); + rc = lpfc_ns_cmd(vport, ndlp, SLI_CTNS_GID_FT); if (rc == 0) break; } - phba->fc_ns_retry = 0; + vport->fc_ns_retry = 0; } /* Nothing to authenticate, so CLEAR_LA right now */ @@ -2114,13 +2197,16 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) "%d:0226 Device Discovery " "completion error\n", phba->brd_no); - phba->hba_state = LPFC_HBA_ERROR; + phba->link_state = LPFC_HBA_ERROR; break; } - phba->hba_state = LPFC_CLEAR_LA; + phba->link_state = LPFC_CLEAR_LA; lpfc_clear_la(phba, clearlambox); + printk(KERN_ERR "%s (%d): do clear_la\n", + __FUNCTION__, __LINE__); clearlambox->mbox_cmpl = lpfc_mbx_cmpl_clear_la; + clearlambox->vport = vport; rc = lpfc_sli_issue_mbox(phba, clearlambox, (MBX_NOWAIT | MBX_STOP_IOCB)); if (rc == MBX_NOT_FINISHED) { @@ -2136,7 +2222,7 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) "%d:0206 Device Discovery " "completion error\n", phba->brd_no); - phba->hba_state = LPFC_HBA_ERROR; + phba->link_state = LPFC_HBA_ERROR; break; } @@ -2159,7 +2245,8 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) LOG_DISCOVERY, "%d:0227 Node Authentication timeout\n", phba->brd_no); - lpfc_disc_flush_list(phba); + lpfc_disc_flush_list(vport); + clearlambox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!clearlambox) { clrlaerr = 1; @@ -2167,12 +2254,15 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) "%d:0207 Device Discovery " "completion error\n", phba->brd_no); - phba->hba_state = LPFC_HBA_ERROR; + phba->link_state = LPFC_HBA_ERROR; break; } - phba->hba_state = LPFC_CLEAR_LA; + phba->link_state = LPFC_CLEAR_LA; lpfc_clear_la(phba, clearlambox); + printk(KERN_ERR "%s (%d): do clear_la\n", + __FUNCTION__, __LINE__); clearlambox->mbox_cmpl = lpfc_mbx_cmpl_clear_la; + clearlambox->vport = vport; rc = lpfc_sli_issue_mbox(phba, clearlambox, (MBX_NOWAIT | MBX_STOP_IOCB)); if (rc == MBX_NOT_FINISHED) { @@ -2181,40 +2271,73 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) } break; - case LPFC_CLEAR_LA: - /* CLEAR LA timeout */ - lpfc_printf_log(phba, - KERN_ERR, - LOG_DISCOVERY, - "%d:0228 CLEAR LA timeout\n", - phba->brd_no); - clrlaerr = 1; - break; - - case LPFC_HBA_READY: - if (phba->fc_flag & FC_RSCN_MODE) { + case LPFC_VPORT_READY: + if (vport->fc_flag & FC_RSCN_MODE) { lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, "%d:0231 RSCN timeout Data: x%x x%x\n", phba->brd_no, - phba->fc_ns_retry, LPFC_MAX_NS_RETRY); + vport->fc_ns_retry, LPFC_MAX_NS_RETRY); /* Cleanup any outstanding ELS commands */ - lpfc_els_flush_cmd(phba); + lpfc_els_flush_cmd(vport); - lpfc_els_flush_rscn(phba); - lpfc_disc_flush_list(phba); + lpfc_els_flush_rscn(vport); + lpfc_disc_flush_list(vport); } break; + + case LPFC_STATE_UNKNOWN: + case LPFC_NS_REG: + case LPFC_BUILD_DISC_LIST: + lpfc_printf_log(phba, + KERN_ERR, + LOG_DISCOVERY, + "%d:0229 Unexpected discovery timeout, vport " + "State x%x\n", + vport->port_state, + phba->brd_no); + + break; + } + + switch (phba->link_state) { + case LPFC_CLEAR_LA: + /* CLEAR LA timeout */ + lpfc_printf_log(phba, + KERN_ERR, + LOG_DISCOVERY, + "%d:0228 CLEAR LA timeout\n", + phba->brd_no); + clrlaerr = 1; + break; + + case LPFC_LINK_UNKNOWN: + case LPFC_WARM_START: + case LPFC_INIT_START: + case LPFC_INIT_MBX_CMDS: + case LPFC_LINK_DOWN: + case LPFC_LINK_UP: + case LPFC_HBA_ERROR: + lpfc_printf_log(phba, + KERN_ERR, + LOG_DISCOVERY, + "%d:0230 Unexpected timeout, hba link " + "state x%x\n", + phba->brd_no, phba->link_state); + clrlaerr = 1; + break; } if (clrlaerr) { - lpfc_disc_flush_list(phba); + lpfc_disc_flush_list(vport); 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; + printk(KERN_ERR "%s (%d): vport ready\n", + __FUNCTION__, __LINE__); + vport->port_state = LPFC_VPORT_READY; } return; @@ -2227,37 +2350,29 @@ lpfc_disc_timeout_handler(struct lpfc_hba *phba) * handed off to the SLI layer. */ void -lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba * phba, LPFC_MBOXQ_t * pmb) +lpfc_mbx_cmpl_fdmi_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { - struct lpfc_sli *psli; - MAILBOX_t *mb; - struct lpfc_dmabuf *mp; - struct lpfc_nodelist *ndlp; - - psli = &phba->sli; - mb = &pmb->mb; - - ndlp = (struct lpfc_nodelist *) pmb->context2; - mp = (struct lpfc_dmabuf *) (pmb->context1); + MAILBOX_t *mb = &pmb->mb; + struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); + struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; + struct lpfc_vport *vport = pmb->vport; pmb->context1 = NULL; ndlp->nlp_rpi = mb->un.varWords[0]; ndlp->nlp_type |= NLP_FABRIC; - lpfc_nlp_set_state(phba, ndlp, NLP_STE_UNMAPPED_NODE); + lpfc_nlp_set_state(vport, ndlp, NLP_STE_UNMAPPED_NODE); - /* Start issuing Fabric-Device Management Interface (FDMI) - * command to 0xfffffa (FDMI well known port) + /* + * Start issuing Fabric-Device Management Interface (FDMI) command to + * 0xfffffa (FDMI well known port) or Delay issuing FDMI command if + * fdmi-on=2 (supporting RPA/hostnmae) */ - if (phba->cfg_fdmi_on == 1) { - lpfc_fdmi_cmd(phba, ndlp, SLI_MGMT_DHBA); - } else { - /* - * Delay issuing FDMI command if fdmi-on=2 - * (supporting RPA/hostnmae) - */ - mod_timer(&phba->fc_fdmitmo, jiffies + HZ * 60); - } + + if (phba->cfg_fdmi_on == 1) + lpfc_fdmi_cmd(vport, ndlp, SLI_MGMT_DHBA); + else + mod_timer(&vport->fc_fdmitmo, jiffies + HZ * 60); /* Mailbox took a reference to the node */ lpfc_nlp_put(ndlp); @@ -2283,16 +2398,12 @@ lpfc_filter_by_wwpn(struct lpfc_nodelist *ndlp, void *param) sizeof(ndlp->nlp_portname)) == 0; } -/* - * Search node lists for a remote port matching filter criteria - * Caller needs to hold host_lock before calling this routine. - */ struct lpfc_nodelist * -__lpfc_find_node(struct lpfc_hba *phba, node_filter filter, void *param) +__lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) { struct lpfc_nodelist *ndlp; - list_for_each_entry(ndlp, &phba->fc_nodes, nlp_listp) { + list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { if (ndlp->nlp_state != NLP_STE_UNUSED_NODE && filter(ndlp, param)) return ndlp; @@ -2305,54 +2416,58 @@ __lpfc_find_node(struct lpfc_hba *phba, node_filter filter, void *param) * This routine is used when the caller does NOT have host_lock. */ struct lpfc_nodelist * -lpfc_find_node(struct lpfc_hba *phba, node_filter filter, void *param) +lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) { + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp; - spin_lock_irq(phba->host->host_lock); - ndlp = __lpfc_find_node(phba, filter, param); - spin_unlock_irq(phba->host->host_lock); + spin_lock_irq(shost->host_lock); + ndlp = __lpfc_find_node(vport, filter, param); + spin_unlock_irq(shost->host_lock); return ndlp; } /* * This routine looks up the ndlp lists for the given RPI. If rpi found it - * returns the node list pointer else return NULL. + * returns the node list element pointer else return NULL. */ struct lpfc_nodelist * -__lpfc_findnode_rpi(struct lpfc_hba *phba, uint16_t rpi) +__lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi) { - return __lpfc_find_node(phba, lpfc_filter_by_rpi, &rpi); + return __lpfc_find_node(vport, lpfc_filter_by_rpi, &rpi); } struct lpfc_nodelist * -lpfc_findnode_rpi(struct lpfc_hba * phba, uint16_t rpi) +lpfc_findnode_rpi(struct lpfc_vport *vport, uint16_t rpi) { + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp; - spin_lock_irq(phba->host->host_lock); - ndlp = __lpfc_findnode_rpi(phba, rpi); - spin_unlock_irq(phba->host->host_lock); + spin_lock_irq(shost->host_lock); + ndlp = __lpfc_findnode_rpi(vport, rpi); + spin_unlock_irq(shost->host_lock); return ndlp; } /* * This routine looks up the ndlp lists for the given WWPN. If WWPN found it - * returns the node list pointer else return NULL. + * returns the node element list pointer else return NULL. */ struct lpfc_nodelist * -lpfc_findnode_wwpn(struct lpfc_hba *phba, struct lpfc_name *wwpn) +lpfc_findnode_wwpn(struct lpfc_vport *vport, struct lpfc_name *wwpn) { + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp; - spin_lock_irq(phba->host->host_lock); - ndlp = __lpfc_find_node(phba, lpfc_filter_by_wwpn, wwpn); - spin_unlock_irq(phba->host->host_lock); + spin_lock_irq(shost->host_lock); + ndlp = __lpfc_find_node(vport, lpfc_filter_by_wwpn, wwpn); + spin_unlock_irq(shost->host_lock); return NULL; } void -lpfc_nlp_init(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did) +lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, + uint32_t did) { memset(ndlp, 0, sizeof (struct lpfc_nodelist)); INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); @@ -2360,7 +2475,7 @@ lpfc_nlp_init(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp, uint32_t did) ndlp->nlp_delayfunc.function = lpfc_els_retry_delay; ndlp->nlp_delayfunc.data = (unsigned long)ndlp; ndlp->nlp_DID = did; - ndlp->nlp_phba = phba; + ndlp->vport = vport; ndlp->nlp_sid = NLP_NO_SID; INIT_LIST_HEAD(&ndlp->nlp_listp); kref_init(&ndlp->kref); @@ -2372,8 +2487,8 @@ lpfc_nlp_release(struct kref *kref) { struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist, kref); - lpfc_nlp_remove(ndlp->nlp_phba, ndlp); - mempool_free(ndlp, ndlp->nlp_phba->nlp_mem_pool); + lpfc_nlp_remove(ndlp->vport, ndlp); + mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool); } struct lpfc_nodelist * -- cgit v1.2.2 From ed957684294618602b48f1950b0c9bbcb036583f Mon Sep 17 00:00:00 2001 From: James Smart Date: Sun, 17 Jun 2007 19:56:37 -0500 Subject: [SCSI] lpfc: NPIV: add SLI-3 interface NPIV support is only available via new adapter interface extensions, termed SLI-3. This interface changes some of the basic behaviors such as command and response ring element sizes and data structures, as well as a change in buffer posting. Note: the new firmware extensions are found only on our mid-range and enterprise 4Gig adapters - so NPIV support is available only on these newer adapters. The latest firmware can be downloaded from the Emulex support page. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_hbadisc.c | 79 ++++++++++------------------------------ 1 file changed, 20 insertions(+), 59 deletions(-) (limited to 'drivers/scsi/lpfc/lpfc_hbadisc.c') diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index dee875ee6165..20b2a4905daa 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -232,9 +232,9 @@ static void lpfc_work_done(struct lpfc_hba *phba) { struct lpfc_sli_ring *pring; - int i; uint32_t ha_copy, control, work_port_events; struct lpfc_vport *vport; + int i; spin_lock_irq(&phba->hbalock); ha_copy = phba->work_ha; @@ -303,9 +303,9 @@ check_work_wait_done(struct lpfc_hba *phba) struct lpfc_vport *vport = phba->pport; int rc = 0; - if (!vport) return 0; + spin_lock_irq(&phba->hbalock); if (phba->work_ha || @@ -354,6 +354,7 @@ lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2, uint32_t evt) { struct lpfc_work_evt *evtp; + unsigned long flags; /* * All Mailbox completions and LPFC_ELS_RING rcv ring IOCB events will @@ -367,11 +368,11 @@ lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2, evtp->evt_arg2 = arg2; evtp->evt = evt; - spin_lock_irq(&phba->hbalock); + spin_lock_irqsave(&phba->hbalock, flags); list_add_tail(&evtp->evt_listp, &phba->work_list); if (phba->work_wait) wake_up(phba->work_wait); - spin_unlock_irq(&phba->hbalock); + spin_unlock_irqrestore(&phba->hbalock, flags); return 1; } @@ -401,6 +402,7 @@ lpfc_linkdown(struct lpfc_hba *phba) mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (mb) { lpfc_unreg_did(phba, 0xffffffff, mb); + mb->vport = vport; mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; if (lpfc_sli_issue_mbox(phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB)) == MBX_NOT_FINISHED) { @@ -433,6 +435,7 @@ lpfc_linkdown(struct lpfc_hba *phba) if (mb) { lpfc_config_link(phba, mb); mb->mbox_cmpl=lpfc_sli_def_mbox_cmpl; + mb->vport = vport; if (lpfc_sli_issue_mbox(phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB)) == MBX_NOT_FINISHED) { @@ -550,15 +553,11 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) spin_unlock_irq(shost->host_lock); } - printk(KERN_ERR "%s (%d): vport ready\n", - __FUNCTION__, __LINE__); vport->port_state = LPFC_VPORT_READY; out: /* Device Discovery completes */ - lpfc_printf_log(phba, - KERN_INFO, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, "%d:0225 Device Discovery completes\n", phba->brd_no); @@ -632,8 +631,6 @@ out: phba->brd_no, vport->port_state); lpfc_clear_la(phba, pmb); - printk(KERN_ERR "%s (%d): do clear_la\n", - __FUNCTION__, __LINE__); pmb->mbox_cmpl = lpfc_mbx_cmpl_clear_la; pmb->vport = vport; rc = lpfc_sli_issue_mbox(phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB)); @@ -643,8 +640,6 @@ out: 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; - printk(KERN_ERR "%s (%d): vport ready\n", - __FUNCTION__, __LINE__); vport->port_state = LPFC_VPORT_READY; } return; @@ -702,8 +697,6 @@ out: struct lpfc_sli_ring *next_ring = &psli->ring[psli->next_ring]; lpfc_clear_la(phba, pmb); - printk(KERN_ERR "%s (%d): do clear_la\n", - __FUNCTION__, __LINE__); pmb->mbox_cmpl = lpfc_mbx_cmpl_clear_la; pmb->vport = vport; if (lpfc_sli_issue_mbox(phba, pmb, (MBX_NOWAIT | MBX_STOP_IOCB)) @@ -713,8 +706,6 @@ out: extra_ring->flag &= ~LPFC_STOP_IOCB_EVENT; fcp_ring->flag &= ~LPFC_STOP_IOCB_EVENT; next_ring->flag &= ~LPFC_STOP_IOCB_EVENT; - printk(KERN_ERR "%s (%d): vport ready\n", - __FUNCTION__, __LINE__); vport->port_state = LPFC_VPORT_READY; } } else { @@ -875,12 +866,9 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) /* Check for error */ if (mb->mbxStatus) { - lpfc_printf_log(phba, - KERN_INFO, - LOG_LINK_EVENT, + lpfc_printf_log(phba, KERN_INFO, LOG_LINK_EVENT, "%d:1307 READ_LA mbox error x%x state x%x\n", - phba->brd_no, - mb->mbxStatus, vport->port_state); + phba->brd_no, mb->mbxStatus, vport->port_state); lpfc_mbx_issue_link_down(phba); phba->link_state = LPFC_HBA_ERROR; goto lpfc_mbx_cmpl_read_la_free_mbuf; @@ -955,7 +943,6 @@ lpfc_mbx_cmpl_reg_login(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; - pmb->context1 = NULL; /* Good status, call state machine */ @@ -1553,6 +1540,7 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (mbox) { lpfc_unreg_login(phba, ndlp->nlp_rpi, mbox); + mbox->vport = vport; mbox->mbox_cmpl=lpfc_sli_def_mbox_cmpl; rc = lpfc_sli_issue_mbox (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); @@ -1925,8 +1913,6 @@ lpfc_disc_start(struct lpfc_vport *vport) if (vport->port_state < LPFC_VPORT_READY && !clear_la_pending) { if (vport->port_type == LPFC_PHYSICAL_PORT) { /* If we get here, there is nothing to ADISC */ - printk(KERN_ERR "%s (%d): do clear_la\n", - __FUNCTION__, __LINE__); lpfc_issue_clear_la(phba, vport); } else if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) { @@ -1940,8 +1926,6 @@ lpfc_disc_start(struct lpfc_vport *vport) vport->fc_flag &= ~FC_NDISC_ACTIVE; spin_unlock_irq(shost->host_lock); } - printk(KERN_ERR "%s (%d): vport ready\n", - __FUNCTION__, __LINE__); vport->port_state = LPFC_VPORT_READY; } } else { @@ -2095,13 +2079,10 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) if (!(vport->fc_flag & FC_DISC_TMO)) return; - spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_DISC_TMO; spin_unlock_irq(shost->host_lock); - printk(KERN_ERR "%s (%d): link_state = %d, port_state = %d\n", - __FUNCTION__, __LINE__, phba->link_state, vport->port_state); switch (vport->port_state) { case LPFC_LOCAL_CFG_LINK: @@ -2109,9 +2090,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) * FAN */ /* FAN timeout */ - lpfc_printf_log(phba, - KERN_WARNING, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_WARNING, LOG_DISCOVERY, "%d:0221 FAN timeout\n", phba->brd_no); @@ -2138,9 +2117,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) case LPFC_FLOGI: /* port_state is identically LPFC_FLOGI while waiting for FLOGI cmpl */ /* Initial FLOGI timeout */ - lpfc_printf_log(phba, - KERN_ERR, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, "%d:0222 Initial FLOGI timeout\n", phba->brd_no); @@ -2203,8 +2180,6 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) phba->link_state = LPFC_CLEAR_LA; lpfc_clear_la(phba, clearlambox); - printk(KERN_ERR "%s (%d): do clear_la\n", - __FUNCTION__, __LINE__); clearlambox->mbox_cmpl = lpfc_mbx_cmpl_clear_la; clearlambox->vport = vport; rc = lpfc_sli_issue_mbox(phba, clearlambox, @@ -2230,6 +2205,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) lpfc_init_link(phba, initlinkmbox, phba->cfg_topology, phba->cfg_link_speed); initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0; + initlinkmbox->vport = vport; rc = lpfc_sli_issue_mbox(phba, initlinkmbox, (MBX_NOWAIT | MBX_STOP_IOCB)); lpfc_set_loopback_flag(phba); @@ -2240,9 +2216,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) case LPFC_DISC_AUTH: /* Node Authentication timeout */ - lpfc_printf_log(phba, - KERN_ERR, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, "%d:0227 Node Authentication timeout\n", phba->brd_no); lpfc_disc_flush_list(vport); @@ -2259,8 +2233,6 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) } phba->link_state = LPFC_CLEAR_LA; lpfc_clear_la(phba, clearlambox); - printk(KERN_ERR "%s (%d): do clear_la\n", - __FUNCTION__, __LINE__); clearlambox->mbox_cmpl = lpfc_mbx_cmpl_clear_la; clearlambox->vport = vport; rc = lpfc_sli_issue_mbox(phba, clearlambox, @@ -2273,9 +2245,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) case LPFC_VPORT_READY: if (vport->fc_flag & FC_RSCN_MODE) { - lpfc_printf_log(phba, - KERN_ERR, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, "%d:0231 RSCN timeout Data: x%x x%x\n", phba->brd_no, vport->fc_ns_retry, LPFC_MAX_NS_RETRY); @@ -2291,13 +2261,10 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) case LPFC_STATE_UNKNOWN: case LPFC_NS_REG: case LPFC_BUILD_DISC_LIST: - lpfc_printf_log(phba, - KERN_ERR, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, "%d:0229 Unexpected discovery timeout, vport " "State x%x\n", - vport->port_state, - phba->brd_no); + vport->port_state, phba->brd_no); break; } @@ -2305,9 +2272,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) switch (phba->link_state) { case LPFC_CLEAR_LA: /* CLEAR LA timeout */ - lpfc_printf_log(phba, - KERN_ERR, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, "%d:0228 CLEAR LA timeout\n", phba->brd_no); clrlaerr = 1; @@ -2320,9 +2285,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) case LPFC_LINK_DOWN: case LPFC_LINK_UP: case LPFC_HBA_ERROR: - lpfc_printf_log(phba, - KERN_ERR, - LOG_DISCOVERY, + lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, "%d:0230 Unexpected timeout, hba link " "state x%x\n", phba->brd_no, phba->link_state); @@ -2335,8 +2298,6 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) 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; - printk(KERN_ERR "%s (%d): vport ready\n", - __FUNCTION__, __LINE__); vport->port_state = LPFC_VPORT_READY; } -- cgit v1.2.2 From 92d7f7b0cde3ad2260e7462b40867b57efd49851 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sun, 17 Jun 2007 19:56:38 -0500 Subject: [SCSI] lpfc: NPIV: add NPIV support on top of SLI-3 NPIV support is added to the driver. It utilizes the interfaces of the fc transport for the creation and deletion of vports. Within the driver, a new Scsi_Host is created for each NPIV instance, and is paired with a new instance of a FC port. This allows N FC Port elements to share a single Adapter. Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_hbadisc.c | 1140 +++++++++++++++++++++++++------------- 1 file changed, 745 insertions(+), 395 deletions(-) (limited to 'drivers/scsi/lpfc/lpfc_hbadisc.c') diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 20b2a4905daa..94ee9675b5b0 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -36,6 +36,7 @@ #include "lpfc.h" #include "lpfc_logmsg.h" #include "lpfc_crtn.h" +#include "lpfc_vport.h" /* AlpaArray for assignment of scsid for scan-down and bind_method */ static uint8_t lpfcAlpaArray[] = { @@ -96,50 +97,68 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) int warn_on = 0; struct lpfc_hba *phba; struct lpfc_vport *vport; + int put_node; + int put_rport; rdata = rport->dd_data; ndlp = rdata->pnode; if (!ndlp) { - if (rport->roles & FC_RPORT_ROLE_FCP_TARGET) + if (rport->scsi_target_id != -1) { printk(KERN_ERR "Cannot find remote node" - " for rport in dev_loss_tmo_callbk x%x\n", - rport->port_id); + " for rport in dev_loss_tmo_callbk x%x\n", + rport->port_id); + } return; } - if (ndlp->nlp_state == NLP_STE_MAPPED_NODE) + if (ndlp->nlp_type & NLP_FABRIC) { + /* We will clean up these Nodes in linkup */ + put_node = rdata->pnode != NULL; + put_rport = ndlp->rport != NULL; + rdata->pnode = NULL; + ndlp->rport = NULL; + if (put_node) + lpfc_nlp_put(ndlp); + if (put_rport) + put_device(&rport->dev); return; + } name = (uint8_t *)&ndlp->nlp_portname; vport = ndlp->vport; phba = vport->phba; + if (!(vport->load_flag & FC_UNLOADING) && + ndlp->nlp_state == NLP_STE_MAPPED_NODE) + return; + + if (ndlp->nlp_sid != NLP_NO_SID) { warn_on = 1; /* flush the target */ lpfc_sli_abort_iocb(phba, &phba->sli.ring[phba->sli.fcp_ring], - ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT); + ndlp->nlp_sid, 0, 0, LPFC_CTX_TGT); } if (vport->load_flag & FC_UNLOADING) warn_on = 0; if (warn_on) { lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "%d:0203 Devloss timeout on " + "%d (%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, + phba->brd_no, vport->vpi, *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 Devloss timeout on " + "%d (%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, + phba->brd_no, vport->vpi, *name, *(name+1), *(name+2), *(name+3), *(name+4), *(name+5), *(name+6), *(name+7), ndlp->nlp_DID, ndlp->nlp_flag, @@ -152,12 +171,23 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); else { + put_node = rdata->pnode != NULL; + put_rport = ndlp->rport != NULL; rdata->pnode = NULL; ndlp->rport = NULL; - lpfc_nlp_put(ndlp); - put_device(&rport->dev); + if (put_node) + lpfc_nlp_put(ndlp); + if (put_rport) + put_device(&rport->dev); } + return; +} + +void +lpfc_worker_wake_up(struct lpfc_hba *phba) +{ + wake_up(phba->work_wait); return; } @@ -166,6 +196,7 @@ lpfc_work_list_done(struct lpfc_hba *phba) { struct lpfc_work_evt *evtp = NULL; struct lpfc_nodelist *ndlp; + struct lpfc_vport *vport; int free_evt; spin_lock_irq(&phba->hbalock); @@ -175,10 +206,23 @@ lpfc_work_list_done(struct lpfc_hba *phba) spin_unlock_irq(&phba->hbalock); free_evt = 1; switch (evtp->evt) { + case LPFC_EVT_DEV_LOSS: + free_evt = 0; /* evt is part of ndlp */ + ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1); + vport = ndlp->vport; + if (!vport) + break; + if (!(vport->load_flag & FC_UNLOADING) && + !(ndlp->nlp_flag & NLP_DELAY_TMO) && + !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) { + lpfc_disc_state_machine(vport, ndlp, NULL, + NLP_EVT_DEVICE_RM); + } + break; case LPFC_EVT_ELS_RETRY: ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1); lpfc_els_retry_delay_handler(ndlp); - free_evt = 0; + free_evt = 0; /* evt is part of ndlp */ break; case LPFC_EVT_ONLINE: if (phba->link_state < LPFC_LINK_DOWN) @@ -250,24 +294,43 @@ lpfc_work_done(struct lpfc_hba *phba) if (ha_copy & HA_LATT) lpfc_handle_latt(phba); - vport = phba->pport; + spin_lock_irq(&phba->hbalock); + list_for_each_entry(vport, &phba->port_list, listentry) { + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - work_port_events = vport->work_port_events; + if (!scsi_host_get(shost)) { + continue; + } + spin_unlock_irq(&phba->hbalock); + work_port_events = vport->work_port_events; - if (work_port_events & WORKER_DISC_TMO) - lpfc_disc_timeout_handler(vport); + if (work_port_events & WORKER_DISC_TMO) + lpfc_disc_timeout_handler(vport); - if (work_port_events & WORKER_ELS_TMO) - lpfc_els_timeout_handler(vport); + if (work_port_events & WORKER_ELS_TMO) + lpfc_els_timeout_handler(vport); - if (work_port_events & WORKER_MBOX_TMO) - lpfc_mbox_timeout_handler(phba); + if (work_port_events & WORKER_MBOX_TMO) + lpfc_mbox_timeout_handler(phba); - if (work_port_events & WORKER_FDMI_TMO) - lpfc_fdmi_timeout_handler(vport); + if (work_port_events & WORKER_FABRIC_BLOCK_TMO) + lpfc_unblock_fabric_iocbs(phba); - spin_lock_irq(&phba->hbalock); - vport->work_port_events &= ~work_port_events; + if (work_port_events & WORKER_FDMI_TMO) + lpfc_fdmi_timeout_handler(vport); + + if (work_port_events & WORKER_RAMP_DOWN_QUEUE) + lpfc_ramp_down_queue_handler(phba); + + if (work_port_events & WORKER_RAMP_UP_QUEUE) + lpfc_ramp_up_queue_handler(phba); + + spin_lock_irq(&vport->work_port_lock); + vport->work_port_events &= ~work_port_events; + spin_unlock_irq(&vport->work_port_lock); + scsi_host_put(shost); + spin_lock_irq(&phba->hbalock); + } spin_unlock_irq(&phba->hbalock); for (i = 0; i < phba->sli.num_rings; i++, ha_copy >>= 4) { @@ -300,24 +363,41 @@ lpfc_work_done(struct lpfc_hba *phba) static int check_work_wait_done(struct lpfc_hba *phba) { - struct lpfc_vport *vport = phba->pport; - int rc = 0; - - if (!vport) - return 0; + struct lpfc_vport *vport; + struct lpfc_sli_ring *pring; + int i, rc = 0; spin_lock_irq(&phba->hbalock); + list_for_each_entry(vport, &phba->port_list, listentry) { + if (vport->work_port_events) { + rc = 1; + goto exit; + } + } - if (phba->work_ha || - vport->work_port_events || - (!list_empty(&phba->work_list)) || - kthread_should_stop()) + if (phba->work_ha || (!list_empty(&phba->work_list)) || + kthread_should_stop()) { rc = 1; + goto exit; + } + for (i = 0; i < phba->sli.num_rings; i++) { + pring = &phba->sli.ring[i]; + if (pring->flag & LPFC_DEFERRED_RING_EVENT) { + rc = 1; + goto exit; + } + } +exit: + if (rc) + phba->work_found++; + else + phba->work_found = 0; spin_unlock_irq(&phba->hbalock); return rc; } + int lpfc_do_work(void *p) { @@ -327,11 +407,13 @@ lpfc_do_work(void *p) set_user_nice(current, -20); phba->work_wait = &work_waitq; + phba->work_found = 0; while (1) { rc = wait_event_interruptible(work_waitq, - check_work_wait_done(phba)); + check_work_wait_done(phba)); + BUG_ON(rc); if (kthread_should_stop()) @@ -339,6 +421,17 @@ lpfc_do_work(void *p) lpfc_work_done(phba); + /* If there is alot of slow ring work, like during link up + * check_work_wait_done() may cause this thread to not give + * up the CPU for very long periods of time. This may cause + * soft lockups or other problems. To avoid these situations + * give up the CPU here after LPFC_MAX_WORKER_ITERATION + * consecutive iterations. + */ + if (phba->work_found >= LPFC_MAX_WORKER_ITERATION) { + phba->work_found = 0; + schedule(); + } } phba->work_wait = NULL; return 0; @@ -360,7 +453,7 @@ lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2, * All Mailbox completions and LPFC_ELS_RING rcv ring IOCB events will * be queued to worker thread for processing */ - evtp = kmalloc(sizeof(struct lpfc_work_evt), GFP_KERNEL); + evtp = kmalloc(sizeof(struct lpfc_work_evt), GFP_ATOMIC); if (!evtp) return 0; @@ -371,37 +464,94 @@ lpfc_workq_post_event(struct lpfc_hba *phba, void *arg1, void *arg2, spin_lock_irqsave(&phba->hbalock, flags); list_add_tail(&evtp->evt_listp, &phba->work_list); if (phba->work_wait) - wake_up(phba->work_wait); + lpfc_worker_wake_up(phba); spin_unlock_irqrestore(&phba->hbalock, flags); return 1; } +void +lpfc_cleanup_rpis(struct lpfc_vport *vport, int remove) +{ + struct lpfc_hba *phba = vport->phba; + struct lpfc_nodelist *ndlp, *next_ndlp; + int rc; + + list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { + if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) + continue; + + if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) + lpfc_unreg_rpi(vport, ndlp); + + /* Leave Fabric nodes alone on link down */ + if (!remove && ndlp->nlp_type & NLP_FABRIC) + continue; + rc = lpfc_disc_state_machine(vport, ndlp, NULL, + remove + ? NLP_EVT_DEVICE_RM + : NLP_EVT_DEVICE_RECOVERY); + } + if (phba->sli3_options & LPFC_SLI3_VPORT_TEARDOWN) { + lpfc_mbx_unreg_vpi(vport); + vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI; + } +} + +static void +lpfc_linkdown_port(struct lpfc_vport *vport) +{ + struct lpfc_nodelist *ndlp, *next_ndlp; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + + fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKDOWN, 0); + + /* Cleanup any outstanding RSCN activity */ + lpfc_els_flush_rscn(vport); + + /* Cleanup any outstanding ELS commands */ + lpfc_els_flush_cmd(vport); + + lpfc_cleanup_rpis(vport, 0); + + /* free any ndlp's on unused list */ + list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) + /* free any ndlp's in unused state */ + if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) + lpfc_drop_node(vport, ndlp); + + /* Turn off discovery timer if its running */ + lpfc_can_disctmo(vport); +} + int lpfc_linkdown(struct lpfc_hba *phba) { struct lpfc_vport *vport = phba->pport; struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_sli *psli; - struct lpfc_nodelist *ndlp, *next_ndlp; + struct lpfc_vport *port_iterator; LPFC_MBOXQ_t *mb; - int rc; - psli = &phba->sli; if (phba->link_state == LPFC_LINK_DOWN) { return 0; } spin_lock_irq(&phba->hbalock); - if (phba->link_state > LPFC_LINK_DOWN) + if (phba->link_state > LPFC_LINK_DOWN) { phba->link_state = LPFC_LINK_DOWN; + phba->pport->fc_flag &= ~FC_LBIT; + } spin_unlock_irq(&phba->hbalock); - fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKDOWN, 0); + list_for_each_entry(port_iterator, &phba->port_list, listentry) { + + /* Issue a LINK DOWN event to all nodes */ + lpfc_linkdown_port(port_iterator); + } /* Clean up any firmware default rpi's */ mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (mb) { - lpfc_unreg_did(phba, 0xffffffff, mb); + lpfc_unreg_did(phba, 0xffff, 0xffffffff, mb); mb->vport = vport; mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; if (lpfc_sli_issue_mbox(phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB)) @@ -410,31 +560,13 @@ lpfc_linkdown(struct lpfc_hba *phba) } } - /* Cleanup any outstanding RSCN activity */ - lpfc_els_flush_rscn(vport); - - /* Cleanup any outstanding ELS commands */ - lpfc_els_flush_cmd(vport); - - /* - * Issue a LINK DOWN event to all nodes. - */ - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - /* free any ndlp's on unused state */ - if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) - lpfc_drop_node(vport, ndlp); - else /* otherwise, force node recovery. */ - rc = lpfc_disc_state_machine(vport, ndlp, NULL, - NLP_EVT_DEVICE_RECOVERY); - } - /* Setup myDID for link up if we are in pt2pt mode */ - if (vport->fc_flag & FC_PT2PT) { - vport->fc_myDID = 0; + if (phba->pport->fc_flag & FC_PT2PT) { + phba->pport->fc_myDID = 0; mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (mb) { lpfc_config_link(phba, mb); - mb->mbox_cmpl=lpfc_sli_def_mbox_cmpl; + mb->mbox_cmpl = lpfc_sli_def_mbox_cmpl; mb->vport = vport; if (lpfc_sli_issue_mbox(phba, mb, (MBX_NOWAIT | MBX_STOP_IOCB)) @@ -443,66 +575,88 @@ lpfc_linkdown(struct lpfc_hba *phba) } } spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI); + phba->pport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI); spin_unlock_irq(shost->host_lock); } - spin_lock_irq(shost->host_lock); - vport->fc_flag &= ~FC_LBIT; - spin_unlock_irq(shost->host_lock); + return 0; +} - /* Turn off discovery timer if its running */ - lpfc_can_disctmo(vport); +static void +lpfc_linkup_cleanup_nodes(struct lpfc_vport *vport) +{ + struct lpfc_nodelist *ndlp; - /* Must process IOCBs on all rings to handle ABORTed I/Os */ - return 0; + list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { + if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) + continue; + + if (ndlp->nlp_type & NLP_FABRIC) { + /* On Linkup its safe to clean up the ndlp + * from Fabric connections. + */ + if (ndlp->nlp_DID != Fabric_DID) + lpfc_unreg_rpi(vport, ndlp); + lpfc_nlp_set_state(vport, ndlp, NLP_STE_NPR_NODE); + } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { + /* Fail outstanding IO now since device is + * marked for PLOGI. + */ + lpfc_unreg_rpi(vport, ndlp); + } + } } -static int -lpfc_linkup(struct lpfc_hba *phba) +static void +lpfc_linkup_port(struct lpfc_vport *vport) { - struct lpfc_vport *vport = phba->pport; - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_nodelist *ndlp, *next_ndlp; + struct lpfc_hba *phba = vport->phba; + + if ((vport->load_flag & FC_UNLOADING) != 0) + return; + + /* If NPIV is not enabled, only bring the physical port up */ + if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && + (vport != phba->pport)) + return; fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKUP, 0); spin_lock_irq(shost->host_lock); - phba->link_state = LPFC_LINK_UP; vport->fc_flag &= ~(FC_PT2PT | FC_PT2PT_PLOGI | FC_ABORT_DISCOVERY | FC_RSCN_MODE | FC_NLP_MORE | FC_RSCN_DISCOVERY); vport->fc_flag |= FC_NDISC_ACTIVE; vport->fc_ns_retry = 0; spin_unlock_irq(shost->host_lock); + if (vport->fc_flag & FC_LBIT) + lpfc_linkup_cleanup_nodes(vport); - if (vport->fc_flag & FC_LBIT) { - list_for_each_entry(ndlp, &vport->fc_nodes, nlp_listp) { - if (ndlp->nlp_state != NLP_STE_UNUSED_NODE) { - if (ndlp->nlp_type & NLP_FABRIC) { - /* - * On Linkup its safe to clean up the - * ndlp from Fabric connections. - */ - lpfc_nlp_set_state(vport, ndlp, - NLP_STE_UNUSED_NODE); - } else if (!(ndlp->nlp_flag & NLP_NPR_ADISC)) { - /* - * Fail outstanding IO now since - * device is marked for PLOGI. - */ - lpfc_unreg_rpi(vport, ndlp); - } - } - } - } - - /* free any ndlp's in unused state */ + /* free any ndlp's in unused state */ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, - nlp_listp) { + nlp_listp) if (ndlp->nlp_state == NLP_STE_UNUSED_NODE) lpfc_drop_node(vport, ndlp); +} + +static int +lpfc_linkup(struct lpfc_hba *phba) +{ + struct lpfc_vport *vport; + + phba->link_state = LPFC_LINK_UP; + + /* Unblock fabric iocbs if they are blocked */ + clear_bit(FABRIC_COMANDS_BLOCKED, &phba->bit_flags); + del_timer_sync(&phba->fabric_block_timer); + + list_for_each_entry(vport, &phba->port_list, listentry) { + lpfc_linkup_port(vport); } + if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) + lpfc_issue_clear_la(phba, phba->pport); return 0; } @@ -529,18 +683,28 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) /* Check for error */ if ((mb->mbxStatus) && (mb->mbxStatus != 0x1601)) { - /* CLEAR_LA mbox error state */ + /* CLEAR_LA mbox error state */ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, - "%d:0320 CLEAR_LA mbxStatus error x%x hba " + "%d (%d):0320 CLEAR_LA mbxStatus error x%x hba " "state x%x\n", - phba->brd_no, mb->mbxStatus, vport->port_state); + phba->brd_no, vport->vpi, mb->mbxStatus, + vport->port_state); phba->link_state = LPFC_HBA_ERROR; goto out; } - if (vport->fc_flag & FC_ABORT_DISCOVERY) - goto out; + if (vport->port_type == LPFC_PHYSICAL_PORT) + phba->link_state = LPFC_HBA_READY; + + spin_lock_irq(&phba->hbalock); + psli->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); + return; vport->num_disc_nodes = 0; /* go thru NPR nodes and issue ELS PLOGIs */ @@ -558,8 +722,8 @@ lpfc_mbx_cmpl_clear_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) out: /* Device Discovery completes */ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, - "%d:0225 Device Discovery completes\n", - phba->brd_no); + "%d (%d):0225 Device Discovery completes\n", + phba->brd_no, vport->vpi); mempool_free(pmb, phba->mbox_mem_pool); @@ -589,8 +753,6 @@ static void lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { struct lpfc_vport *vport = pmb->vport; - struct lpfc_sli *psli = &phba->sli; - int rc; if (pmb->mb.mbxStatus) goto out; @@ -606,49 +768,40 @@ lpfc_mbx_cmpl_local_config_link(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) */ lpfc_set_disctmo(vport); return; - } + } /* Start discovery by sending a FLOGI. port_state is identically * LPFC_FLOGI while waiting for FLOGI cmpl */ - vport->port_state = LPFC_FLOGI; - lpfc_set_disctmo(vport); - lpfc_initial_flogi(vport); + if (vport->port_state != LPFC_FLOGI) { + vport->port_state = LPFC_FLOGI; + lpfc_set_disctmo(vport); + lpfc_initial_flogi(vport); + } return; out: lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, - "%d:0306 CONFIG_LINK mbxStatus error x%x " + "%d (%d):0306 CONFIG_LINK mbxStatus error x%x " "HBA state x%x\n", - phba->brd_no, pmb->mb.mbxStatus, vport->port_state); + phba->brd_no, vport->vpi, pmb->mb.mbxStatus, + vport->port_state); - lpfc_linkdown(phba); + mempool_free(pmb, phba->mbox_mem_pool); - phba->link_state = LPFC_HBA_ERROR; + lpfc_linkdown(phba); lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "%d:0200 CONFIG_LINK bad hba state x%x\n", - phba->brd_no, vport->port_state); + "%d (%d):0200 CONFIG_LINK bad hba state x%x\n", + phba->brd_no, vport->vpi, vport->port_state); - lpfc_clear_la(phba, pmb); - pmb->mbox_cmpl = lpfc_mbx_cmpl_clear_la; - pmb->vport = vport; - 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(vport); - 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; - vport->port_state = LPFC_VPORT_READY; - } + lpfc_issue_clear_la(phba, vport); return; } static void lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { - struct lpfc_sli *psli = &phba->sli; MAILBOX_t *mb = &pmb->mb; struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) pmb->context1; struct lpfc_vport *vport = pmb->vport; @@ -658,12 +811,12 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (mb->mbxStatus) { /* READ_SPARAM mbox error state */ lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, - "%d:0319 READ_SPARAM mbxStatus error x%x " + "%d (%d):0319 READ_SPARAM mbxStatus error x%x " "hba state x%x>\n", - phba->brd_no, mb->mbxStatus, vport->port_state); + phba->brd_no, vport->vpi, mb->mbxStatus, + vport->port_state); lpfc_linkdown(phba); - phba->link_state = LPFC_HBA_ERROR; goto out; } @@ -675,12 +828,15 @@ lpfc_mbx_cmpl_read_sparam(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (phba->cfg_soft_wwpn) u64_to_wwn(phba->cfg_soft_wwpn, vport->fc_sparam.portName.u.wwn); - memcpy((uint8_t *) &vport->fc_nodename, - (uint8_t *) &vport->fc_sparam.nodeName, - sizeof (struct lpfc_name)); - memcpy((uint8_t *) &vport->fc_portname, - (uint8_t *) &vport->fc_sparam.portName, - sizeof (struct lpfc_name)); + memcpy(&vport->fc_nodename, &vport->fc_sparam.nodeName, + sizeof(vport->fc_nodename)); + memcpy(&vport->fc_portname, &vport->fc_sparam.portName, + sizeof(vport->fc_portname)); + if (vport->port_type == LPFC_PHYSICAL_PORT) { + memcpy(&phba->wwnn, &vport->fc_nodename, sizeof(phba->wwnn)); + memcpy(&phba->wwpn, &vport->fc_portname, sizeof(phba->wwnn)); + } + lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free(pmb, phba->mbox_mem_pool); @@ -690,35 +846,15 @@ out: pmb->context1 = NULL; lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); - if (phba->link_state != LPFC_CLEAR_LA) { - struct lpfc_sli_ring *extra_ring = - &psli->ring[psli->extra_ring]; - struct lpfc_sli_ring *fcp_ring = &psli->ring[psli->fcp_ring]; - struct lpfc_sli_ring *next_ring = &psli->ring[psli->next_ring]; - - lpfc_clear_la(phba, pmb); - pmb->mbox_cmpl = lpfc_mbx_cmpl_clear_la; - pmb->vport = vport; - 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(vport); - extra_ring->flag &= ~LPFC_STOP_IOCB_EVENT; - fcp_ring->flag &= ~LPFC_STOP_IOCB_EVENT; - next_ring->flag &= ~LPFC_STOP_IOCB_EVENT; - vport->port_state = LPFC_VPORT_READY; - } - } else { - mempool_free(pmb, phba->mbox_mem_pool); - } + lpfc_issue_clear_la(phba, vport); + mempool_free(pmb, phba->mbox_mem_pool); return; } static void -lpfc_mbx_process_link_up(struct lpfc_vport *vport, READ_LA_VAR *la) +lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) { - struct Scsi_Host *shost = lpfc_shost_from_vport(vport); - struct lpfc_hba *phba = vport->phba; + struct lpfc_vport *vport = phba->pport; LPFC_MBOXQ_t *sparam_mbox, *cfglink_mbox; int i; struct lpfc_dmabuf *mp; @@ -727,30 +863,32 @@ lpfc_mbx_process_link_up(struct lpfc_vport *vport, READ_LA_VAR *la) sparam_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); cfglink_mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - spin_lock_irq(shost->host_lock); + spin_lock_irq(&phba->hbalock); switch (la->UlnkSpeed) { - case LA_1GHZ_LINK: - phba->fc_linkspeed = LA_1GHZ_LINK; - break; - case LA_2GHZ_LINK: - phba->fc_linkspeed = LA_2GHZ_LINK; - break; - case LA_4GHZ_LINK: - phba->fc_linkspeed = LA_4GHZ_LINK; - break; - case LA_8GHZ_LINK: - phba->fc_linkspeed = LA_8GHZ_LINK; - break; - default: - phba->fc_linkspeed = LA_UNKNW_LINK; - break; + case LA_1GHZ_LINK: + phba->fc_linkspeed = LA_1GHZ_LINK; + break; + case LA_2GHZ_LINK: + phba->fc_linkspeed = LA_2GHZ_LINK; + break; + case LA_4GHZ_LINK: + phba->fc_linkspeed = LA_4GHZ_LINK; + break; + case LA_8GHZ_LINK: + phba->fc_linkspeed = LA_8GHZ_LINK; + break; + default: + phba->fc_linkspeed = LA_UNKNW_LINK; + break; } phba->fc_topology = la->topology; + phba->link_flag &= ~LS_NPIV_FAB_SUPPORTED; if (phba->fc_topology == TOPOLOGY_LOOP) { - /* Get Loop Map information */ + phba->sli3_options &= ~LPFC_SLI3_NPIV_ENABLED; + /* Get Loop Map information */ if (la->il) vport->fc_flag |= FC_LBIT; @@ -784,30 +922,35 @@ lpfc_mbx_process_link_up(struct lpfc_vport *vport, READ_LA_VAR *la) } /* Link Up Event ALPA map */ lpfc_printf_log(phba, - KERN_WARNING, - LOG_LINK_EVENT, - "%d:1304 Link Up Event " - "ALPA map Data: x%x " - "x%x x%x x%x\n", - phba->brd_no, - un.pa.wd1, un.pa.wd2, - un.pa.wd3, un.pa.wd4); + KERN_WARNING, + LOG_LINK_EVENT, + "%d:1304 Link Up Event " + "ALPA map Data: x%x " + "x%x x%x x%x\n", + phba->brd_no, + un.pa.wd1, un.pa.wd2, + un.pa.wd3, un.pa.wd4); } } } } else { + if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) { + if (phba->max_vpi && lpfc_npiv_enable && + (phba->sli_rev == 3)) + phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED; + } vport->fc_myDID = phba->fc_pref_DID; vport->fc_flag |= FC_LBIT; } - spin_unlock_irq(shost->host_lock); + spin_unlock_irq(&phba->hbalock); lpfc_linkup(phba); if (sparam_mbox) { - lpfc_read_sparam(phba, sparam_mbox); + lpfc_read_sparam(phba, sparam_mbox, 0); sparam_mbox->vport = vport; sparam_mbox->mbox_cmpl = lpfc_mbx_cmpl_read_sparam; rc = lpfc_sli_issue_mbox(phba, sparam_mbox, - (MBX_NOWAIT | MBX_STOP_IOCB)); + (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); @@ -815,7 +958,7 @@ lpfc_mbx_process_link_up(struct lpfc_vport *vport, READ_LA_VAR *la) mempool_free(sparam_mbox, phba->mbox_mem_pool); if (cfglink_mbox) mempool_free(cfglink_mbox, phba->mbox_mem_pool); - return; + goto out; } } @@ -825,10 +968,20 @@ lpfc_mbx_process_link_up(struct lpfc_vport *vport, READ_LA_VAR *la) cfglink_mbox->vport = vport; 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); + (MBX_NOWAIT | MBX_STOP_IOCB)); + if (rc != MBX_NOT_FINISHED) + return; + mempool_free(cfglink_mbox, phba->mbox_mem_pool); } +out: + lpfc_vport_set_state(vport, FC_VPORT_FAILED); + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + "%d (%d):0263 Discovery Mailbox error: state: 0x%x : %p %p\n", + phba->brd_no, vport->vpi, + vport->port_state, sparam_mbox, cfglink_mbox); + + lpfc_issue_clear_la(phba, vport); + return; } static void @@ -886,12 +1039,12 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) spin_unlock_irq(shost->host_lock); if (((phba->fc_eventTag + 1) < la->eventTag) || - (phba->fc_eventTag == la->eventTag)) { + (phba->fc_eventTag == la->eventTag)) { phba->fc_stat.LinkMultiEvent++; if (la->attType == AT_LINK_UP) if (phba->fc_eventTag != 0) lpfc_linkdown(phba); - } + } phba->fc_eventTag = la->eventTag; @@ -912,7 +1065,7 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) la->granted_AL_PA, la->UlnkSpeed, phba->alpa_map[0]); } - lpfc_mbx_process_link_up(vport, la); + lpfc_mbx_process_link_up(phba, la); } else { phba->fc_stat.LinkDown++; lpfc_printf_log(phba, KERN_ERR, LOG_LINK_EVENT, @@ -940,7 +1093,7 @@ void lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { struct lpfc_vport *vport = pmb->vport; - struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) pmb->context1; + struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) pmb->context2; pmb->context1 = NULL; @@ -955,6 +1108,100 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) return; } +static void +lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) +{ + MAILBOX_t *mb = &pmb->mb; + struct lpfc_vport *vport = pmb->vport; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + + switch (mb->mbxStatus) { + case 0x0011: + case 0x0020: + case 0x9700: + lpfc_printf_log(phba, KERN_INFO, LOG_NODE, + "%d (%d):0911 cmpl_unreg_vpi, " + "mb status = 0x%x\n", + phba->brd_no, vport->vpi, mb->mbxStatus); + break; + default: + phba->vpi_cnt--; + } + vport->unreg_vpi_cmpl = VPORT_OK; + mempool_free(pmb, phba->mbox_mem_pool); + /* + * This shost reference might have been taken at the beginning of + * lpfc_vport_delete() + */ + if (vport->load_flag & FC_UNLOADING) + scsi_host_put(shost); +} + +void +lpfc_mbx_unreg_vpi(struct lpfc_vport *vport) +{ + struct lpfc_hba *phba = vport->phba; + LPFC_MBOXQ_t *mbox; + int rc; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (!mbox) + return; + + lpfc_unreg_vpi(phba, vport->vpi, mbox); + mbox->vport = vport; + mbox->mbox_cmpl = lpfc_mbx_cmpl_unreg_vpi; + rc = lpfc_sli_issue_mbox(phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); + if (rc == MBX_NOT_FINISHED) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_VPORT, + "%d (%d):1800 Could not issue unreg_vpi\n", + phba->brd_no, vport->vpi); + mempool_free(mbox, phba->mbox_mem_pool); + vport->unreg_vpi_cmpl = VPORT_ERROR; + } +} + +static void +lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) +{ + struct lpfc_vport *vport = pmb->vport; + struct Scsi_Host *shost = lpfc_shost_from_vport(vport); + MAILBOX_t *mb = &pmb->mb; + + switch (mb->mbxStatus) { + case 0x0011: + case 0x9601: + case 0x9602: + lpfc_printf_log(phba, KERN_INFO, LOG_NODE, + "%d (%d):0912 cmpl_reg_vpi, mb status = 0x%x\n", + phba->brd_no, vport->vpi, mb->mbxStatus); + lpfc_vport_set_state(vport, FC_VPORT_FAILED); + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~(FC_FABRIC | FC_PUBLIC_LOOP); + spin_unlock_irq(shost->host_lock); + vport->fc_myDID = 0; + goto out; + } + phba->vpi_cnt++; + + vport->num_disc_nodes = 0; + /* go thru NPR list and issue ELS PLOGIs */ + if (vport->fc_npr_cnt) + lpfc_els_disc_plogi(vport); + + if (!vport->num_disc_nodes) { + spin_lock_irq(shost->host_lock); + vport->fc_flag &= ~FC_NDISC_ACTIVE; + spin_unlock_irq(shost->host_lock); + lpfc_can_disctmo(vport); + } + vport->port_state = LPFC_VPORT_READY; + +out: + mempool_free(pmb, phba->mbox_mem_pool); + return; +} + /* * This routine handles processing a Fabric REG_LOGIN mailbox * command upon completion. It is setup in the LPFC_MBOXQ @@ -964,10 +1211,11 @@ lpfc_mbx_cmpl_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) void lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) { - struct lpfc_vport *vport = pmb->vport; + struct lpfc_vport *vport = pmb->vport; + struct lpfc_vport *next_vport; MAILBOX_t *mb = &pmb->mb; struct lpfc_dmabuf *mp = (struct lpfc_dmabuf *) (pmb->context1); - struct lpfc_nodelist *ndlp, *ndlp_fdmi; + struct lpfc_nodelist *ndlp; ndlp = (struct lpfc_nodelist *) pmb->context2; pmb->context1 = NULL; @@ -979,11 +1227,20 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) mempool_free(pmb, phba->mbox_mem_pool); lpfc_nlp_put(ndlp); - /* FLOGI failed, so just use loop map to make discovery list */ - lpfc_disc_list_loopmap(vport); + if (phba->fc_topology == TOPOLOGY_LOOP) { + /* FLOGI failed, use loop map to make discovery list */ + lpfc_disc_list_loopmap(vport); + + /* Start discovery */ + lpfc_disc_start(vport); + return; + } + + lpfc_vport_set_state(vport, FC_VPORT_FAILED); + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX, + "%d (%d):0258 Register Fabric login error: 0x%x\n", + phba->brd_no, vport->vpi, mb->mbxStatus); - /* Start discovery */ - lpfc_disc_start(vport); return; } @@ -994,47 +1251,25 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) lpfc_nlp_put(ndlp); /* Drop the reference from the mbox */ if (vport->port_state == LPFC_FABRIC_CFG_LINK) { - /* This NPort has been assigned an NPort_ID by the fabric as a - * result of the completed fabric login. Issue a State Change - * Registration (SCR) ELS request to the fabric controller - * (SCR_DID) so that this NPort gets RSCN events from the - * fabric. - */ - lpfc_issue_els_scr(vport, SCR_DID, 0); - - ndlp = lpfc_findnode_did(vport, 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 - * the NameServer - */ - ndlp = mempool_alloc(phba->nlp_mem_pool, GFP_KERNEL); - if (!ndlp) { - lpfc_disc_start(vport); - lpfc_mbuf_free(phba, mp->virt, mp->phys); - kfree(mp); - mempool_free(pmb, phba->mbox_mem_pool); - return; - } else { - lpfc_nlp_init(vport, ndlp, NameServer_DID); - ndlp->nlp_type |= NLP_FABRIC; - } - } + list_for_each_entry(next_vport, &phba->port_list, listentry) { + if (next_vport->port_type == LPFC_PHYSICAL_PORT) + continue; - lpfc_nlp_set_state(vport, ndlp, NLP_STE_PLOGI_ISSUE); - lpfc_issue_els_plogi(vport, NameServer_DID, 0); - if (phba->cfg_fdmi_on) { - ndlp_fdmi = mempool_alloc(phba->nlp_mem_pool, - GFP_KERNEL); - if (ndlp_fdmi) { - lpfc_nlp_init(vport, ndlp_fdmi, FDMI_DID); - ndlp_fdmi->nlp_type |= NLP_FABRIC; - ndlp_fdmi->nlp_state = NLP_STE_PLOGI_ISSUE; - lpfc_issue_els_plogi(vport, FDMI_DID, 0); + if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) + lpfc_initial_fdisc(next_vport); + else { + if (phba->sli3_options & + LPFC_SLI3_NPIV_ENABLED) { + lpfc_vport_set_state(vport, + FC_VPORT_NO_FABRIC_SUPP); + lpfc_printf_log(phba, KERN_ERR, LOG_ELS, + "%d (%d):0259 No NPIV Fabric " + "support\n", + phba->brd_no, vport->vpi); + } } } + lpfc_do_scr_ns_plogi(phba, vport); } lpfc_mbuf_free(phba, mp->virt, mp->phys); @@ -1058,20 +1293,28 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) struct lpfc_vport *vport = pmb->vport; if (mb->mbxStatus) { +out: lpfc_nlp_put(ndlp); lpfc_mbuf_free(phba, mp->virt, mp->phys); kfree(mp); mempool_free(pmb, phba->mbox_mem_pool); lpfc_drop_node(vport, ndlp); - /* - * RegLogin failed, so just use loop map to make discovery - * list - */ - lpfc_disc_list_loopmap(vport); + if (phba->fc_topology == TOPOLOGY_LOOP) { + /* + * RegLogin failed, use loop map to make discovery + * list + */ + lpfc_disc_list_loopmap(vport); - /* Start discovery */ - lpfc_disc_start(vport); + /* Start discovery */ + lpfc_disc_start(vport); + return; + } + lpfc_vport_set_state(vport, FC_VPORT_FAILED); + lpfc_printf_log(phba, KERN_ERR, LOG_ELS, + "%d (%d):0260 Register NameServer error: 0x%x\n", + phba->brd_no, vport->vpi, mb->mbxStatus); return; } @@ -1083,17 +1326,21 @@ lpfc_mbx_cmpl_ns_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (vport->port_state < LPFC_VPORT_READY) { /* Link up discovery requires Fabric registration. */ - lpfc_ns_cmd(vport, ndlp, SLI_CTNS_RNN_ID); - lpfc_ns_cmd(vport, ndlp, SLI_CTNS_RSNN_NN); - lpfc_ns_cmd(vport, ndlp, SLI_CTNS_RFT_ID); - lpfc_ns_cmd(vport, ndlp, SLI_CTNS_RFF_ID); + lpfc_ns_cmd(vport, SLI_CTNS_RFF_ID, 0, 0); /* Do this first! */ + lpfc_ns_cmd(vport, SLI_CTNS_RNN_ID, 0, 0); + lpfc_ns_cmd(vport, SLI_CTNS_RSNN_NN, 0, 0); + lpfc_ns_cmd(vport, SLI_CTNS_RSPN_ID, 0, 0); + lpfc_ns_cmd(vport, SLI_CTNS_RFT_ID, 0, 0); + + /* Issue SCR just before NameServer GID_FT Query */ + lpfc_issue_els_scr(vport, SCR_DID, 0); } vport->fc_ns_retry = 0; /* Good status, issue CT Request to NameServer */ - if (lpfc_ns_cmd(vport, ndlp, SLI_CTNS_GID_FT)) { + if (lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, 0, 0)) { /* Cannot issue NameServer Query, so finish up discovery */ - lpfc_disc_start(vport); + goto out; } lpfc_nlp_put(ndlp); @@ -1127,7 +1374,7 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) * registered the port. */ if (ndlp->rport && ndlp->rport->dd_data && - *(struct lpfc_rport_data **) ndlp->rport->dd_data) { + ((struct lpfc_rport_data *) ndlp->rport->dd_data)->pnode == ndlp) { lpfc_nlp_put(ndlp); } ndlp->rport = rport = fc_remote_port_add(shost, 0, &rport_ids); @@ -1147,16 +1394,16 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET; if (ndlp->nlp_type & NLP_FCP_INITIATOR) rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR; + del_timer_sync(&ndlp->nlp_initiator_tmr); 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)) { + (rport->scsi_target_id < LPFC_MAX_TARGET)) { ndlp->nlp_sid = rport->scsi_target_id; } - return; } @@ -1164,14 +1411,6 @@ static void lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp) { struct fc_rport *rport = ndlp->rport; - struct lpfc_rport_data *rdata = rport->dd_data; - - if (rport->scsi_target_id == -1) { - ndlp->rport = NULL; - rdata->pnode = NULL; - lpfc_nlp_put(ndlp); - put_device(&rport->dev); - } fc_remote_port_delete(rport); @@ -1377,9 +1616,9 @@ lpfc_set_disctmo(struct lpfc_vport *vport) /* Start Discovery Timer state */ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, - "%d:0247 Start Discovery Timer state x%x " + "%d (%d):0247 Start Discovery Timer state x%x " "Data: x%x x%lx x%x x%x\n", - phba->brd_no, vport->port_state, tmo, + phba->brd_no, vport->vpi, vport->port_state, tmo, (unsigned long)&vport->fc_disctmo, vport->fc_plogi_cnt, vport->fc_adisc_cnt); @@ -1409,10 +1648,11 @@ lpfc_can_disctmo(struct lpfc_vport *vport) /* Cancel Discovery Timer state */ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, - "%d:0248 Cancel Discovery Timer state x%x " + "%d (%d):0248 Cancel Discovery Timer state x%x " "Data: x%x x%x x%x\n", - phba->brd_no, vport->port_state, vport->fc_flag, - vport->fc_plogi_cnt, vport->fc_adisc_cnt); + phba->brd_no, vport->vpi, vport->port_state, + vport->fc_flag, vport->fc_plogi_cnt, + vport->fc_adisc_cnt); return 0; } @@ -1429,6 +1669,11 @@ lpfc_check_sli_ndlp(struct lpfc_hba *phba, { struct lpfc_sli *psli = &phba->sli; IOCB_t *icmd = &iocb->iocb; + struct lpfc_vport *vport = ndlp->vport; + + if (iocb->vport != vport) + return 0; + if (pring->ringno == LPFC_ELS_RING) { switch (icmd->ulpCommand) { case CMD_GEN_REQUEST64_CR: @@ -1446,7 +1691,7 @@ lpfc_check_sli_ndlp(struct lpfc_hba *phba, } 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)) { + (ndlp->nlp_flag & NLP_DELAY_TMO)) { return 0; } if (icmd->ulpContext == (volatile ushort)ndlp->nlp_rpi) { @@ -1472,6 +1717,8 @@ lpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) IOCB_t *icmd; uint32_t rpi, i; + lpfc_fabric_abort_nport(ndlp); + /* * Everything that matches on txcmplq will be returned * by firmware with a no rpi error. @@ -1490,8 +1737,8 @@ lpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) * Check to see if iocb matches the nport we are * looking for */ - if ((lpfc_check_sli_ndlp - (phba, pring, iocb, ndlp))) { + if ((lpfc_check_sli_ndlp(phba, pring, iocb, + ndlp))) { /* It matches, so deque and call compl with an error */ list_move_tail(&iocb->list, @@ -1505,7 +1752,7 @@ lpfc_no_rpi(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) while (!list_empty(&completions)) { iocb = list_get_first(&completions, struct lpfc_iocbq, list); - list_del(&iocb->list); + list_del_init(&iocb->list); if (!iocb->iocb_cmpl) lpfc_sli_release_iocbq(phba, iocb); @@ -1539,11 +1786,11 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) if (ndlp->nlp_rpi) { mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (mbox) { - lpfc_unreg_login(phba, ndlp->nlp_rpi, mbox); + lpfc_unreg_login(phba, vport->vpi, ndlp->nlp_rpi, mbox); mbox->vport = vport; - mbox->mbox_cmpl=lpfc_sli_def_mbox_cmpl; - rc = lpfc_sli_issue_mbox - (phba, mbox, (MBX_NOWAIT | MBX_STOP_IOCB)); + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + rc = lpfc_sli_issue_mbox(phba, mbox, + (MBX_NOWAIT | MBX_STOP_IOCB)); if (rc == MBX_NOT_FINISHED) mempool_free(mbox, phba->mbox_mem_pool); } @@ -1554,6 +1801,50 @@ lpfc_unreg_rpi(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) return 0; } +void +lpfc_unreg_all_rpis(struct lpfc_vport *vport) +{ + struct lpfc_hba *phba = vport->phba; + LPFC_MBOXQ_t *mbox; + int rc; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (mbox) { + lpfc_unreg_login(phba, vport->vpi, 0xffff, mbox); + mbox->vport = vport; + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + rc = lpfc_sli_issue_mbox(phba, mbox, + (MBX_NOWAIT | MBX_STOP_IOCB)); + if (rc == MBX_NOT_FINISHED) { + mempool_free(mbox, phba->mbox_mem_pool); + } + } +} + +void +lpfc_unreg_default_rpis(struct lpfc_vport *vport) +{ + struct lpfc_hba *phba = vport->phba; + LPFC_MBOXQ_t *mbox; + int rc; + + mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (mbox) { + lpfc_unreg_did(phba, vport->vpi, 0xffffffff, mbox); + mbox->vport = vport; + mbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; + rc = lpfc_sli_issue_mbox(phba, mbox, + (MBX_NOWAIT | MBX_STOP_IOCB)); + if (rc == MBX_NOT_FINISHED) { + lpfc_printf_log(phba, KERN_ERR, LOG_MBOX | LOG_VPORT, + "%d (%d):1815 Could not issue " + "unreg_did (default rpis)\n", + phba->brd_no, vport->vpi); + mempool_free(mbox, phba->mbox_mem_pool); + } + } +} + /* * Free resources associated with LPFC_NODELIST entry * so it can be freed. @@ -1568,9 +1859,9 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) /* Cleanup node for NPort */ lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0900 Cleanup node for NPort x%x " + "%d (%d):0900 Cleanup node for NPort x%x " "Data: x%x x%x x%x\n", - phba->brd_no, ndlp->nlp_DID, ndlp->nlp_flag, + phba->brd_no, vport->vpi, ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_state, ndlp->nlp_rpi); lpfc_dequeue_node(vport, ndlp); @@ -1587,7 +1878,7 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) spin_lock_irq(&phba->hbalock); list_for_each_entry_safe(mb, nextmb, &phba->sli.mboxq, list) { if ((mb->mb.mbxCommand == MBX_REG_LOGIN64) && - (ndlp == (struct lpfc_nodelist *) mb->context2)) { + (ndlp == (struct lpfc_nodelist *) mb->context2)) { mp = (struct lpfc_dmabuf *) (mb->context1); if (mp) { __lpfc_mbuf_free(phba, mp->virt, mp->phys); @@ -1607,9 +1898,12 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) ndlp->nlp_last_elscmd = 0; del_timer_sync(&ndlp->nlp_delayfunc); + del_timer_sync(&ndlp->nlp_initiator_tmr); if (!list_empty(&ndlp->els_retry_evt.evt_listp)) list_del_init(&ndlp->els_retry_evt.evt_listp); + if (!list_empty(&ndlp->dev_loss_evt.evt_listp)) + list_del_init(&ndlp->dev_loss_evt.evt_listp); lpfc_unreg_rpi(vport, ndlp); @@ -1633,12 +1927,11 @@ lpfc_nlp_remove(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_cleanup_node(vport, ndlp); /* - * We should never get here with a non-NULL ndlp->rport. But - * if we do, drop the reference to the rport. That seems the - * intelligent thing to do. + * We can get here with a non-NULL ndlp->rport because when we + * unregister a rport we don't break the rport/node linkage. So if we + * do, make sure we don't leaving any dangling pointers behind. */ - if (ndlp->rport && !(vport->load_flag & FC_UNLOADING)) { - put_device(&ndlp->rport->dev); + if (ndlp->rport) { rdata = ndlp->rport->dd_data; rdata->pnode = NULL; ndlp->rport = NULL; @@ -1709,9 +2002,9 @@ __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) ((uint32_t) ndlp->nlp_type << 8) | ((uint32_t) ndlp->nlp_rpi & 0xff)); lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0929 FIND node DID " + "%d (%d):0929 FIND node DID " " Data: x%p x%x x%x x%x\n", - phba->brd_no, + phba->brd_no, vport->vpi, ndlp, ndlp->nlp_DID, ndlp->nlp_flag, data1); return ndlp; @@ -1720,8 +2013,8 @@ __lpfc_findnode_did(struct lpfc_vport *vport, uint32_t did) /* FIND node did NOT FOUND */ lpfc_printf_log(phba, KERN_INFO, LOG_NODE, - "%d:0932 FIND node did x%x NOT FOUND.\n", - phba->brd_no, did); + "%d (%d):0932 FIND node did x%x NOT FOUND.\n", + phba->brd_no, vport->vpi, did); return NULL; } @@ -1835,6 +2128,14 @@ lpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport) struct lpfc_sli_ring *next_ring = &psli->ring[psli->next_ring]; int rc; + /* + * if it's not a physical port or if we already send + * clear_la then don't send it. + */ + if ((phba->link_state >= LPFC_CLEAR_LA) || + (vport->port_type != LPFC_PHYSICAL_PORT)) + return; + /* Link up discovery */ if ((mbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL)) != NULL) { phba->link_state = LPFC_CLEAR_LA; @@ -1849,7 +2150,26 @@ lpfc_issue_clear_la(struct lpfc_hba *phba, struct lpfc_vport *vport) extra_ring->flag &= ~LPFC_STOP_IOCB_EVENT; fcp_ring->flag &= ~LPFC_STOP_IOCB_EVENT; next_ring->flag &= ~LPFC_STOP_IOCB_EVENT; - vport->port_state = LPFC_VPORT_READY; + phba->link_state = LPFC_HBA_ERROR; + } + } +} + +/* Reg_vpi to tell firmware to resume normal operations */ +void +lpfc_issue_reg_vpi(struct lpfc_hba *phba, struct lpfc_vport *vport) +{ + LPFC_MBOXQ_t *regvpimbox; + + regvpimbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); + if (regvpimbox) { + lpfc_reg_vpi(phba, vport->vpi, vport->fc_myDID, regvpimbox); + regvpimbox->mbox_cmpl = lpfc_mbx_cmpl_reg_vpi; + regvpimbox->vport = vport; + if (lpfc_sli_issue_mbox(phba, regvpimbox, + (MBX_NOWAIT | MBX_STOP_IOCB)) + == MBX_NOT_FINISHED) { + mempool_free(regvpimbox, phba->mbox_mem_pool); } } } @@ -1860,7 +2180,6 @@ lpfc_disc_start(struct lpfc_vport *vport) { struct Scsi_Host *shost = lpfc_shost_from_vport(vport); struct lpfc_hba *phba = vport->phba; - struct lpfc_nodelist *ndlp, *next_ndlp; uint32_t num_sent; uint32_t clear_la_pending; int did_changed; @@ -1888,21 +2207,11 @@ lpfc_disc_start(struct lpfc_vport *vport) /* Start Discovery state */ lpfc_printf_log(phba, KERN_INFO, LOG_DISCOVERY, - "%d:0202 Start Discovery hba state x%x " + "%d (%d):0202 Start Discovery hba state x%x " "Data: x%x x%x x%x\n", - phba->brd_no, vport->port_state, vport->fc_flag, - vport->fc_plogi_cnt, vport->fc_adisc_cnt); - - /* If our did changed, we MUST do PLOGI */ - list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, nlp_listp) { - if (ndlp->nlp_state == NLP_STE_NPR_NODE && - (ndlp->nlp_flag & NLP_NPR_2B_DISC) != 0 && - did_changed) { - spin_lock_irq(shost->host_lock); - ndlp->nlp_flag &= ~NLP_NPR_ADISC; - spin_unlock_irq(shost->host_lock); - } - } + phba->brd_no, vport->vpi, vport->port_state, + vport->fc_flag, vport->fc_plogi_cnt, + vport->fc_adisc_cnt); /* First do ADISCs - if any */ num_sent = lpfc_els_disc_adisc(vport); @@ -1910,12 +2219,26 @@ lpfc_disc_start(struct lpfc_vport *vport) if (num_sent) return; + /* + * For SLI3, cmpl_reg_vpi will set port_state to READY, and + * continue discovery. + */ + if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && + !(vport->fc_flag & FC_RSCN_MODE)) { + lpfc_issue_reg_vpi(phba, vport); + return; + } + + /* + * For SLI2, we need to set port_state to READY and continue + * discovery. + */ if (vport->port_state < LPFC_VPORT_READY && !clear_la_pending) { - if (vport->port_type == LPFC_PHYSICAL_PORT) { /* If we get here, there is nothing to ADISC */ + if (vport->port_type == LPFC_PHYSICAL_PORT) lpfc_issue_clear_la(phba, vport); - } else if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) { + if (!(vport->fc_flag & FC_ABORT_DISCOVERY)) { vport->num_disc_nodes = 0; /* go thru NPR nodes and issue ELS PLOGIs */ if (vport->fc_npr_cnt) @@ -1925,9 +2248,10 @@ lpfc_disc_start(struct lpfc_vport *vport) spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_NDISC_ACTIVE; spin_unlock_irq(shost->host_lock); + lpfc_can_disctmo(vport); } - vport->port_state = LPFC_VPORT_READY; } + vport->port_state = LPFC_VPORT_READY; } else { /* Next do PLOGIs - if any */ num_sent = lpfc_els_disc_plogi(vport); @@ -1944,6 +2268,7 @@ lpfc_disc_start(struct lpfc_vport *vport) spin_lock_irq(shost->host_lock); vport->fc_flag &= ~FC_RSCN_MODE; spin_unlock_irq(shost->host_lock); + lpfc_can_disctmo(vport); } else lpfc_els_handle_rscn(vport); } @@ -1999,7 +2324,7 @@ lpfc_free_tx(struct lpfc_hba *phba, struct lpfc_nodelist *ndlp) while (!list_empty(&completions)) { iocb = list_get_first(&completions, struct lpfc_iocbq, list); - list_del(&iocb->list); + list_del_init(&iocb->list); if (!iocb->iocb_cmpl) lpfc_sli_release_iocbq(phba, iocb); @@ -2030,6 +2355,14 @@ lpfc_disc_flush_list(struct lpfc_vport *vport) } } +void +lpfc_cleanup_discovery_resources(struct lpfc_vport *vport) +{ + lpfc_els_flush_rscn(vport); + lpfc_els_flush_cmd(vport); + lpfc_disc_flush_list(vport); +} + /*****************************************************************************/ /* * NAME: lpfc_disc_timeout @@ -2060,8 +2393,10 @@ lpfc_disc_timeout(unsigned long ptr) vport->work_port_events |= WORKER_DISC_TMO; spin_unlock_irqrestore(&vport->work_port_lock, flags); + spin_lock_irqsave(&phba->hbalock, flags); if (phba->work_wait) - wake_up(phba->work_wait); + lpfc_worker_wake_up(phba); + spin_unlock_irqrestore(&phba->hbalock, flags); } return; } @@ -2073,7 +2408,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) struct lpfc_hba *phba = vport->phba; struct lpfc_sli *psli = &phba->sli; struct lpfc_nodelist *ndlp, *next_ndlp; - LPFC_MBOXQ_t *clearlambox, *initlinkmbox; + LPFC_MBOXQ_t *initlinkmbox; int rc, clrlaerr = 0; if (!(vport->fc_flag & FC_DISC_TMO)) @@ -2091,8 +2426,8 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) */ /* FAN timeout */ lpfc_printf_log(phba, KERN_WARNING, LOG_DISCOVERY, - "%d:0221 FAN timeout\n", - phba->brd_no); + "%d (%d):0221 FAN timeout\n", + phba->brd_no, vport->vpi); /* Start discovery by sending FLOGI, clean up old rpis */ list_for_each_entry_safe(ndlp, next_ndlp, &vport->fc_nodes, @@ -2109,17 +2444,21 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) lpfc_unreg_rpi(vport, ndlp); } } - vport->port_state = LPFC_FLOGI; - lpfc_set_disctmo(vport); - lpfc_initial_flogi(vport); + if (vport->port_state != LPFC_FLOGI) { + vport->port_state = LPFC_FLOGI; + lpfc_set_disctmo(vport); + lpfc_initial_flogi(vport); + } break; + case LPFC_FDISC: case LPFC_FLOGI: /* port_state is identically LPFC_FLOGI while waiting for FLOGI cmpl */ /* Initial FLOGI timeout */ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "%d:0222 Initial FLOGI timeout\n", - phba->brd_no); + "%d (%d):0222 Initial %s timeout\n", + phba->brd_no, vport->vpi, + vport->vpi ? "FLOGI" : "FDISC"); /* Assume no Fabric and go on with discovery. * Check for outstanding ELS FLOGI to abort. @@ -2136,8 +2475,9 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) /* hba_state is identically LPFC_FABRIC_CFG_LINK while waiting for NameServer login */ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "%d:0223 Timeout while waiting for NameServer " - "login\n", phba->brd_no); + "%d (%d):0223 Timeout while waiting for " + "NameServer login\n", + phba->brd_no, vport->vpi); /* Next look for NameServer ndlp */ ndlp = lpfc_findnode_did(vport, NameServer_DID); @@ -2150,53 +2490,40 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) case LPFC_NS_QRY: /* Check for wait for NameServer Rsp timeout */ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "%d:0224 NameServer Query timeout " + "%d (%d):0224 NameServer Query timeout " "Data: x%x x%x\n", - phba->brd_no, + phba->brd_no, vport->vpi, vport->fc_ns_retry, LPFC_MAX_NS_RETRY); - ndlp = lpfc_findnode_did(vport, NameServer_DID); - if (ndlp && ndlp->nlp_state == NLP_STE_UNMAPPED_NODE) { - if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) { - /* Try it one more time */ - rc = lpfc_ns_cmd(vport, ndlp, SLI_CTNS_GID_FT); - if (rc == 0) - break; - } - vport->fc_ns_retry = 0; - } - - /* Nothing to authenticate, so CLEAR_LA right now */ - clearlambox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!clearlambox) { - clrlaerr = 1; - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "%d:0226 Device Discovery " - "completion error\n", - phba->brd_no); - phba->link_state = LPFC_HBA_ERROR; - break; + if (vport->fc_ns_retry < LPFC_MAX_NS_RETRY) { + /* Try it one more time */ + vport->fc_ns_retry++; + rc = lpfc_ns_cmd(vport, SLI_CTNS_GID_FT, + vport->fc_ns_retry, 0); + if (rc == 0) + break; } + vport->fc_ns_retry = 0; - phba->link_state = LPFC_CLEAR_LA; - lpfc_clear_la(phba, clearlambox); - clearlambox->mbox_cmpl = lpfc_mbx_cmpl_clear_la; - clearlambox->vport = vport; - rc = lpfc_sli_issue_mbox(phba, clearlambox, - (MBX_NOWAIT | MBX_STOP_IOCB)); - if (rc == MBX_NOT_FINISHED) { - mempool_free(clearlambox, phba->mbox_mem_pool); - clrlaerr = 1; - break; + /* + * Discovery is over. + * set port_state to PORT_READY if SLI2. + * cmpl_reg_vpi will set port_state to READY for SLI3. + */ + if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) + lpfc_issue_reg_vpi(phba, vport); + else { /* NPIV Not enabled */ + lpfc_issue_clear_la(phba, vport); + vport->port_state = LPFC_VPORT_READY; } /* Setup and issue mailbox INITIALIZE LINK command */ initlinkmbox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); if (!initlinkmbox) { lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "%d:0206 Device Discovery " + "%d (%d):0206 Device Discovery " "completion error\n", - phba->brd_no); + phba->brd_no, vport->vpi); phba->link_state = LPFC_HBA_ERROR; break; } @@ -2206,6 +2533,7 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) phba->cfg_link_speed); initlinkmbox->mb.un.varInitLnk.lipsr_AL_PA = 0; initlinkmbox->vport = vport; + initlinkmbox->mbox_cmpl = lpfc_sli_def_mbox_cmpl; rc = lpfc_sli_issue_mbox(phba, initlinkmbox, (MBX_NOWAIT | MBX_STOP_IOCB)); lpfc_set_loopback_flag(phba); @@ -2217,37 +2545,28 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) case LPFC_DISC_AUTH: /* Node Authentication timeout */ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "%d:0227 Node Authentication timeout\n", - phba->brd_no); + "%d (%d):0227 Node Authentication timeout\n", + phba->brd_no, vport->vpi); lpfc_disc_flush_list(vport); - clearlambox = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL); - if (!clearlambox) { - clrlaerr = 1; - lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "%d:0207 Device Discovery " - "completion error\n", - phba->brd_no); - phba->link_state = LPFC_HBA_ERROR; - break; - } - phba->link_state = LPFC_CLEAR_LA; - lpfc_clear_la(phba, clearlambox); - clearlambox->mbox_cmpl = lpfc_mbx_cmpl_clear_la; - clearlambox->vport = vport; - rc = lpfc_sli_issue_mbox(phba, clearlambox, - (MBX_NOWAIT | MBX_STOP_IOCB)); - if (rc == MBX_NOT_FINISHED) { - mempool_free(clearlambox, phba->mbox_mem_pool); - clrlaerr = 1; + /* + * set port_state to PORT_READY if SLI2. + * cmpl_reg_vpi will set port_state to READY for SLI3. + */ + if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) + lpfc_issue_reg_vpi(phba, vport); + else { /* NPIV Not enabled */ + lpfc_issue_clear_la(phba, vport); + vport->port_state = LPFC_VPORT_READY; } break; case LPFC_VPORT_READY: if (vport->fc_flag & FC_RSCN_MODE) { lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "%d:0231 RSCN timeout Data: x%x x%x\n", - phba->brd_no, + "%d (%d):0231 RSCN timeout Data: x%x " + "x%x\n", + phba->brd_no, vport->vpi, vport->fc_ns_retry, LPFC_MAX_NS_RETRY); /* Cleanup any outstanding ELS commands */ @@ -2258,23 +2577,21 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) } break; - case LPFC_STATE_UNKNOWN: - case LPFC_NS_REG: - case LPFC_BUILD_DISC_LIST: + default: lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "%d:0229 Unexpected discovery timeout, vport " - "State x%x\n", - vport->port_state, phba->brd_no); + "%d (%d):0229 Unexpected discovery timeout, " + "vport State x%x\n", + phba->brd_no, vport->vpi, vport->port_state); break; } switch (phba->link_state) { case LPFC_CLEAR_LA: - /* CLEAR LA timeout */ + /* CLEAR LA timeout */ lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "%d:0228 CLEAR LA timeout\n", - phba->brd_no); + "%d (%d):0228 CLEAR LA timeout\n", + phba->brd_no, vport->vpi); clrlaerr = 1; break; @@ -2286,11 +2603,14 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) case LPFC_LINK_UP: case LPFC_HBA_ERROR: lpfc_printf_log(phba, KERN_ERR, LOG_DISCOVERY, - "%d:0230 Unexpected timeout, hba link " + "%d (%d):0230 Unexpected timeout, hba link " "state x%x\n", - phba->brd_no, phba->link_state); + phba->brd_no, vport->vpi, phba->link_state); clrlaerr = 1; break; + + case LPFC_HBA_READY: + break; } if (clrlaerr) { @@ -2374,7 +2694,7 @@ __lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) /* * Search node lists for a remote port matching filter criteria - * This routine is used when the caller does NOT have host_lock. + * Caller needs to hold host_lock before calling this routine. */ struct lpfc_nodelist * lpfc_find_node(struct lpfc_vport *vport, node_filter filter, void *param) @@ -2426,12 +2746,42 @@ lpfc_findnode_wwpn(struct lpfc_vport *vport, struct lpfc_name *wwpn) return NULL; } +void +lpfc_dev_loss_delay(unsigned long ptr) +{ + struct lpfc_nodelist *ndlp = (struct lpfc_nodelist *) ptr; + struct lpfc_vport *vport = ndlp->vport; + struct lpfc_hba *phba = vport->phba; + struct lpfc_work_evt *evtp = &ndlp->dev_loss_evt; + unsigned long flags; + + evtp = &ndlp->dev_loss_evt; + + spin_lock_irqsave(&phba->hbalock, flags); + if (!list_empty(&evtp->evt_listp)) { + spin_unlock_irqrestore(&phba->hbalock, flags); + return; + } + + evtp->evt_arg1 = ndlp; + evtp->evt = LPFC_EVT_DEV_LOSS; + list_add_tail(&evtp->evt_listp, &phba->work_list); + if (phba->work_wait) + lpfc_worker_wake_up(phba); + spin_unlock_irqrestore(&phba->hbalock, flags); + return; +} + void lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, uint32_t did) { memset(ndlp, 0, sizeof (struct lpfc_nodelist)); INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); + INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp); + init_timer(&ndlp->nlp_initiator_tmr); + ndlp->nlp_initiator_tmr.function = lpfc_dev_loss_delay; + ndlp->nlp_initiator_tmr.data = (unsigned long)ndlp; init_timer(&ndlp->nlp_delayfunc); ndlp->nlp_delayfunc.function = lpfc_els_retry_delay; ndlp->nlp_delayfunc.data = (unsigned long)ndlp; -- cgit v1.2.2 From 858c9f6c19c6f9bf86cbbc64ce0d17c61d6131b8 Mon Sep 17 00:00:00 2001 From: James Smart Date: Sun, 17 Jun 2007 19:56:39 -0500 Subject: [SCSI] lpfc: bug fixes Following the NPIV support, the following changes have been accumulated in the testing and qualification of the driver: - Fix affinity of ELS ring to slow/deferred event processing - Fix Ring attention masks - Defer dev_loss_tmo timeout handling to worker thread - Consolidate link down error classification for better error checking - Remove unused/deprecated nlp_initiator_tmr timer - Fix for async scan - move adapter init code back into pci_probe_one context. Fix async scan interfaces. - Expand validation of ability to create vports - Extract VPI resource cnt from firmware - Tuning of Login/Reject policies to better deal with overwhelmned targets - Misc ELS and discovery fixes - Export the npiv_enable attribute to sysfs - Mailbox handling fix - Add debugfs support - A few other small misc fixes: - wrong return values, double-frees, bad locking - Added adapter failure heartbeat Signed-off-by: James Smart Signed-off-by: James Bottomley --- drivers/scsi/lpfc/lpfc_hbadisc.c | 276 +++++++++++++++++++++++++++------------ 1 file changed, 195 insertions(+), 81 deletions(-) (limited to 'drivers/scsi/lpfc/lpfc_hbadisc.c') diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 94ee9675b5b0..f2f4639eab59 100644 --- a/drivers/scsi/lpfc/lpfc_hbadisc.c +++ b/drivers/scsi/lpfc/lpfc_hbadisc.c @@ -37,6 +37,7 @@ #include "lpfc_logmsg.h" #include "lpfc_crtn.h" #include "lpfc_vport.h" +#include "lpfc_debugfs.h" /* AlpaArray for assignment of scsid for scan-down and bind_method */ static uint8_t lpfcAlpaArray[] = { @@ -77,6 +78,10 @@ lpfc_terminate_rport_io(struct fc_rport *rport) phba = ndlp->vport->phba; + lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_RPORT, + "rport terminate: sid:x%x did:x%x flg:x%x", + ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); + 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); @@ -93,12 +98,10 @@ 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; struct lpfc_vport *vport; - int put_node; - int put_rport; + struct lpfc_hba *phba; + struct completion devloss_compl; + struct lpfc_work_evt *evtp; rdata = rport->dd_data; ndlp = rdata->pnode; @@ -112,7 +115,70 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) return; } + vport = ndlp->vport; + phba = vport->phba; + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, + "rport devlosscb: sid:x%x did:x%x flg:x%x", + ndlp->nlp_sid, ndlp->nlp_DID, ndlp->nlp_flag); + + init_completion(&devloss_compl); + evtp = &ndlp->dev_loss_evt; + + if (!list_empty(&evtp->evt_listp)) + return; + + spin_lock_irq(&phba->hbalock); + evtp->evt_arg1 = ndlp; + evtp->evt_arg2 = &devloss_compl; + evtp->evt = LPFC_EVT_DEV_LOSS; + list_add_tail(&evtp->evt_listp, &phba->work_list); + if (phba->work_wait) + wake_up(phba->work_wait); + + spin_unlock_irq(&phba->hbalock); + + wait_for_completion(&devloss_compl); + + return; +} + +/* + * This function is called from the worker thread when dev_loss_tmo + * expire. + */ +void +lpfc_dev_loss_tmo_handler(struct lpfc_nodelist *ndlp) +{ + struct lpfc_rport_data *rdata; + struct fc_rport *rport; + struct lpfc_vport *vport; + struct lpfc_hba *phba; + uint8_t *name; + int warn_on = 0; + + rport = ndlp->rport; + + if (!rport) + return; + + rdata = rport->dd_data; + name = (uint8_t *) &ndlp->nlp_portname; + vport = ndlp->vport; + phba = vport->phba; + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, + "rport devlosstmo:did:x%x type:x%x id:x%x", + ndlp->nlp_DID, ndlp->nlp_type, rport->scsi_target_id); + + if (!(vport->load_flag & FC_UNLOADING) && + ndlp->nlp_state == NLP_STE_MAPPED_NODE) + return; + if (ndlp->nlp_type & NLP_FABRIC) { + int put_node; + int put_rport; + /* We will clean up these Nodes in linkup */ put_node = rdata->pnode != NULL; put_rport = ndlp->rport != NULL; @@ -125,15 +191,6 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) return; } - name = (uint8_t *)&ndlp->nlp_portname; - vport = ndlp->vport; - phba = vport->phba; - - if (!(vport->load_flag & FC_UNLOADING) && - ndlp->nlp_state == NLP_STE_MAPPED_NODE) - return; - - if (ndlp->nlp_sid != NLP_NO_SID) { warn_on = 1; /* flush the target */ @@ -171,6 +228,9 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) (ndlp->nlp_state != NLP_STE_UNMAPPED_NODE)) lpfc_disc_state_machine(vport, ndlp, NULL, NLP_EVT_DEVICE_RM); else { + int put_node; + int put_rport; + put_node = rdata->pnode != NULL; put_rport = ndlp->rport != NULL; rdata->pnode = NULL; @@ -180,7 +240,6 @@ lpfc_dev_loss_tmo_callbk(struct fc_rport *rport) if (put_rport) put_device(&rport->dev); } - return; } @@ -206,12 +265,17 @@ lpfc_work_list_done(struct lpfc_hba *phba) spin_unlock_irq(&phba->hbalock); free_evt = 1; switch (evtp->evt) { - case LPFC_EVT_DEV_LOSS: + case LPFC_EVT_DEV_LOSS_DELAY: free_evt = 0; /* evt is part of ndlp */ ndlp = (struct lpfc_nodelist *) (evtp->evt_arg1); vport = ndlp->vport; if (!vport) break; + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, + "rport devlossdly:did:x%x flg:x%x", + ndlp->nlp_DID, ndlp->nlp_flag, 0); + if (!(vport->load_flag & FC_UNLOADING) && !(ndlp->nlp_flag & NLP_DELAY_TMO) && !(ndlp->nlp_flag & NLP_NPR_2B_DISC)) { @@ -224,6 +288,14 @@ lpfc_work_list_done(struct lpfc_hba *phba) lpfc_els_retry_delay_handler(ndlp); free_evt = 0; /* evt is part of ndlp */ break; + case LPFC_EVT_DEV_LOSS: + ndlp = (struct lpfc_nodelist *)(evtp->evt_arg1); + lpfc_nlp_get(ndlp); + lpfc_dev_loss_tmo_handler(ndlp); + free_evt = 0; + complete((struct completion *)(evtp->evt_arg2)); + lpfc_nlp_put(ndlp); + break; case LPFC_EVT_ONLINE: if (phba->link_state < LPFC_LINK_DOWN) *(int *) (evtp->evt_arg1) = lpfc_online(phba); @@ -272,13 +344,12 @@ lpfc_work_list_done(struct lpfc_hba *phba) } -static void +void lpfc_work_done(struct lpfc_hba *phba) { struct lpfc_sli_ring *pring; - uint32_t ha_copy, control, work_port_events; + uint32_t ha_copy, status, control, work_port_events; struct lpfc_vport *vport; - int i; spin_lock_irq(&phba->hbalock); ha_copy = phba->work_ha; @@ -310,6 +381,9 @@ lpfc_work_done(struct lpfc_hba *phba) if (work_port_events & WORKER_ELS_TMO) lpfc_els_timeout_handler(vport); + if (work_port_events & WORKER_HB_TMO) + lpfc_hb_timeout_handler(phba); + if (work_port_events & WORKER_MBOX_TMO) lpfc_mbox_timeout_handler(phba); @@ -333,30 +407,31 @@ lpfc_work_done(struct lpfc_hba *phba) } spin_unlock_irq(&phba->hbalock); - for (i = 0; i < phba->sli.num_rings; i++, ha_copy >>= 4) { - pring = &phba->sli.ring[i]; - if ((ha_copy & HA_RXATT) - || (pring->flag & LPFC_DEFERRED_RING_EVENT)) { - if (pring->flag & LPFC_STOP_IOCB_MASK) { - pring->flag |= LPFC_DEFERRED_RING_EVENT; - } else { - lpfc_sli_handle_slow_ring_event(phba, pring, - (ha_copy & - HA_RXMASK)); - pring->flag &= ~LPFC_DEFERRED_RING_EVENT; - } - /* - * Turn on Ring interrupts - */ - spin_lock_irq(&phba->hbalock); - control = readl(phba->HCregaddr); - control |= (HC_R0INT_ENA << i); + pring = &phba->sli.ring[LPFC_ELS_RING]; + status = (ha_copy & (HA_RXMASK << (4*LPFC_ELS_RING))); + status >>= (4*LPFC_ELS_RING); + if ((status & HA_RXMASK) + || (pring->flag & LPFC_DEFERRED_RING_EVENT)) { + if (pring->flag & LPFC_STOP_IOCB_MASK) { + pring->flag |= LPFC_DEFERRED_RING_EVENT; + } else { + lpfc_sli_handle_slow_ring_event(phba, pring, + (status & + HA_RXMASK)); + pring->flag &= ~LPFC_DEFERRED_RING_EVENT; + } + /* + * Turn on Ring interrupts + */ + spin_lock_irq(&phba->hbalock); + control = readl(phba->HCregaddr); + if (!(control & (HC_R0INT_ENA << LPFC_ELS_RING))) { + control |= (HC_R0INT_ENA << LPFC_ELS_RING); writel(control, phba->HCregaddr); readl(phba->HCregaddr); /* flush */ - spin_unlock_irq(&phba->hbalock); } + spin_unlock_irq(&phba->hbalock); } - lpfc_work_list_done(phba); } @@ -365,7 +440,7 @@ check_work_wait_done(struct lpfc_hba *phba) { struct lpfc_vport *vport; struct lpfc_sli_ring *pring; - int i, rc = 0; + int rc = 0; spin_lock_irq(&phba->hbalock); list_for_each_entry(vport, &phba->port_list, listentry) { @@ -380,13 +455,10 @@ check_work_wait_done(struct lpfc_hba *phba) rc = 1; goto exit; } - for (i = 0; i < phba->sli.num_rings; i++) { - pring = &phba->sli.ring[i]; - if (pring->flag & LPFC_DEFERRED_RING_EVENT) { - rc = 1; - goto exit; - } - } + + pring = &phba->sli.ring[LPFC_ELS_RING]; + if (pring->flag & LPFC_DEFERRED_RING_EVENT) + rc = 1; exit: if (rc) phba->work_found++; @@ -506,6 +578,10 @@ lpfc_linkdown_port(struct lpfc_vport *vport) fc_host_post_event(shost, fc_get_event_number(), FCH_EVT_LINKDOWN, 0); + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "Link Down: state:x%x rtry:x%x flg:x%x", + vport->port_state, vport->fc_ns_retry, vport->fc_flag); + /* Cleanup any outstanding RSCN activity */ lpfc_els_flush_rscn(vport); @@ -617,6 +693,10 @@ lpfc_linkup_port(struct lpfc_vport *vport) if ((vport->load_flag & FC_UNLOADING) != 0) return; + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "Link Up: top:x%x speed:x%x flg:x%x", + phba->fc_topology, phba->fc_linkspeed, phba->link_flag); + /* If NPIV is not enabled, only bring the physical port up */ if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) && (vport != phba->pport)) @@ -935,7 +1015,7 @@ lpfc_mbx_process_link_up(struct lpfc_hba *phba, READ_LA_VAR *la) } } else { if (!(phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)) { - if (phba->max_vpi && lpfc_npiv_enable && + if (phba->max_vpi && phba->cfg_npiv_enable && (phba->sli_rev == 3)) phba->sli3_options |= LPFC_SLI3_NPIV_ENABLED; } @@ -1124,8 +1204,6 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) "mb status = 0x%x\n", phba->brd_no, vport->vpi, mb->mbxStatus); break; - default: - phba->vpi_cnt--; } vport->unreg_vpi_cmpl = VPORT_OK; mempool_free(pmb, phba->mbox_mem_pool); @@ -1182,7 +1260,6 @@ lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) vport->fc_myDID = 0; goto out; } - phba->vpi_cnt++; vport->num_disc_nodes = 0; /* go thru NPR list and issue ELS PLOGIs */ @@ -1257,16 +1334,13 @@ lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb) if (phba->link_flag & LS_NPIV_FAB_SUPPORTED) lpfc_initial_fdisc(next_vport); - else { - if (phba->sli3_options & - LPFC_SLI3_NPIV_ENABLED) { - lpfc_vport_set_state(vport, - FC_VPORT_NO_FABRIC_SUPP); - lpfc_printf_log(phba, KERN_ERR, LOG_ELS, + else if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) { + lpfc_vport_set_state(vport, + FC_VPORT_NO_FABRIC_SUPP); + lpfc_printf_log(phba, KERN_ERR, LOG_ELS, "%d (%d):0259 No NPIV Fabric " "support\n", phba->brd_no, vport->vpi); - } } } lpfc_do_scr_ns_plogi(phba, vport); @@ -1377,6 +1451,11 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) ((struct lpfc_rport_data *) ndlp->rport->dd_data)->pnode == ndlp) { lpfc_nlp_put(ndlp); } + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_RPORT, + "rport add: did:x%x flg:x%x type x%x", + ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); + ndlp->rport = rport = fc_remote_port_add(shost, 0, &rport_ids); if (!rport || !get_device(&rport->dev)) { dev_printk(KERN_WARNING, &phba->pcidev->dev, @@ -1394,7 +1473,6 @@ lpfc_register_remote_port(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) rport_ids.roles |= FC_RPORT_ROLE_FCP_TARGET; if (ndlp->nlp_type & NLP_FCP_INITIATOR) rport_ids.roles |= FC_RPORT_ROLE_FCP_INITIATOR; - del_timer_sync(&ndlp->nlp_initiator_tmr); if (rport_ids.roles != FC_RPORT_ROLE_UNKNOWN) @@ -1412,6 +1490,10 @@ lpfc_unregister_remote_port(struct lpfc_nodelist *ndlp) { struct fc_rport *rport = ndlp->rport; + lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_RPORT, + "rport delete: did:x%x flg:x%x type x%x", + ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); + fc_remote_port_delete(rport); return; @@ -1478,20 +1560,19 @@ lpfc_nlp_state_cleanup(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, if (new_state == NLP_STE_MAPPED_NODE || new_state == NLP_STE_UNMAPPED_NODE) { vport->phba->nport_event_cnt++; - /* - * Tell the fc transport about the port, if we haven't - * already. If we have, and it's a scsi entity, be - * sure to unblock any attached scsi devices - */ - lpfc_register_remote_port(vport, ndlp); + /* + * Tell the fc transport about the port, if we haven't + * already. If we have, and it's a scsi entity, be + * sure to unblock any attached scsi devices + */ + lpfc_register_remote_port(vport, ndlp); } - - /* - * if we added to Mapped list, but the remote port - * registration failed or assigned a target id outside - * our presentable range - move the node to the - * Unmapped List - */ + /* + * if we added to Mapped list, but the remote port + * registration failed or assigned a target id outside + * our presentable range - move the node to the + * Unmapped List + */ if (new_state == NLP_STE_MAPPED_NODE && (!ndlp->rport || ndlp->rport->scsi_target_id == -1 || @@ -1533,11 +1614,16 @@ lpfc_nlp_set_state(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, char name1[16], name2[16]; lpfc_printf_log(vport->phba, KERN_INFO, LOG_NODE, - "%d:0904 NPort state transition x%06x, %s -> %s\n", - vport->phba->brd_no, + "%d (%d):0904 NPort state transition x%06x, %s -> %s\n", + vport->phba->brd_no, vport->vpi, ndlp->nlp_DID, lpfc_nlp_state_name(name1, sizeof(name1), old_state), lpfc_nlp_state_name(name2, sizeof(name2), state)); + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, + "node statechg did:x%x old:%d ste:%d", + ndlp->nlp_DID, old_state, state); + if (old_state == NLP_STE_NPR_NODE && (ndlp->nlp_flag & NLP_DELAY_TMO) != 0 && state != NLP_STE_NPR_NODE) @@ -1571,7 +1657,8 @@ lpfc_dequeue_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) spin_lock_irq(shost->host_lock); list_del_init(&ndlp->nlp_listp); spin_unlock_irq(shost->host_lock); - lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, 0); + lpfc_nlp_state_cleanup(vport, ndlp, ndlp->nlp_state, + NLP_STE_UNUSED_NODE); } void @@ -1585,6 +1672,7 @@ lpfc_drop_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) lpfc_nlp_counters(vport, ndlp->nlp_state, -1); spin_lock_irq(shost->host_lock); list_del_init(&ndlp->nlp_listp); + ndlp->nlp_flag &= ~NLP_TARGET_REMOVE; spin_unlock_irq(shost->host_lock); lpfc_nlp_put(ndlp); } @@ -1609,6 +1697,13 @@ lpfc_set_disctmo(struct lpfc_vport *vport) tmo = ((phba->fc_ratov * 3) + 3); } + + if (!timer_pending(&vport->fc_disctmo)) { + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "set disc timer: tmo:x%x state:x%x flg:x%x", + tmo, vport->port_state, vport->fc_flag); + } + mod_timer(&vport->fc_disctmo, jiffies + HZ * tmo); spin_lock_irq(shost->host_lock); vport->fc_flag |= FC_DISC_TMO; @@ -1635,6 +1730,10 @@ lpfc_can_disctmo(struct lpfc_vport *vport) struct lpfc_hba *phba = vport->phba; unsigned long iflags; + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "can disc timer: state:x%x rtry:x%x flg:x%x", + vport->port_state, vport->fc_ns_retry, vport->fc_flag); + /* Turn off discovery timer if its running */ if (vport->fc_flag & FC_DISC_TMO) { spin_lock_irqsave(shost->host_lock, iflags); @@ -1898,13 +1997,17 @@ lpfc_cleanup_node(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp) ndlp->nlp_last_elscmd = 0; del_timer_sync(&ndlp->nlp_delayfunc); - del_timer_sync(&ndlp->nlp_initiator_tmr); if (!list_empty(&ndlp->els_retry_evt.evt_listp)) list_del_init(&ndlp->els_retry_evt.evt_listp); if (!list_empty(&ndlp->dev_loss_evt.evt_listp)) list_del_init(&ndlp->dev_loss_evt.evt_listp); + if (!list_empty(&ndlp->dev_loss_evt.evt_listp)) { + list_del_init(&ndlp->dev_loss_evt.evt_listp); + complete((struct completion *)(ndlp->dev_loss_evt.evt_arg2)); + } + lpfc_unreg_rpi(vport, ndlp); return 0; @@ -2418,6 +2521,10 @@ lpfc_disc_timeout_handler(struct lpfc_vport *vport) vport->fc_flag &= ~FC_DISC_TMO; spin_unlock_irq(shost->host_lock); + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_ELS_CMD, + "disc timeout: state:x%x rtry:x%x flg:x%x", + vport->port_state, vport->fc_ns_retry, vport->fc_flag); + switch (vport->port_state) { case LPFC_LOCAL_CFG_LINK: @@ -2743,7 +2850,7 @@ lpfc_findnode_wwpn(struct lpfc_vport *vport, struct lpfc_name *wwpn) spin_lock_irq(shost->host_lock); ndlp = __lpfc_find_node(vport, lpfc_filter_by_wwpn, wwpn); spin_unlock_irq(shost->host_lock); - return NULL; + return ndlp; } void @@ -2764,7 +2871,7 @@ lpfc_dev_loss_delay(unsigned long ptr) } evtp->evt_arg1 = ndlp; - evtp->evt = LPFC_EVT_DEV_LOSS; + evtp->evt = LPFC_EVT_DEV_LOSS_DELAY; list_add_tail(&evtp->evt_listp, &phba->work_list); if (phba->work_wait) lpfc_worker_wake_up(phba); @@ -2779,9 +2886,6 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, memset(ndlp, 0, sizeof (struct lpfc_nodelist)); INIT_LIST_HEAD(&ndlp->els_retry_evt.evt_listp); INIT_LIST_HEAD(&ndlp->dev_loss_evt.evt_listp); - init_timer(&ndlp->nlp_initiator_tmr); - ndlp->nlp_initiator_tmr.function = lpfc_dev_loss_delay; - ndlp->nlp_initiator_tmr.data = (unsigned long)ndlp; init_timer(&ndlp->nlp_delayfunc); ndlp->nlp_delayfunc.function = lpfc_els_retry_delay; ndlp->nlp_delayfunc.data = (unsigned long)ndlp; @@ -2790,6 +2894,11 @@ lpfc_nlp_init(struct lpfc_vport *vport, struct lpfc_nodelist *ndlp, ndlp->nlp_sid = NLP_NO_SID; INIT_LIST_HEAD(&ndlp->nlp_listp); kref_init(&ndlp->kref); + + lpfc_debugfs_disc_trc(vport, LPFC_DISC_TRC_NODE, + "node init: did:x%x", + ndlp->nlp_DID, 0, 0); + return; } @@ -2798,6 +2907,11 @@ lpfc_nlp_release(struct kref *kref) { struct lpfc_nodelist *ndlp = container_of(kref, struct lpfc_nodelist, kref); + + lpfc_debugfs_disc_trc(ndlp->vport, LPFC_DISC_TRC_NODE, + "node release: did:x%x flg:x%x type:x%x", + ndlp->nlp_DID, ndlp->nlp_flag, ndlp->nlp_type); + lpfc_nlp_remove(ndlp->vport, ndlp); mempool_free(ndlp, ndlp->vport->phba->nlp_mem_pool); } -- cgit v1.2.2