Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d11e31dd authored by James Smart's avatar James Smart Committed by James Bottomley
Browse files

[SCSI] lpfc 8.3.3 : Fix a couple of spin_lock and memory issues and a crash



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: default avatarJames Smart <James.Smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 0c287589
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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);
+1 −0
Original line number Diff line number Diff line
@@ -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)
+33 −9
Original line number Diff line number Diff line
@@ -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;
}