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

Commit 41f79bde authored by Santosh Vernekar's avatar Santosh Vernekar Committed by James Bottomley
Browse files

[SCSI] qla4xxx: Add pex-dma support for capturing minidump



Add pex-dma support for ISP8324 and ISP8042 to improve
the minidump capture time.

Signed-off-by: default avatarSantosh Vernekar <santosh.vernekar@qlogic.com>
Signed-off-by: default avatarVikas Chaudhary <vikas.chaudhary@qlogic.com>
Signed-off-by: default avatarJames Bottomley <JBottomley@Parallels.com>
parent 909ee499
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -259,7 +259,7 @@ void qla4_83xx_rom_lock_recovery(struct scsi_qla_host *ha)
 * Return: On success return QLA_SUCCESS
 *	   On error return QLA_ERROR
 **/
static int qla4_83xx_ms_mem_write_128b(struct scsi_qla_host *ha, uint64_t addr,
int qla4_83xx_ms_mem_write_128b(struct scsi_qla_host *ha, uint64_t addr,
				uint32_t *data, uint32_t count)
{
	int i, j;
+34 −0
Original line number Diff line number Diff line
@@ -290,4 +290,38 @@ struct qla4_83xx_idc_information {
	uint32_t info3; /* IDC additional info */
};

#define QLA83XX_PEX_DMA_ENGINE_INDEX		8
#define QLA83XX_PEX_DMA_BASE_ADDRESS		0x77320000
#define QLA83XX_PEX_DMA_NUM_OFFSET		0x10000
#define QLA83XX_PEX_DMA_CMD_ADDR_LOW		0x0
#define QLA83XX_PEX_DMA_CMD_ADDR_HIGH		0x04
#define QLA83XX_PEX_DMA_CMD_STS_AND_CNTRL	0x08

#define QLA83XX_PEX_DMA_READ_SIZE	(16 * 1024)
#define QLA83XX_PEX_DMA_MAX_WAIT	(100 * 100) /* Max wait of 100 msecs */

/* Read Memory: For Pex-DMA */
struct qla4_83xx_minidump_entry_rdmem_pex_dma {
	struct qla8xxx_minidump_entry_hdr h;
	uint32_t desc_card_addr;
	uint16_t dma_desc_cmd;
	uint8_t rsvd[2];
	uint32_t start_dma_cmd;
	uint8_t rsvd2[12];
	uint32_t read_addr;
	uint32_t read_data_size;
};

struct qla4_83xx_pex_dma_descriptor {
	struct {
		uint32_t read_data_size; /* 0-23: size, 24-31: rsvd */
		uint8_t rsvd[2];
		uint16_t dma_desc_cmd;
	} cmd;
	uint64_t src_addr;
	uint64_t dma_bus_addr; /* 0-3: desc-cmd, 4-7: pci-func,
				* 8-15: desc-cmd */
	uint8_t rsvd[24];
} __packed;

#endif
+2 −0
Original line number Diff line number Diff line
@@ -272,6 +272,8 @@ int qla4xxx_set_acb(struct scsi_qla_host *ha, uint32_t *mbox_cmd,
int qla4xxx_get_acb(struct scsi_qla_host *ha, dma_addr_t acb_dma,
		    uint32_t acb_type, uint32_t len);
int qla4_84xx_config_acb(struct scsi_qla_host *ha, int acb_config);
int qla4_83xx_ms_mem_write_128b(struct scsi_qla_host *ha,
				uint64_t addr, uint32_t *data, uint32_t count);

extern int ql4xextended_error_logging;
extern int ql4xdontresethba;
+225 −1
Original line number Diff line number Diff line
@@ -1737,6 +1737,208 @@ static void qla4_8xxx_minidump_process_rdcrb(struct scsi_qla_host *ha,
	*d_ptr = data_ptr;
}

static int qla4_83xx_check_dma_engine_state(struct scsi_qla_host *ha)
{
	int rval = QLA_SUCCESS;
	uint32_t dma_eng_num = 0, cmd_sts_and_cntrl = 0;
	uint64_t dma_base_addr = 0;
	struct qla4_8xxx_minidump_template_hdr *tmplt_hdr = NULL;

	tmplt_hdr = (struct qla4_8xxx_minidump_template_hdr *)
							ha->fw_dump_tmplt_hdr;
	dma_eng_num =
		tmplt_hdr->saved_state_array[QLA83XX_PEX_DMA_ENGINE_INDEX];
	dma_base_addr = QLA83XX_PEX_DMA_BASE_ADDRESS +
				(dma_eng_num * QLA83XX_PEX_DMA_NUM_OFFSET);

	/* Read the pex-dma's command-status-and-control register. */
	rval = ha->isp_ops->rd_reg_indirect(ha,
			(dma_base_addr + QLA83XX_PEX_DMA_CMD_STS_AND_CNTRL),
			&cmd_sts_and_cntrl);

	if (rval)
		return QLA_ERROR;

	/* Check if requested pex-dma engine is available. */
	if (cmd_sts_and_cntrl & BIT_31)
		return QLA_SUCCESS;
	else
		return QLA_ERROR;
}

static int qla4_83xx_start_pex_dma(struct scsi_qla_host *ha,
			   struct qla4_83xx_minidump_entry_rdmem_pex_dma *m_hdr)
{
	int rval = QLA_SUCCESS, wait = 0;
	uint32_t dma_eng_num = 0, cmd_sts_and_cntrl = 0;
	uint64_t dma_base_addr = 0;
	struct qla4_8xxx_minidump_template_hdr *tmplt_hdr = NULL;

	tmplt_hdr = (struct qla4_8xxx_minidump_template_hdr *)
							ha->fw_dump_tmplt_hdr;
	dma_eng_num =
		tmplt_hdr->saved_state_array[QLA83XX_PEX_DMA_ENGINE_INDEX];
	dma_base_addr = QLA83XX_PEX_DMA_BASE_ADDRESS +
				(dma_eng_num * QLA83XX_PEX_DMA_NUM_OFFSET);

	rval = ha->isp_ops->wr_reg_indirect(ha,
				dma_base_addr + QLA83XX_PEX_DMA_CMD_ADDR_LOW,
				m_hdr->desc_card_addr);
	if (rval)
		goto error_exit;

	rval = ha->isp_ops->wr_reg_indirect(ha,
			      dma_base_addr + QLA83XX_PEX_DMA_CMD_ADDR_HIGH, 0);
	if (rval)
		goto error_exit;

	rval = ha->isp_ops->wr_reg_indirect(ha,
			      dma_base_addr + QLA83XX_PEX_DMA_CMD_STS_AND_CNTRL,
			      m_hdr->start_dma_cmd);
	if (rval)
		goto error_exit;

	/* Wait for dma operation to complete. */
	for (wait = 0; wait < QLA83XX_PEX_DMA_MAX_WAIT; wait++) {
		rval = ha->isp_ops->rd_reg_indirect(ha,
			    (dma_base_addr + QLA83XX_PEX_DMA_CMD_STS_AND_CNTRL),
			    &cmd_sts_and_cntrl);
		if (rval)
			goto error_exit;

		if ((cmd_sts_and_cntrl & BIT_1) == 0)
			break;
		else
			udelay(10);
	}

	/* Wait a max of 100 ms, otherwise fallback to rdmem entry read */
	if (wait >= QLA83XX_PEX_DMA_MAX_WAIT) {
		rval = QLA_ERROR;
		goto error_exit;
	}

error_exit:
	return rval;
}

static int qla4_83xx_minidump_pex_dma_read(struct scsi_qla_host *ha,
				struct qla8xxx_minidump_entry_hdr *entry_hdr,
				uint32_t **d_ptr)
{
	int rval = QLA_SUCCESS;
	struct qla4_83xx_minidump_entry_rdmem_pex_dma *m_hdr = NULL;
	uint32_t size, read_size;
	uint8_t *data_ptr = (uint8_t *)*d_ptr;
	void *rdmem_buffer = NULL;
	dma_addr_t rdmem_dma;
	struct qla4_83xx_pex_dma_descriptor dma_desc;

	DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__));

	rval = qla4_83xx_check_dma_engine_state(ha);
	if (rval != QLA_SUCCESS) {
		DEBUG2(ql4_printk(KERN_INFO, ha,
				  "%s: DMA engine not available. Fallback to rdmem-read.\n",
				  __func__));
		return QLA_ERROR;
	}

	m_hdr = (struct qla4_83xx_minidump_entry_rdmem_pex_dma *)entry_hdr;
	rdmem_buffer = dma_alloc_coherent(&ha->pdev->dev,
					  QLA83XX_PEX_DMA_READ_SIZE,
					  &rdmem_dma, GFP_KERNEL);
	if (!rdmem_buffer) {
		DEBUG2(ql4_printk(KERN_INFO, ha,
				  "%s: Unable to allocate rdmem dma buffer\n",
				  __func__));
		return QLA_ERROR;
	}

	/* Prepare pex-dma descriptor to be written to MS memory. */
	/* dma-desc-cmd layout:
	 *              0-3: dma-desc-cmd 0-3
	 *              4-7: pcid function number
	 *              8-15: dma-desc-cmd 8-15
	 */
	dma_desc.cmd.dma_desc_cmd = (m_hdr->dma_desc_cmd & 0xff0f);
	dma_desc.cmd.dma_desc_cmd |= ((PCI_FUNC(ha->pdev->devfn) & 0xf) << 0x4);
	dma_desc.dma_bus_addr = rdmem_dma;

	size = 0;
	read_size = 0;
	/*
	 * Perform rdmem operation using pex-dma.
	 * Prepare dma in chunks of QLA83XX_PEX_DMA_READ_SIZE.
	 */
	while (read_size < m_hdr->read_data_size) {
		if (m_hdr->read_data_size - read_size >=
		    QLA83XX_PEX_DMA_READ_SIZE)
			size = QLA83XX_PEX_DMA_READ_SIZE;
		else {
			size = (m_hdr->read_data_size - read_size);

			if (rdmem_buffer)
				dma_free_coherent(&ha->pdev->dev,
						  QLA83XX_PEX_DMA_READ_SIZE,
						  rdmem_buffer, rdmem_dma);

			rdmem_buffer = dma_alloc_coherent(&ha->pdev->dev, size,
							  &rdmem_dma,
							  GFP_KERNEL);
			if (!rdmem_buffer) {
				DEBUG2(ql4_printk(KERN_INFO, ha,
						  "%s: Unable to allocate rdmem dma buffer\n",
						  __func__));
				return QLA_ERROR;
			}
			dma_desc.dma_bus_addr = rdmem_dma;
		}

		dma_desc.src_addr = m_hdr->read_addr + read_size;
		dma_desc.cmd.read_data_size = size;

		/* Prepare: Write pex-dma descriptor to MS memory. */
		rval = qla4_83xx_ms_mem_write_128b(ha,
			      (uint64_t)m_hdr->desc_card_addr,
			      (uint32_t *)&dma_desc,
			      (sizeof(struct qla4_83xx_pex_dma_descriptor)/16));
		if (rval == -1) {
			ql4_printk(KERN_INFO, ha,
				   "%s: Error writing rdmem-dma-init to MS !!!\n",
				   __func__);
			goto error_exit;
		}

		DEBUG2(ql4_printk(KERN_INFO, ha,
				  "%s: Dma-desc: Instruct for rdmem dma (size 0x%x).\n",
				  __func__, size));
		/* Execute: Start pex-dma operation. */
		rval = qla4_83xx_start_pex_dma(ha, m_hdr);
		if (rval != QLA_SUCCESS) {
			DEBUG2(ql4_printk(KERN_INFO, ha,
					  "scsi(%ld): start-pex-dma failed rval=0x%x\n",
					  ha->host_no, rval));
			goto error_exit;
		}

		memcpy(data_ptr, rdmem_buffer, size);
		data_ptr += size;
		read_size += size;
	}

	DEBUG2(ql4_printk(KERN_INFO, ha, "Leaving fn: %s\n", __func__));

	*d_ptr = (uint32_t *)data_ptr;

error_exit:
	if (rdmem_buffer)
		dma_free_coherent(&ha->pdev->dev, size, rdmem_buffer,
				  rdmem_dma);

	return rval;
}

static int qla4_8xxx_minidump_process_l2tag(struct scsi_qla_host *ha,
				 struct qla8xxx_minidump_entry_hdr *entry_hdr,
				 uint32_t **d_ptr)
@@ -2068,7 +2270,7 @@ static void qla4_82xx_minidump_process_rdrom(struct scsi_qla_host *ha,
#define MD_MIU_TEST_AGT_ADDR_LO		0x41000094
#define MD_MIU_TEST_AGT_ADDR_HI		0x41000098

static int qla4_8xxx_minidump_process_rdmem(struct scsi_qla_host *ha,
static int __qla4_8xxx_minidump_process_rdmem(struct scsi_qla_host *ha,
				struct qla8xxx_minidump_entry_hdr *entry_hdr,
				uint32_t **d_ptr)
{
@@ -2150,6 +2352,28 @@ static int qla4_8xxx_minidump_process_rdmem(struct scsi_qla_host *ha,
	return QLA_SUCCESS;
}

static int qla4_8xxx_minidump_process_rdmem(struct scsi_qla_host *ha,
				struct qla8xxx_minidump_entry_hdr *entry_hdr,
				uint32_t **d_ptr)
{
	uint32_t *data_ptr = *d_ptr;
	int rval = QLA_SUCCESS;

	if (is_qla8032(ha) || is_qla8042(ha)) {
		rval = qla4_83xx_minidump_pex_dma_read(ha, entry_hdr,
						       &data_ptr);
		if (rval != QLA_SUCCESS) {
			rval = __qla4_8xxx_minidump_process_rdmem(ha, entry_hdr,
								  &data_ptr);
		}
	} else {
		rval = __qla4_8xxx_minidump_process_rdmem(ha, entry_hdr,
							  &data_ptr);
	}
	*d_ptr = data_ptr;
	return rval;
}

static void qla4_8xxx_mark_entry_skipped(struct scsi_qla_host *ha,
				struct qla8xxx_minidump_entry_hdr *entry_hdr,
				int index)