[SCSI] lpfc 8.2.2 : Fix locking around HBA's port_list

Cleans up a lot of bad behaviors that have been in this area a while

Signed-off-by: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
This commit is contained in:
James Smart
2007-08-02 11:09:51 -04:00
committed by James Bottomley
parent a58cbd5212
commit 549e55cd2a
10 changed files with 307 additions and 222 deletions

View File

@ -349,7 +349,8 @@ lpfc_work_done(struct lpfc_hba *phba)
{
struct lpfc_sli_ring *pring;
uint32_t ha_copy, status, control, work_port_events;
struct lpfc_vport *vport;
struct lpfc_vport **vports;
int i;
spin_lock_irq(&phba->hbalock);
ha_copy = phba->work_ha;
@ -364,48 +365,31 @@ lpfc_work_done(struct lpfc_hba *phba)
if (ha_copy & HA_LATT)
lpfc_handle_latt(phba);
spin_lock_irq(&phba->hbalock);
list_for_each_entry(vport, &phba->port_list, listentry) {
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
if (!scsi_host_get(shost)) {
continue;
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL)
for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
work_port_events = vports[i]->work_port_events;
if (work_port_events & WORKER_DISC_TMO)
lpfc_disc_timeout_handler(vports[i]);
if (work_port_events & WORKER_ELS_TMO)
lpfc_els_timeout_handler(vports[i]);
if (work_port_events & WORKER_HB_TMO)
lpfc_hb_timeout_handler(phba);
if (work_port_events & WORKER_MBOX_TMO)
lpfc_mbox_timeout_handler(phba);
if (work_port_events & WORKER_FABRIC_BLOCK_TMO)
lpfc_unblock_fabric_iocbs(phba);
if (work_port_events & WORKER_FDMI_TMO)
lpfc_fdmi_timeout_handler(vports[i]);
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(&vports[i]->work_port_lock);
vports[i]->work_port_events &= ~work_port_events;
spin_unlock_irq(&vports[i]->work_port_lock);
}
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_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);
if (work_port_events & WORKER_FABRIC_BLOCK_TMO)
lpfc_unblock_fabric_iocbs(phba);
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);
lpfc_destroy_vport_work_array(vports);
pring = &phba->sli.ring[LPFC_ELS_RING];
status = (ha_copy & (HA_RXMASK << (4*LPFC_ELS_RING)));
@ -448,32 +432,22 @@ static int
check_work_wait_done(struct lpfc_hba *phba)
{
struct lpfc_vport *vport;
struct lpfc_sli_ring *pring;
struct lpfc_sli_ring *pring = &phba->sli.ring[LPFC_ELS_RING];
int 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;
break;
}
}
if (phba->work_ha || (!list_empty(&phba->work_list)) ||
kthread_should_stop()) {
if (rc || phba->work_ha || (!list_empty(&phba->work_list)) ||
kthread_should_stop() || 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++;
else
} else
phba->work_found = 0;
spin_unlock_irq(&phba->hbalock);
return rc;
}
@ -601,7 +575,6 @@ lpfc_linkdown_port(struct lpfc_vport *vport)
/* 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);
@ -614,8 +587,9 @@ lpfc_linkdown(struct lpfc_hba *phba)
{
struct lpfc_vport *vport = phba->pport;
struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
struct lpfc_vport *port_iterator;
struct lpfc_vport **vports;
LPFC_MBOXQ_t *mb;
int i;
if (phba->link_state == LPFC_LINK_DOWN) {
return 0;
@ -626,13 +600,13 @@ lpfc_linkdown(struct lpfc_hba *phba)
phba->pport->fc_flag &= ~FC_LBIT;
}
spin_unlock_irq(&phba->hbalock);
list_for_each_entry(port_iterator, &phba->port_list, listentry) {
/* Issue a LINK DOWN event to all nodes */
lpfc_linkdown_port(port_iterator);
}
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL)
for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++) {
/* Issue a LINK DOWN event to all nodes */
lpfc_linkdown_port(vports[i]);
}
lpfc_destroy_vport_work_array(vports);
/* Clean up any firmware default rpi's */
mb = mempool_alloc(phba->mbox_mem_pool, GFP_KERNEL);
if (mb) {
@ -733,7 +707,8 @@ lpfc_linkup_port(struct lpfc_vport *vport)
static int
lpfc_linkup(struct lpfc_hba *phba)
{
struct lpfc_vport *vport;
struct lpfc_vport **vports;
int i;
phba->link_state = LPFC_LINK_UP;
@ -741,9 +716,11 @@ lpfc_linkup(struct lpfc_hba *phba)
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);
}
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL)
for(i = 0; i < LPFC_MAX_VPORTS && vports[i] != NULL; i++)
lpfc_linkup_port(vports[i]);
lpfc_destroy_vport_work_array(vports);
if (phba->sli3_options & LPFC_SLI3_NPIV_ENABLED)
lpfc_issue_clear_la(phba, phba->pport);
@ -1298,15 +1275,15 @@ void
lpfc_mbx_cmpl_fabric_reg_login(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
{
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 = (struct lpfc_nodelist *) pmb->context2;
struct lpfc_vport **vports;
int i;
ndlp = (struct lpfc_nodelist *) pmb->context2;
pmb->context1 = NULL;
pmb->context2 = NULL;
if (mb->mbxStatus) {
lpfc_mbuf_free(phba, mp->virt, mp->phys);
kfree(mp);
@ -1337,21 +1314,27 @@ 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) {
list_for_each_entry(next_vport, &phba->port_list, listentry) {
if (next_vport->port_type == LPFC_PHYSICAL_PORT)
continue;
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);
vports = lpfc_create_vport_work_array(phba);
if (vports != NULL)
for(i = 0;
i < LPFC_MAX_VPORTS && vports[i] != NULL;
i++) {
if (vports[i]->port_type == LPFC_PHYSICAL_PORT)
continue;
if (phba->link_flag & LS_NPIV_FAB_SUPPORTED)
lpfc_initial_fdisc(vports[i]);
else if (phba->sli3_options &
LPFC_SLI3_NPIV_ENABLED) {
lpfc_vport_set_state(vports[i],
FC_VPORT_NO_FABRIC_SUPP);
lpfc_printf_log(phba, KERN_ERR, LOG_ELS,
"%d (%d):0259 No NPIV "
"Fabric support\n",
phba->brd_no,
vports[i]->vpi);
}
}
}
lpfc_destroy_vport_work_array(vports);
lpfc_do_scr_ns_plogi(phba, vport);
}