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

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

[SCSI] lpfc 8.3.0 : Fix some memory handling issues



- Fix mailbox buffer leak on dump mailbox completion

- Fix mbuf leak in lpfc_pci_probe_one() SLI-2 mode error path

- Don't allocate HBQs in interrupt context

- Use correct size for FCP response buffer so that all available sense
  data is copied

- Fix jiffies calculation to prevent crash when collecting statistical
  data

Signed-off-by: default avatarJames Smart <James.Smart@emulex.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 5b75da2f
Loading
Loading
Loading
Loading
+6 −1
Original line number Diff line number Diff line
@@ -255,8 +255,10 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
	/* character array used for decoding dist type. */
	char dist_char[] = "nabx";

	if (pmboxq->mb.mbxStatus != MBX_SUCCESS)
	if (pmboxq->mb.mbxStatus != MBX_SUCCESS) {
		mempool_free(pmboxq, phba->mbox_mem_pool);
		return;
	}

	prg = (struct prog_id *) &prog_id_word;

@@ -274,6 +276,7 @@ lpfc_dump_wakeup_param_cmpl(struct lpfc_hba *phba, LPFC_MBOXQ_t *pmboxq)
		sprintf(phba->OptionROMVersion, "%d.%d%d%c%d",
			prg->ver, prg->rev, prg->lev,
			dist, prg->num);
	mempool_free(pmboxq, phba->mbox_mem_pool);
	return;
}

@@ -2889,6 +2892,8 @@ lpfc_pci_probe_one(struct pci_dev *pdev, const struct pci_device_id *pid)
	lpfc_stop_phba_timers(phba);
	phba->pport->work_port_events = 0;
	lpfc_disable_intr(phba);
	lpfc_sli_hba_down(phba);
	lpfc_sli_brdrestart(phba);
out_free_sysfs_attr:
	lpfc_free_sysfs_attr(vport);
