[SCSI] lpfc 8.3.9: Fix locking and memory issues
authorJames Smart <james.smart@emulex.com>
Fri, 12 Feb 2010 19:43:01 +0000 (14:43 -0500)
committerJames Bottomley <James.Bottomley@suse.de>
Wed, 17 Feb 2010 23:41:19 +0000 (17:41 -0600)
- Use the hbalock when changing the fc_flag.
- Use the host_lock when changeing the sli_flag.
- Prevent NULL pointer dereference after dma_alloc_coherent failure.

Signed-off-by: James Smart <james.smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@suse.de>
drivers/scsi/lpfc/lpfc_hbadisc.c
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_mbox.c
drivers/scsi/lpfc/lpfc_vport.c

index b890e2dc15db07db5bda9e5c92c6154fec10b48c..2359d0bfb734f0cd352ca8c68560a07757a8c47c 100644 (file)
@@ -757,11 +757,13 @@ lpfc_linkdown(struct lpfc_hba *phba)
 
        spin_lock_irq(&phba->hbalock);
        phba->fcf.fcf_flag &= ~(FCF_AVAILABLE | FCF_SCAN_DONE);
+       spin_unlock_irq(&phba->hbalock);
        if (phba->link_state > LPFC_LINK_DOWN) {
                phba->link_state = LPFC_LINK_DOWN;
+               spin_lock_irq(shost->host_lock);
                phba->pport->fc_flag &= ~FC_LBIT;
+               spin_unlock_irq(shost->host_lock);
        }
-       spin_unlock_irq(&phba->hbalock);
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL)
                for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
