Commit b1829789 authored by Tej Parkash's avatar Tej Parkash Committed by Christoph Hellwig
Browse files

qla4xxx: Added new opcodes for 84XX Minidump template



Updated driver with new opcode (RDDFE, RDMDIO and POLLWR) which are
added with latest firmware minidump template

Signed-off-by: default avatarTej Parkash <tej.parkash@qlogic.com>
Signed-off-by: default avatarVikas Chaudhary <vikas.chaudhary@qlogic.com>
Reviewed-by: default avatarMike Christie <michaelc@cs.wisc.edu>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
parent b410982c
Loading
Loading
Loading
Loading
+44 −0
Original line number Diff line number Diff line
@@ -254,6 +254,50 @@ struct qla83xx_minidump_entry_pollrd {
	uint32_t rsvd_1;
};

struct qla8044_minidump_entry_rddfe {
	struct qla8xxx_minidump_entry_hdr h;
	uint32_t addr_1;
	uint32_t value;
	uint8_t stride;
	uint8_t stride2;
	uint16_t count;
	uint32_t poll;
	uint32_t mask;
	uint32_t modify_mask;
	uint32_t data_size;
	uint32_t rsvd;

} __packed;

struct qla8044_minidump_entry_rdmdio {
	struct qla8xxx_minidump_entry_hdr h;

	uint32_t addr_1;
	uint32_t addr_2;
	uint32_t value_1;
	uint8_t stride_1;
	uint8_t stride_2;
	uint16_t count;
	uint32_t poll;
	uint32_t mask;
	uint32_t value_2;
	uint32_t data_size;

} __packed;

struct qla8044_minidump_entry_pollwr {
	struct qla8xxx_minidump_entry_hdr h;
	uint32_t addr_1;
	uint32_t addr_2;
	uint32_t value_1;
	uint32_t value_2;
	uint32_t poll;
	uint32_t mask;
	uint32_t data_size;
	uint32_t rsvd;

} __packed;

/* RDMUX2 Entry */
struct qla83xx_minidump_entry_rdmux2 {
	struct qla8xxx_minidump_entry_hdr h;
+335 −0
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@

#include <asm-generic/io-64-nonatomic-lo-hi.h>

#define TIMEOUT_100_MS	100
#define MASK(n)		DMA_BIT_MASK(n)
#define MN_WIN(addr)	(((addr & 0x1fc0000) >> 1) | ((addr >> 25) & 0x3ff))
#define OCM_WIN(addr)	(((addr & 0x1ff0000) >> 1) | ((addr >> 25) & 0x3ff))
@@ -1714,6 +1715,101 @@ void qla4_82xx_rom_lock_recovery(struct scsi_qla_host *ha)
	qla4_82xx_rom_unlock(ha);
}

static uint32_t ql4_84xx_poll_wait_for_ready(struct scsi_qla_host *ha,
					     uint32_t addr1, uint32_t mask)
{
	unsigned long timeout;
	uint32_t rval = QLA_SUCCESS;
	uint32_t temp;

	timeout = jiffies + msecs_to_jiffies(TIMEOUT_100_MS);
	do {
		ha->isp_ops->rd_reg_indirect(ha, addr1, &temp);
		if ((temp & mask) != 0)
			break;

		if (time_after_eq(jiffies, timeout)) {
			ql4_printk(KERN_INFO, ha, "Error in processing rdmdio entry\n");
			return QLA_ERROR;
		}
	} while (1);

	return rval;
}

uint32_t ql4_84xx_ipmdio_rd_reg(struct scsi_qla_host *ha, uint32_t addr1,
				uint32_t addr3, uint32_t mask, uint32_t addr,
				uint32_t *data_ptr)
{
	int rval = QLA_SUCCESS;
	uint32_t temp;
	uint32_t data;

	rval = ql4_84xx_poll_wait_for_ready(ha, addr1, mask);
	if (rval)
		goto exit_ipmdio_rd_reg;

	temp = (0x40000000 | addr);
	ha->isp_ops->wr_reg_indirect(ha, addr1, temp);

	rval = ql4_84xx_poll_wait_for_ready(ha, addr1, mask);
	if (rval)
		goto exit_ipmdio_rd_reg;

	ha->isp_ops->rd_reg_indirect(ha, addr3, &data);
	*data_ptr = data;

exit_ipmdio_rd_reg:
	return rval;
}


