[SCSI] lpfc 8.3.3 : Fix a couple of spin_lock and memory issues and a crash
authorJames Smart <James.Smart@Emulex.Com>
Wed, 10 Jun 2009 21:23:06 +0000 (17:23 -0400)
committerJames Bottomley <James.Bottomley@HansenPartnership.com>
Mon, 15 Jun 2009 15:09:33 +0000 (10:09 -0500)
Contains the following changes:
- Fixed error paths retaking a spin lock which they already hold
- Added code to free memory in a couple of error paths
- Added code to free RPI bit map while unloading driver
- Added code to write zero to memory object allocated through dma_alloc_coherent
- Fixed crash/hang with target or LUN resets

Signed-off-by: James Smart <James.Smart@emulex.com>
Signed-off-by: James Bottomley <James.Bottomley@HansenPartnership.com>
drivers/scsi/lpfc/lpfc_init.c
drivers/scsi/lpfc/lpfc_mbox.c
drivers/scsi/lpfc/lpfc_sli.c

index 4363331..fc67cc6 100644 (file)
@@ -3540,6 +3540,7 @@ lpfc_sli4_driver_resource_unset(struct lpfc_hba *phba)
 
        /* Free the allocated rpi headers. */
        lpfc_sli4_remove_rpi_hdrs(phba);
+       lpfc_sli4_remove_rpis(phba);
 
        /* Free the ELS sgl list */
        lpfc_free_active_sgl(phba);
index bb3dc1d..3423571 100644 (file)
@@ -1631,6 +1631,7 @@ lpfc_sli4_config(struct lpfc_hba *phba, struct lpfcMboxq *mbox,
                /* In case of malloc fails, proceed with whatever we have */
                if (!viraddr)
                        break;
+               memset(viraddr, 0, PAGE_SIZE);
                mbox->sge_array->addr[pagen] = viraddr;
                /* Keep the first page for later sub-header construction */
                if (pagen == 0)
index ba698d5..acc43b0 100644 (file)
@@ -4139,8 +4139,11 @@ lpfc_sli4_read_fcoe_params(struct lpfc_hba *phba,
                return -EIO;
        }
        data_length = mqe->un.mb_words[5];
-       if (data_length > DMP_FCOEPARAM_RGN_SIZE)
+       if (data_length > DMP_FCOEPARAM_RGN_SIZE) {
+               lpfc_mbuf_free(phba, mp->virt, mp->phys);
+               kfree(mp);
                return -EIO;
+       }
 
        lpfc_parse_fcoe_conf(phba, mp->virt, data_length);
        lpfc_mbuf_free(phba, mp->virt, mp->phys);
@@ -7350,6 +7353,32 @@ lpfc_sli_wake_iocb_wait(struct lpfc_hba *phba,
        return;
 }
 
+/**
+ * lpfc_chk_iocb_flg - Test IOCB flag with lock held.
+ * @phba: Pointer to HBA context object..
+ * @piocbq: Pointer to command iocb.
+ * @flag: Flag to test.
+ *
+ * This routine grabs the hbalock and then test the iocb_flag to
+ * see if the passed in flag is set.
+ * Returns:
+ * 1 if flag is set.
+ * 0 if flag is not set.
+ **/
+static int
+lpfc_chk_iocb_flg(struct lpfc_hba *phba,
+                struct lpfc_iocbq *piocbq, uint32_t flag)
+{
+       unsigned long iflags;
+       int ret;
+
+       spin_lock_irqsave(&phba->hbalock, iflags);
+       ret = piocbq->iocb_flag & flag;
+       spin_unlock_irqrestore(&phba->hbalock, iflags);
+       return ret;
+
+}
+
 /**
  * lpfc_sli_issue_iocb_wait - Synchronous function to issue iocb commands
  * @phba: Pointer to HBA context object..
@@ -7417,7 +7446,7 @@ lpfc_sli_issue_iocb_wait(struct lpfc_hba *phba,
        if (retval == IOCB_SUCCESS) {
                timeout_req = timeout * HZ;
                timeleft = wait_event_timeout(done_q,
-                               piocb->iocb_flag & LPFC_IO_WAKE,
+                               lpfc_chk_iocb_flg(phba, piocb, LPFC_IO_WAKE),
                                timeout_req);
 
                if (piocb->iocb_flag & LPFC_IO_WAKE) {
@@ -7602,20 +7631,16 @@ lpfc_sli_eratt_read(struct lpfc_hba *phba)
                if ((HS_FFER1 & phba->work_hs) &&
                    ((HS_FFER2 | HS_FFER3 | HS_FFER4 | HS_FFER5 |
                     HS_FFER6 | HS_FFER7) & phba->work_hs)) {
-                       spin_lock_irq(&phba->hbalock);
                        phba->hba_flag |= DEFER_ERATT;
-                       spin_unlock_irq(&phba->hbalock);
                        /* Clear all interrupt enable conditions */
                        writel(0, phba->HCregaddr);
                        readl(phba->HCregaddr);
                }
 
                /* Set the driver HA work bitmap */
-               spin_lock_irq(&phba->hbalock);
                phba->work_ha |= HA_ERATT;
                /* Indicate polling handles this ERATT */
                phba->hba_flag |= HBA_ERATT_HANDLED;
-               spin_unlock_irq(&phba->hbalock);
                return 1;
        }
        return 0;
@@ -7661,12 +7686,10 @@ lpfc_sli4_eratt_read(struct lpfc_hba *phba)
                        return 0;
                        phba->work_status[0] = uerr_sta_lo;
                        phba->work_status[1] = uerr_sta_hi;
-                       spin_lock_irq(&phba->hbalock);
                        /* Set the driver HA work bitmap */
                        phba->work_ha |= HA_ERATT;
                        /* Indicate polling handles this ERATT */
                        phba->hba_flag |= HBA_ERATT_HANDLED;
-                       spin_unlock_irq(&phba->hbalock);
                        return 1;
                }
        }
@@ -9349,6 +9372,7 @@ lpfc_sli4_queue_alloc(struct lpfc_hba *phba, uint32_t entry_size,
                        kfree(dmabuf);
                        goto out_fail;
                }
+               memset(dmabuf->virt, 0, PAGE_SIZE);
                dmabuf->buffer_tag = x;
                list_add_tail(&dmabuf->list, &queue->page_list);
                /* initialize queue's entry array */
@@ -9771,7 +9795,7 @@ lpfc_wq_create(struct lpfc_hba *phba, struct lpfc_queue *wq,
        /* link the wq onto the parent cq child list */
        list_add_tail(&wq->list, &cq->child_list);
 out:
-       if (rc == MBX_TIMEOUT)
+       if (rc != MBX_TIMEOUT)
                mempool_free(mbox, phba->mbox_mem_pool);
        return status;
 }