@@ -1802,6 +1804,8 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
 {
        struct lpfc_vport *vport = mboxq->vport;
        struct lpfc_nodelist *ndlp;
+       struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
+
        if (mboxq->u.mb.mbxStatus) {
                lpfc_printf_vlog(vport, KERN_ERR,
                                LOG_MBOX,
@@ -1811,9 +1815,9 @@ lpfc_init_vpi_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                lpfc_vport_set_state(vport, FC_VPORT_FAILED);
                return;
        }
-       spin_lock_irq(&phba->hbalock);
+       spin_lock_irq(shost->host_lock);
        vport->fc_flag &= ~FC_VPORT_NEEDS_INIT_VPI;
-       spin_unlock_irq(&phba->hbalock);
+       spin_unlock_irq(shost->host_lock);
 
        /* If this port is physical port or FDISC is done, do reg_vpi */
        if ((phba->pport == vport) || (vport->port_state == LPFC_FDISC)) {
@@ -1924,6 +1928,7 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
 {
        struct lpfc_dmabuf *dmabuf = mboxq->context1;
        struct lpfc_vport *vport = mboxq->vport;
+       struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 
        if (mboxq->u.mb.mbxStatus) {
                lpfc_printf_vlog(vport, KERN_ERR, LOG_MBOX,
@@ -1941,10 +1946,11 @@ lpfc_mbx_cmpl_reg_vfi(struct lpfc_hba *phba, LPFC_MBOXQ_t *mboxq)
                goto fail_free_mem;
        }
        /* The VPI is implicitly registered when the VFI is registered */
+       spin_lock_irq(shost->host_lock);
        vport->vpi_state |= LPFC_VPI_REGISTERED;
        vport->fc_flag |= FC_VFI_REGISTERED;
-
        vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+       spin_unlock_irq(shost->host_lock);
 
        if (vport->port_state == LPFC_FABRIC_CFG_LINK) {
                lpfc_start_fdiscs(phba);
@@ -2269,10 +2275,12 @@ lpfc_mbx_cmpl_read_la(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
        }
 
        phba->fc_eventTag = la->eventTag;
+       spin_lock_irq(&phba->hbalock);
        if (la->mm)
                phba->sli.sli_flag |= LPFC_MENLO_MAINT;
        else
                phba->sli.sli_flag &= ~LPFC_MENLO_MAINT;
+       spin_unlock_irq(&phba->hbalock);
 
        phba->link_events++;
        if (la->attType == AT_LINK_UP && (!la->mm)) {
@@ -2401,10 +2409,10 @@ lpfc_mbx_cmpl_unreg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                                 mb->mbxStatus);
                break;
        }
-       spin_lock_irq(&phba->hbalock);
+       spin_lock_irq(shost->host_lock);
        vport->vpi_state &= ~LPFC_VPI_REGISTERED;
        vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
-       spin_unlock_irq(&phba->hbalock);
+       spin_unlock_irq(shost->host_lock);
        vport->unreg_vpi_cmpl = VPORT_OK;
        mempool_free(pmb, phba->mbox_mem_pool);
        /*
@@ -2462,8 +2470,10 @@ lpfc_mbx_cmpl_reg_vpi(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmb)
                goto out;
        }
 
+       spin_lock_irq(shost->host_lock);
        vport->vpi_state |= LPFC_VPI_REGISTERED;
        vport->fc_flag &= ~FC_VPORT_NEEDS_REG_VPI;
+       spin_unlock_irq(shost->host_lock);
        vport->num_disc_nodes = 0;
        /* go thru NPR list and issue ELS PLOGIs */
        if (vport->fc_npr_cnt)
@@ -4620,6 +4630,7 @@ lpfc_unregister_fcf_prep(struct lpfc_hba *phba)
        LPFC_MBOXQ_t *mbox;
        struct lpfc_vport **vports;
        struct lpfc_nodelist *ndlp;
+       struct Scsi_Host *shost;
        int i, rc;
 
        /* Unregister RPIs */
@@ -4638,10 +4649,11 @@ lpfc_unregister_fcf_prep(struct lpfc_hba *phba)
                        if (ndlp)
                                lpfc_cancel_retry_delay_tmo(vports[i], ndlp);
                        lpfc_mbx_unreg_vpi(vports[i]);
-                       spin_lock_irq(&phba->hbalock);
+                       shost = lpfc_shost_from_vport(vports[i]);
+                       spin_lock_irq(shost->host_lock);
                        vports[i]->fc_flag |= FC_VPORT_NEEDS_INIT_VPI;
                        vports[i]->vpi_state &= ~LPFC_VPI_REGISTERED;
-                       spin_unlock_irq(&phba->hbalock);
+                       spin_unlock_irq(shost->host_lock);
                }
        lpfc_destroy_vport_work_array(phba, vports);
 
@@ -4671,9 +4683,10 @@ lpfc_unregister_fcf_prep(struct lpfc_hba *phba)
                return -EIO;
        }
 
-       spin_lock_irq(&phba->hbalock);
+       shost = lpfc_shost_from_vport(phba->pport);
+       spin_lock_irq(shost->host_lock);
        phba->pport->fc_flag &= ~FC_VFI_REGISTERED;
-       spin_unlock_irq(&phba->hbalock);
+       spin_unlock_irq(shost->host_lock);
 
        return 0;
 }
index 89d886c72e0aa70c3ea64bddb57a394f7623ed82..d29ac7c317d9d7324b13807f2329615320c2d37f 100644 (file)
@@ -2363,6 +2363,7 @@ lpfc_offline_prep(struct lpfc_hba * phba)
        struct lpfc_vport *vport = phba->pport;
        struct lpfc_nodelist  *ndlp, *next_ndlp;
        struct lpfc_vport **vports;
+       struct Scsi_Host *shost;
        int i;
 
        if (vport->fc_flag & FC_OFFLINE_MODE)
@@ -2376,13 +2377,14 @@ lpfc_offline_prep(struct lpfc_hba * phba)
        vports = lpfc_create_vport_work_array(phba);
        if (vports != NULL) {
                for (i = 0; i <= phba->max_vports && vports[i] != NULL; i++) {
-                       struct Scsi_Host *shost;
-
                        if (vports[i]->load_flag & FC_UNLOADING)
                                continue;
+                       shost = lpfc_shost_from_vport(vports[i]);
+                       spin_lock_irq(shost->host_lock);
                        vports[i]->vpi_state &= ~LPFC_VPI_REGISTERED;
                        vports[i]->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
                        vports[i]->fc_flag &= ~FC_VFI_REGISTERED;
+                       spin_unlock_irq(shost->host_lock);
 
                        shost = lpfc_shost_from_vport(vports[i]);
                        list_for_each_entry_safe(ndlp, next_ndlp,
@@ -2789,8 +2791,6 @@ lpfc_stop_port_s4(struct lpfc_hba *phba)
        lpfc_stop_hba_timers(phba);
        phba->pport->work_port_events = 0;
        phba->sli4_hba.intr_enable = 0;
-       /* Hard clear it for now, shall have more graceful way to wait later */
-       phba->sli.sli_flag &= ~LPFC_SLI_MBOX_ACTIVE;
 }
 
 /**
index 6c1d8b3fe8cc3af8167d118e6319cfac9387e961..6c4dce1a30ca70dded02523804b133cc169c40af 100644 (file)
@@ -1707,7 +1707,8 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox,
                                alloc_len - sizeof(union  lpfc_sli4_cfg_shdr);
        }
        /* The sub-header is in DMA memory, which needs endian converstion */
-       lpfc_sli_pcimem_bcopy(cfg_shdr, cfg_shdr,
+       if (cfg_shdr)
+               lpfc_sli_pcimem_bcopy(cfg_shdr, cfg_shdr,
                              sizeof(union  lpfc_sli4_cfg_shdr));
 
        return alloc_len;
index 281ff033a7b2c9f9722d0ba32db184b5bca9e828..dc86e873102a1763a445e285b9d671d7411058a8 100644 (file)
@@ -505,6 +505,7 @@ enable_vport(struct fc_vport *fc_vport)
        struct lpfc_vport *vport = *(struct lpfc_vport **)fc_vport->dd_data;
        struct lpfc_hba   *phba = vport->phba;
        struct lpfc_nodelist *ndlp = NULL;
+       struct Scsi_Host *shost = lpfc_shost_from_vport(vport);
 
        if ((phba->link_state < LPFC_LINK_UP) ||
            (phba->fc_topology == TOPOLOGY_LOOP)) {
@@ -512,10 +513,10 @@ enable_vport(struct fc_vport *fc_vport)
                return VPORT_OK;
        }
 
-       spin_lock_irq(&phba->hbalock);
+       spin_lock_irq(shost->host_lock);
        vport->load_flag |= FC_LOADING;
        vport->fc_flag |= FC_VPORT_NEEDS_REG_VPI;
-       spin_unlock_irq(&phba->hbalock);
+       spin_unlock_irq(shost->host_lock);
 
        /* Use the Physical nodes Fabric NDLP to determine if the link is
         * up and ready to FDISC.