static uint32_t ql4_84xx_poll_wait_ipmdio_bus_idle(struct scsi_qla_host *ha,
						    uint32_t addr1,
						    uint32_t addr2,
						    uint32_t addr3,
						    uint32_t mask)
{
	unsigned long timeout;
	uint32_t temp;
	uint32_t rval = QLA_SUCCESS;

	timeout = jiffies + msecs_to_jiffies(TIMEOUT_100_MS);
	do {
		ql4_84xx_ipmdio_rd_reg(ha, addr1, addr3, mask, addr2, &temp);
		if ((temp & 0x1) != 1)
			break;
		if (time_after_eq(jiffies, timeout)) {
			ql4_printk(KERN_INFO, ha, "Error in processing mdiobus idle\n");
			return QLA_ERROR;
		}
	} while (1);

	return rval;
}

static int ql4_84xx_ipmdio_wr_reg(struct scsi_qla_host *ha,
				  uint32_t addr1, uint32_t addr3,
				  uint32_t mask, uint32_t addr,
				  uint32_t value)
{
	int rval = QLA_SUCCESS;

	rval = ql4_84xx_poll_wait_for_ready(ha, addr1, mask);
	if (rval)
		goto exit_ipmdio_wr_reg;

	ha->isp_ops->wr_reg_indirect(ha, addr3, value);
	ha->isp_ops->wr_reg_indirect(ha, addr1, addr);

	rval = ql4_84xx_poll_wait_for_ready(ha, addr1, mask);
	if (rval)
		goto exit_ipmdio_wr_reg;

exit_ipmdio_wr_reg:
	return rval;
}

static void qla4_8xxx_minidump_process_rdcrb(struct scsi_qla_host *ha,
				struct qla8xxx_minidump_entry_hdr *entry_hdr,
				uint32_t **d_ptr)
@@ -2440,6 +2536,227 @@ exit_process_pollrd:
	return rval;
}

static uint32_t qla4_84xx_minidump_process_rddfe(struct scsi_qla_host *ha,
				struct qla8xxx_minidump_entry_hdr *entry_hdr,
				uint32_t **d_ptr)
{
	int loop_cnt;
	uint32_t addr1, addr2, value, data, temp, wrval;
	uint8_t stride, stride2;
	uint16_t count;
	uint32_t poll, mask, data_size, modify_mask;
	uint32_t wait_count = 0;
	uint32_t *data_ptr = *d_ptr;
	struct qla8044_minidump_entry_rddfe *rddfe;
	uint32_t rval = QLA_SUCCESS;

	rddfe = (struct qla8044_minidump_entry_rddfe *)entry_hdr;
	addr1 = le32_to_cpu(rddfe->addr_1);
	value = le32_to_cpu(rddfe->value);
	stride = le32_to_cpu(rddfe->stride);
	stride2 = le32_to_cpu(rddfe->stride2);
	count = le32_to_cpu(rddfe->count);

	poll = le32_to_cpu(rddfe->poll);
	mask = le32_to_cpu(rddfe->mask);
	modify_mask = le32_to_cpu(rddfe->modify_mask);
	data_size = le32_to_cpu(rddfe->data_size);

	addr2 = addr1 + stride;

	for (loop_cnt = 0x0; loop_cnt < count; loop_cnt++) {
		ha->isp_ops->wr_reg_indirect(ha, addr1, (0x40000000 | value));

		wait_count = 0;
		while (wait_count < poll) {
			ha->isp_ops->rd_reg_indirect(ha, addr1, &temp);
			if ((temp & mask) != 0)
				break;
			wait_count++;
		}

		if (wait_count == poll) {
			ql4_printk(KERN_ERR, ha, "%s: TIMEOUT\n", __func__);
			rval = QLA_ERROR;
			goto exit_process_rddfe;
		} else {
			ha->isp_ops->rd_reg_indirect(ha, addr2, &temp);
			temp = temp & modify_mask;
			temp = (temp | ((loop_cnt << 16) | loop_cnt));
			wrval = ((temp << 16) | temp);

			ha->isp_ops->wr_reg_indirect(ha, addr2, wrval);
			ha->isp_ops->wr_reg_indirect(ha, addr1, value);

			wait_count = 0;
			while (wait_count < poll) {
				ha->isp_ops->rd_reg_indirect(ha, addr1, &temp);
				if ((temp & mask) != 0)
					break;
				wait_count++;
			}
			if (wait_count == poll) {
				ql4_printk(KERN_ERR, ha, "%s: TIMEOUT\n",
					   __func__);
				rval = QLA_ERROR;
				goto exit_process_rddfe;
			}

			ha->isp_ops->wr_reg_indirect(ha, addr1,
						     ((0x40000000 | value) +
						     stride2));
			wait_count = 0;
			while (wait_count < poll) {
				ha->isp_ops->rd_reg_indirect(ha, addr1, &temp);
				if ((temp & mask) != 0)
					break;
				wait_count++;
			}

			if (wait_count == poll) {
				ql4_printk(KERN_ERR, ha, "%s: TIMEOUT\n",
					   __func__);
				rval = QLA_ERROR;
				goto exit_process_rddfe;
			}

			ha->isp_ops->rd_reg_indirect(ha, addr2, &data);

			*data_ptr++ = cpu_to_le32(wrval);
			*data_ptr++ = cpu_to_le32(data);
		}
	}

	*d_ptr = data_ptr;
exit_process_rddfe:
	return rval;
}