out_destroy_port:
+9 −5
Original line number Diff line number Diff line
@@ -66,6 +66,8 @@ lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
	if (cmd->result)
		return;

	latency = jiffies_to_msecs((long)jiffies - (long)lpfc_cmd->start_time);

	spin_lock_irqsave(shost->host_lock, flags);
	if (!vport->stat_data_enabled ||
		vport->stat_data_blocked ||
@@ -74,13 +76,15 @@ lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
		spin_unlock_irqrestore(shost->host_lock, flags);
		return;
	}
	latency = jiffies_to_msecs(jiffies - lpfc_cmd->start_time);

	if (phba->bucket_type == LPFC_LINEAR_BUCKET) {
		i = (latency + phba->bucket_step - 1 - phba->bucket_base)/
			phba->bucket_step;
		if (i >= LPFC_MAX_BUCKET_COUNT)
			i = LPFC_MAX_BUCKET_COUNT;
		/* check array subscript bounds */
		if (i < 0)
			i = 0;
		else if (i >= LPFC_MAX_BUCKET_COUNT)
			i = LPFC_MAX_BUCKET_COUNT - 1;
	} else {
		for (i = 0; i < LPFC_MAX_BUCKET_COUNT-1; i++)
			if (latency <= (phba->bucket_base +
@@ -444,14 +448,14 @@ lpfc_new_scsi_buf(struct lpfc_vport *vport)
	bpl[0].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_cmd));
	bpl[0].tus.f.bdeSize = sizeof(struct fcp_cmnd);
	bpl[0].tus.f.bdeFlags = BUFF_TYPE_BDE_64;
	bpl[0].tus.w = le32_to_cpu(bpl->tus.w);
	bpl[0].tus.w = le32_to_cpu(bpl[0].tus.w);

	/* Setup the physical region for the FCP RSP */
	bpl[1].addrHigh = le32_to_cpu(putPaddrHigh(pdma_phys_fcp_rsp));
	bpl[1].addrLow = le32_to_cpu(putPaddrLow(pdma_phys_fcp_rsp));
	bpl[1].tus.f.bdeSize = sizeof(struct fcp_rsp);
	bpl[1].tus.f.bdeFlags = BUFF_TYPE_BDE_64;
	bpl[1].tus.w = le32_to_cpu(bpl->tus.w);
	bpl[1].tus.w = le32_to_cpu(bpl[1].tus.w);

	/*
	 * Since the IOCB for the FCP I/O is built into this lpfc_scsi_buf,
+8 −68
Original line number Diff line number Diff line
@@ -1258,68 +1258,6 @@ lpfc_sli_handle_mb_event(struct lpfc_hba *phba)
	return 0;
}

/**
 * lpfc_sli_replace_hbqbuff: Replace the HBQ buffer with a new buffer.
 * @phba: Pointer to HBA context object.
 * @tag: Tag for the HBQ buffer.
 *
 * This function is called from unsolicited event handler code path to get the
 * HBQ buffer associated with an unsolicited iocb. This function is called with
 * no lock held. It returns the buffer associated with the given tag and posts
 * another buffer to the firmware. Note that the new buffer must be allocated
 * before taking the hbalock and that the hba lock must be held until it is
 * finished with the hbq entry swap.
 **/
static struct lpfc_dmabuf *
lpfc_sli_replace_hbqbuff(struct lpfc_hba *phba, uint32_t tag)
{
	struct hbq_dmabuf *hbq_entry, *new_hbq_entry;
	uint32_t hbqno;
	void *virt;		/* virtual address ptr */
	dma_addr_t phys;	/* mapped address */
	unsigned long flags;

	hbqno = tag >> 16;
	new_hbq_entry = (phba->hbqs[hbqno].hbq_alloc_buffer)(phba);
	/* Check whether HBQ is still in use */
	spin_lock_irqsave(&phba->hbalock, flags);
	if (!phba->hbq_in_use) {
		if (new_hbq_entry)
			(phba->hbqs[hbqno].hbq_free_buffer)(phba,
							    new_hbq_entry);
		spin_unlock_irqrestore(&phba->hbalock, flags);
		return NULL;
	}

	hbq_entry = lpfc_sli_hbqbuf_find(phba, tag);
	if (hbq_entry == NULL) {
		if (new_hbq_entry)
			(phba->hbqs[hbqno].hbq_free_buffer)(phba,
							    new_hbq_entry);
		spin_unlock_irqrestore(&phba->hbalock, flags);
		return NULL;
	}
	list_del(&hbq_entry->dbuf.list);

	if (new_hbq_entry == NULL) {
		list_add_tail(&hbq_entry->dbuf.list, &phba->hbqbuf_in_list);
		spin_unlock_irqrestore(&phba->hbalock, flags);
		return &hbq_entry->dbuf;
	}
	new_hbq_entry->tag = -1;
	phys = new_hbq_entry->dbuf.phys;
	virt = new_hbq_entry->dbuf.virt;
	new_hbq_entry->dbuf.phys = hbq_entry->dbuf.phys;
	new_hbq_entry->dbuf.virt = hbq_entry->dbuf.virt;
	hbq_entry->dbuf.phys = phys;
	hbq_entry->dbuf.virt = virt;
	lpfc_sli_free_hbq(phba, hbq_entry);
	list_add_tail(&new_hbq_entry->dbuf.list, &phba->hbqbuf_in_list);
	spin_unlock_irqrestore(&phba->hbalock, flags);

	return &new_hbq_entry->dbuf;
}

/**
 * lpfc_sli_get_buff: Get the buffer associated with the buffer tag.
 * @phba: Pointer to HBA context object.
@@ -1337,10 +1275,14 @@ lpfc_sli_get_buff(struct lpfc_hba *phba,
		  struct lpfc_sli_ring *pring,
		  uint32_t tag)
{
	struct hbq_dmabuf *hbq_entry;

	if (tag & QUE_BUFTAG_BIT)
		return lpfc_sli_ring_taggedbuf_get(phba, pring, tag);
	else
		return lpfc_sli_replace_hbqbuff(phba, tag);
	hbq_entry = lpfc_sli_hbqbuf_find(phba, tag);
	if (!hbq_entry)
		return NULL;
	return &hbq_entry->dbuf;
}


@@ -1372,8 +1314,6 @@ lpfc_sli_process_unsol_iocb(struct lpfc_hba *phba, struct lpfc_sli_ring *pring,
	match = 0;
	irsp = &(saveq->iocb);

	if (irsp->ulpStatus == IOSTAT_NEED_BUFFER)
		return 1;
	if (irsp->ulpCommand == CMD_ASYNC_STATUS) {
		if (pring->lpfc_sli_rcv_async_status)
			pring->lpfc_sli_rcv_async_status(phba, pring, saveq);