diff options
Diffstat (limited to 'drivers/scsi/lpfc/lpfc_hbadisc.c')
-rw-r--r-- | drivers/scsi/lpfc/lpfc_hbadisc.c | 276 |
1 files changed, 195 insertions, 81 deletions
diff --git a/drivers/scsi/lpfc/lpfc_hbadisc.c b/drivers/scsi/lpfc/lpfc_hbadisc.c index 94ee9675b5b..f2f4639eab5 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); } |