static uint32_t qla4_84xx_minidump_process_rdmdio(struct scsi_qla_host *ha,
				struct qla8xxx_minidump_entry_hdr *entry_hdr,
				uint32_t **d_ptr)
{
	int rval = QLA_SUCCESS;
	uint32_t addr1, addr2, value1, value2, data, selval;
	uint8_t stride1, stride2;
	uint32_t addr3, addr4, addr5, addr6, addr7;
	uint16_t count, loop_cnt;
	uint32_t poll, mask;
	uint32_t *data_ptr = *d_ptr;
	struct qla8044_minidump_entry_rdmdio *rdmdio;

	rdmdio = (struct qla8044_minidump_entry_rdmdio *)entry_hdr;
	addr1 = le32_to_cpu(rdmdio->addr_1);
	addr2 = le32_to_cpu(rdmdio->addr_2);
	value1 = le32_to_cpu(rdmdio->value_1);
	stride1 = le32_to_cpu(rdmdio->stride_1);
	stride2 = le32_to_cpu(rdmdio->stride_2);
	count = le32_to_cpu(rdmdio->count);

	poll = le32_to_cpu(rdmdio->poll);
	mask = le32_to_cpu(rdmdio->mask);
	value2 = le32_to_cpu(rdmdio->value_2);

	addr3 = addr1 + stride1;

	for (loop_cnt = 0; loop_cnt < count; loop_cnt++) {
		rval = ql4_84xx_poll_wait_ipmdio_bus_idle(ha, addr1, addr2,
							 addr3, mask);
		if (rval)
			goto exit_process_rdmdio;

		addr4 = addr2 - stride1;
		rval = ql4_84xx_ipmdio_wr_reg(ha, addr1, addr3, mask, addr4,
					     value2);
		if (rval)
			goto exit_process_rdmdio;

		addr5 = addr2 - (2 * stride1);
		rval = ql4_84xx_ipmdio_wr_reg(ha, addr1, addr3, mask, addr5,
					     value1);
		if (rval)
			goto exit_process_rdmdio;

		addr6 = addr2 - (3 * stride1);
		rval = ql4_84xx_ipmdio_wr_reg(ha, addr1, addr3, mask,
					     addr6, 0x2);
		if (rval)
			goto exit_process_rdmdio;

		rval = ql4_84xx_poll_wait_ipmdio_bus_idle(ha, addr1, addr2,
							 addr3, mask);
		if (rval)
			goto exit_process_rdmdio;

		addr7 = addr2 - (4 * stride1);
		rval = ql4_84xx_ipmdio_rd_reg(ha, addr1, addr3,
						      mask, addr7, &data);
		if (rval)
			goto exit_process_rdmdio;

		selval = (value2 << 18) | (value1 << 2) | 2;

		stride2 = le32_to_cpu(rdmdio->stride_2);
		*data_ptr++ = cpu_to_le32(selval);
		*data_ptr++ = cpu_to_le32(data);

		value1 = value1 + stride2;
		*d_ptr = data_ptr;
	}

exit_process_rdmdio:
	return rval;
}

static uint32_t qla4_84xx_minidump_process_pollwr(struct scsi_qla_host *ha,
				struct qla8xxx_minidump_entry_hdr *entry_hdr,
				uint32_t **d_ptr)
{
	uint32_t addr1, addr2, value1, value2, poll, mask, r_value;
	struct qla8044_minidump_entry_pollwr *pollwr_hdr;
	uint32_t wait_count = 0;
	uint32_t rval = QLA_SUCCESS;

	pollwr_hdr = (struct qla8044_minidump_entry_pollwr *)entry_hdr;
	addr1 = le32_to_cpu(pollwr_hdr->addr_1);
	addr2 = le32_to_cpu(pollwr_hdr->addr_2);
	value1 = le32_to_cpu(pollwr_hdr->value_1);
	value2 = le32_to_cpu(pollwr_hdr->value_2);

	poll = le32_to_cpu(pollwr_hdr->poll);
	mask = le32_to_cpu(pollwr_hdr->mask);

	while (wait_count < poll) {
		ha->isp_ops->rd_reg_indirect(ha, addr1, &r_value);

		if ((r_value & poll) != 0)
			break;

		wait_count++;
	}

	if (wait_count == poll) {
		ql4_printk(KERN_ERR, ha, "%s: TIMEOUT\n", __func__);
		rval = QLA_ERROR;
		goto exit_process_pollwr;
	}

	ha->isp_ops->wr_reg_indirect(ha, addr2, value2);
	ha->isp_ops->wr_reg_indirect(ha, addr1, value1);

	wait_count = 0;
	while (wait_count < poll) {
		ha->isp_ops->rd_reg_indirect(ha, addr1, &r_value);

		if ((r_value & poll) != 0)
			break;
		wait_count++;
	}

exit_process_pollwr:
	return rval;
}

static void qla83xx_minidump_process_rdmux2(struct scsi_qla_host *ha,
				struct qla8xxx_minidump_entry_hdr *entry_hdr,
				uint32_t **d_ptr)
@@ -2753,6 +3070,24 @@ static int qla4_8xxx_collect_md_data(struct scsi_qla_host *ha)
			if (rval != QLA_SUCCESS)
				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
			break;
		case QLA8044_RDDFE:
			rval = qla4_84xx_minidump_process_rddfe(ha, entry_hdr,
								&data_ptr);
			if (rval != QLA_SUCCESS)
				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
			break;
		case QLA8044_RDMDIO:
			rval = qla4_84xx_minidump_process_rdmdio(ha, entry_hdr,
								 &data_ptr);
			if (rval != QLA_SUCCESS)
				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
			break;
		case QLA8044_POLLWR:
			rval = qla4_84xx_minidump_process_pollwr(ha, entry_hdr,
								 &data_ptr);
			if (rval != QLA_SUCCESS)
				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
			break;
		case QLA8XXX_RDNOP:
		default:
			qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
+3 −0
Original line number Diff line number Diff line
@@ -858,6 +858,9 @@ struct crb_addr_pair {
#define QLA83XX_POLLRD	35
#define QLA83XX_RDMUX2	36
#define QLA83XX_POLLRDMWR  37
#define QLA8044_RDDFE	38
#define QLA8044_RDMDIO	39
#define QLA8044_POLLWR	40
#define QLA8XXX_RDROM	71
#define QLA8XXX_RDMEM	72
#define QLA8XXX_CNTRL	98