162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * QLogic Fibre Channel HBA Driver
462306a36Sopenharmony_ci * Copyright (c)  2003-2014 QLogic Corporation
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/vmalloc.h>
862306a36Sopenharmony_ci#include <linux/delay.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include "qla_def.h"
1162306a36Sopenharmony_ci#include "qla_gbl.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#define TIMEOUT_100_MS 100
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_cistatic const uint32_t qla8044_reg_tbl[] = {
1662306a36Sopenharmony_ci	QLA8044_PEG_HALT_STATUS1,
1762306a36Sopenharmony_ci	QLA8044_PEG_HALT_STATUS2,
1862306a36Sopenharmony_ci	QLA8044_PEG_ALIVE_COUNTER,
1962306a36Sopenharmony_ci	QLA8044_CRB_DRV_ACTIVE,
2062306a36Sopenharmony_ci	QLA8044_CRB_DEV_STATE,
2162306a36Sopenharmony_ci	QLA8044_CRB_DRV_STATE,
2262306a36Sopenharmony_ci	QLA8044_CRB_DRV_SCRATCH,
2362306a36Sopenharmony_ci	QLA8044_CRB_DEV_PART_INFO1,
2462306a36Sopenharmony_ci	QLA8044_CRB_IDC_VER_MAJOR,
2562306a36Sopenharmony_ci	QLA8044_FW_VER_MAJOR,
2662306a36Sopenharmony_ci	QLA8044_FW_VER_MINOR,
2762306a36Sopenharmony_ci	QLA8044_FW_VER_SUB,
2862306a36Sopenharmony_ci	QLA8044_CMDPEG_STATE,
2962306a36Sopenharmony_ci	QLA8044_ASIC_TEMP,
3062306a36Sopenharmony_ci};
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci/* 8044 Flash Read/Write functions */
3362306a36Sopenharmony_ciuint32_t
3462306a36Sopenharmony_ciqla8044_rd_reg(struct qla_hw_data *ha, ulong addr)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	return readl((void __iomem *) (ha->nx_pcibase + addr));
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_civoid
4062306a36Sopenharmony_ciqla8044_wr_reg(struct qla_hw_data *ha, ulong addr, uint32_t val)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	writel(val, (void __iomem *)((ha)->nx_pcibase + addr));
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ciint
4662306a36Sopenharmony_ciqla8044_rd_direct(struct scsi_qla_host *vha,
4762306a36Sopenharmony_ci	const uint32_t crb_reg)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci	if (crb_reg < CRB_REG_INDEX_MAX)
5262306a36Sopenharmony_ci		return qla8044_rd_reg(ha, qla8044_reg_tbl[crb_reg]);
5362306a36Sopenharmony_ci	else
5462306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
5562306a36Sopenharmony_ci}
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_civoid
5862306a36Sopenharmony_ciqla8044_wr_direct(struct scsi_qla_host *vha,
5962306a36Sopenharmony_ci	const uint32_t crb_reg,
6062306a36Sopenharmony_ci	const uint32_t value)
6162306a36Sopenharmony_ci{
6262306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci	if (crb_reg < CRB_REG_INDEX_MAX)
6562306a36Sopenharmony_ci		qla8044_wr_reg(ha, qla8044_reg_tbl[crb_reg], value);
6662306a36Sopenharmony_ci}
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_cistatic int
6962306a36Sopenharmony_ciqla8044_set_win_base(scsi_qla_host_t *vha, uint32_t addr)
7062306a36Sopenharmony_ci{
7162306a36Sopenharmony_ci	uint32_t val;
7262306a36Sopenharmony_ci	int ret_val = QLA_SUCCESS;
7362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci	qla8044_wr_reg(ha, QLA8044_CRB_WIN_FUNC(ha->portnum), addr);
7662306a36Sopenharmony_ci	val = qla8044_rd_reg(ha, QLA8044_CRB_WIN_FUNC(ha->portnum));
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci	if (val != addr) {
7962306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb087,
8062306a36Sopenharmony_ci		    "%s: Failed to set register window : "
8162306a36Sopenharmony_ci		    "addr written 0x%x, read 0x%x!\n",
8262306a36Sopenharmony_ci		    __func__, addr, val);
8362306a36Sopenharmony_ci		ret_val = QLA_FUNCTION_FAILED;
8462306a36Sopenharmony_ci	}
8562306a36Sopenharmony_ci	return ret_val;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic int
8962306a36Sopenharmony_ciqla8044_rd_reg_indirect(scsi_qla_host_t *vha, uint32_t addr, uint32_t *data)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	int ret_val = QLA_SUCCESS;
9262306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	ret_val = qla8044_set_win_base(vha, addr);
9562306a36Sopenharmony_ci	if (!ret_val)
9662306a36Sopenharmony_ci		*data = qla8044_rd_reg(ha, QLA8044_WILDCARD);
9762306a36Sopenharmony_ci	else
9862306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb088,
9962306a36Sopenharmony_ci		    "%s: failed read of addr 0x%x!\n", __func__, addr);
10062306a36Sopenharmony_ci	return ret_val;
10162306a36Sopenharmony_ci}
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_cistatic int
10462306a36Sopenharmony_ciqla8044_wr_reg_indirect(scsi_qla_host_t *vha, uint32_t addr, uint32_t data)
10562306a36Sopenharmony_ci{
10662306a36Sopenharmony_ci	int ret_val = QLA_SUCCESS;
10762306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	ret_val = qla8044_set_win_base(vha, addr);
11062306a36Sopenharmony_ci	if (!ret_val)
11162306a36Sopenharmony_ci		qla8044_wr_reg(ha, QLA8044_WILDCARD, data);
11262306a36Sopenharmony_ci	else
11362306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb089,
11462306a36Sopenharmony_ci		    "%s: failed wrt to addr 0x%x, data 0x%x\n",
11562306a36Sopenharmony_ci		    __func__, addr, data);
11662306a36Sopenharmony_ci	return ret_val;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci/*
12062306a36Sopenharmony_ci * qla8044_read_write_crb_reg - Read from raddr and write value to waddr.
12162306a36Sopenharmony_ci *
12262306a36Sopenharmony_ci * @ha : Pointer to adapter structure
12362306a36Sopenharmony_ci * @raddr : CRB address to read from
12462306a36Sopenharmony_ci * @waddr : CRB address to write to
12562306a36Sopenharmony_ci *
12662306a36Sopenharmony_ci */
12762306a36Sopenharmony_cistatic void
12862306a36Sopenharmony_ciqla8044_read_write_crb_reg(struct scsi_qla_host *vha,
12962306a36Sopenharmony_ci	uint32_t raddr, uint32_t waddr)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	uint32_t value;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	qla8044_rd_reg_indirect(vha, raddr, &value);
13462306a36Sopenharmony_ci	qla8044_wr_reg_indirect(vha, waddr, value);
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_cistatic int
13862306a36Sopenharmony_ciqla8044_poll_wait_for_ready(struct scsi_qla_host *vha, uint32_t addr1,
13962306a36Sopenharmony_ci	uint32_t mask)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	unsigned long timeout;
14262306a36Sopenharmony_ci	uint32_t temp = 0;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	/* jiffies after 100ms */
14562306a36Sopenharmony_ci	timeout = jiffies + msecs_to_jiffies(TIMEOUT_100_MS);
14662306a36Sopenharmony_ci	do {
14762306a36Sopenharmony_ci		qla8044_rd_reg_indirect(vha, addr1, &temp);
14862306a36Sopenharmony_ci		if ((temp & mask) != 0)
14962306a36Sopenharmony_ci			break;
15062306a36Sopenharmony_ci		if (time_after_eq(jiffies, timeout)) {
15162306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb151,
15262306a36Sopenharmony_ci				"Error in processing rdmdio entry\n");
15362306a36Sopenharmony_ci			return -1;
15462306a36Sopenharmony_ci		}
15562306a36Sopenharmony_ci	} while (1);
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	return 0;
15862306a36Sopenharmony_ci}
15962306a36Sopenharmony_ci
16062306a36Sopenharmony_cistatic uint32_t
16162306a36Sopenharmony_ciqla8044_ipmdio_rd_reg(struct scsi_qla_host *vha,
16262306a36Sopenharmony_ci	uint32_t addr1, uint32_t addr3, uint32_t mask, uint32_t addr)
16362306a36Sopenharmony_ci{
16462306a36Sopenharmony_ci	uint32_t temp;
16562306a36Sopenharmony_ci	int ret = 0;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	ret = qla8044_poll_wait_for_ready(vha, addr1, mask);
16862306a36Sopenharmony_ci	if (ret == -1)
16962306a36Sopenharmony_ci		return -1;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	temp = (0x40000000 | addr);
17262306a36Sopenharmony_ci	qla8044_wr_reg_indirect(vha, addr1, temp);
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci	ret = qla8044_poll_wait_for_ready(vha, addr1, mask);
17562306a36Sopenharmony_ci	if (ret == -1)
17662306a36Sopenharmony_ci		return 0;
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	qla8044_rd_reg_indirect(vha, addr3, &ret);
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	return ret;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cistatic int
18562306a36Sopenharmony_ciqla8044_poll_wait_ipmdio_bus_idle(struct scsi_qla_host *vha,
18662306a36Sopenharmony_ci	uint32_t addr1, uint32_t addr2, uint32_t addr3, uint32_t mask)
18762306a36Sopenharmony_ci{
18862306a36Sopenharmony_ci	unsigned long timeout;
18962306a36Sopenharmony_ci	uint32_t temp;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	/* jiffies after 100 msecs */
19262306a36Sopenharmony_ci	timeout = jiffies + msecs_to_jiffies(TIMEOUT_100_MS);
19362306a36Sopenharmony_ci	do {
19462306a36Sopenharmony_ci		temp = qla8044_ipmdio_rd_reg(vha, addr1, addr3, mask, addr2);
19562306a36Sopenharmony_ci		if ((temp & 0x1) != 1)
19662306a36Sopenharmony_ci			break;
19762306a36Sopenharmony_ci		if (time_after_eq(jiffies, timeout)) {
19862306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb152,
19962306a36Sopenharmony_ci			    "Error in processing mdiobus idle\n");
20062306a36Sopenharmony_ci			return -1;
20162306a36Sopenharmony_ci		}
20262306a36Sopenharmony_ci	} while (1);
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	return 0;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_cistatic int
20862306a36Sopenharmony_ciqla8044_ipmdio_wr_reg(struct scsi_qla_host *vha, uint32_t addr1,
20962306a36Sopenharmony_ci	uint32_t addr3, uint32_t mask, uint32_t addr, uint32_t value)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	int ret = 0;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	ret = qla8044_poll_wait_for_ready(vha, addr1, mask);
21462306a36Sopenharmony_ci	if (ret == -1)
21562306a36Sopenharmony_ci		return -1;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	qla8044_wr_reg_indirect(vha, addr3, value);
21862306a36Sopenharmony_ci	qla8044_wr_reg_indirect(vha, addr1, addr);
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	ret = qla8044_poll_wait_for_ready(vha, addr1, mask);
22162306a36Sopenharmony_ci	if (ret == -1)
22262306a36Sopenharmony_ci		return -1;
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	return 0;
22562306a36Sopenharmony_ci}
22662306a36Sopenharmony_ci/*
22762306a36Sopenharmony_ci * qla8044_rmw_crb_reg - Read value from raddr, AND with test_mask,
22862306a36Sopenharmony_ci * Shift Left,Right/OR/XOR with values RMW header and write value to waddr.
22962306a36Sopenharmony_ci *
23062306a36Sopenharmony_ci * @vha : Pointer to adapter structure
23162306a36Sopenharmony_ci * @raddr : CRB address to read from
23262306a36Sopenharmony_ci * @waddr : CRB address to write to
23362306a36Sopenharmony_ci * @p_rmw_hdr : header with shift/or/xor values.
23462306a36Sopenharmony_ci *
23562306a36Sopenharmony_ci */
23662306a36Sopenharmony_cistatic void
23762306a36Sopenharmony_ciqla8044_rmw_crb_reg(struct scsi_qla_host *vha,
23862306a36Sopenharmony_ci	uint32_t raddr, uint32_t waddr,	struct qla8044_rmw *p_rmw_hdr)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	uint32_t value;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	if (p_rmw_hdr->index_a)
24362306a36Sopenharmony_ci		value = vha->reset_tmplt.array[p_rmw_hdr->index_a];
24462306a36Sopenharmony_ci	else
24562306a36Sopenharmony_ci		qla8044_rd_reg_indirect(vha, raddr, &value);
24662306a36Sopenharmony_ci	value &= p_rmw_hdr->test_mask;
24762306a36Sopenharmony_ci	value <<= p_rmw_hdr->shl;
24862306a36Sopenharmony_ci	value >>= p_rmw_hdr->shr;
24962306a36Sopenharmony_ci	value |= p_rmw_hdr->or_value;
25062306a36Sopenharmony_ci	value ^= p_rmw_hdr->xor_value;
25162306a36Sopenharmony_ci	qla8044_wr_reg_indirect(vha, waddr, value);
25262306a36Sopenharmony_ci	return;
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_cistatic inline void
25662306a36Sopenharmony_ciqla8044_set_qsnt_ready(struct scsi_qla_host *vha)
25762306a36Sopenharmony_ci{
25862306a36Sopenharmony_ci	uint32_t qsnt_state;
25962306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
26062306a36Sopenharmony_ci
26162306a36Sopenharmony_ci	qsnt_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX);
26262306a36Sopenharmony_ci	qsnt_state |= (1 << ha->portnum);
26362306a36Sopenharmony_ci	qla8044_wr_direct(vha, QLA8044_CRB_DRV_STATE_INDEX, qsnt_state);
26462306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0xb08e, "%s(%ld): qsnt_state: 0x%08x\n",
26562306a36Sopenharmony_ci	     __func__, vha->host_no, qsnt_state);
26662306a36Sopenharmony_ci}
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_civoid
26962306a36Sopenharmony_ciqla8044_clear_qsnt_ready(struct scsi_qla_host *vha)
27062306a36Sopenharmony_ci{
27162306a36Sopenharmony_ci	uint32_t qsnt_state;
27262306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_ci	qsnt_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX);
27562306a36Sopenharmony_ci	qsnt_state &= ~(1 << ha->portnum);
27662306a36Sopenharmony_ci	qla8044_wr_direct(vha, QLA8044_CRB_DRV_STATE_INDEX, qsnt_state);
27762306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0xb08f, "%s(%ld): qsnt_state: 0x%08x\n",
27862306a36Sopenharmony_ci	    __func__, vha->host_no, qsnt_state);
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_ci/**
28262306a36Sopenharmony_ci * qla8044_lock_recovery - Recovers the idc_lock.
28362306a36Sopenharmony_ci * @vha : Pointer to adapter structure
28462306a36Sopenharmony_ci *
28562306a36Sopenharmony_ci * Lock Recovery Register
28662306a36Sopenharmony_ci * 5-2	Lock recovery owner: Function ID of driver doing lock recovery,
28762306a36Sopenharmony_ci *	valid if bits 1..0 are set by driver doing lock recovery.
28862306a36Sopenharmony_ci * 1-0  1 - Driver intends to force unlock the IDC lock.
28962306a36Sopenharmony_ci *	2 - Driver is moving forward to unlock the IDC lock. Driver clears
29062306a36Sopenharmony_ci *	    this field after force unlocking the IDC lock.
29162306a36Sopenharmony_ci *
29262306a36Sopenharmony_ci * Lock Recovery process
29362306a36Sopenharmony_ci * a. Read the IDC_LOCK_RECOVERY register. If the value in bits 1..0 is
29462306a36Sopenharmony_ci *    greater than 0, then wait for the other driver to unlock otherwise
29562306a36Sopenharmony_ci *    move to the next step.
29662306a36Sopenharmony_ci * b. Indicate intent to force-unlock by writing 1h to the IDC_LOCK_RECOVERY
29762306a36Sopenharmony_ci *    register bits 1..0 and also set the function# in bits 5..2.
29862306a36Sopenharmony_ci * c. Read the IDC_LOCK_RECOVERY register again after a delay of 200ms.
29962306a36Sopenharmony_ci *    Wait for the other driver to perform lock recovery if the function
30062306a36Sopenharmony_ci *    number in bits 5..2 has changed, otherwise move to the next step.
30162306a36Sopenharmony_ci * d. Write a value of 2h to the IDC_LOCK_RECOVERY register bits 1..0
30262306a36Sopenharmony_ci *    leaving your function# in bits 5..2.
30362306a36Sopenharmony_ci * e. Force unlock using the DRIVER_UNLOCK register and immediately clear
30462306a36Sopenharmony_ci *    the IDC_LOCK_RECOVERY bits 5..0 by writing 0.
30562306a36Sopenharmony_ci **/
30662306a36Sopenharmony_cistatic int
30762306a36Sopenharmony_ciqla8044_lock_recovery(struct scsi_qla_host *vha)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	uint32_t lock = 0, lockid;
31062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	lockid = qla8044_rd_reg(ha, QLA8044_DRV_LOCKRECOVERY);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	/* Check for other Recovery in progress, go wait */
31562306a36Sopenharmony_ci	if ((lockid & IDC_LOCK_RECOVERY_STATE_MASK) != 0)
31662306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	/* Intent to Recover */
31962306a36Sopenharmony_ci	qla8044_wr_reg(ha, QLA8044_DRV_LOCKRECOVERY,
32062306a36Sopenharmony_ci	    (ha->portnum <<
32162306a36Sopenharmony_ci	     IDC_LOCK_RECOVERY_STATE_SHIFT_BITS) | INTENT_TO_RECOVER);
32262306a36Sopenharmony_ci	msleep(200);
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	/* Check Intent to Recover is advertised */
32562306a36Sopenharmony_ci	lockid = qla8044_rd_reg(ha, QLA8044_DRV_LOCKRECOVERY);
32662306a36Sopenharmony_ci	if ((lockid & IDC_LOCK_RECOVERY_OWNER_MASK) != (ha->portnum <<
32762306a36Sopenharmony_ci	    IDC_LOCK_RECOVERY_STATE_SHIFT_BITS))
32862306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb08B, "%s:%d: IDC Lock recovery initiated\n"
33162306a36Sopenharmony_ci	    , __func__, ha->portnum);
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ci	/* Proceed to Recover */
33462306a36Sopenharmony_ci	qla8044_wr_reg(ha, QLA8044_DRV_LOCKRECOVERY,
33562306a36Sopenharmony_ci	    (ha->portnum << IDC_LOCK_RECOVERY_STATE_SHIFT_BITS) |
33662306a36Sopenharmony_ci	    PROCEED_TO_RECOVER);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	/* Force Unlock() */
33962306a36Sopenharmony_ci	qla8044_wr_reg(ha, QLA8044_DRV_LOCK_ID, 0xFF);
34062306a36Sopenharmony_ci	qla8044_rd_reg(ha, QLA8044_DRV_UNLOCK);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	/* Clear bits 0-5 in IDC_RECOVERY register*/
34362306a36Sopenharmony_ci	qla8044_wr_reg(ha, QLA8044_DRV_LOCKRECOVERY, 0);
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/* Get lock() */
34662306a36Sopenharmony_ci	lock = qla8044_rd_reg(ha, QLA8044_DRV_LOCK);
34762306a36Sopenharmony_ci	if (lock) {
34862306a36Sopenharmony_ci		lockid = qla8044_rd_reg(ha, QLA8044_DRV_LOCK_ID);
34962306a36Sopenharmony_ci		lockid = ((lockid + (1 << 8)) & ~0xFF) | ha->portnum;
35062306a36Sopenharmony_ci		qla8044_wr_reg(ha, QLA8044_DRV_LOCK_ID, lockid);
35162306a36Sopenharmony_ci		return QLA_SUCCESS;
35262306a36Sopenharmony_ci	} else
35362306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
35462306a36Sopenharmony_ci}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ciint
35762306a36Sopenharmony_ciqla8044_idc_lock(struct qla_hw_data *ha)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	uint32_t ret_val = QLA_SUCCESS, timeout = 0, status = 0;
36062306a36Sopenharmony_ci	uint32_t lock_id, lock_cnt, func_num, tmo_owner = 0, first_owner = 0;
36162306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	while (status == 0) {
36462306a36Sopenharmony_ci		/* acquire semaphore5 from PCI HW block */
36562306a36Sopenharmony_ci		status = qla8044_rd_reg(ha, QLA8044_DRV_LOCK);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci		if (status) {
36862306a36Sopenharmony_ci			/* Increment Counter (8-31) and update func_num (0-7) on
36962306a36Sopenharmony_ci			 * getting a successful lock  */
37062306a36Sopenharmony_ci			lock_id = qla8044_rd_reg(ha, QLA8044_DRV_LOCK_ID);
37162306a36Sopenharmony_ci			lock_id = ((lock_id + (1 << 8)) & ~0xFF) | ha->portnum;
37262306a36Sopenharmony_ci			qla8044_wr_reg(ha, QLA8044_DRV_LOCK_ID, lock_id);
37362306a36Sopenharmony_ci			break;
37462306a36Sopenharmony_ci		}
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci		if (timeout == 0)
37762306a36Sopenharmony_ci			first_owner = qla8044_rd_reg(ha, QLA8044_DRV_LOCK_ID);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci		if (++timeout >=
38062306a36Sopenharmony_ci		    (QLA8044_DRV_LOCK_TIMEOUT / QLA8044_DRV_LOCK_MSLEEP)) {
38162306a36Sopenharmony_ci			tmo_owner = qla8044_rd_reg(ha, QLA8044_DRV_LOCK_ID);
38262306a36Sopenharmony_ci			func_num = tmo_owner & 0xFF;
38362306a36Sopenharmony_ci			lock_cnt = tmo_owner >> 8;
38462306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb114,
38562306a36Sopenharmony_ci			    "%s: Lock by func %d failed after 2s, lock held "
38662306a36Sopenharmony_ci			    "by func %d, lock count %d, first_owner %d\n",
38762306a36Sopenharmony_ci			    __func__, ha->portnum, func_num, lock_cnt,
38862306a36Sopenharmony_ci			    (first_owner & 0xFF));
38962306a36Sopenharmony_ci			if (first_owner != tmo_owner) {
39062306a36Sopenharmony_ci				/* Some other driver got lock,
39162306a36Sopenharmony_ci				 * OR same driver got lock again (counter
39262306a36Sopenharmony_ci				 * value changed), when we were waiting for
39362306a36Sopenharmony_ci				 * lock. Retry for another 2 sec */
39462306a36Sopenharmony_ci				ql_dbg(ql_dbg_p3p, vha, 0xb115,
39562306a36Sopenharmony_ci				    "%s: %d: IDC lock failed\n",
39662306a36Sopenharmony_ci				    __func__, ha->portnum);
39762306a36Sopenharmony_ci				timeout = 0;
39862306a36Sopenharmony_ci			} else {
39962306a36Sopenharmony_ci				/* Same driver holding lock > 2sec.
40062306a36Sopenharmony_ci				 * Force Recovery */
40162306a36Sopenharmony_ci				if (qla8044_lock_recovery(vha) == QLA_SUCCESS) {
40262306a36Sopenharmony_ci					/* Recovered and got lock */
40362306a36Sopenharmony_ci					ret_val = QLA_SUCCESS;
40462306a36Sopenharmony_ci					ql_dbg(ql_dbg_p3p, vha, 0xb116,
40562306a36Sopenharmony_ci					    "%s:IDC lock Recovery by %d"
40662306a36Sopenharmony_ci					    "successful...\n", __func__,
40762306a36Sopenharmony_ci					     ha->portnum);
40862306a36Sopenharmony_ci				}
40962306a36Sopenharmony_ci				/* Recovery Failed, some other function
41062306a36Sopenharmony_ci				 * has the lock, wait for 2secs
41162306a36Sopenharmony_ci				 * and retry
41262306a36Sopenharmony_ci				 */
41362306a36Sopenharmony_ci				ql_dbg(ql_dbg_p3p, vha, 0xb08a,
41462306a36Sopenharmony_ci				       "%s: IDC lock Recovery by %d "
41562306a36Sopenharmony_ci				       "failed, Retrying timeout\n", __func__,
41662306a36Sopenharmony_ci				       ha->portnum);
41762306a36Sopenharmony_ci				timeout = 0;
41862306a36Sopenharmony_ci			}
41962306a36Sopenharmony_ci		}
42062306a36Sopenharmony_ci		msleep(QLA8044_DRV_LOCK_MSLEEP);
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci	return ret_val;
42362306a36Sopenharmony_ci}
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_civoid
42662306a36Sopenharmony_ciqla8044_idc_unlock(struct qla_hw_data *ha)
42762306a36Sopenharmony_ci{
42862306a36Sopenharmony_ci	int id;
42962306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	id = qla8044_rd_reg(ha, QLA8044_DRV_LOCK_ID);
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	if ((id & 0xFF) != ha->portnum) {
43462306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb118,
43562306a36Sopenharmony_ci		    "%s: IDC Unlock by %d failed, lock owner is %d!\n",
43662306a36Sopenharmony_ci		    __func__, ha->portnum, (id & 0xFF));
43762306a36Sopenharmony_ci		return;
43862306a36Sopenharmony_ci	}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_ci	/* Keep lock counter value, update the ha->func_num to 0xFF */
44162306a36Sopenharmony_ci	qla8044_wr_reg(ha, QLA8044_DRV_LOCK_ID, (id | 0xFF));
44262306a36Sopenharmony_ci	qla8044_rd_reg(ha, QLA8044_DRV_UNLOCK);
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci/* 8044 Flash Lock/Unlock functions */
44662306a36Sopenharmony_cistatic int
44762306a36Sopenharmony_ciqla8044_flash_lock(scsi_qla_host_t *vha)
44862306a36Sopenharmony_ci{
44962306a36Sopenharmony_ci	int lock_owner;
45062306a36Sopenharmony_ci	int timeout = 0;
45162306a36Sopenharmony_ci	uint32_t lock_status = 0;
45262306a36Sopenharmony_ci	int ret_val = QLA_SUCCESS;
45362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci	while (lock_status == 0) {
45662306a36Sopenharmony_ci		lock_status = qla8044_rd_reg(ha, QLA8044_FLASH_LOCK);
45762306a36Sopenharmony_ci		if (lock_status)
45862306a36Sopenharmony_ci			break;
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_ci		if (++timeout >= QLA8044_FLASH_LOCK_TIMEOUT / 20) {
46162306a36Sopenharmony_ci			lock_owner = qla8044_rd_reg(ha,
46262306a36Sopenharmony_ci			    QLA8044_FLASH_LOCK_ID);
46362306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb113,
46462306a36Sopenharmony_ci			    "%s: Simultaneous flash access by following ports, active port = %d: accessing port = %d",
46562306a36Sopenharmony_ci			    __func__, ha->portnum, lock_owner);
46662306a36Sopenharmony_ci			ret_val = QLA_FUNCTION_FAILED;
46762306a36Sopenharmony_ci			break;
46862306a36Sopenharmony_ci		}
46962306a36Sopenharmony_ci		msleep(20);
47062306a36Sopenharmony_ci	}
47162306a36Sopenharmony_ci	qla8044_wr_reg(ha, QLA8044_FLASH_LOCK_ID, ha->portnum);
47262306a36Sopenharmony_ci	return ret_val;
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic void
47662306a36Sopenharmony_ciqla8044_flash_unlock(scsi_qla_host_t *vha)
47762306a36Sopenharmony_ci{
47862306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	/* Reading FLASH_UNLOCK register unlocks the Flash */
48162306a36Sopenharmony_ci	qla8044_wr_reg(ha, QLA8044_FLASH_LOCK_ID, 0xFF);
48262306a36Sopenharmony_ci	qla8044_rd_reg(ha, QLA8044_FLASH_UNLOCK);
48362306a36Sopenharmony_ci}
48462306a36Sopenharmony_ci
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_cistatic
48762306a36Sopenharmony_civoid qla8044_flash_lock_recovery(struct scsi_qla_host *vha)
48862306a36Sopenharmony_ci{
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	if (qla8044_flash_lock(vha)) {
49162306a36Sopenharmony_ci		/* Someone else is holding the lock. */
49262306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb120, "Resetting flash_lock\n");
49362306a36Sopenharmony_ci	}
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	/*
49662306a36Sopenharmony_ci	 * Either we got the lock, or someone
49762306a36Sopenharmony_ci	 * else died while holding it.
49862306a36Sopenharmony_ci	 * In either case, unlock.
49962306a36Sopenharmony_ci	 */
50062306a36Sopenharmony_ci	qla8044_flash_unlock(vha);
50162306a36Sopenharmony_ci}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci/*
50462306a36Sopenharmony_ci * Address and length are byte address
50562306a36Sopenharmony_ci */
50662306a36Sopenharmony_cistatic int
50762306a36Sopenharmony_ciqla8044_read_flash_data(scsi_qla_host_t *vha,  uint8_t *p_data,
50862306a36Sopenharmony_ci	uint32_t flash_addr, int u32_word_count)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	int i, ret_val = QLA_SUCCESS;
51162306a36Sopenharmony_ci	uint32_t u32_word;
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	if (qla8044_flash_lock(vha) != QLA_SUCCESS) {
51462306a36Sopenharmony_ci		ret_val = QLA_FUNCTION_FAILED;
51562306a36Sopenharmony_ci		goto exit_lock_error;
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	if (flash_addr & 0x03) {
51962306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb117,
52062306a36Sopenharmony_ci		    "%s: Illegal addr = 0x%x\n", __func__, flash_addr);
52162306a36Sopenharmony_ci		ret_val = QLA_FUNCTION_FAILED;
52262306a36Sopenharmony_ci		goto exit_flash_read;
52362306a36Sopenharmony_ci	}
52462306a36Sopenharmony_ci
52562306a36Sopenharmony_ci	for (i = 0; i < u32_word_count; i++) {
52662306a36Sopenharmony_ci		if (qla8044_wr_reg_indirect(vha, QLA8044_FLASH_DIRECT_WINDOW,
52762306a36Sopenharmony_ci		    (flash_addr & 0xFFFF0000))) {
52862306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb119,
52962306a36Sopenharmony_ci			    "%s: failed to write addr 0x%x to "
53062306a36Sopenharmony_ci			    "FLASH_DIRECT_WINDOW\n! ",
53162306a36Sopenharmony_ci			    __func__, flash_addr);
53262306a36Sopenharmony_ci			ret_val = QLA_FUNCTION_FAILED;
53362306a36Sopenharmony_ci			goto exit_flash_read;
53462306a36Sopenharmony_ci		}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci		ret_val = qla8044_rd_reg_indirect(vha,
53762306a36Sopenharmony_ci		    QLA8044_FLASH_DIRECT_DATA(flash_addr),
53862306a36Sopenharmony_ci		    &u32_word);
53962306a36Sopenharmony_ci		if (ret_val != QLA_SUCCESS) {
54062306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb08c,
54162306a36Sopenharmony_ci			    "%s: failed to read addr 0x%x!\n",
54262306a36Sopenharmony_ci			    __func__, flash_addr);
54362306a36Sopenharmony_ci			goto exit_flash_read;
54462306a36Sopenharmony_ci		}
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci		*(uint32_t *)p_data = u32_word;
54762306a36Sopenharmony_ci		p_data = p_data + 4;
54862306a36Sopenharmony_ci		flash_addr = flash_addr + 4;
54962306a36Sopenharmony_ci	}
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ciexit_flash_read:
55262306a36Sopenharmony_ci	qla8044_flash_unlock(vha);
55362306a36Sopenharmony_ci
55462306a36Sopenharmony_ciexit_lock_error:
55562306a36Sopenharmony_ci	return ret_val;
55662306a36Sopenharmony_ci}
55762306a36Sopenharmony_ci
55862306a36Sopenharmony_ci/*
55962306a36Sopenharmony_ci * Address and length are byte address
56062306a36Sopenharmony_ci */
56162306a36Sopenharmony_civoid *
56262306a36Sopenharmony_ciqla8044_read_optrom_data(struct scsi_qla_host *vha, void *buf,
56362306a36Sopenharmony_ci	uint32_t offset, uint32_t length)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	scsi_block_requests(vha->host);
56662306a36Sopenharmony_ci	if (qla8044_read_flash_data(vha, buf, offset, length / 4)
56762306a36Sopenharmony_ci	    != QLA_SUCCESS) {
56862306a36Sopenharmony_ci		ql_log(ql_log_warn, vha,  0xb08d,
56962306a36Sopenharmony_ci		    "%s: Failed to read from flash\n",
57062306a36Sopenharmony_ci		    __func__);
57162306a36Sopenharmony_ci	}
57262306a36Sopenharmony_ci	scsi_unblock_requests(vha->host);
57362306a36Sopenharmony_ci	return buf;
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_cistatic inline int
57762306a36Sopenharmony_ciqla8044_need_reset(struct scsi_qla_host *vha)
57862306a36Sopenharmony_ci{
57962306a36Sopenharmony_ci	uint32_t drv_state, drv_active;
58062306a36Sopenharmony_ci	int rval;
58162306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX);
58462306a36Sopenharmony_ci	drv_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	rval = drv_state & (1 << ha->portnum);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	if (ha->flags.eeh_busy && drv_active)
58962306a36Sopenharmony_ci		rval = 1;
59062306a36Sopenharmony_ci	return rval;
59162306a36Sopenharmony_ci}
59262306a36Sopenharmony_ci
59362306a36Sopenharmony_ci/*
59462306a36Sopenharmony_ci * qla8044_write_list - Write the value (p_entry->arg2) to address specified
59562306a36Sopenharmony_ci * by p_entry->arg1 for all entries in header with delay of p_hdr->delay between
59662306a36Sopenharmony_ci * entries.
59762306a36Sopenharmony_ci *
59862306a36Sopenharmony_ci * @vha : Pointer to adapter structure
59962306a36Sopenharmony_ci * @p_hdr : reset_entry header for WRITE_LIST opcode.
60062306a36Sopenharmony_ci *
60162306a36Sopenharmony_ci */
60262306a36Sopenharmony_cistatic void
60362306a36Sopenharmony_ciqla8044_write_list(struct scsi_qla_host *vha,
60462306a36Sopenharmony_ci	struct qla8044_reset_entry_hdr *p_hdr)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	struct qla8044_entry *p_entry;
60762306a36Sopenharmony_ci	uint32_t i;
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_ci	p_entry = (struct qla8044_entry *)((char *)p_hdr +
61062306a36Sopenharmony_ci	    sizeof(struct qla8044_reset_entry_hdr));
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	for (i = 0; i < p_hdr->count; i++, p_entry++) {
61362306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha, p_entry->arg1, p_entry->arg2);
61462306a36Sopenharmony_ci		if (p_hdr->delay)
61562306a36Sopenharmony_ci			udelay((uint32_t)(p_hdr->delay));
61662306a36Sopenharmony_ci	}
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci/*
62062306a36Sopenharmony_ci * qla8044_read_write_list - Read from address specified by p_entry->arg1,
62162306a36Sopenharmony_ci * write value read to address specified by p_entry->arg2, for all entries in
62262306a36Sopenharmony_ci * header with delay of p_hdr->delay between entries.
62362306a36Sopenharmony_ci *
62462306a36Sopenharmony_ci * @vha : Pointer to adapter structure
62562306a36Sopenharmony_ci * @p_hdr : reset_entry header for READ_WRITE_LIST opcode.
62662306a36Sopenharmony_ci *
62762306a36Sopenharmony_ci */
62862306a36Sopenharmony_cistatic void
62962306a36Sopenharmony_ciqla8044_read_write_list(struct scsi_qla_host *vha,
63062306a36Sopenharmony_ci	struct qla8044_reset_entry_hdr *p_hdr)
63162306a36Sopenharmony_ci{
63262306a36Sopenharmony_ci	struct qla8044_entry *p_entry;
63362306a36Sopenharmony_ci	uint32_t i;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	p_entry = (struct qla8044_entry *)((char *)p_hdr +
63662306a36Sopenharmony_ci	    sizeof(struct qla8044_reset_entry_hdr));
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_ci	for (i = 0; i < p_hdr->count; i++, p_entry++) {
63962306a36Sopenharmony_ci		qla8044_read_write_crb_reg(vha, p_entry->arg1,
64062306a36Sopenharmony_ci		    p_entry->arg2);
64162306a36Sopenharmony_ci		if (p_hdr->delay)
64262306a36Sopenharmony_ci			udelay((uint32_t)(p_hdr->delay));
64362306a36Sopenharmony_ci	}
64462306a36Sopenharmony_ci}
64562306a36Sopenharmony_ci
64662306a36Sopenharmony_ci/*
64762306a36Sopenharmony_ci * qla8044_poll_reg - Poll the given CRB addr for duration msecs till
64862306a36Sopenharmony_ci * value read ANDed with test_mask is equal to test_result.
64962306a36Sopenharmony_ci *
65062306a36Sopenharmony_ci * @ha : Pointer to adapter structure
65162306a36Sopenharmony_ci * @addr : CRB register address
65262306a36Sopenharmony_ci * @duration : Poll for total of "duration" msecs
65362306a36Sopenharmony_ci * @test_mask : Mask value read with "test_mask"
65462306a36Sopenharmony_ci * @test_result : Compare (value&test_mask) with test_result.
65562306a36Sopenharmony_ci *
65662306a36Sopenharmony_ci * Return Value - QLA_SUCCESS/QLA_FUNCTION_FAILED
65762306a36Sopenharmony_ci */
65862306a36Sopenharmony_cistatic int
65962306a36Sopenharmony_ciqla8044_poll_reg(struct scsi_qla_host *vha, uint32_t addr,
66062306a36Sopenharmony_ci	int duration, uint32_t test_mask, uint32_t test_result)
66162306a36Sopenharmony_ci{
66262306a36Sopenharmony_ci	uint32_t value = 0;
66362306a36Sopenharmony_ci	int timeout_error;
66462306a36Sopenharmony_ci	uint8_t retries;
66562306a36Sopenharmony_ci	int ret_val = QLA_SUCCESS;
66662306a36Sopenharmony_ci
66762306a36Sopenharmony_ci	ret_val = qla8044_rd_reg_indirect(vha, addr, &value);
66862306a36Sopenharmony_ci	if (ret_val == QLA_FUNCTION_FAILED) {
66962306a36Sopenharmony_ci		timeout_error = 1;
67062306a36Sopenharmony_ci		goto exit_poll_reg;
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	/* poll every 1/10 of the total duration */
67462306a36Sopenharmony_ci	retries = duration/10;
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	do {
67762306a36Sopenharmony_ci		if ((value & test_mask) != test_result) {
67862306a36Sopenharmony_ci			timeout_error = 1;
67962306a36Sopenharmony_ci			msleep(duration/10);
68062306a36Sopenharmony_ci			ret_val = qla8044_rd_reg_indirect(vha, addr, &value);
68162306a36Sopenharmony_ci			if (ret_val == QLA_FUNCTION_FAILED) {
68262306a36Sopenharmony_ci				timeout_error = 1;
68362306a36Sopenharmony_ci				goto exit_poll_reg;
68462306a36Sopenharmony_ci			}
68562306a36Sopenharmony_ci		} else {
68662306a36Sopenharmony_ci			timeout_error = 0;
68762306a36Sopenharmony_ci			break;
68862306a36Sopenharmony_ci		}
68962306a36Sopenharmony_ci	} while (retries--);
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ciexit_poll_reg:
69262306a36Sopenharmony_ci	if (timeout_error) {
69362306a36Sopenharmony_ci		vha->reset_tmplt.seq_error++;
69462306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb090,
69562306a36Sopenharmony_ci		    "%s: Poll Failed: 0x%08x 0x%08x 0x%08x\n",
69662306a36Sopenharmony_ci		    __func__, value, test_mask, test_result);
69762306a36Sopenharmony_ci	}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	return timeout_error;
70062306a36Sopenharmony_ci}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_ci/*
70362306a36Sopenharmony_ci * qla8044_poll_list - For all entries in the POLL_LIST header, poll read CRB
70462306a36Sopenharmony_ci * register specified by p_entry->arg1 and compare (value AND test_mask) with
70562306a36Sopenharmony_ci * test_result to validate it. Wait for p_hdr->delay between processing entries.
70662306a36Sopenharmony_ci *
70762306a36Sopenharmony_ci * @ha : Pointer to adapter structure
70862306a36Sopenharmony_ci * @p_hdr : reset_entry header for POLL_LIST opcode.
70962306a36Sopenharmony_ci *
71062306a36Sopenharmony_ci */
71162306a36Sopenharmony_cistatic void
71262306a36Sopenharmony_ciqla8044_poll_list(struct scsi_qla_host *vha,
71362306a36Sopenharmony_ci	struct qla8044_reset_entry_hdr *p_hdr)
71462306a36Sopenharmony_ci{
71562306a36Sopenharmony_ci	long delay;
71662306a36Sopenharmony_ci	struct qla8044_entry *p_entry;
71762306a36Sopenharmony_ci	struct qla8044_poll *p_poll;
71862306a36Sopenharmony_ci	uint32_t i;
71962306a36Sopenharmony_ci	uint32_t value;
72062306a36Sopenharmony_ci
72162306a36Sopenharmony_ci	p_poll = (struct qla8044_poll *)
72262306a36Sopenharmony_ci		((char *)p_hdr + sizeof(struct qla8044_reset_entry_hdr));
72362306a36Sopenharmony_ci
72462306a36Sopenharmony_ci	/* Entries start after 8 byte qla8044_poll, poll header contains
72562306a36Sopenharmony_ci	 * the test_mask, test_value.
72662306a36Sopenharmony_ci	 */
72762306a36Sopenharmony_ci	p_entry = (struct qla8044_entry *)((char *)p_poll +
72862306a36Sopenharmony_ci	    sizeof(struct qla8044_poll));
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci	delay = (long)p_hdr->delay;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ci	if (!delay) {
73362306a36Sopenharmony_ci		for (i = 0; i < p_hdr->count; i++, p_entry++)
73462306a36Sopenharmony_ci			qla8044_poll_reg(vha, p_entry->arg1,
73562306a36Sopenharmony_ci			    delay, p_poll->test_mask, p_poll->test_value);
73662306a36Sopenharmony_ci	} else {
73762306a36Sopenharmony_ci		for (i = 0; i < p_hdr->count; i++, p_entry++) {
73862306a36Sopenharmony_ci			if (delay) {
73962306a36Sopenharmony_ci				if (qla8044_poll_reg(vha,
74062306a36Sopenharmony_ci				    p_entry->arg1, delay,
74162306a36Sopenharmony_ci				    p_poll->test_mask,
74262306a36Sopenharmony_ci				    p_poll->test_value)) {
74362306a36Sopenharmony_ci					/*If
74462306a36Sopenharmony_ci					* (data_read&test_mask != test_value)
74562306a36Sopenharmony_ci					* read TIMEOUT_ADDR (arg1) and
74662306a36Sopenharmony_ci					* ADDR (arg2) registers
74762306a36Sopenharmony_ci					*/
74862306a36Sopenharmony_ci					qla8044_rd_reg_indirect(vha,
74962306a36Sopenharmony_ci					    p_entry->arg1, &value);
75062306a36Sopenharmony_ci					qla8044_rd_reg_indirect(vha,
75162306a36Sopenharmony_ci					    p_entry->arg2, &value);
75262306a36Sopenharmony_ci				}
75362306a36Sopenharmony_ci			}
75462306a36Sopenharmony_ci		}
75562306a36Sopenharmony_ci	}
75662306a36Sopenharmony_ci}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_ci/*
75962306a36Sopenharmony_ci * qla8044_poll_write_list - Write dr_value, ar_value to dr_addr/ar_addr,
76062306a36Sopenharmony_ci * read ar_addr, if (value& test_mask != test_mask) re-read till timeout
76162306a36Sopenharmony_ci * expires.
76262306a36Sopenharmony_ci *
76362306a36Sopenharmony_ci * @vha : Pointer to adapter structure
76462306a36Sopenharmony_ci * @p_hdr : reset entry header for POLL_WRITE_LIST opcode.
76562306a36Sopenharmony_ci *
76662306a36Sopenharmony_ci */
76762306a36Sopenharmony_cistatic void
76862306a36Sopenharmony_ciqla8044_poll_write_list(struct scsi_qla_host *vha,
76962306a36Sopenharmony_ci	struct qla8044_reset_entry_hdr *p_hdr)
77062306a36Sopenharmony_ci{
77162306a36Sopenharmony_ci	long delay;
77262306a36Sopenharmony_ci	struct qla8044_quad_entry *p_entry;
77362306a36Sopenharmony_ci	struct qla8044_poll *p_poll;
77462306a36Sopenharmony_ci	uint32_t i;
77562306a36Sopenharmony_ci
77662306a36Sopenharmony_ci	p_poll = (struct qla8044_poll *)((char *)p_hdr +
77762306a36Sopenharmony_ci	    sizeof(struct qla8044_reset_entry_hdr));
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	p_entry = (struct qla8044_quad_entry *)((char *)p_poll +
78062306a36Sopenharmony_ci	    sizeof(struct qla8044_poll));
78162306a36Sopenharmony_ci
78262306a36Sopenharmony_ci	delay = (long)p_hdr->delay;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	for (i = 0; i < p_hdr->count; i++, p_entry++) {
78562306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha,
78662306a36Sopenharmony_ci		    p_entry->dr_addr, p_entry->dr_value);
78762306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha,
78862306a36Sopenharmony_ci		    p_entry->ar_addr, p_entry->ar_value);
78962306a36Sopenharmony_ci		if (delay) {
79062306a36Sopenharmony_ci			if (qla8044_poll_reg(vha,
79162306a36Sopenharmony_ci			    p_entry->ar_addr, delay,
79262306a36Sopenharmony_ci			    p_poll->test_mask,
79362306a36Sopenharmony_ci			    p_poll->test_value)) {
79462306a36Sopenharmony_ci				ql_dbg(ql_dbg_p3p, vha, 0xb091,
79562306a36Sopenharmony_ci				    "%s: Timeout Error: poll list, ",
79662306a36Sopenharmony_ci				    __func__);
79762306a36Sopenharmony_ci				ql_dbg(ql_dbg_p3p, vha, 0xb092,
79862306a36Sopenharmony_ci				    "item_num %d, entry_num %d\n", i,
79962306a36Sopenharmony_ci				    vha->reset_tmplt.seq_index);
80062306a36Sopenharmony_ci			}
80162306a36Sopenharmony_ci		}
80262306a36Sopenharmony_ci	}
80362306a36Sopenharmony_ci}
80462306a36Sopenharmony_ci
80562306a36Sopenharmony_ci/*
80662306a36Sopenharmony_ci * qla8044_read_modify_write - Read value from p_entry->arg1, modify the
80762306a36Sopenharmony_ci * value, write value to p_entry->arg2. Process entries with p_hdr->delay
80862306a36Sopenharmony_ci * between entries.
80962306a36Sopenharmony_ci *
81062306a36Sopenharmony_ci * @vha : Pointer to adapter structure
81162306a36Sopenharmony_ci * @p_hdr : header with shift/or/xor values.
81262306a36Sopenharmony_ci *
81362306a36Sopenharmony_ci */
81462306a36Sopenharmony_cistatic void
81562306a36Sopenharmony_ciqla8044_read_modify_write(struct scsi_qla_host *vha,
81662306a36Sopenharmony_ci	struct qla8044_reset_entry_hdr *p_hdr)
81762306a36Sopenharmony_ci{
81862306a36Sopenharmony_ci	struct qla8044_entry *p_entry;
81962306a36Sopenharmony_ci	struct qla8044_rmw *p_rmw_hdr;
82062306a36Sopenharmony_ci	uint32_t i;
82162306a36Sopenharmony_ci
82262306a36Sopenharmony_ci	p_rmw_hdr = (struct qla8044_rmw *)((char *)p_hdr +
82362306a36Sopenharmony_ci	    sizeof(struct qla8044_reset_entry_hdr));
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	p_entry = (struct qla8044_entry *)((char *)p_rmw_hdr +
82662306a36Sopenharmony_ci	    sizeof(struct qla8044_rmw));
82762306a36Sopenharmony_ci
82862306a36Sopenharmony_ci	for (i = 0; i < p_hdr->count; i++, p_entry++) {
82962306a36Sopenharmony_ci		qla8044_rmw_crb_reg(vha, p_entry->arg1,
83062306a36Sopenharmony_ci		    p_entry->arg2, p_rmw_hdr);
83162306a36Sopenharmony_ci		if (p_hdr->delay)
83262306a36Sopenharmony_ci			udelay((uint32_t)(p_hdr->delay));
83362306a36Sopenharmony_ci	}
83462306a36Sopenharmony_ci}
83562306a36Sopenharmony_ci
83662306a36Sopenharmony_ci/*
83762306a36Sopenharmony_ci * qla8044_pause - Wait for p_hdr->delay msecs, called between processing
83862306a36Sopenharmony_ci * two entries of a sequence.
83962306a36Sopenharmony_ci *
84062306a36Sopenharmony_ci * @vha : Pointer to adapter structure
84162306a36Sopenharmony_ci * @p_hdr : Common reset entry header.
84262306a36Sopenharmony_ci *
84362306a36Sopenharmony_ci */
84462306a36Sopenharmony_cistatic
84562306a36Sopenharmony_civoid qla8044_pause(struct scsi_qla_host *vha,
84662306a36Sopenharmony_ci	struct qla8044_reset_entry_hdr *p_hdr)
84762306a36Sopenharmony_ci{
84862306a36Sopenharmony_ci	if (p_hdr->delay)
84962306a36Sopenharmony_ci		mdelay((uint32_t)((long)p_hdr->delay));
85062306a36Sopenharmony_ci}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci/*
85362306a36Sopenharmony_ci * qla8044_template_end - Indicates end of reset sequence processing.
85462306a36Sopenharmony_ci *
85562306a36Sopenharmony_ci * @vha : Pointer to adapter structure
85662306a36Sopenharmony_ci * @p_hdr : Common reset entry header.
85762306a36Sopenharmony_ci *
85862306a36Sopenharmony_ci */
85962306a36Sopenharmony_cistatic void
86062306a36Sopenharmony_ciqla8044_template_end(struct scsi_qla_host *vha,
86162306a36Sopenharmony_ci	struct qla8044_reset_entry_hdr *p_hdr)
86262306a36Sopenharmony_ci{
86362306a36Sopenharmony_ci	vha->reset_tmplt.template_end = 1;
86462306a36Sopenharmony_ci
86562306a36Sopenharmony_ci	if (vha->reset_tmplt.seq_error == 0) {
86662306a36Sopenharmony_ci		ql_dbg(ql_dbg_p3p, vha, 0xb093,
86762306a36Sopenharmony_ci		    "%s: Reset sequence completed SUCCESSFULLY.\n", __func__);
86862306a36Sopenharmony_ci	} else {
86962306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb094,
87062306a36Sopenharmony_ci		    "%s: Reset sequence completed with some timeout "
87162306a36Sopenharmony_ci		    "errors.\n", __func__);
87262306a36Sopenharmony_ci	}
87362306a36Sopenharmony_ci}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci/*
87662306a36Sopenharmony_ci * qla8044_poll_read_list - Write ar_value to ar_addr register, read ar_addr,
87762306a36Sopenharmony_ci * if (value & test_mask != test_value) re-read till timeout value expires,
87862306a36Sopenharmony_ci * read dr_addr register and assign to reset_tmplt.array.
87962306a36Sopenharmony_ci *
88062306a36Sopenharmony_ci * @vha : Pointer to adapter structure
88162306a36Sopenharmony_ci * @p_hdr : Common reset entry header.
88262306a36Sopenharmony_ci *
88362306a36Sopenharmony_ci */
88462306a36Sopenharmony_cistatic void
88562306a36Sopenharmony_ciqla8044_poll_read_list(struct scsi_qla_host *vha,
88662306a36Sopenharmony_ci	struct qla8044_reset_entry_hdr *p_hdr)
88762306a36Sopenharmony_ci{
88862306a36Sopenharmony_ci	long delay;
88962306a36Sopenharmony_ci	int index;
89062306a36Sopenharmony_ci	struct qla8044_quad_entry *p_entry;
89162306a36Sopenharmony_ci	struct qla8044_poll *p_poll;
89262306a36Sopenharmony_ci	uint32_t i;
89362306a36Sopenharmony_ci	uint32_t value;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	p_poll = (struct qla8044_poll *)
89662306a36Sopenharmony_ci		((char *)p_hdr + sizeof(struct qla8044_reset_entry_hdr));
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	p_entry = (struct qla8044_quad_entry *)
89962306a36Sopenharmony_ci		((char *)p_poll + sizeof(struct qla8044_poll));
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	delay = (long)p_hdr->delay;
90262306a36Sopenharmony_ci
90362306a36Sopenharmony_ci	for (i = 0; i < p_hdr->count; i++, p_entry++) {
90462306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha, p_entry->ar_addr,
90562306a36Sopenharmony_ci		    p_entry->ar_value);
90662306a36Sopenharmony_ci		if (delay) {
90762306a36Sopenharmony_ci			if (qla8044_poll_reg(vha, p_entry->ar_addr, delay,
90862306a36Sopenharmony_ci			    p_poll->test_mask, p_poll->test_value)) {
90962306a36Sopenharmony_ci				ql_dbg(ql_dbg_p3p, vha, 0xb095,
91062306a36Sopenharmony_ci				    "%s: Timeout Error: poll "
91162306a36Sopenharmony_ci				    "list, ", __func__);
91262306a36Sopenharmony_ci				ql_dbg(ql_dbg_p3p, vha, 0xb096,
91362306a36Sopenharmony_ci				    "Item_num %d, "
91462306a36Sopenharmony_ci				    "entry_num %d\n", i,
91562306a36Sopenharmony_ci				    vha->reset_tmplt.seq_index);
91662306a36Sopenharmony_ci			} else {
91762306a36Sopenharmony_ci				index = vha->reset_tmplt.array_index;
91862306a36Sopenharmony_ci				qla8044_rd_reg_indirect(vha,
91962306a36Sopenharmony_ci				    p_entry->dr_addr, &value);
92062306a36Sopenharmony_ci				vha->reset_tmplt.array[index++] = value;
92162306a36Sopenharmony_ci				if (index == QLA8044_MAX_RESET_SEQ_ENTRIES)
92262306a36Sopenharmony_ci					vha->reset_tmplt.array_index = 1;
92362306a36Sopenharmony_ci			}
92462306a36Sopenharmony_ci		}
92562306a36Sopenharmony_ci	}
92662306a36Sopenharmony_ci}
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci/*
92962306a36Sopenharmony_ci * qla8031_process_reset_template - Process all entries in reset template
93062306a36Sopenharmony_ci * till entry with SEQ_END opcode, which indicates end of the reset template
93162306a36Sopenharmony_ci * processing. Each entry has a Reset Entry header, entry opcode/command, with
93262306a36Sopenharmony_ci * size of the entry, number of entries in sub-sequence and delay in microsecs
93362306a36Sopenharmony_ci * or timeout in millisecs.
93462306a36Sopenharmony_ci *
93562306a36Sopenharmony_ci * @ha : Pointer to adapter structure
93662306a36Sopenharmony_ci * @p_buff : Common reset entry header.
93762306a36Sopenharmony_ci *
93862306a36Sopenharmony_ci */
93962306a36Sopenharmony_cistatic void
94062306a36Sopenharmony_ciqla8044_process_reset_template(struct scsi_qla_host *vha,
94162306a36Sopenharmony_ci	char *p_buff)
94262306a36Sopenharmony_ci{
94362306a36Sopenharmony_ci	int index, entries;
94462306a36Sopenharmony_ci	struct qla8044_reset_entry_hdr *p_hdr;
94562306a36Sopenharmony_ci	char *p_entry = p_buff;
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	vha->reset_tmplt.seq_end = 0;
94862306a36Sopenharmony_ci	vha->reset_tmplt.template_end = 0;
94962306a36Sopenharmony_ci	entries = vha->reset_tmplt.hdr->entries;
95062306a36Sopenharmony_ci	index = vha->reset_tmplt.seq_index;
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_ci	for (; (!vha->reset_tmplt.seq_end) && (index  < entries); index++) {
95362306a36Sopenharmony_ci		p_hdr = (struct qla8044_reset_entry_hdr *)p_entry;
95462306a36Sopenharmony_ci		switch (p_hdr->cmd) {
95562306a36Sopenharmony_ci		case OPCODE_NOP:
95662306a36Sopenharmony_ci			break;
95762306a36Sopenharmony_ci		case OPCODE_WRITE_LIST:
95862306a36Sopenharmony_ci			qla8044_write_list(vha, p_hdr);
95962306a36Sopenharmony_ci			break;
96062306a36Sopenharmony_ci		case OPCODE_READ_WRITE_LIST:
96162306a36Sopenharmony_ci			qla8044_read_write_list(vha, p_hdr);
96262306a36Sopenharmony_ci			break;
96362306a36Sopenharmony_ci		case OPCODE_POLL_LIST:
96462306a36Sopenharmony_ci			qla8044_poll_list(vha, p_hdr);
96562306a36Sopenharmony_ci			break;
96662306a36Sopenharmony_ci		case OPCODE_POLL_WRITE_LIST:
96762306a36Sopenharmony_ci			qla8044_poll_write_list(vha, p_hdr);
96862306a36Sopenharmony_ci			break;
96962306a36Sopenharmony_ci		case OPCODE_READ_MODIFY_WRITE:
97062306a36Sopenharmony_ci			qla8044_read_modify_write(vha, p_hdr);
97162306a36Sopenharmony_ci			break;
97262306a36Sopenharmony_ci		case OPCODE_SEQ_PAUSE:
97362306a36Sopenharmony_ci			qla8044_pause(vha, p_hdr);
97462306a36Sopenharmony_ci			break;
97562306a36Sopenharmony_ci		case OPCODE_SEQ_END:
97662306a36Sopenharmony_ci			vha->reset_tmplt.seq_end = 1;
97762306a36Sopenharmony_ci			break;
97862306a36Sopenharmony_ci		case OPCODE_TMPL_END:
97962306a36Sopenharmony_ci			qla8044_template_end(vha, p_hdr);
98062306a36Sopenharmony_ci			break;
98162306a36Sopenharmony_ci		case OPCODE_POLL_READ_LIST:
98262306a36Sopenharmony_ci			qla8044_poll_read_list(vha, p_hdr);
98362306a36Sopenharmony_ci			break;
98462306a36Sopenharmony_ci		default:
98562306a36Sopenharmony_ci			ql_log(ql_log_fatal, vha, 0xb097,
98662306a36Sopenharmony_ci			    "%s: Unknown command ==> 0x%04x on "
98762306a36Sopenharmony_ci			    "entry = %d\n", __func__, p_hdr->cmd, index);
98862306a36Sopenharmony_ci			break;
98962306a36Sopenharmony_ci		}
99062306a36Sopenharmony_ci		/*
99162306a36Sopenharmony_ci		 *Set pointer to next entry in the sequence.
99262306a36Sopenharmony_ci		*/
99362306a36Sopenharmony_ci		p_entry += p_hdr->size;
99462306a36Sopenharmony_ci	}
99562306a36Sopenharmony_ci	vha->reset_tmplt.seq_index = index;
99662306a36Sopenharmony_ci}
99762306a36Sopenharmony_ci
99862306a36Sopenharmony_cistatic void
99962306a36Sopenharmony_ciqla8044_process_init_seq(struct scsi_qla_host *vha)
100062306a36Sopenharmony_ci{
100162306a36Sopenharmony_ci	qla8044_process_reset_template(vha,
100262306a36Sopenharmony_ci	    vha->reset_tmplt.init_offset);
100362306a36Sopenharmony_ci	if (vha->reset_tmplt.seq_end != 1)
100462306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb098,
100562306a36Sopenharmony_ci		    "%s: Abrupt INIT Sub-Sequence end.\n",
100662306a36Sopenharmony_ci		    __func__);
100762306a36Sopenharmony_ci}
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_cistatic void
101062306a36Sopenharmony_ciqla8044_process_stop_seq(struct scsi_qla_host *vha)
101162306a36Sopenharmony_ci{
101262306a36Sopenharmony_ci	vha->reset_tmplt.seq_index = 0;
101362306a36Sopenharmony_ci	qla8044_process_reset_template(vha, vha->reset_tmplt.stop_offset);
101462306a36Sopenharmony_ci	if (vha->reset_tmplt.seq_end != 1)
101562306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb099,
101662306a36Sopenharmony_ci		    "%s: Abrupt STOP Sub-Sequence end.\n", __func__);
101762306a36Sopenharmony_ci}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_cistatic void
102062306a36Sopenharmony_ciqla8044_process_start_seq(struct scsi_qla_host *vha)
102162306a36Sopenharmony_ci{
102262306a36Sopenharmony_ci	qla8044_process_reset_template(vha, vha->reset_tmplt.start_offset);
102362306a36Sopenharmony_ci	if (vha->reset_tmplt.template_end != 1)
102462306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb09a,
102562306a36Sopenharmony_ci		    "%s: Abrupt START Sub-Sequence end.\n",
102662306a36Sopenharmony_ci		    __func__);
102762306a36Sopenharmony_ci}
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_cistatic int
103062306a36Sopenharmony_ciqla8044_lockless_flash_read_u32(struct scsi_qla_host *vha,
103162306a36Sopenharmony_ci	uint32_t flash_addr, uint8_t *p_data, int u32_word_count)
103262306a36Sopenharmony_ci{
103362306a36Sopenharmony_ci	uint32_t i;
103462306a36Sopenharmony_ci	uint32_t u32_word;
103562306a36Sopenharmony_ci	uint32_t flash_offset;
103662306a36Sopenharmony_ci	uint32_t addr = flash_addr;
103762306a36Sopenharmony_ci	int ret_val = QLA_SUCCESS;
103862306a36Sopenharmony_ci
103962306a36Sopenharmony_ci	flash_offset = addr & (QLA8044_FLASH_SECTOR_SIZE - 1);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_ci	if (addr & 0x3) {
104262306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb09b, "%s: Illegal addr = 0x%x\n",
104362306a36Sopenharmony_ci		    __func__, addr);
104462306a36Sopenharmony_ci		ret_val = QLA_FUNCTION_FAILED;
104562306a36Sopenharmony_ci		goto exit_lockless_read;
104662306a36Sopenharmony_ci	}
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_ci	ret_val = qla8044_wr_reg_indirect(vha,
104962306a36Sopenharmony_ci	    QLA8044_FLASH_DIRECT_WINDOW, (addr));
105062306a36Sopenharmony_ci
105162306a36Sopenharmony_ci	if (ret_val != QLA_SUCCESS) {
105262306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb09c,
105362306a36Sopenharmony_ci		    "%s: failed to write addr 0x%x to FLASH_DIRECT_WINDOW!\n",
105462306a36Sopenharmony_ci		    __func__, addr);
105562306a36Sopenharmony_ci		goto exit_lockless_read;
105662306a36Sopenharmony_ci	}
105762306a36Sopenharmony_ci
105862306a36Sopenharmony_ci	/* Check if data is spread across multiple sectors  */
105962306a36Sopenharmony_ci	if ((flash_offset + (u32_word_count * sizeof(uint32_t))) >
106062306a36Sopenharmony_ci	    (QLA8044_FLASH_SECTOR_SIZE - 1)) {
106162306a36Sopenharmony_ci		/* Multi sector read */
106262306a36Sopenharmony_ci		for (i = 0; i < u32_word_count; i++) {
106362306a36Sopenharmony_ci			ret_val = qla8044_rd_reg_indirect(vha,
106462306a36Sopenharmony_ci			    QLA8044_FLASH_DIRECT_DATA(addr), &u32_word);
106562306a36Sopenharmony_ci			if (ret_val != QLA_SUCCESS) {
106662306a36Sopenharmony_ci				ql_log(ql_log_fatal, vha, 0xb09d,
106762306a36Sopenharmony_ci				    "%s: failed to read addr 0x%x!\n",
106862306a36Sopenharmony_ci				    __func__, addr);
106962306a36Sopenharmony_ci				goto exit_lockless_read;
107062306a36Sopenharmony_ci			}
107162306a36Sopenharmony_ci			*(uint32_t *)p_data  = u32_word;
107262306a36Sopenharmony_ci			p_data = p_data + 4;
107362306a36Sopenharmony_ci			addr = addr + 4;
107462306a36Sopenharmony_ci			flash_offset = flash_offset + 4;
107562306a36Sopenharmony_ci			if (flash_offset > (QLA8044_FLASH_SECTOR_SIZE - 1)) {
107662306a36Sopenharmony_ci				/* This write is needed once for each sector */
107762306a36Sopenharmony_ci				ret_val = qla8044_wr_reg_indirect(vha,
107862306a36Sopenharmony_ci				    QLA8044_FLASH_DIRECT_WINDOW, (addr));
107962306a36Sopenharmony_ci				if (ret_val != QLA_SUCCESS) {
108062306a36Sopenharmony_ci					ql_log(ql_log_fatal, vha, 0xb09f,
108162306a36Sopenharmony_ci					    "%s: failed to write addr "
108262306a36Sopenharmony_ci					    "0x%x to FLASH_DIRECT_WINDOW!\n",
108362306a36Sopenharmony_ci					    __func__, addr);
108462306a36Sopenharmony_ci					goto exit_lockless_read;
108562306a36Sopenharmony_ci				}
108662306a36Sopenharmony_ci				flash_offset = 0;
108762306a36Sopenharmony_ci			}
108862306a36Sopenharmony_ci		}
108962306a36Sopenharmony_ci	} else {
109062306a36Sopenharmony_ci		/* Single sector read */
109162306a36Sopenharmony_ci		for (i = 0; i < u32_word_count; i++) {
109262306a36Sopenharmony_ci			ret_val = qla8044_rd_reg_indirect(vha,
109362306a36Sopenharmony_ci			    QLA8044_FLASH_DIRECT_DATA(addr), &u32_word);
109462306a36Sopenharmony_ci			if (ret_val != QLA_SUCCESS) {
109562306a36Sopenharmony_ci				ql_log(ql_log_fatal, vha, 0xb0a0,
109662306a36Sopenharmony_ci				    "%s: failed to read addr 0x%x!\n",
109762306a36Sopenharmony_ci				    __func__, addr);
109862306a36Sopenharmony_ci				goto exit_lockless_read;
109962306a36Sopenharmony_ci			}
110062306a36Sopenharmony_ci			*(uint32_t *)p_data = u32_word;
110162306a36Sopenharmony_ci			p_data = p_data + 4;
110262306a36Sopenharmony_ci			addr = addr + 4;
110362306a36Sopenharmony_ci		}
110462306a36Sopenharmony_ci	}
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ciexit_lockless_read:
110762306a36Sopenharmony_ci	return ret_val;
110862306a36Sopenharmony_ci}
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci/*
111162306a36Sopenharmony_ci * qla8044_ms_mem_write_128b - Writes data to MS/off-chip memory
111262306a36Sopenharmony_ci *
111362306a36Sopenharmony_ci * @vha : Pointer to adapter structure
111462306a36Sopenharmony_ci * addr : Flash address to write to
111562306a36Sopenharmony_ci * data : Data to be written
111662306a36Sopenharmony_ci * count : word_count to be written
111762306a36Sopenharmony_ci *
111862306a36Sopenharmony_ci * Return Value - QLA_SUCCESS/QLA_FUNCTION_FAILED
111962306a36Sopenharmony_ci */
112062306a36Sopenharmony_cistatic int
112162306a36Sopenharmony_ciqla8044_ms_mem_write_128b(struct scsi_qla_host *vha,
112262306a36Sopenharmony_ci	uint64_t addr, uint32_t *data, uint32_t count)
112362306a36Sopenharmony_ci{
112462306a36Sopenharmony_ci	int i, j, ret_val = QLA_SUCCESS;
112562306a36Sopenharmony_ci	uint32_t agt_ctrl;
112662306a36Sopenharmony_ci	unsigned long flags;
112762306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
112862306a36Sopenharmony_ci
112962306a36Sopenharmony_ci	/* Only 128-bit aligned access */
113062306a36Sopenharmony_ci	if (addr & 0xF) {
113162306a36Sopenharmony_ci		ret_val = QLA_FUNCTION_FAILED;
113262306a36Sopenharmony_ci		goto exit_ms_mem_write;
113362306a36Sopenharmony_ci	}
113462306a36Sopenharmony_ci	write_lock_irqsave(&ha->hw_lock, flags);
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci	/* Write address */
113762306a36Sopenharmony_ci	ret_val = qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_ADDR_HI, 0);
113862306a36Sopenharmony_ci	if (ret_val == QLA_FUNCTION_FAILED) {
113962306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb0a1,
114062306a36Sopenharmony_ci		    "%s: write to AGT_ADDR_HI failed!\n", __func__);
114162306a36Sopenharmony_ci		goto exit_ms_mem_write_unlock;
114262306a36Sopenharmony_ci	}
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	for (i = 0; i < count; i++, addr += 16) {
114562306a36Sopenharmony_ci		if (!((addr_in_range(addr, QLA8044_ADDR_QDR_NET,
114662306a36Sopenharmony_ci		    QLA8044_ADDR_QDR_NET_MAX)) ||
114762306a36Sopenharmony_ci		    (addr_in_range(addr, QLA8044_ADDR_DDR_NET,
114862306a36Sopenharmony_ci			QLA8044_ADDR_DDR_NET_MAX)))) {
114962306a36Sopenharmony_ci			ret_val = QLA_FUNCTION_FAILED;
115062306a36Sopenharmony_ci			goto exit_ms_mem_write_unlock;
115162306a36Sopenharmony_ci		}
115262306a36Sopenharmony_ci
115362306a36Sopenharmony_ci		ret_val = qla8044_wr_reg_indirect(vha,
115462306a36Sopenharmony_ci		    MD_MIU_TEST_AGT_ADDR_LO, addr);
115562306a36Sopenharmony_ci
115662306a36Sopenharmony_ci		/* Write data */
115762306a36Sopenharmony_ci		ret_val += qla8044_wr_reg_indirect(vha,
115862306a36Sopenharmony_ci		    MD_MIU_TEST_AGT_WRDATA_LO, *data++);
115962306a36Sopenharmony_ci		ret_val += qla8044_wr_reg_indirect(vha,
116062306a36Sopenharmony_ci		    MD_MIU_TEST_AGT_WRDATA_HI, *data++);
116162306a36Sopenharmony_ci		ret_val += qla8044_wr_reg_indirect(vha,
116262306a36Sopenharmony_ci		    MD_MIU_TEST_AGT_WRDATA_ULO, *data++);
116362306a36Sopenharmony_ci		ret_val += qla8044_wr_reg_indirect(vha,
116462306a36Sopenharmony_ci		    MD_MIU_TEST_AGT_WRDATA_UHI, *data++);
116562306a36Sopenharmony_ci		if (ret_val == QLA_FUNCTION_FAILED) {
116662306a36Sopenharmony_ci			ql_log(ql_log_fatal, vha, 0xb0a2,
116762306a36Sopenharmony_ci			    "%s: write to AGT_WRDATA failed!\n",
116862306a36Sopenharmony_ci			    __func__);
116962306a36Sopenharmony_ci			goto exit_ms_mem_write_unlock;
117062306a36Sopenharmony_ci		}
117162306a36Sopenharmony_ci
117262306a36Sopenharmony_ci		/* Check write status */
117362306a36Sopenharmony_ci		ret_val = qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_CTRL,
117462306a36Sopenharmony_ci		    MIU_TA_CTL_WRITE_ENABLE);
117562306a36Sopenharmony_ci		ret_val += qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_CTRL,
117662306a36Sopenharmony_ci		    MIU_TA_CTL_WRITE_START);
117762306a36Sopenharmony_ci		if (ret_val == QLA_FUNCTION_FAILED) {
117862306a36Sopenharmony_ci			ql_log(ql_log_fatal, vha, 0xb0a3,
117962306a36Sopenharmony_ci			    "%s: write to AGT_CTRL failed!\n", __func__);
118062306a36Sopenharmony_ci			goto exit_ms_mem_write_unlock;
118162306a36Sopenharmony_ci		}
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci		for (j = 0; j < MAX_CTL_CHECK; j++) {
118462306a36Sopenharmony_ci			ret_val = qla8044_rd_reg_indirect(vha,
118562306a36Sopenharmony_ci			    MD_MIU_TEST_AGT_CTRL, &agt_ctrl);
118662306a36Sopenharmony_ci			if (ret_val == QLA_FUNCTION_FAILED) {
118762306a36Sopenharmony_ci				ql_log(ql_log_fatal, vha, 0xb0a4,
118862306a36Sopenharmony_ci				    "%s: failed to read "
118962306a36Sopenharmony_ci				    "MD_MIU_TEST_AGT_CTRL!\n", __func__);
119062306a36Sopenharmony_ci				goto exit_ms_mem_write_unlock;
119162306a36Sopenharmony_ci			}
119262306a36Sopenharmony_ci			if ((agt_ctrl & MIU_TA_CTL_BUSY) == 0)
119362306a36Sopenharmony_ci				break;
119462306a36Sopenharmony_ci		}
119562306a36Sopenharmony_ci
119662306a36Sopenharmony_ci		/* Status check failed */
119762306a36Sopenharmony_ci		if (j >= MAX_CTL_CHECK) {
119862306a36Sopenharmony_ci			ql_log(ql_log_fatal, vha, 0xb0a5,
119962306a36Sopenharmony_ci			    "%s: MS memory write failed!\n",
120062306a36Sopenharmony_ci			   __func__);
120162306a36Sopenharmony_ci			ret_val = QLA_FUNCTION_FAILED;
120262306a36Sopenharmony_ci			goto exit_ms_mem_write_unlock;
120362306a36Sopenharmony_ci		}
120462306a36Sopenharmony_ci	}
120562306a36Sopenharmony_ci
120662306a36Sopenharmony_ciexit_ms_mem_write_unlock:
120762306a36Sopenharmony_ci	write_unlock_irqrestore(&ha->hw_lock, flags);
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ciexit_ms_mem_write:
121062306a36Sopenharmony_ci	return ret_val;
121162306a36Sopenharmony_ci}
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_cistatic int
121462306a36Sopenharmony_ciqla8044_copy_bootloader(struct scsi_qla_host *vha)
121562306a36Sopenharmony_ci{
121662306a36Sopenharmony_ci	uint8_t *p_cache;
121762306a36Sopenharmony_ci	uint32_t src, count, size;
121862306a36Sopenharmony_ci	uint64_t dest;
121962306a36Sopenharmony_ci	int ret_val = QLA_SUCCESS;
122062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	src = QLA8044_BOOTLOADER_FLASH_ADDR;
122362306a36Sopenharmony_ci	dest = qla8044_rd_reg(ha, QLA8044_BOOTLOADER_ADDR);
122462306a36Sopenharmony_ci	size = qla8044_rd_reg(ha, QLA8044_BOOTLOADER_SIZE);
122562306a36Sopenharmony_ci
122662306a36Sopenharmony_ci	/* 128 bit alignment check */
122762306a36Sopenharmony_ci	if (size & 0xF)
122862306a36Sopenharmony_ci		size = (size + 16) & ~0xF;
122962306a36Sopenharmony_ci
123062306a36Sopenharmony_ci	/* 16 byte count */
123162306a36Sopenharmony_ci	count = size/16;
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci	p_cache = vmalloc(size);
123462306a36Sopenharmony_ci	if (p_cache == NULL) {
123562306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb0a6,
123662306a36Sopenharmony_ci		    "%s: Failed to allocate memory for "
123762306a36Sopenharmony_ci		    "boot loader cache\n", __func__);
123862306a36Sopenharmony_ci		ret_val = QLA_FUNCTION_FAILED;
123962306a36Sopenharmony_ci		goto exit_copy_bootloader;
124062306a36Sopenharmony_ci	}
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	ret_val = qla8044_lockless_flash_read_u32(vha, src,
124362306a36Sopenharmony_ci	    p_cache, size/sizeof(uint32_t));
124462306a36Sopenharmony_ci	if (ret_val == QLA_FUNCTION_FAILED) {
124562306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb0a7,
124662306a36Sopenharmony_ci		    "%s: Error reading F/W from flash!!!\n", __func__);
124762306a36Sopenharmony_ci		goto exit_copy_error;
124862306a36Sopenharmony_ci	}
124962306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0a8, "%s: Read F/W from flash!\n",
125062306a36Sopenharmony_ci	    __func__);
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	/* 128 bit/16 byte write to MS memory */
125362306a36Sopenharmony_ci	ret_val = qla8044_ms_mem_write_128b(vha, dest,
125462306a36Sopenharmony_ci	    (uint32_t *)p_cache, count);
125562306a36Sopenharmony_ci	if (ret_val == QLA_FUNCTION_FAILED) {
125662306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb0a9,
125762306a36Sopenharmony_ci		    "%s: Error writing F/W to MS !!!\n", __func__);
125862306a36Sopenharmony_ci		goto exit_copy_error;
125962306a36Sopenharmony_ci	}
126062306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0aa,
126162306a36Sopenharmony_ci	    "%s: Wrote F/W (size %d) to MS !!!\n",
126262306a36Sopenharmony_ci	    __func__, size);
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ciexit_copy_error:
126562306a36Sopenharmony_ci	vfree(p_cache);
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ciexit_copy_bootloader:
126862306a36Sopenharmony_ci	return ret_val;
126962306a36Sopenharmony_ci}
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_cistatic int
127262306a36Sopenharmony_ciqla8044_restart(struct scsi_qla_host *vha)
127362306a36Sopenharmony_ci{
127462306a36Sopenharmony_ci	int ret_val = QLA_SUCCESS;
127562306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	qla8044_process_stop_seq(vha);
127862306a36Sopenharmony_ci
127962306a36Sopenharmony_ci	/* Collect minidump */
128062306a36Sopenharmony_ci	if (ql2xmdenable)
128162306a36Sopenharmony_ci		qla8044_get_minidump(vha);
128262306a36Sopenharmony_ci	else
128362306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb14c,
128462306a36Sopenharmony_ci		    "Minidump disabled.\n");
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	qla8044_process_init_seq(vha);
128762306a36Sopenharmony_ci
128862306a36Sopenharmony_ci	if (qla8044_copy_bootloader(vha)) {
128962306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb0ab,
129062306a36Sopenharmony_ci		    "%s: Copy bootloader, firmware restart failed!\n",
129162306a36Sopenharmony_ci		    __func__);
129262306a36Sopenharmony_ci		ret_val = QLA_FUNCTION_FAILED;
129362306a36Sopenharmony_ci		goto exit_restart;
129462306a36Sopenharmony_ci	}
129562306a36Sopenharmony_ci
129662306a36Sopenharmony_ci	/*
129762306a36Sopenharmony_ci	 *  Loads F/W from flash
129862306a36Sopenharmony_ci	 */
129962306a36Sopenharmony_ci	qla8044_wr_reg(ha, QLA8044_FW_IMAGE_VALID, QLA8044_BOOT_FROM_FLASH);
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci	qla8044_process_start_seq(vha);
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_ciexit_restart:
130462306a36Sopenharmony_ci	return ret_val;
130562306a36Sopenharmony_ci}
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci/*
130862306a36Sopenharmony_ci * qla8044_check_cmd_peg_status - Check peg status to see if Peg is
130962306a36Sopenharmony_ci * initialized.
131062306a36Sopenharmony_ci *
131162306a36Sopenharmony_ci * @ha : Pointer to adapter structure
131262306a36Sopenharmony_ci *
131362306a36Sopenharmony_ci * Return Value - QLA_SUCCESS/QLA_FUNCTION_FAILED
131462306a36Sopenharmony_ci */
131562306a36Sopenharmony_cistatic int
131662306a36Sopenharmony_ciqla8044_check_cmd_peg_status(struct scsi_qla_host *vha)
131762306a36Sopenharmony_ci{
131862306a36Sopenharmony_ci	uint32_t val, ret_val = QLA_FUNCTION_FAILED;
131962306a36Sopenharmony_ci	int retries = CRB_CMDPEG_CHECK_RETRY_COUNT;
132062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
132162306a36Sopenharmony_ci
132262306a36Sopenharmony_ci	do {
132362306a36Sopenharmony_ci		val = qla8044_rd_reg(ha, QLA8044_CMDPEG_STATE);
132462306a36Sopenharmony_ci		if (val == PHAN_INITIALIZE_COMPLETE) {
132562306a36Sopenharmony_ci			ql_dbg(ql_dbg_p3p, vha, 0xb0ac,
132662306a36Sopenharmony_ci			    "%s: Command Peg initialization "
132762306a36Sopenharmony_ci			    "complete! state=0x%x\n", __func__, val);
132862306a36Sopenharmony_ci			ret_val = QLA_SUCCESS;
132962306a36Sopenharmony_ci			break;
133062306a36Sopenharmony_ci		}
133162306a36Sopenharmony_ci		msleep(CRB_CMDPEG_CHECK_DELAY);
133262306a36Sopenharmony_ci	} while (--retries);
133362306a36Sopenharmony_ci
133462306a36Sopenharmony_ci	return ret_val;
133562306a36Sopenharmony_ci}
133662306a36Sopenharmony_ci
133762306a36Sopenharmony_cistatic int
133862306a36Sopenharmony_ciqla8044_start_firmware(struct scsi_qla_host *vha)
133962306a36Sopenharmony_ci{
134062306a36Sopenharmony_ci	int ret_val = QLA_SUCCESS;
134162306a36Sopenharmony_ci
134262306a36Sopenharmony_ci	if (qla8044_restart(vha)) {
134362306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb0ad,
134462306a36Sopenharmony_ci		    "%s: Restart Error!!!, Need Reset!!!\n",
134562306a36Sopenharmony_ci		    __func__);
134662306a36Sopenharmony_ci		ret_val = QLA_FUNCTION_FAILED;
134762306a36Sopenharmony_ci		goto exit_start_fw;
134862306a36Sopenharmony_ci	} else
134962306a36Sopenharmony_ci		ql_dbg(ql_dbg_p3p, vha, 0xb0af,
135062306a36Sopenharmony_ci		    "%s: Restart done!\n", __func__);
135162306a36Sopenharmony_ci
135262306a36Sopenharmony_ci	ret_val = qla8044_check_cmd_peg_status(vha);
135362306a36Sopenharmony_ci	if (ret_val) {
135462306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb0b0,
135562306a36Sopenharmony_ci		    "%s: Peg not initialized!\n", __func__);
135662306a36Sopenharmony_ci		ret_val = QLA_FUNCTION_FAILED;
135762306a36Sopenharmony_ci	}
135862306a36Sopenharmony_ci
135962306a36Sopenharmony_ciexit_start_fw:
136062306a36Sopenharmony_ci	return ret_val;
136162306a36Sopenharmony_ci}
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_civoid
136462306a36Sopenharmony_ciqla8044_clear_drv_active(struct qla_hw_data *ha)
136562306a36Sopenharmony_ci{
136662306a36Sopenharmony_ci	uint32_t drv_active;
136762306a36Sopenharmony_ci	struct scsi_qla_host *vha = pci_get_drvdata(ha->pdev);
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci	drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX);
137062306a36Sopenharmony_ci	drv_active &= ~(1 << (ha->portnum));
137162306a36Sopenharmony_ci
137262306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0xb0b1,
137362306a36Sopenharmony_ci	    "%s(%ld): drv_active: 0x%08x\n",
137462306a36Sopenharmony_ci	    __func__, vha->host_no, drv_active);
137562306a36Sopenharmony_ci
137662306a36Sopenharmony_ci	qla8044_wr_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX, drv_active);
137762306a36Sopenharmony_ci}
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci/*
138062306a36Sopenharmony_ci * qla8044_device_bootstrap - Initialize device, set DEV_READY, start fw
138162306a36Sopenharmony_ci * @ha: pointer to adapter structure
138262306a36Sopenharmony_ci *
138362306a36Sopenharmony_ci * Note: IDC lock must be held upon entry
138462306a36Sopenharmony_ci **/
138562306a36Sopenharmony_cistatic int
138662306a36Sopenharmony_ciqla8044_device_bootstrap(struct scsi_qla_host *vha)
138762306a36Sopenharmony_ci{
138862306a36Sopenharmony_ci	int rval = QLA_FUNCTION_FAILED;
138962306a36Sopenharmony_ci	int i;
139062306a36Sopenharmony_ci	uint32_t old_count = 0, count = 0;
139162306a36Sopenharmony_ci	int need_reset = 0;
139262306a36Sopenharmony_ci	uint32_t idc_ctrl;
139362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
139462306a36Sopenharmony_ci
139562306a36Sopenharmony_ci	need_reset = qla8044_need_reset(vha);
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	if (!need_reset) {
139862306a36Sopenharmony_ci		old_count = qla8044_rd_direct(vha,
139962306a36Sopenharmony_ci		    QLA8044_PEG_ALIVE_COUNTER_INDEX);
140062306a36Sopenharmony_ci
140162306a36Sopenharmony_ci		for (i = 0; i < 10; i++) {
140262306a36Sopenharmony_ci			msleep(200);
140362306a36Sopenharmony_ci
140462306a36Sopenharmony_ci			count = qla8044_rd_direct(vha,
140562306a36Sopenharmony_ci			    QLA8044_PEG_ALIVE_COUNTER_INDEX);
140662306a36Sopenharmony_ci			if (count != old_count) {
140762306a36Sopenharmony_ci				rval = QLA_SUCCESS;
140862306a36Sopenharmony_ci				goto dev_ready;
140962306a36Sopenharmony_ci			}
141062306a36Sopenharmony_ci		}
141162306a36Sopenharmony_ci		qla8044_flash_lock_recovery(vha);
141262306a36Sopenharmony_ci	} else {
141362306a36Sopenharmony_ci		/* We are trying to perform a recovery here. */
141462306a36Sopenharmony_ci		if (ha->flags.isp82xx_fw_hung)
141562306a36Sopenharmony_ci			qla8044_flash_lock_recovery(vha);
141662306a36Sopenharmony_ci	}
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	/* set to DEV_INITIALIZING */
141962306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0xb0b2,
142062306a36Sopenharmony_ci	    "%s: HW State: INITIALIZING\n", __func__);
142162306a36Sopenharmony_ci	qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
142262306a36Sopenharmony_ci	    QLA8XXX_DEV_INITIALIZING);
142362306a36Sopenharmony_ci
142462306a36Sopenharmony_ci	qla8044_idc_unlock(ha);
142562306a36Sopenharmony_ci	rval = qla8044_start_firmware(vha);
142662306a36Sopenharmony_ci	qla8044_idc_lock(ha);
142762306a36Sopenharmony_ci
142862306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
142962306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0xb0b3,
143062306a36Sopenharmony_ci		     "%s: HW State: FAILED\n", __func__);
143162306a36Sopenharmony_ci		qla8044_clear_drv_active(ha);
143262306a36Sopenharmony_ci		qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
143362306a36Sopenharmony_ci		    QLA8XXX_DEV_FAILED);
143462306a36Sopenharmony_ci		return rval;
143562306a36Sopenharmony_ci	}
143662306a36Sopenharmony_ci
143762306a36Sopenharmony_ci	/* For ISP8044, If IDC_CTRL GRACEFUL_RESET_BIT1 is set , reset it after
143862306a36Sopenharmony_ci	 * device goes to INIT state. */
143962306a36Sopenharmony_ci	idc_ctrl = qla8044_rd_reg(ha, QLA8044_IDC_DRV_CTRL);
144062306a36Sopenharmony_ci	if (idc_ctrl & GRACEFUL_RESET_BIT1) {
144162306a36Sopenharmony_ci		qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL,
144262306a36Sopenharmony_ci		    (idc_ctrl & ~GRACEFUL_RESET_BIT1));
144362306a36Sopenharmony_ci		ha->fw_dumped = false;
144462306a36Sopenharmony_ci	}
144562306a36Sopenharmony_ci
144662306a36Sopenharmony_cidev_ready:
144762306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0xb0b4,
144862306a36Sopenharmony_ci	    "%s: HW State: READY\n", __func__);
144962306a36Sopenharmony_ci	qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX, QLA8XXX_DEV_READY);
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	return rval;
145262306a36Sopenharmony_ci}
145362306a36Sopenharmony_ci
145462306a36Sopenharmony_ci/*-------------------------Reset Sequence Functions-----------------------*/
145562306a36Sopenharmony_cistatic void
145662306a36Sopenharmony_ciqla8044_dump_reset_seq_hdr(struct scsi_qla_host *vha)
145762306a36Sopenharmony_ci{
145862306a36Sopenharmony_ci	u8 *phdr;
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci	if (!vha->reset_tmplt.buff) {
146162306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb0b5,
146262306a36Sopenharmony_ci		    "%s: Error Invalid reset_seq_template\n", __func__);
146362306a36Sopenharmony_ci		return;
146462306a36Sopenharmony_ci	}
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci	phdr = vha->reset_tmplt.buff;
146762306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0b6,
146862306a36Sopenharmony_ci	    "Reset Template :\n\t0x%X 0x%X 0x%X 0x%X"
146962306a36Sopenharmony_ci	    "0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n"
147062306a36Sopenharmony_ci	    "\t0x%X 0x%X 0x%X 0x%X 0x%X 0x%X\n\n",
147162306a36Sopenharmony_ci	    *phdr, *(phdr+1), *(phdr+2), *(phdr+3), *(phdr+4),
147262306a36Sopenharmony_ci	    *(phdr+5), *(phdr+6), *(phdr+7), *(phdr + 8),
147362306a36Sopenharmony_ci	    *(phdr+9), *(phdr+10), *(phdr+11), *(phdr+12),
147462306a36Sopenharmony_ci	    *(phdr+13), *(phdr+14), *(phdr+15));
147562306a36Sopenharmony_ci}
147662306a36Sopenharmony_ci
147762306a36Sopenharmony_ci/*
147862306a36Sopenharmony_ci * qla8044_reset_seq_checksum_test - Validate Reset Sequence template.
147962306a36Sopenharmony_ci *
148062306a36Sopenharmony_ci * @ha : Pointer to adapter structure
148162306a36Sopenharmony_ci *
148262306a36Sopenharmony_ci * Return Value - QLA_SUCCESS/QLA_FUNCTION_FAILED
148362306a36Sopenharmony_ci */
148462306a36Sopenharmony_cistatic int
148562306a36Sopenharmony_ciqla8044_reset_seq_checksum_test(struct scsi_qla_host *vha)
148662306a36Sopenharmony_ci{
148762306a36Sopenharmony_ci	uint32_t sum =  0;
148862306a36Sopenharmony_ci	uint16_t *buff = (uint16_t *)vha->reset_tmplt.buff;
148962306a36Sopenharmony_ci	int u16_count =  vha->reset_tmplt.hdr->size / sizeof(uint16_t);
149062306a36Sopenharmony_ci
149162306a36Sopenharmony_ci	while (u16_count-- > 0)
149262306a36Sopenharmony_ci		sum += *buff++;
149362306a36Sopenharmony_ci
149462306a36Sopenharmony_ci	while (sum >> 16)
149562306a36Sopenharmony_ci		sum = (sum & 0xFFFF) +  (sum >> 16);
149662306a36Sopenharmony_ci
149762306a36Sopenharmony_ci	/* checksum of 0 indicates a valid template */
149862306a36Sopenharmony_ci	if (~sum) {
149962306a36Sopenharmony_ci		return QLA_SUCCESS;
150062306a36Sopenharmony_ci	} else {
150162306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb0b7,
150262306a36Sopenharmony_ci		    "%s: Reset seq checksum failed\n", __func__);
150362306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
150462306a36Sopenharmony_ci	}
150562306a36Sopenharmony_ci}
150662306a36Sopenharmony_ci
150762306a36Sopenharmony_ci/*
150862306a36Sopenharmony_ci * qla8044_read_reset_template - Read Reset Template from Flash, validate
150962306a36Sopenharmony_ci * the template and store offsets of stop/start/init offsets in ha->reset_tmplt.
151062306a36Sopenharmony_ci *
151162306a36Sopenharmony_ci * @ha : Pointer to adapter structure
151262306a36Sopenharmony_ci */
151362306a36Sopenharmony_civoid
151462306a36Sopenharmony_ciqla8044_read_reset_template(struct scsi_qla_host *vha)
151562306a36Sopenharmony_ci{
151662306a36Sopenharmony_ci	uint8_t *p_buff;
151762306a36Sopenharmony_ci	uint32_t addr, tmplt_hdr_def_size, tmplt_hdr_size;
151862306a36Sopenharmony_ci
151962306a36Sopenharmony_ci	vha->reset_tmplt.seq_error = 0;
152062306a36Sopenharmony_ci	vha->reset_tmplt.buff = vmalloc(QLA8044_RESTART_TEMPLATE_SIZE);
152162306a36Sopenharmony_ci	if (vha->reset_tmplt.buff == NULL) {
152262306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb0b8,
152362306a36Sopenharmony_ci		    "%s: Failed to allocate reset template resources\n",
152462306a36Sopenharmony_ci		    __func__);
152562306a36Sopenharmony_ci		goto exit_read_reset_template;
152662306a36Sopenharmony_ci	}
152762306a36Sopenharmony_ci
152862306a36Sopenharmony_ci	p_buff = vha->reset_tmplt.buff;
152962306a36Sopenharmony_ci	addr = QLA8044_RESET_TEMPLATE_ADDR;
153062306a36Sopenharmony_ci
153162306a36Sopenharmony_ci	tmplt_hdr_def_size =
153262306a36Sopenharmony_ci	    sizeof(struct qla8044_reset_template_hdr) / sizeof(uint32_t);
153362306a36Sopenharmony_ci
153462306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0b9,
153562306a36Sopenharmony_ci	    "%s: Read template hdr size %d from Flash\n",
153662306a36Sopenharmony_ci	    __func__, tmplt_hdr_def_size);
153762306a36Sopenharmony_ci
153862306a36Sopenharmony_ci	/* Copy template header from flash */
153962306a36Sopenharmony_ci	if (qla8044_read_flash_data(vha, p_buff, addr, tmplt_hdr_def_size)) {
154062306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb0ba,
154162306a36Sopenharmony_ci		    "%s: Failed to read reset template\n", __func__);
154262306a36Sopenharmony_ci		goto exit_read_template_error;
154362306a36Sopenharmony_ci	}
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	vha->reset_tmplt.hdr =
154662306a36Sopenharmony_ci	 (struct qla8044_reset_template_hdr *) vha->reset_tmplt.buff;
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	/* Validate the template header size and signature */
154962306a36Sopenharmony_ci	tmplt_hdr_size = vha->reset_tmplt.hdr->hdr_size/sizeof(uint32_t);
155062306a36Sopenharmony_ci	if ((tmplt_hdr_size != tmplt_hdr_def_size) ||
155162306a36Sopenharmony_ci	    (vha->reset_tmplt.hdr->signature != RESET_TMPLT_HDR_SIGNATURE)) {
155262306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb0bb,
155362306a36Sopenharmony_ci		    "%s: Template Header size invalid %d "
155462306a36Sopenharmony_ci		    "tmplt_hdr_def_size %d!!!\n", __func__,
155562306a36Sopenharmony_ci		    tmplt_hdr_size, tmplt_hdr_def_size);
155662306a36Sopenharmony_ci		goto exit_read_template_error;
155762306a36Sopenharmony_ci	}
155862306a36Sopenharmony_ci
155962306a36Sopenharmony_ci	addr = QLA8044_RESET_TEMPLATE_ADDR + vha->reset_tmplt.hdr->hdr_size;
156062306a36Sopenharmony_ci	p_buff = vha->reset_tmplt.buff + vha->reset_tmplt.hdr->hdr_size;
156162306a36Sopenharmony_ci	tmplt_hdr_def_size = (vha->reset_tmplt.hdr->size -
156262306a36Sopenharmony_ci	    vha->reset_tmplt.hdr->hdr_size)/sizeof(uint32_t);
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0bc,
156562306a36Sopenharmony_ci	    "%s: Read rest of the template size %d\n",
156662306a36Sopenharmony_ci	    __func__, vha->reset_tmplt.hdr->size);
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_ci	/* Copy rest of the template */
156962306a36Sopenharmony_ci	if (qla8044_read_flash_data(vha, p_buff, addr, tmplt_hdr_def_size)) {
157062306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb0bd,
157162306a36Sopenharmony_ci		    "%s: Failed to read reset template\n", __func__);
157262306a36Sopenharmony_ci		goto exit_read_template_error;
157362306a36Sopenharmony_ci	}
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_ci	/* Integrity check */
157662306a36Sopenharmony_ci	if (qla8044_reset_seq_checksum_test(vha)) {
157762306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb0be,
157862306a36Sopenharmony_ci		    "%s: Reset Seq checksum failed!\n", __func__);
157962306a36Sopenharmony_ci		goto exit_read_template_error;
158062306a36Sopenharmony_ci	}
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0bf,
158362306a36Sopenharmony_ci	    "%s: Reset Seq checksum passed! Get stop, "
158462306a36Sopenharmony_ci	    "start and init seq offsets\n", __func__);
158562306a36Sopenharmony_ci
158662306a36Sopenharmony_ci	/* Get STOP, START, INIT sequence offsets */
158762306a36Sopenharmony_ci	vha->reset_tmplt.init_offset = vha->reset_tmplt.buff +
158862306a36Sopenharmony_ci	    vha->reset_tmplt.hdr->init_seq_offset;
158962306a36Sopenharmony_ci
159062306a36Sopenharmony_ci	vha->reset_tmplt.start_offset = vha->reset_tmplt.buff +
159162306a36Sopenharmony_ci	    vha->reset_tmplt.hdr->start_seq_offset;
159262306a36Sopenharmony_ci
159362306a36Sopenharmony_ci	vha->reset_tmplt.stop_offset = vha->reset_tmplt.buff +
159462306a36Sopenharmony_ci	    vha->reset_tmplt.hdr->hdr_size;
159562306a36Sopenharmony_ci
159662306a36Sopenharmony_ci	qla8044_dump_reset_seq_hdr(vha);
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci	goto exit_read_reset_template;
159962306a36Sopenharmony_ci
160062306a36Sopenharmony_ciexit_read_template_error:
160162306a36Sopenharmony_ci	vfree(vha->reset_tmplt.buff);
160262306a36Sopenharmony_ci
160362306a36Sopenharmony_ciexit_read_reset_template:
160462306a36Sopenharmony_ci	return;
160562306a36Sopenharmony_ci}
160662306a36Sopenharmony_ci
160762306a36Sopenharmony_civoid
160862306a36Sopenharmony_ciqla8044_set_idc_dontreset(struct scsi_qla_host *vha)
160962306a36Sopenharmony_ci{
161062306a36Sopenharmony_ci	uint32_t idc_ctrl;
161162306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
161262306a36Sopenharmony_ci
161362306a36Sopenharmony_ci	idc_ctrl = qla8044_rd_reg(ha, QLA8044_IDC_DRV_CTRL);
161462306a36Sopenharmony_ci	idc_ctrl |= DONTRESET_BIT0;
161562306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0c0,
161662306a36Sopenharmony_ci	    "%s: idc_ctrl = %d\n", __func__, idc_ctrl);
161762306a36Sopenharmony_ci	qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL, idc_ctrl);
161862306a36Sopenharmony_ci}
161962306a36Sopenharmony_ci
162062306a36Sopenharmony_cistatic inline void
162162306a36Sopenharmony_ciqla8044_set_rst_ready(struct scsi_qla_host *vha)
162262306a36Sopenharmony_ci{
162362306a36Sopenharmony_ci	uint32_t drv_state;
162462306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_ci	drv_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX);
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	/* For ISP8044, drv_active register has 1 bit per function,
162962306a36Sopenharmony_ci	 * shift 1 by func_num to set a bit for the function.*/
163062306a36Sopenharmony_ci	drv_state |= (1 << ha->portnum);
163162306a36Sopenharmony_ci
163262306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0xb0c1,
163362306a36Sopenharmony_ci	    "%s(%ld): drv_state: 0x%08x\n",
163462306a36Sopenharmony_ci	    __func__, vha->host_no, drv_state);
163562306a36Sopenharmony_ci	qla8044_wr_direct(vha, QLA8044_CRB_DRV_STATE_INDEX, drv_state);
163662306a36Sopenharmony_ci}
163762306a36Sopenharmony_ci
163862306a36Sopenharmony_ci/**
163962306a36Sopenharmony_ci * qla8044_need_reset_handler - Code to start reset sequence
164062306a36Sopenharmony_ci * @vha: pointer to adapter structure
164162306a36Sopenharmony_ci *
164262306a36Sopenharmony_ci * Note: IDC lock must be held upon entry
164362306a36Sopenharmony_ci */
164462306a36Sopenharmony_cistatic void
164562306a36Sopenharmony_ciqla8044_need_reset_handler(struct scsi_qla_host *vha)
164662306a36Sopenharmony_ci{
164762306a36Sopenharmony_ci	uint32_t dev_state = 0, drv_state, drv_active;
164862306a36Sopenharmony_ci	unsigned long reset_timeout;
164962306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
165062306a36Sopenharmony_ci
165162306a36Sopenharmony_ci	ql_log(ql_log_fatal, vha, 0xb0c2,
165262306a36Sopenharmony_ci	    "%s: Performing ISP error recovery\n", __func__);
165362306a36Sopenharmony_ci
165462306a36Sopenharmony_ci	if (vha->flags.online) {
165562306a36Sopenharmony_ci		qla8044_idc_unlock(ha);
165662306a36Sopenharmony_ci		qla2x00_abort_isp_cleanup(vha);
165762306a36Sopenharmony_ci		ha->isp_ops->get_flash_version(vha, vha->req->ring);
165862306a36Sopenharmony_ci		ha->isp_ops->nvram_config(vha);
165962306a36Sopenharmony_ci		qla8044_idc_lock(ha);
166062306a36Sopenharmony_ci	}
166162306a36Sopenharmony_ci
166262306a36Sopenharmony_ci	dev_state = qla8044_rd_direct(vha,
166362306a36Sopenharmony_ci	    QLA8044_CRB_DEV_STATE_INDEX);
166462306a36Sopenharmony_ci	drv_state = qla8044_rd_direct(vha,
166562306a36Sopenharmony_ci	    QLA8044_CRB_DRV_STATE_INDEX);
166662306a36Sopenharmony_ci	drv_active = qla8044_rd_direct(vha,
166762306a36Sopenharmony_ci	    QLA8044_CRB_DRV_ACTIVE_INDEX);
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0xb0c5,
167062306a36Sopenharmony_ci	    "%s(%ld): drv_state = 0x%x, drv_active = 0x%x dev_state = 0x%x\n",
167162306a36Sopenharmony_ci	    __func__, vha->host_no, drv_state, drv_active, dev_state);
167262306a36Sopenharmony_ci
167362306a36Sopenharmony_ci	qla8044_set_rst_ready(vha);
167462306a36Sopenharmony_ci
167562306a36Sopenharmony_ci	/* wait for 10 seconds for reset ack from all functions */
167662306a36Sopenharmony_ci	reset_timeout = jiffies + (ha->fcoe_reset_timeout * HZ);
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	do {
167962306a36Sopenharmony_ci		if (time_after_eq(jiffies, reset_timeout)) {
168062306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0xb0c4,
168162306a36Sopenharmony_ci			    "%s: Function %d: Reset Ack Timeout!, drv_state: 0x%08x, drv_active: 0x%08x\n",
168262306a36Sopenharmony_ci			    __func__, ha->portnum, drv_state, drv_active);
168362306a36Sopenharmony_ci			break;
168462306a36Sopenharmony_ci		}
168562306a36Sopenharmony_ci
168662306a36Sopenharmony_ci		qla8044_idc_unlock(ha);
168762306a36Sopenharmony_ci		msleep(1000);
168862306a36Sopenharmony_ci		qla8044_idc_lock(ha);
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci		dev_state = qla8044_rd_direct(vha,
169162306a36Sopenharmony_ci		    QLA8044_CRB_DEV_STATE_INDEX);
169262306a36Sopenharmony_ci		drv_state = qla8044_rd_direct(vha,
169362306a36Sopenharmony_ci		    QLA8044_CRB_DRV_STATE_INDEX);
169462306a36Sopenharmony_ci		drv_active = qla8044_rd_direct(vha,
169562306a36Sopenharmony_ci		    QLA8044_CRB_DRV_ACTIVE_INDEX);
169662306a36Sopenharmony_ci	} while (((drv_state & drv_active) != drv_active) &&
169762306a36Sopenharmony_ci	    (dev_state == QLA8XXX_DEV_NEED_RESET));
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	/* Remove IDC participation of functions not acknowledging */
170062306a36Sopenharmony_ci	if (drv_state != drv_active) {
170162306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0xb0c7,
170262306a36Sopenharmony_ci		    "%s(%ld): Function %d turning off drv_active of non-acking function 0x%x\n",
170362306a36Sopenharmony_ci		    __func__, vha->host_no, ha->portnum,
170462306a36Sopenharmony_ci		    (drv_active ^ drv_state));
170562306a36Sopenharmony_ci		drv_active = drv_active & drv_state;
170662306a36Sopenharmony_ci		qla8044_wr_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX,
170762306a36Sopenharmony_ci		    drv_active);
170862306a36Sopenharmony_ci	} else {
170962306a36Sopenharmony_ci		/*
171062306a36Sopenharmony_ci		 * Reset owner should execute reset recovery,
171162306a36Sopenharmony_ci		 * if all functions acknowledged
171262306a36Sopenharmony_ci		 */
171362306a36Sopenharmony_ci		if ((ha->flags.nic_core_reset_owner) &&
171462306a36Sopenharmony_ci		    (dev_state == QLA8XXX_DEV_NEED_RESET)) {
171562306a36Sopenharmony_ci			ha->flags.nic_core_reset_owner = 0;
171662306a36Sopenharmony_ci			qla8044_device_bootstrap(vha);
171762306a36Sopenharmony_ci			return;
171862306a36Sopenharmony_ci		}
171962306a36Sopenharmony_ci	}
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	/* Exit if non active function */
172262306a36Sopenharmony_ci	if (!(drv_active & (1 << ha->portnum))) {
172362306a36Sopenharmony_ci		ha->flags.nic_core_reset_owner = 0;
172462306a36Sopenharmony_ci		return;
172562306a36Sopenharmony_ci	}
172662306a36Sopenharmony_ci
172762306a36Sopenharmony_ci	/*
172862306a36Sopenharmony_ci	 * Execute Reset Recovery if Reset Owner or Function 7
172962306a36Sopenharmony_ci	 * is the only active function
173062306a36Sopenharmony_ci	 */
173162306a36Sopenharmony_ci	if (ha->flags.nic_core_reset_owner ||
173262306a36Sopenharmony_ci	    ((drv_state & drv_active) == QLA8044_FUN7_ACTIVE_INDEX)) {
173362306a36Sopenharmony_ci		ha->flags.nic_core_reset_owner = 0;
173462306a36Sopenharmony_ci		qla8044_device_bootstrap(vha);
173562306a36Sopenharmony_ci	}
173662306a36Sopenharmony_ci}
173762306a36Sopenharmony_ci
173862306a36Sopenharmony_cistatic void
173962306a36Sopenharmony_ciqla8044_set_drv_active(struct scsi_qla_host *vha)
174062306a36Sopenharmony_ci{
174162306a36Sopenharmony_ci	uint32_t drv_active;
174262306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
174362306a36Sopenharmony_ci
174462306a36Sopenharmony_ci	drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX);
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	/* For ISP8044, drv_active register has 1 bit per function,
174762306a36Sopenharmony_ci	 * shift 1 by func_num to set a bit for the function.*/
174862306a36Sopenharmony_ci	drv_active |= (1 << ha->portnum);
174962306a36Sopenharmony_ci
175062306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0xb0c8,
175162306a36Sopenharmony_ci	    "%s(%ld): drv_active: 0x%08x\n",
175262306a36Sopenharmony_ci	    __func__, vha->host_no, drv_active);
175362306a36Sopenharmony_ci	qla8044_wr_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX, drv_active);
175462306a36Sopenharmony_ci}
175562306a36Sopenharmony_ci
175662306a36Sopenharmony_cistatic int
175762306a36Sopenharmony_ciqla8044_check_drv_active(struct scsi_qla_host *vha)
175862306a36Sopenharmony_ci{
175962306a36Sopenharmony_ci	uint32_t drv_active;
176062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
176162306a36Sopenharmony_ci
176262306a36Sopenharmony_ci	drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX);
176362306a36Sopenharmony_ci	if (drv_active & (1 << ha->portnum))
176462306a36Sopenharmony_ci		return QLA_SUCCESS;
176562306a36Sopenharmony_ci	else
176662306a36Sopenharmony_ci		return QLA_TEST_FAILED;
176762306a36Sopenharmony_ci}
176862306a36Sopenharmony_ci
176962306a36Sopenharmony_cistatic void
177062306a36Sopenharmony_ciqla8044_clear_idc_dontreset(struct scsi_qla_host *vha)
177162306a36Sopenharmony_ci{
177262306a36Sopenharmony_ci	uint32_t idc_ctrl;
177362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
177462306a36Sopenharmony_ci
177562306a36Sopenharmony_ci	idc_ctrl = qla8044_rd_reg(ha, QLA8044_IDC_DRV_CTRL);
177662306a36Sopenharmony_ci	idc_ctrl &= ~DONTRESET_BIT0;
177762306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0xb0c9,
177862306a36Sopenharmony_ci	    "%s: idc_ctrl = %d\n", __func__,
177962306a36Sopenharmony_ci	    idc_ctrl);
178062306a36Sopenharmony_ci	qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL, idc_ctrl);
178162306a36Sopenharmony_ci}
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_cistatic int
178462306a36Sopenharmony_ciqla8044_set_idc_ver(struct scsi_qla_host *vha)
178562306a36Sopenharmony_ci{
178662306a36Sopenharmony_ci	int idc_ver;
178762306a36Sopenharmony_ci	uint32_t drv_active;
178862306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
178962306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
179062306a36Sopenharmony_ci
179162306a36Sopenharmony_ci	drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX);
179262306a36Sopenharmony_ci	if (drv_active == (1 << ha->portnum)) {
179362306a36Sopenharmony_ci		idc_ver = qla8044_rd_direct(vha,
179462306a36Sopenharmony_ci		    QLA8044_CRB_DRV_IDC_VERSION_INDEX);
179562306a36Sopenharmony_ci		idc_ver &= (~0xFF);
179662306a36Sopenharmony_ci		idc_ver |= QLA8044_IDC_VER_MAJ_VALUE;
179762306a36Sopenharmony_ci		qla8044_wr_direct(vha, QLA8044_CRB_DRV_IDC_VERSION_INDEX,
179862306a36Sopenharmony_ci		    idc_ver);
179962306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0xb0ca,
180062306a36Sopenharmony_ci		    "%s: IDC version updated to %d\n",
180162306a36Sopenharmony_ci		    __func__, idc_ver);
180262306a36Sopenharmony_ci	} else {
180362306a36Sopenharmony_ci		idc_ver = qla8044_rd_direct(vha,
180462306a36Sopenharmony_ci		    QLA8044_CRB_DRV_IDC_VERSION_INDEX);
180562306a36Sopenharmony_ci		idc_ver &= 0xFF;
180662306a36Sopenharmony_ci		if (QLA8044_IDC_VER_MAJ_VALUE != idc_ver) {
180762306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0xb0cb,
180862306a36Sopenharmony_ci			    "%s: qla4xxx driver IDC version %d "
180962306a36Sopenharmony_ci			    "is not compatible with IDC version %d "
181062306a36Sopenharmony_ci			    "of other drivers!\n",
181162306a36Sopenharmony_ci			    __func__, QLA8044_IDC_VER_MAJ_VALUE,
181262306a36Sopenharmony_ci			    idc_ver);
181362306a36Sopenharmony_ci			rval = QLA_FUNCTION_FAILED;
181462306a36Sopenharmony_ci			goto exit_set_idc_ver;
181562306a36Sopenharmony_ci		}
181662306a36Sopenharmony_ci	}
181762306a36Sopenharmony_ci
181862306a36Sopenharmony_ci	/* Update IDC_MINOR_VERSION */
181962306a36Sopenharmony_ci	idc_ver = qla8044_rd_reg(ha, QLA8044_CRB_IDC_VER_MINOR);
182062306a36Sopenharmony_ci	idc_ver &= ~(0x03 << (ha->portnum * 2));
182162306a36Sopenharmony_ci	idc_ver |= (QLA8044_IDC_VER_MIN_VALUE << (ha->portnum * 2));
182262306a36Sopenharmony_ci	qla8044_wr_reg(ha, QLA8044_CRB_IDC_VER_MINOR, idc_ver);
182362306a36Sopenharmony_ci
182462306a36Sopenharmony_ciexit_set_idc_ver:
182562306a36Sopenharmony_ci	return rval;
182662306a36Sopenharmony_ci}
182762306a36Sopenharmony_ci
182862306a36Sopenharmony_cistatic int
182962306a36Sopenharmony_ciqla8044_update_idc_reg(struct scsi_qla_host *vha)
183062306a36Sopenharmony_ci{
183162306a36Sopenharmony_ci	uint32_t drv_active;
183262306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
183362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_ci	if (vha->flags.init_done)
183662306a36Sopenharmony_ci		goto exit_update_idc_reg;
183762306a36Sopenharmony_ci
183862306a36Sopenharmony_ci	qla8044_idc_lock(ha);
183962306a36Sopenharmony_ci	qla8044_set_drv_active(vha);
184062306a36Sopenharmony_ci
184162306a36Sopenharmony_ci	drv_active = qla8044_rd_direct(vha,
184262306a36Sopenharmony_ci	    QLA8044_CRB_DRV_ACTIVE_INDEX);
184362306a36Sopenharmony_ci
184462306a36Sopenharmony_ci	/* If we are the first driver to load and
184562306a36Sopenharmony_ci	 * ql2xdontresethba is not set, clear IDC_CTRL BIT0. */
184662306a36Sopenharmony_ci	if ((drv_active == (1 << ha->portnum)) && !ql2xdontresethba)
184762306a36Sopenharmony_ci		qla8044_clear_idc_dontreset(vha);
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci	rval = qla8044_set_idc_ver(vha);
185062306a36Sopenharmony_ci	if (rval == QLA_FUNCTION_FAILED)
185162306a36Sopenharmony_ci		qla8044_clear_drv_active(ha);
185262306a36Sopenharmony_ci	qla8044_idc_unlock(ha);
185362306a36Sopenharmony_ci
185462306a36Sopenharmony_ciexit_update_idc_reg:
185562306a36Sopenharmony_ci	return rval;
185662306a36Sopenharmony_ci}
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci/**
185962306a36Sopenharmony_ci * qla8044_need_qsnt_handler - Code to start qsnt
186062306a36Sopenharmony_ci * @vha: pointer to adapter structure
186162306a36Sopenharmony_ci */
186262306a36Sopenharmony_cistatic void
186362306a36Sopenharmony_ciqla8044_need_qsnt_handler(struct scsi_qla_host *vha)
186462306a36Sopenharmony_ci{
186562306a36Sopenharmony_ci	unsigned long qsnt_timeout;
186662306a36Sopenharmony_ci	uint32_t drv_state, drv_active, dev_state;
186762306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
186862306a36Sopenharmony_ci
186962306a36Sopenharmony_ci	if (vha->flags.online)
187062306a36Sopenharmony_ci		qla2x00_quiesce_io(vha);
187162306a36Sopenharmony_ci	else
187262306a36Sopenharmony_ci		return;
187362306a36Sopenharmony_ci
187462306a36Sopenharmony_ci	qla8044_set_qsnt_ready(vha);
187562306a36Sopenharmony_ci
187662306a36Sopenharmony_ci	/* Wait for 30 secs for all functions to ack qsnt mode */
187762306a36Sopenharmony_ci	qsnt_timeout = jiffies + (QSNT_ACK_TOV * HZ);
187862306a36Sopenharmony_ci	drv_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX);
187962306a36Sopenharmony_ci	drv_active = qla8044_rd_direct(vha, QLA8044_CRB_DRV_ACTIVE_INDEX);
188062306a36Sopenharmony_ci
188162306a36Sopenharmony_ci	/* Shift drv_active by 1 to match drv_state. As quiescent ready bit
188262306a36Sopenharmony_ci	   position is at bit 1 and drv active is at bit 0 */
188362306a36Sopenharmony_ci	drv_active = drv_active << 1;
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_ci	while (drv_state != drv_active) {
188662306a36Sopenharmony_ci		if (time_after_eq(jiffies, qsnt_timeout)) {
188762306a36Sopenharmony_ci			/* Other functions did not ack, changing state to
188862306a36Sopenharmony_ci			 * DEV_READY
188962306a36Sopenharmony_ci			 */
189062306a36Sopenharmony_ci			clear_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
189162306a36Sopenharmony_ci			qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
189262306a36Sopenharmony_ci					    QLA8XXX_DEV_READY);
189362306a36Sopenharmony_ci			qla8044_clear_qsnt_ready(vha);
189462306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0xb0cc,
189562306a36Sopenharmony_ci			    "Timeout waiting for quiescent ack!!!\n");
189662306a36Sopenharmony_ci			return;
189762306a36Sopenharmony_ci		}
189862306a36Sopenharmony_ci		qla8044_idc_unlock(ha);
189962306a36Sopenharmony_ci		msleep(1000);
190062306a36Sopenharmony_ci		qla8044_idc_lock(ha);
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_ci		drv_state = qla8044_rd_direct(vha,
190362306a36Sopenharmony_ci		    QLA8044_CRB_DRV_STATE_INDEX);
190462306a36Sopenharmony_ci		drv_active = qla8044_rd_direct(vha,
190562306a36Sopenharmony_ci		    QLA8044_CRB_DRV_ACTIVE_INDEX);
190662306a36Sopenharmony_ci		drv_active = drv_active << 1;
190762306a36Sopenharmony_ci	}
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	/* All functions have Acked. Set quiescent state */
191062306a36Sopenharmony_ci	dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX);
191162306a36Sopenharmony_ci
191262306a36Sopenharmony_ci	if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT) {
191362306a36Sopenharmony_ci		qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
191462306a36Sopenharmony_ci		    QLA8XXX_DEV_QUIESCENT);
191562306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0xb0cd,
191662306a36Sopenharmony_ci		    "%s: HW State: QUIESCENT\n", __func__);
191762306a36Sopenharmony_ci	}
191862306a36Sopenharmony_ci}
191962306a36Sopenharmony_ci
192062306a36Sopenharmony_ci/*
192162306a36Sopenharmony_ci * qla8044_device_state_handler - Adapter state machine
192262306a36Sopenharmony_ci * @ha: pointer to host adapter structure.
192362306a36Sopenharmony_ci *
192462306a36Sopenharmony_ci * Note: IDC lock must be UNLOCKED upon entry
192562306a36Sopenharmony_ci **/
192662306a36Sopenharmony_ciint
192762306a36Sopenharmony_ciqla8044_device_state_handler(struct scsi_qla_host *vha)
192862306a36Sopenharmony_ci{
192962306a36Sopenharmony_ci	uint32_t dev_state;
193062306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
193162306a36Sopenharmony_ci	unsigned long dev_init_timeout;
193262306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
193362306a36Sopenharmony_ci
193462306a36Sopenharmony_ci	rval = qla8044_update_idc_reg(vha);
193562306a36Sopenharmony_ci	if (rval == QLA_FUNCTION_FAILED)
193662306a36Sopenharmony_ci		goto exit_error;
193762306a36Sopenharmony_ci
193862306a36Sopenharmony_ci	dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX);
193962306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0ce,
194062306a36Sopenharmony_ci	    "Device state is 0x%x = %s\n",
194162306a36Sopenharmony_ci	    dev_state, qdev_state(dev_state));
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci	/* wait for 30 seconds for device to go ready */
194462306a36Sopenharmony_ci	dev_init_timeout = jiffies + (ha->fcoe_dev_init_timeout * HZ);
194562306a36Sopenharmony_ci
194662306a36Sopenharmony_ci	qla8044_idc_lock(ha);
194762306a36Sopenharmony_ci
194862306a36Sopenharmony_ci	while (1) {
194962306a36Sopenharmony_ci		if (time_after_eq(jiffies, dev_init_timeout)) {
195062306a36Sopenharmony_ci			if (qla8044_check_drv_active(vha) == QLA_SUCCESS) {
195162306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0xb0cf,
195262306a36Sopenharmony_ci				    "%s: Device Init Failed 0x%x = %s\n",
195362306a36Sopenharmony_ci				    QLA2XXX_DRIVER_NAME, dev_state,
195462306a36Sopenharmony_ci				    qdev_state(dev_state));
195562306a36Sopenharmony_ci				qla8044_wr_direct(vha,
195662306a36Sopenharmony_ci				    QLA8044_CRB_DEV_STATE_INDEX,
195762306a36Sopenharmony_ci				    QLA8XXX_DEV_FAILED);
195862306a36Sopenharmony_ci			}
195962306a36Sopenharmony_ci		}
196062306a36Sopenharmony_ci
196162306a36Sopenharmony_ci		dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX);
196262306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0xb0d0,
196362306a36Sopenharmony_ci		    "Device state is 0x%x = %s\n",
196462306a36Sopenharmony_ci		    dev_state, qdev_state(dev_state));
196562306a36Sopenharmony_ci
196662306a36Sopenharmony_ci		/* NOTE: Make sure idc unlocked upon exit of switch statement */
196762306a36Sopenharmony_ci		switch (dev_state) {
196862306a36Sopenharmony_ci		case QLA8XXX_DEV_READY:
196962306a36Sopenharmony_ci			ha->flags.nic_core_reset_owner = 0;
197062306a36Sopenharmony_ci			goto exit;
197162306a36Sopenharmony_ci		case QLA8XXX_DEV_COLD:
197262306a36Sopenharmony_ci			rval = qla8044_device_bootstrap(vha);
197362306a36Sopenharmony_ci			break;
197462306a36Sopenharmony_ci		case QLA8XXX_DEV_INITIALIZING:
197562306a36Sopenharmony_ci			qla8044_idc_unlock(ha);
197662306a36Sopenharmony_ci			msleep(1000);
197762306a36Sopenharmony_ci			qla8044_idc_lock(ha);
197862306a36Sopenharmony_ci			break;
197962306a36Sopenharmony_ci		case QLA8XXX_DEV_NEED_RESET:
198062306a36Sopenharmony_ci			/* For ISP8044, if NEED_RESET is set by any driver,
198162306a36Sopenharmony_ci			 * it should be honored, irrespective of IDC_CTRL
198262306a36Sopenharmony_ci			 * DONTRESET_BIT0 */
198362306a36Sopenharmony_ci			qla8044_need_reset_handler(vha);
198462306a36Sopenharmony_ci			break;
198562306a36Sopenharmony_ci		case QLA8XXX_DEV_NEED_QUIESCENT:
198662306a36Sopenharmony_ci			/* idc locked/unlocked in handler */
198762306a36Sopenharmony_ci			qla8044_need_qsnt_handler(vha);
198862306a36Sopenharmony_ci
198962306a36Sopenharmony_ci			/* Reset the init timeout after qsnt handler */
199062306a36Sopenharmony_ci			dev_init_timeout = jiffies +
199162306a36Sopenharmony_ci			    (ha->fcoe_reset_timeout * HZ);
199262306a36Sopenharmony_ci			break;
199362306a36Sopenharmony_ci		case QLA8XXX_DEV_QUIESCENT:
199462306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0xb0d1,
199562306a36Sopenharmony_ci			    "HW State: QUIESCENT\n");
199662306a36Sopenharmony_ci
199762306a36Sopenharmony_ci			qla8044_idc_unlock(ha);
199862306a36Sopenharmony_ci			msleep(1000);
199962306a36Sopenharmony_ci			qla8044_idc_lock(ha);
200062306a36Sopenharmony_ci
200162306a36Sopenharmony_ci			/* Reset the init timeout after qsnt handler */
200262306a36Sopenharmony_ci			dev_init_timeout = jiffies +
200362306a36Sopenharmony_ci			    (ha->fcoe_reset_timeout * HZ);
200462306a36Sopenharmony_ci			break;
200562306a36Sopenharmony_ci		case QLA8XXX_DEV_FAILED:
200662306a36Sopenharmony_ci			ha->flags.nic_core_reset_owner = 0;
200762306a36Sopenharmony_ci			qla8044_idc_unlock(ha);
200862306a36Sopenharmony_ci			qla8xxx_dev_failed_handler(vha);
200962306a36Sopenharmony_ci			rval = QLA_FUNCTION_FAILED;
201062306a36Sopenharmony_ci			qla8044_idc_lock(ha);
201162306a36Sopenharmony_ci			goto exit;
201262306a36Sopenharmony_ci		default:
201362306a36Sopenharmony_ci			qla8044_idc_unlock(ha);
201462306a36Sopenharmony_ci			qla8xxx_dev_failed_handler(vha);
201562306a36Sopenharmony_ci			rval = QLA_FUNCTION_FAILED;
201662306a36Sopenharmony_ci			qla8044_idc_lock(ha);
201762306a36Sopenharmony_ci			goto exit;
201862306a36Sopenharmony_ci		}
201962306a36Sopenharmony_ci	}
202062306a36Sopenharmony_ciexit:
202162306a36Sopenharmony_ci	qla8044_idc_unlock(ha);
202262306a36Sopenharmony_ci
202362306a36Sopenharmony_ciexit_error:
202462306a36Sopenharmony_ci	return rval;
202562306a36Sopenharmony_ci}
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci/**
202862306a36Sopenharmony_ci * qla8044_check_temp - Check the ISP82XX temperature.
202962306a36Sopenharmony_ci * @vha: adapter block pointer.
203062306a36Sopenharmony_ci *
203162306a36Sopenharmony_ci * Note: The caller should not hold the idc lock.
203262306a36Sopenharmony_ci */
203362306a36Sopenharmony_cistatic int
203462306a36Sopenharmony_ciqla8044_check_temp(struct scsi_qla_host *vha)
203562306a36Sopenharmony_ci{
203662306a36Sopenharmony_ci	uint32_t temp, temp_state, temp_val;
203762306a36Sopenharmony_ci	int status = QLA_SUCCESS;
203862306a36Sopenharmony_ci
203962306a36Sopenharmony_ci	temp = qla8044_rd_direct(vha, QLA8044_CRB_TEMP_STATE_INDEX);
204062306a36Sopenharmony_ci	temp_state = qla82xx_get_temp_state(temp);
204162306a36Sopenharmony_ci	temp_val = qla82xx_get_temp_val(temp);
204262306a36Sopenharmony_ci
204362306a36Sopenharmony_ci	if (temp_state == QLA82XX_TEMP_PANIC) {
204462306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb0d2,
204562306a36Sopenharmony_ci		    "Device temperature %d degrees C"
204662306a36Sopenharmony_ci		    " exceeds maximum allowed. Hardware has been shut"
204762306a36Sopenharmony_ci		    " down\n", temp_val);
204862306a36Sopenharmony_ci		status = QLA_FUNCTION_FAILED;
204962306a36Sopenharmony_ci		return status;
205062306a36Sopenharmony_ci	} else if (temp_state == QLA82XX_TEMP_WARN) {
205162306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb0d3,
205262306a36Sopenharmony_ci		    "Device temperature %d"
205362306a36Sopenharmony_ci		    " degrees C exceeds operating range."
205462306a36Sopenharmony_ci		    " Immediate action needed.\n", temp_val);
205562306a36Sopenharmony_ci	}
205662306a36Sopenharmony_ci	return 0;
205762306a36Sopenharmony_ci}
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ciint qla8044_read_temperature(scsi_qla_host_t *vha)
206062306a36Sopenharmony_ci{
206162306a36Sopenharmony_ci	uint32_t temp;
206262306a36Sopenharmony_ci
206362306a36Sopenharmony_ci	temp = qla8044_rd_direct(vha, QLA8044_CRB_TEMP_STATE_INDEX);
206462306a36Sopenharmony_ci	return qla82xx_get_temp_val(temp);
206562306a36Sopenharmony_ci}
206662306a36Sopenharmony_ci
206762306a36Sopenharmony_ci/**
206862306a36Sopenharmony_ci * qla8044_check_fw_alive  - Check firmware health
206962306a36Sopenharmony_ci * @vha: Pointer to host adapter structure.
207062306a36Sopenharmony_ci *
207162306a36Sopenharmony_ci * Context: Interrupt
207262306a36Sopenharmony_ci */
207362306a36Sopenharmony_ciint
207462306a36Sopenharmony_ciqla8044_check_fw_alive(struct scsi_qla_host *vha)
207562306a36Sopenharmony_ci{
207662306a36Sopenharmony_ci	uint32_t fw_heartbeat_counter;
207762306a36Sopenharmony_ci	uint32_t halt_status1, halt_status2;
207862306a36Sopenharmony_ci	int status = QLA_SUCCESS;
207962306a36Sopenharmony_ci
208062306a36Sopenharmony_ci	fw_heartbeat_counter = qla8044_rd_direct(vha,
208162306a36Sopenharmony_ci	    QLA8044_PEG_ALIVE_COUNTER_INDEX);
208262306a36Sopenharmony_ci
208362306a36Sopenharmony_ci	/* If PEG_ALIVE_COUNTER is 0xffffffff, AER/EEH is in progress, ignore */
208462306a36Sopenharmony_ci	if (fw_heartbeat_counter == 0xffffffff) {
208562306a36Sopenharmony_ci		ql_dbg(ql_dbg_p3p, vha, 0xb0d4,
208662306a36Sopenharmony_ci		    "scsi%ld: %s: Device in frozen "
208762306a36Sopenharmony_ci		    "state, QLA82XX_PEG_ALIVE_COUNTER is 0xffffffff\n",
208862306a36Sopenharmony_ci		    vha->host_no, __func__);
208962306a36Sopenharmony_ci		return status;
209062306a36Sopenharmony_ci	}
209162306a36Sopenharmony_ci
209262306a36Sopenharmony_ci	if (vha->fw_heartbeat_counter == fw_heartbeat_counter) {
209362306a36Sopenharmony_ci		vha->seconds_since_last_heartbeat++;
209462306a36Sopenharmony_ci		/* FW not alive after 2 seconds */
209562306a36Sopenharmony_ci		if (vha->seconds_since_last_heartbeat == 2) {
209662306a36Sopenharmony_ci			vha->seconds_since_last_heartbeat = 0;
209762306a36Sopenharmony_ci			halt_status1 = qla8044_rd_direct(vha,
209862306a36Sopenharmony_ci			    QLA8044_PEG_HALT_STATUS1_INDEX);
209962306a36Sopenharmony_ci			halt_status2 = qla8044_rd_direct(vha,
210062306a36Sopenharmony_ci			    QLA8044_PEG_HALT_STATUS2_INDEX);
210162306a36Sopenharmony_ci
210262306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0xb0d5,
210362306a36Sopenharmony_ci			    "scsi(%ld): %s, ISP8044 "
210462306a36Sopenharmony_ci			    "Dumping hw/fw registers:\n"
210562306a36Sopenharmony_ci			    " PEG_HALT_STATUS1: 0x%x, "
210662306a36Sopenharmony_ci			    "PEG_HALT_STATUS2: 0x%x,\n",
210762306a36Sopenharmony_ci			    vha->host_no, __func__, halt_status1,
210862306a36Sopenharmony_ci			    halt_status2);
210962306a36Sopenharmony_ci			status = QLA_FUNCTION_FAILED;
211062306a36Sopenharmony_ci		}
211162306a36Sopenharmony_ci	} else
211262306a36Sopenharmony_ci		vha->seconds_since_last_heartbeat = 0;
211362306a36Sopenharmony_ci
211462306a36Sopenharmony_ci	vha->fw_heartbeat_counter = fw_heartbeat_counter;
211562306a36Sopenharmony_ci	return status;
211662306a36Sopenharmony_ci}
211762306a36Sopenharmony_ci
211862306a36Sopenharmony_civoid
211962306a36Sopenharmony_ciqla8044_watchdog(struct scsi_qla_host *vha)
212062306a36Sopenharmony_ci{
212162306a36Sopenharmony_ci	uint32_t dev_state, halt_status;
212262306a36Sopenharmony_ci	int halt_status_unrecoverable = 0;
212362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci	/* don't poll if reset is going on or FW hang in quiescent state */
212662306a36Sopenharmony_ci	if (!(test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags) ||
212762306a36Sopenharmony_ci	    test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags))) {
212862306a36Sopenharmony_ci		dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX);
212962306a36Sopenharmony_ci
213062306a36Sopenharmony_ci		if (qla8044_check_fw_alive(vha)) {
213162306a36Sopenharmony_ci			ha->flags.isp82xx_fw_hung = 1;
213262306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb10a,
213362306a36Sopenharmony_ci			    "Firmware hung.\n");
213462306a36Sopenharmony_ci			qla82xx_clear_pending_mbx(vha);
213562306a36Sopenharmony_ci		}
213662306a36Sopenharmony_ci
213762306a36Sopenharmony_ci		if (qla8044_check_temp(vha)) {
213862306a36Sopenharmony_ci			set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags);
213962306a36Sopenharmony_ci			ha->flags.isp82xx_fw_hung = 1;
214062306a36Sopenharmony_ci			qla2xxx_wake_dpc(vha);
214162306a36Sopenharmony_ci		} else if (dev_state == QLA8XXX_DEV_NEED_RESET &&
214262306a36Sopenharmony_ci			   !test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) {
214362306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0xb0d6,
214462306a36Sopenharmony_ci			    "%s: HW State: NEED RESET!\n",
214562306a36Sopenharmony_ci			    __func__);
214662306a36Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
214762306a36Sopenharmony_ci			qla2xxx_wake_dpc(vha);
214862306a36Sopenharmony_ci		} else if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT &&
214962306a36Sopenharmony_ci		    !test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) {
215062306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0xb0d7,
215162306a36Sopenharmony_ci			    "%s: HW State: NEED QUIES detected!\n",
215262306a36Sopenharmony_ci			    __func__);
215362306a36Sopenharmony_ci			set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
215462306a36Sopenharmony_ci			qla2xxx_wake_dpc(vha);
215562306a36Sopenharmony_ci		} else  {
215662306a36Sopenharmony_ci			/* Check firmware health */
215762306a36Sopenharmony_ci			if (ha->flags.isp82xx_fw_hung) {
215862306a36Sopenharmony_ci				halt_status = qla8044_rd_direct(vha,
215962306a36Sopenharmony_ci					QLA8044_PEG_HALT_STATUS1_INDEX);
216062306a36Sopenharmony_ci				if (halt_status &
216162306a36Sopenharmony_ci				    QLA8044_HALT_STATUS_FW_RESET) {
216262306a36Sopenharmony_ci					ql_log(ql_log_fatal, vha,
216362306a36Sopenharmony_ci					    0xb0d8, "%s: Firmware "
216462306a36Sopenharmony_ci					    "error detected device "
216562306a36Sopenharmony_ci					    "is being reset\n",
216662306a36Sopenharmony_ci					    __func__);
216762306a36Sopenharmony_ci				} else if (halt_status &
216862306a36Sopenharmony_ci					    QLA8044_HALT_STATUS_UNRECOVERABLE) {
216962306a36Sopenharmony_ci						halt_status_unrecoverable = 1;
217062306a36Sopenharmony_ci				}
217162306a36Sopenharmony_ci
217262306a36Sopenharmony_ci				/* Since we cannot change dev_state in interrupt
217362306a36Sopenharmony_ci				 * context, set appropriate DPC flag then wakeup
217462306a36Sopenharmony_ci				 *  DPC */
217562306a36Sopenharmony_ci				if (halt_status_unrecoverable) {
217662306a36Sopenharmony_ci					set_bit(ISP_UNRECOVERABLE,
217762306a36Sopenharmony_ci					    &vha->dpc_flags);
217862306a36Sopenharmony_ci				} else {
217962306a36Sopenharmony_ci					if (dev_state ==
218062306a36Sopenharmony_ci					    QLA8XXX_DEV_QUIESCENT) {
218162306a36Sopenharmony_ci						set_bit(FCOE_CTX_RESET_NEEDED,
218262306a36Sopenharmony_ci						    &vha->dpc_flags);
218362306a36Sopenharmony_ci						ql_log(ql_log_info, vha, 0xb0d9,
218462306a36Sopenharmony_ci						    "%s: FW CONTEXT Reset "
218562306a36Sopenharmony_ci						    "needed!\n", __func__);
218662306a36Sopenharmony_ci					} else {
218762306a36Sopenharmony_ci						ql_log(ql_log_info, vha,
218862306a36Sopenharmony_ci						    0xb0da, "%s: "
218962306a36Sopenharmony_ci						    "detect abort needed\n",
219062306a36Sopenharmony_ci						    __func__);
219162306a36Sopenharmony_ci						set_bit(ISP_ABORT_NEEDED,
219262306a36Sopenharmony_ci						    &vha->dpc_flags);
219362306a36Sopenharmony_ci					}
219462306a36Sopenharmony_ci				}
219562306a36Sopenharmony_ci				qla2xxx_wake_dpc(vha);
219662306a36Sopenharmony_ci			}
219762306a36Sopenharmony_ci		}
219862306a36Sopenharmony_ci
219962306a36Sopenharmony_ci	}
220062306a36Sopenharmony_ci}
220162306a36Sopenharmony_ci
220262306a36Sopenharmony_cistatic int
220362306a36Sopenharmony_ciqla8044_minidump_process_control(struct scsi_qla_host *vha,
220462306a36Sopenharmony_ci				 struct qla8044_minidump_entry_hdr *entry_hdr)
220562306a36Sopenharmony_ci{
220662306a36Sopenharmony_ci	struct qla8044_minidump_entry_crb *crb_entry;
220762306a36Sopenharmony_ci	uint32_t read_value, opcode, poll_time, addr, index;
220862306a36Sopenharmony_ci	uint32_t crb_addr, rval = QLA_SUCCESS;
220962306a36Sopenharmony_ci	unsigned long wtime;
221062306a36Sopenharmony_ci	struct qla8044_minidump_template_hdr *tmplt_hdr;
221162306a36Sopenharmony_ci	int i;
221262306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
221362306a36Sopenharmony_ci
221462306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0dd, "Entering fn: %s\n", __func__);
221562306a36Sopenharmony_ci	tmplt_hdr = (struct qla8044_minidump_template_hdr *)
221662306a36Sopenharmony_ci		ha->md_tmplt_hdr;
221762306a36Sopenharmony_ci	crb_entry = (struct qla8044_minidump_entry_crb *)entry_hdr;
221862306a36Sopenharmony_ci
221962306a36Sopenharmony_ci	crb_addr = crb_entry->addr;
222062306a36Sopenharmony_ci	for (i = 0; i < crb_entry->op_count; i++) {
222162306a36Sopenharmony_ci		opcode = crb_entry->crb_ctrl.opcode;
222262306a36Sopenharmony_ci
222362306a36Sopenharmony_ci		if (opcode & QLA82XX_DBG_OPCODE_WR) {
222462306a36Sopenharmony_ci			qla8044_wr_reg_indirect(vha, crb_addr,
222562306a36Sopenharmony_ci			    crb_entry->value_1);
222662306a36Sopenharmony_ci		}
222762306a36Sopenharmony_ci
222862306a36Sopenharmony_ci		if (opcode & QLA82XX_DBG_OPCODE_RW) {
222962306a36Sopenharmony_ci			qla8044_rd_reg_indirect(vha, crb_addr, &read_value);
223062306a36Sopenharmony_ci			qla8044_wr_reg_indirect(vha, crb_addr, read_value);
223162306a36Sopenharmony_ci		}
223262306a36Sopenharmony_ci
223362306a36Sopenharmony_ci		if (opcode & QLA82XX_DBG_OPCODE_AND) {
223462306a36Sopenharmony_ci			qla8044_rd_reg_indirect(vha, crb_addr, &read_value);
223562306a36Sopenharmony_ci			read_value &= crb_entry->value_2;
223662306a36Sopenharmony_ci			if (opcode & QLA82XX_DBG_OPCODE_OR) {
223762306a36Sopenharmony_ci				read_value |= crb_entry->value_3;
223862306a36Sopenharmony_ci				opcode &= ~QLA82XX_DBG_OPCODE_OR;
223962306a36Sopenharmony_ci			}
224062306a36Sopenharmony_ci			qla8044_wr_reg_indirect(vha, crb_addr, read_value);
224162306a36Sopenharmony_ci		}
224262306a36Sopenharmony_ci		if (opcode & QLA82XX_DBG_OPCODE_OR) {
224362306a36Sopenharmony_ci			qla8044_rd_reg_indirect(vha, crb_addr, &read_value);
224462306a36Sopenharmony_ci			read_value |= crb_entry->value_3;
224562306a36Sopenharmony_ci			qla8044_wr_reg_indirect(vha, crb_addr, read_value);
224662306a36Sopenharmony_ci		}
224762306a36Sopenharmony_ci		if (opcode & QLA82XX_DBG_OPCODE_POLL) {
224862306a36Sopenharmony_ci			poll_time = crb_entry->crb_strd.poll_timeout;
224962306a36Sopenharmony_ci			wtime = jiffies + poll_time;
225062306a36Sopenharmony_ci			qla8044_rd_reg_indirect(vha, crb_addr, &read_value);
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_ci			do {
225362306a36Sopenharmony_ci				if ((read_value & crb_entry->value_2) ==
225462306a36Sopenharmony_ci				    crb_entry->value_1) {
225562306a36Sopenharmony_ci					break;
225662306a36Sopenharmony_ci				} else if (time_after_eq(jiffies, wtime)) {
225762306a36Sopenharmony_ci					/* capturing dump failed */
225862306a36Sopenharmony_ci					rval = QLA_FUNCTION_FAILED;
225962306a36Sopenharmony_ci					break;
226062306a36Sopenharmony_ci				} else {
226162306a36Sopenharmony_ci					qla8044_rd_reg_indirect(vha,
226262306a36Sopenharmony_ci					    crb_addr, &read_value);
226362306a36Sopenharmony_ci				}
226462306a36Sopenharmony_ci			} while (1);
226562306a36Sopenharmony_ci		}
226662306a36Sopenharmony_ci
226762306a36Sopenharmony_ci		if (opcode & QLA82XX_DBG_OPCODE_RDSTATE) {
226862306a36Sopenharmony_ci			if (crb_entry->crb_strd.state_index_a) {
226962306a36Sopenharmony_ci				index = crb_entry->crb_strd.state_index_a;
227062306a36Sopenharmony_ci				addr = tmplt_hdr->saved_state_array[index];
227162306a36Sopenharmony_ci			} else {
227262306a36Sopenharmony_ci				addr = crb_addr;
227362306a36Sopenharmony_ci			}
227462306a36Sopenharmony_ci
227562306a36Sopenharmony_ci			qla8044_rd_reg_indirect(vha, addr, &read_value);
227662306a36Sopenharmony_ci			index = crb_entry->crb_ctrl.state_index_v;
227762306a36Sopenharmony_ci			tmplt_hdr->saved_state_array[index] = read_value;
227862306a36Sopenharmony_ci		}
227962306a36Sopenharmony_ci
228062306a36Sopenharmony_ci		if (opcode & QLA82XX_DBG_OPCODE_WRSTATE) {
228162306a36Sopenharmony_ci			if (crb_entry->crb_strd.state_index_a) {
228262306a36Sopenharmony_ci				index = crb_entry->crb_strd.state_index_a;
228362306a36Sopenharmony_ci				addr = tmplt_hdr->saved_state_array[index];
228462306a36Sopenharmony_ci			} else {
228562306a36Sopenharmony_ci				addr = crb_addr;
228662306a36Sopenharmony_ci			}
228762306a36Sopenharmony_ci
228862306a36Sopenharmony_ci			if (crb_entry->crb_ctrl.state_index_v) {
228962306a36Sopenharmony_ci				index = crb_entry->crb_ctrl.state_index_v;
229062306a36Sopenharmony_ci				read_value =
229162306a36Sopenharmony_ci				    tmplt_hdr->saved_state_array[index];
229262306a36Sopenharmony_ci			} else {
229362306a36Sopenharmony_ci				read_value = crb_entry->value_1;
229462306a36Sopenharmony_ci			}
229562306a36Sopenharmony_ci
229662306a36Sopenharmony_ci			qla8044_wr_reg_indirect(vha, addr, read_value);
229762306a36Sopenharmony_ci		}
229862306a36Sopenharmony_ci
229962306a36Sopenharmony_ci		if (opcode & QLA82XX_DBG_OPCODE_MDSTATE) {
230062306a36Sopenharmony_ci			index = crb_entry->crb_ctrl.state_index_v;
230162306a36Sopenharmony_ci			read_value = tmplt_hdr->saved_state_array[index];
230262306a36Sopenharmony_ci			read_value <<= crb_entry->crb_ctrl.shl;
230362306a36Sopenharmony_ci			read_value >>= crb_entry->crb_ctrl.shr;
230462306a36Sopenharmony_ci			if (crb_entry->value_2)
230562306a36Sopenharmony_ci				read_value &= crb_entry->value_2;
230662306a36Sopenharmony_ci			read_value |= crb_entry->value_3;
230762306a36Sopenharmony_ci			read_value += crb_entry->value_1;
230862306a36Sopenharmony_ci			tmplt_hdr->saved_state_array[index] = read_value;
230962306a36Sopenharmony_ci		}
231062306a36Sopenharmony_ci		crb_addr += crb_entry->crb_strd.addr_stride;
231162306a36Sopenharmony_ci	}
231262306a36Sopenharmony_ci	return rval;
231362306a36Sopenharmony_ci}
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_cistatic void
231662306a36Sopenharmony_ciqla8044_minidump_process_rdcrb(struct scsi_qla_host *vha,
231762306a36Sopenharmony_ci	struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
231862306a36Sopenharmony_ci{
231962306a36Sopenharmony_ci	uint32_t r_addr, r_stride, loop_cnt, i, r_value;
232062306a36Sopenharmony_ci	struct qla8044_minidump_entry_crb *crb_hdr;
232162306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
232262306a36Sopenharmony_ci
232362306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0de, "Entering fn: %s\n", __func__);
232462306a36Sopenharmony_ci	crb_hdr = (struct qla8044_minidump_entry_crb *)entry_hdr;
232562306a36Sopenharmony_ci	r_addr = crb_hdr->addr;
232662306a36Sopenharmony_ci	r_stride = crb_hdr->crb_strd.addr_stride;
232762306a36Sopenharmony_ci	loop_cnt = crb_hdr->op_count;
232862306a36Sopenharmony_ci
232962306a36Sopenharmony_ci	for (i = 0; i < loop_cnt; i++) {
233062306a36Sopenharmony_ci		qla8044_rd_reg_indirect(vha, r_addr, &r_value);
233162306a36Sopenharmony_ci		*data_ptr++ = r_addr;
233262306a36Sopenharmony_ci		*data_ptr++ = r_value;
233362306a36Sopenharmony_ci		r_addr += r_stride;
233462306a36Sopenharmony_ci	}
233562306a36Sopenharmony_ci	*d_ptr = data_ptr;
233662306a36Sopenharmony_ci}
233762306a36Sopenharmony_ci
233862306a36Sopenharmony_cistatic int
233962306a36Sopenharmony_ciqla8044_minidump_process_rdmem(struct scsi_qla_host *vha,
234062306a36Sopenharmony_ci	struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
234162306a36Sopenharmony_ci{
234262306a36Sopenharmony_ci	uint32_t r_addr, r_value, r_data;
234362306a36Sopenharmony_ci	uint32_t i, j, loop_cnt;
234462306a36Sopenharmony_ci	struct qla8044_minidump_entry_rdmem *m_hdr;
234562306a36Sopenharmony_ci	unsigned long flags;
234662306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
234762306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
234862306a36Sopenharmony_ci
234962306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0df, "Entering fn: %s\n", __func__);
235062306a36Sopenharmony_ci	m_hdr = (struct qla8044_minidump_entry_rdmem *)entry_hdr;
235162306a36Sopenharmony_ci	r_addr = m_hdr->read_addr;
235262306a36Sopenharmony_ci	loop_cnt = m_hdr->read_data_size/16;
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0f0,
235562306a36Sopenharmony_ci	    "[%s]: Read addr: 0x%x, read_data_size: 0x%x\n",
235662306a36Sopenharmony_ci	    __func__, r_addr, m_hdr->read_data_size);
235762306a36Sopenharmony_ci
235862306a36Sopenharmony_ci	if (r_addr & 0xf) {
235962306a36Sopenharmony_ci		ql_dbg(ql_dbg_p3p, vha, 0xb0f1,
236062306a36Sopenharmony_ci		    "[%s]: Read addr 0x%x not 16 bytes aligned\n",
236162306a36Sopenharmony_ci		    __func__, r_addr);
236262306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
236362306a36Sopenharmony_ci	}
236462306a36Sopenharmony_ci
236562306a36Sopenharmony_ci	if (m_hdr->read_data_size % 16) {
236662306a36Sopenharmony_ci		ql_dbg(ql_dbg_p3p, vha, 0xb0f2,
236762306a36Sopenharmony_ci		    "[%s]: Read data[0x%x] not multiple of 16 bytes\n",
236862306a36Sopenharmony_ci		    __func__, m_hdr->read_data_size);
236962306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
237062306a36Sopenharmony_ci	}
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0f3,
237362306a36Sopenharmony_ci	    "[%s]: rdmem_addr: 0x%x, read_data_size: 0x%x, loop_cnt: 0x%x\n",
237462306a36Sopenharmony_ci	    __func__, r_addr, m_hdr->read_data_size, loop_cnt);
237562306a36Sopenharmony_ci
237662306a36Sopenharmony_ci	write_lock_irqsave(&ha->hw_lock, flags);
237762306a36Sopenharmony_ci	for (i = 0; i < loop_cnt; i++) {
237862306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_ADDR_LO, r_addr);
237962306a36Sopenharmony_ci		r_value = 0;
238062306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_ADDR_HI, r_value);
238162306a36Sopenharmony_ci		r_value = MIU_TA_CTL_ENABLE;
238262306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_CTRL, r_value);
238362306a36Sopenharmony_ci		r_value = MIU_TA_CTL_START_ENABLE;
238462306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha, MD_MIU_TEST_AGT_CTRL, r_value);
238562306a36Sopenharmony_ci
238662306a36Sopenharmony_ci		for (j = 0; j < MAX_CTL_CHECK; j++) {
238762306a36Sopenharmony_ci			qla8044_rd_reg_indirect(vha, MD_MIU_TEST_AGT_CTRL,
238862306a36Sopenharmony_ci			    &r_value);
238962306a36Sopenharmony_ci			if ((r_value & MIU_TA_CTL_BUSY) == 0)
239062306a36Sopenharmony_ci				break;
239162306a36Sopenharmony_ci		}
239262306a36Sopenharmony_ci
239362306a36Sopenharmony_ci		if (j >= MAX_CTL_CHECK) {
239462306a36Sopenharmony_ci			write_unlock_irqrestore(&ha->hw_lock, flags);
239562306a36Sopenharmony_ci			return QLA_SUCCESS;
239662306a36Sopenharmony_ci		}
239762306a36Sopenharmony_ci
239862306a36Sopenharmony_ci		for (j = 0; j < 4; j++) {
239962306a36Sopenharmony_ci			qla8044_rd_reg_indirect(vha, MD_MIU_TEST_AGT_RDDATA[j],
240062306a36Sopenharmony_ci			    &r_data);
240162306a36Sopenharmony_ci			*data_ptr++ = r_data;
240262306a36Sopenharmony_ci		}
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci		r_addr += 16;
240562306a36Sopenharmony_ci	}
240662306a36Sopenharmony_ci	write_unlock_irqrestore(&ha->hw_lock, flags);
240762306a36Sopenharmony_ci
240862306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0f4,
240962306a36Sopenharmony_ci	    "Leaving fn: %s datacount: 0x%x\n",
241062306a36Sopenharmony_ci	     __func__, (loop_cnt * 16));
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci	*d_ptr = data_ptr;
241362306a36Sopenharmony_ci	return QLA_SUCCESS;
241462306a36Sopenharmony_ci}
241562306a36Sopenharmony_ci
241662306a36Sopenharmony_ci/* ISP83xx flash read for _RDROM _BOARD */
241762306a36Sopenharmony_cistatic uint32_t
241862306a36Sopenharmony_ciqla8044_minidump_process_rdrom(struct scsi_qla_host *vha,
241962306a36Sopenharmony_ci	struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
242062306a36Sopenharmony_ci{
242162306a36Sopenharmony_ci	uint32_t fl_addr, u32_count, rval;
242262306a36Sopenharmony_ci	struct qla8044_minidump_entry_rdrom *rom_hdr;
242362306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
242462306a36Sopenharmony_ci
242562306a36Sopenharmony_ci	rom_hdr = (struct qla8044_minidump_entry_rdrom *)entry_hdr;
242662306a36Sopenharmony_ci	fl_addr = rom_hdr->read_addr;
242762306a36Sopenharmony_ci	u32_count = (rom_hdr->read_data_size)/sizeof(uint32_t);
242862306a36Sopenharmony_ci
242962306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0f5, "[%s]: fl_addr: 0x%x, count: 0x%x\n",
243062306a36Sopenharmony_ci	    __func__, fl_addr, u32_count);
243162306a36Sopenharmony_ci
243262306a36Sopenharmony_ci	rval = qla8044_lockless_flash_read_u32(vha, fl_addr,
243362306a36Sopenharmony_ci	    (u8 *)(data_ptr), u32_count);
243462306a36Sopenharmony_ci
243562306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
243662306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb0f6,
243762306a36Sopenharmony_ci		    "%s: Flash Read Error,Count=%d\n", __func__, u32_count);
243862306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
243962306a36Sopenharmony_ci	} else {
244062306a36Sopenharmony_ci		data_ptr += u32_count;
244162306a36Sopenharmony_ci		*d_ptr = data_ptr;
244262306a36Sopenharmony_ci		return QLA_SUCCESS;
244362306a36Sopenharmony_ci	}
244462306a36Sopenharmony_ci}
244562306a36Sopenharmony_ci
244662306a36Sopenharmony_cistatic void
244762306a36Sopenharmony_ciqla8044_mark_entry_skipped(struct scsi_qla_host *vha,
244862306a36Sopenharmony_ci	struct qla8044_minidump_entry_hdr *entry_hdr, int index)
244962306a36Sopenharmony_ci{
245062306a36Sopenharmony_ci	entry_hdr->d_ctrl.driver_flags |= QLA82XX_DBG_SKIPPED_FLAG;
245162306a36Sopenharmony_ci
245262306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0xb0f7,
245362306a36Sopenharmony_ci	    "scsi(%ld): Skipping entry[%d]: ETYPE[0x%x]-ELEVEL[0x%x]\n",
245462306a36Sopenharmony_ci	    vha->host_no, index, entry_hdr->entry_type,
245562306a36Sopenharmony_ci	    entry_hdr->d_ctrl.entry_capture_mask);
245662306a36Sopenharmony_ci}
245762306a36Sopenharmony_ci
245862306a36Sopenharmony_cistatic int
245962306a36Sopenharmony_ciqla8044_minidump_process_l2tag(struct scsi_qla_host *vha,
246062306a36Sopenharmony_ci	struct qla8044_minidump_entry_hdr *entry_hdr,
246162306a36Sopenharmony_ci				 uint32_t **d_ptr)
246262306a36Sopenharmony_ci{
246362306a36Sopenharmony_ci	uint32_t addr, r_addr, c_addr, t_r_addr;
246462306a36Sopenharmony_ci	uint32_t i, k, loop_count, t_value, r_cnt, r_value;
246562306a36Sopenharmony_ci	unsigned long p_wait, w_time, p_mask;
246662306a36Sopenharmony_ci	uint32_t c_value_w, c_value_r;
246762306a36Sopenharmony_ci	struct qla8044_minidump_entry_cache *cache_hdr;
246862306a36Sopenharmony_ci	int rval = QLA_FUNCTION_FAILED;
246962306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
247062306a36Sopenharmony_ci
247162306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0f8, "Entering fn: %s\n", __func__);
247262306a36Sopenharmony_ci	cache_hdr = (struct qla8044_minidump_entry_cache *)entry_hdr;
247362306a36Sopenharmony_ci
247462306a36Sopenharmony_ci	loop_count = cache_hdr->op_count;
247562306a36Sopenharmony_ci	r_addr = cache_hdr->read_addr;
247662306a36Sopenharmony_ci	c_addr = cache_hdr->control_addr;
247762306a36Sopenharmony_ci	c_value_w = cache_hdr->cache_ctrl.write_value;
247862306a36Sopenharmony_ci
247962306a36Sopenharmony_ci	t_r_addr = cache_hdr->tag_reg_addr;
248062306a36Sopenharmony_ci	t_value = cache_hdr->addr_ctrl.init_tag_value;
248162306a36Sopenharmony_ci	r_cnt = cache_hdr->read_ctrl.read_addr_cnt;
248262306a36Sopenharmony_ci	p_wait = cache_hdr->cache_ctrl.poll_wait;
248362306a36Sopenharmony_ci	p_mask = cache_hdr->cache_ctrl.poll_mask;
248462306a36Sopenharmony_ci
248562306a36Sopenharmony_ci	for (i = 0; i < loop_count; i++) {
248662306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha, t_r_addr, t_value);
248762306a36Sopenharmony_ci		if (c_value_w)
248862306a36Sopenharmony_ci			qla8044_wr_reg_indirect(vha, c_addr, c_value_w);
248962306a36Sopenharmony_ci
249062306a36Sopenharmony_ci		if (p_mask) {
249162306a36Sopenharmony_ci			w_time = jiffies + p_wait;
249262306a36Sopenharmony_ci			do {
249362306a36Sopenharmony_ci				qla8044_rd_reg_indirect(vha, c_addr,
249462306a36Sopenharmony_ci				    &c_value_r);
249562306a36Sopenharmony_ci				if ((c_value_r & p_mask) == 0) {
249662306a36Sopenharmony_ci					break;
249762306a36Sopenharmony_ci				} else if (time_after_eq(jiffies, w_time)) {
249862306a36Sopenharmony_ci					/* capturing dump failed */
249962306a36Sopenharmony_ci					return rval;
250062306a36Sopenharmony_ci				}
250162306a36Sopenharmony_ci			} while (1);
250262306a36Sopenharmony_ci		}
250362306a36Sopenharmony_ci
250462306a36Sopenharmony_ci		addr = r_addr;
250562306a36Sopenharmony_ci		for (k = 0; k < r_cnt; k++) {
250662306a36Sopenharmony_ci			qla8044_rd_reg_indirect(vha, addr, &r_value);
250762306a36Sopenharmony_ci			*data_ptr++ = r_value;
250862306a36Sopenharmony_ci			addr += cache_hdr->read_ctrl.read_addr_stride;
250962306a36Sopenharmony_ci		}
251062306a36Sopenharmony_ci		t_value += cache_hdr->addr_ctrl.tag_value_stride;
251162306a36Sopenharmony_ci	}
251262306a36Sopenharmony_ci	*d_ptr = data_ptr;
251362306a36Sopenharmony_ci	return QLA_SUCCESS;
251462306a36Sopenharmony_ci}
251562306a36Sopenharmony_ci
251662306a36Sopenharmony_cistatic void
251762306a36Sopenharmony_ciqla8044_minidump_process_l1cache(struct scsi_qla_host *vha,
251862306a36Sopenharmony_ci	struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
251962306a36Sopenharmony_ci{
252062306a36Sopenharmony_ci	uint32_t addr, r_addr, c_addr, t_r_addr;
252162306a36Sopenharmony_ci	uint32_t i, k, loop_count, t_value, r_cnt, r_value;
252262306a36Sopenharmony_ci	uint32_t c_value_w;
252362306a36Sopenharmony_ci	struct qla8044_minidump_entry_cache *cache_hdr;
252462306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
252562306a36Sopenharmony_ci
252662306a36Sopenharmony_ci	cache_hdr = (struct qla8044_minidump_entry_cache *)entry_hdr;
252762306a36Sopenharmony_ci	loop_count = cache_hdr->op_count;
252862306a36Sopenharmony_ci	r_addr = cache_hdr->read_addr;
252962306a36Sopenharmony_ci	c_addr = cache_hdr->control_addr;
253062306a36Sopenharmony_ci	c_value_w = cache_hdr->cache_ctrl.write_value;
253162306a36Sopenharmony_ci
253262306a36Sopenharmony_ci	t_r_addr = cache_hdr->tag_reg_addr;
253362306a36Sopenharmony_ci	t_value = cache_hdr->addr_ctrl.init_tag_value;
253462306a36Sopenharmony_ci	r_cnt = cache_hdr->read_ctrl.read_addr_cnt;
253562306a36Sopenharmony_ci
253662306a36Sopenharmony_ci	for (i = 0; i < loop_count; i++) {
253762306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha, t_r_addr, t_value);
253862306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha, c_addr, c_value_w);
253962306a36Sopenharmony_ci		addr = r_addr;
254062306a36Sopenharmony_ci		for (k = 0; k < r_cnt; k++) {
254162306a36Sopenharmony_ci			qla8044_rd_reg_indirect(vha, addr, &r_value);
254262306a36Sopenharmony_ci			*data_ptr++ = r_value;
254362306a36Sopenharmony_ci			addr += cache_hdr->read_ctrl.read_addr_stride;
254462306a36Sopenharmony_ci		}
254562306a36Sopenharmony_ci		t_value += cache_hdr->addr_ctrl.tag_value_stride;
254662306a36Sopenharmony_ci	}
254762306a36Sopenharmony_ci	*d_ptr = data_ptr;
254862306a36Sopenharmony_ci}
254962306a36Sopenharmony_ci
255062306a36Sopenharmony_cistatic void
255162306a36Sopenharmony_ciqla8044_minidump_process_rdocm(struct scsi_qla_host *vha,
255262306a36Sopenharmony_ci	struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
255362306a36Sopenharmony_ci{
255462306a36Sopenharmony_ci	uint32_t r_addr, r_stride, loop_cnt, i, r_value;
255562306a36Sopenharmony_ci	struct qla8044_minidump_entry_rdocm *ocm_hdr;
255662306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
255762306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
255862306a36Sopenharmony_ci
255962306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0f9, "Entering fn: %s\n", __func__);
256062306a36Sopenharmony_ci
256162306a36Sopenharmony_ci	ocm_hdr = (struct qla8044_minidump_entry_rdocm *)entry_hdr;
256262306a36Sopenharmony_ci	r_addr = ocm_hdr->read_addr;
256362306a36Sopenharmony_ci	r_stride = ocm_hdr->read_addr_stride;
256462306a36Sopenharmony_ci	loop_cnt = ocm_hdr->op_count;
256562306a36Sopenharmony_ci
256662306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0fa,
256762306a36Sopenharmony_ci	    "[%s]: r_addr: 0x%x, r_stride: 0x%x, loop_cnt: 0x%x\n",
256862306a36Sopenharmony_ci	    __func__, r_addr, r_stride, loop_cnt);
256962306a36Sopenharmony_ci
257062306a36Sopenharmony_ci	for (i = 0; i < loop_cnt; i++) {
257162306a36Sopenharmony_ci		r_value = readl((void __iomem *)(r_addr + ha->nx_pcibase));
257262306a36Sopenharmony_ci		*data_ptr++ = r_value;
257362306a36Sopenharmony_ci		r_addr += r_stride;
257462306a36Sopenharmony_ci	}
257562306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0fb, "Leaving fn: %s datacount: 0x%lx\n",
257662306a36Sopenharmony_ci	    __func__, (long unsigned int) (loop_cnt * sizeof(uint32_t)));
257762306a36Sopenharmony_ci
257862306a36Sopenharmony_ci	*d_ptr = data_ptr;
257962306a36Sopenharmony_ci}
258062306a36Sopenharmony_ci
258162306a36Sopenharmony_cistatic void
258262306a36Sopenharmony_ciqla8044_minidump_process_rdmux(struct scsi_qla_host *vha,
258362306a36Sopenharmony_ci	struct qla8044_minidump_entry_hdr *entry_hdr,
258462306a36Sopenharmony_ci	uint32_t **d_ptr)
258562306a36Sopenharmony_ci{
258662306a36Sopenharmony_ci	uint32_t r_addr, s_stride, s_addr, s_value, loop_cnt, i, r_value = 0;
258762306a36Sopenharmony_ci	struct qla8044_minidump_entry_mux *mux_hdr;
258862306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
258962306a36Sopenharmony_ci
259062306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0fc, "Entering fn: %s\n", __func__);
259162306a36Sopenharmony_ci
259262306a36Sopenharmony_ci	mux_hdr = (struct qla8044_minidump_entry_mux *)entry_hdr;
259362306a36Sopenharmony_ci	r_addr = mux_hdr->read_addr;
259462306a36Sopenharmony_ci	s_addr = mux_hdr->select_addr;
259562306a36Sopenharmony_ci	s_stride = mux_hdr->select_value_stride;
259662306a36Sopenharmony_ci	s_value = mux_hdr->select_value;
259762306a36Sopenharmony_ci	loop_cnt = mux_hdr->op_count;
259862306a36Sopenharmony_ci
259962306a36Sopenharmony_ci	for (i = 0; i < loop_cnt; i++) {
260062306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha, s_addr, s_value);
260162306a36Sopenharmony_ci		qla8044_rd_reg_indirect(vha, r_addr, &r_value);
260262306a36Sopenharmony_ci		*data_ptr++ = s_value;
260362306a36Sopenharmony_ci		*data_ptr++ = r_value;
260462306a36Sopenharmony_ci		s_value += s_stride;
260562306a36Sopenharmony_ci	}
260662306a36Sopenharmony_ci	*d_ptr = data_ptr;
260762306a36Sopenharmony_ci}
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_cistatic void
261062306a36Sopenharmony_ciqla8044_minidump_process_queue(struct scsi_qla_host *vha,
261162306a36Sopenharmony_ci	struct qla8044_minidump_entry_hdr *entry_hdr,
261262306a36Sopenharmony_ci	uint32_t **d_ptr)
261362306a36Sopenharmony_ci{
261462306a36Sopenharmony_ci	uint32_t s_addr, r_addr;
261562306a36Sopenharmony_ci	uint32_t r_stride, r_value, r_cnt, qid = 0;
261662306a36Sopenharmony_ci	uint32_t i, k, loop_cnt;
261762306a36Sopenharmony_ci	struct qla8044_minidump_entry_queue *q_hdr;
261862306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
261962306a36Sopenharmony_ci
262062306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb0fd, "Entering fn: %s\n", __func__);
262162306a36Sopenharmony_ci	q_hdr = (struct qla8044_minidump_entry_queue *)entry_hdr;
262262306a36Sopenharmony_ci	s_addr = q_hdr->select_addr;
262362306a36Sopenharmony_ci	r_cnt = q_hdr->rd_strd.read_addr_cnt;
262462306a36Sopenharmony_ci	r_stride = q_hdr->rd_strd.read_addr_stride;
262562306a36Sopenharmony_ci	loop_cnt = q_hdr->op_count;
262662306a36Sopenharmony_ci
262762306a36Sopenharmony_ci	for (i = 0; i < loop_cnt; i++) {
262862306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha, s_addr, qid);
262962306a36Sopenharmony_ci		r_addr = q_hdr->read_addr;
263062306a36Sopenharmony_ci		for (k = 0; k < r_cnt; k++) {
263162306a36Sopenharmony_ci			qla8044_rd_reg_indirect(vha, r_addr, &r_value);
263262306a36Sopenharmony_ci			*data_ptr++ = r_value;
263362306a36Sopenharmony_ci			r_addr += r_stride;
263462306a36Sopenharmony_ci		}
263562306a36Sopenharmony_ci		qid += q_hdr->q_strd.queue_id_stride;
263662306a36Sopenharmony_ci	}
263762306a36Sopenharmony_ci	*d_ptr = data_ptr;
263862306a36Sopenharmony_ci}
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_ci/* ISP83xx functions to process new minidump entries... */
264162306a36Sopenharmony_cistatic uint32_t
264262306a36Sopenharmony_ciqla8044_minidump_process_pollrd(struct scsi_qla_host *vha,
264362306a36Sopenharmony_ci	struct qla8044_minidump_entry_hdr *entry_hdr,
264462306a36Sopenharmony_ci	uint32_t **d_ptr)
264562306a36Sopenharmony_ci{
264662306a36Sopenharmony_ci	uint32_t r_addr, s_addr, s_value, r_value, poll_wait, poll_mask;
264762306a36Sopenharmony_ci	uint16_t s_stride, i;
264862306a36Sopenharmony_ci	struct qla8044_minidump_entry_pollrd *pollrd_hdr;
264962306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ci	pollrd_hdr = (struct qla8044_minidump_entry_pollrd *) entry_hdr;
265262306a36Sopenharmony_ci	s_addr = pollrd_hdr->select_addr;
265362306a36Sopenharmony_ci	r_addr = pollrd_hdr->read_addr;
265462306a36Sopenharmony_ci	s_value = pollrd_hdr->select_value;
265562306a36Sopenharmony_ci	s_stride = pollrd_hdr->select_value_stride;
265662306a36Sopenharmony_ci
265762306a36Sopenharmony_ci	poll_wait = pollrd_hdr->poll_wait;
265862306a36Sopenharmony_ci	poll_mask = pollrd_hdr->poll_mask;
265962306a36Sopenharmony_ci
266062306a36Sopenharmony_ci	for (i = 0; i < pollrd_hdr->op_count; i++) {
266162306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha, s_addr, s_value);
266262306a36Sopenharmony_ci		poll_wait = pollrd_hdr->poll_wait;
266362306a36Sopenharmony_ci		while (1) {
266462306a36Sopenharmony_ci			qla8044_rd_reg_indirect(vha, s_addr, &r_value);
266562306a36Sopenharmony_ci			if ((r_value & poll_mask) != 0) {
266662306a36Sopenharmony_ci				break;
266762306a36Sopenharmony_ci			} else {
266862306a36Sopenharmony_ci				usleep_range(1000, 1100);
266962306a36Sopenharmony_ci				if (--poll_wait == 0) {
267062306a36Sopenharmony_ci					ql_log(ql_log_fatal, vha, 0xb0fe,
267162306a36Sopenharmony_ci					    "%s: TIMEOUT\n", __func__);
267262306a36Sopenharmony_ci					goto error;
267362306a36Sopenharmony_ci				}
267462306a36Sopenharmony_ci			}
267562306a36Sopenharmony_ci		}
267662306a36Sopenharmony_ci		qla8044_rd_reg_indirect(vha, r_addr, &r_value);
267762306a36Sopenharmony_ci		*data_ptr++ = s_value;
267862306a36Sopenharmony_ci		*data_ptr++ = r_value;
267962306a36Sopenharmony_ci
268062306a36Sopenharmony_ci		s_value += s_stride;
268162306a36Sopenharmony_ci	}
268262306a36Sopenharmony_ci	*d_ptr = data_ptr;
268362306a36Sopenharmony_ci	return QLA_SUCCESS;
268462306a36Sopenharmony_ci
268562306a36Sopenharmony_cierror:
268662306a36Sopenharmony_ci	return QLA_FUNCTION_FAILED;
268762306a36Sopenharmony_ci}
268862306a36Sopenharmony_ci
268962306a36Sopenharmony_cistatic void
269062306a36Sopenharmony_ciqla8044_minidump_process_rdmux2(struct scsi_qla_host *vha,
269162306a36Sopenharmony_ci	struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
269262306a36Sopenharmony_ci{
269362306a36Sopenharmony_ci	uint32_t sel_val1, sel_val2, t_sel_val, data, i;
269462306a36Sopenharmony_ci	uint32_t sel_addr1, sel_addr2, sel_val_mask, read_addr;
269562306a36Sopenharmony_ci	struct qla8044_minidump_entry_rdmux2 *rdmux2_hdr;
269662306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
269762306a36Sopenharmony_ci
269862306a36Sopenharmony_ci	rdmux2_hdr = (struct qla8044_minidump_entry_rdmux2 *) entry_hdr;
269962306a36Sopenharmony_ci	sel_val1 = rdmux2_hdr->select_value_1;
270062306a36Sopenharmony_ci	sel_val2 = rdmux2_hdr->select_value_2;
270162306a36Sopenharmony_ci	sel_addr1 = rdmux2_hdr->select_addr_1;
270262306a36Sopenharmony_ci	sel_addr2 = rdmux2_hdr->select_addr_2;
270362306a36Sopenharmony_ci	sel_val_mask = rdmux2_hdr->select_value_mask;
270462306a36Sopenharmony_ci	read_addr = rdmux2_hdr->read_addr;
270562306a36Sopenharmony_ci
270662306a36Sopenharmony_ci	for (i = 0; i < rdmux2_hdr->op_count; i++) {
270762306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha, sel_addr1, sel_val1);
270862306a36Sopenharmony_ci		t_sel_val = sel_val1 & sel_val_mask;
270962306a36Sopenharmony_ci		*data_ptr++ = t_sel_val;
271062306a36Sopenharmony_ci
271162306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha, sel_addr2, t_sel_val);
271262306a36Sopenharmony_ci		qla8044_rd_reg_indirect(vha, read_addr, &data);
271362306a36Sopenharmony_ci
271462306a36Sopenharmony_ci		*data_ptr++ = data;
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha, sel_addr1, sel_val2);
271762306a36Sopenharmony_ci		t_sel_val = sel_val2 & sel_val_mask;
271862306a36Sopenharmony_ci		*data_ptr++ = t_sel_val;
271962306a36Sopenharmony_ci
272062306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha, sel_addr2, t_sel_val);
272162306a36Sopenharmony_ci		qla8044_rd_reg_indirect(vha, read_addr, &data);
272262306a36Sopenharmony_ci
272362306a36Sopenharmony_ci		*data_ptr++ = data;
272462306a36Sopenharmony_ci
272562306a36Sopenharmony_ci		sel_val1 += rdmux2_hdr->select_value_stride;
272662306a36Sopenharmony_ci		sel_val2 += rdmux2_hdr->select_value_stride;
272762306a36Sopenharmony_ci	}
272862306a36Sopenharmony_ci
272962306a36Sopenharmony_ci	*d_ptr = data_ptr;
273062306a36Sopenharmony_ci}
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_cistatic uint32_t
273362306a36Sopenharmony_ciqla8044_minidump_process_pollrdmwr(struct scsi_qla_host *vha,
273462306a36Sopenharmony_ci	struct qla8044_minidump_entry_hdr *entry_hdr,
273562306a36Sopenharmony_ci	uint32_t **d_ptr)
273662306a36Sopenharmony_ci{
273762306a36Sopenharmony_ci	uint32_t poll_wait, poll_mask, r_value, data;
273862306a36Sopenharmony_ci	uint32_t addr_1, addr_2, value_1, value_2;
273962306a36Sopenharmony_ci	struct qla8044_minidump_entry_pollrdmwr *poll_hdr;
274062306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
274162306a36Sopenharmony_ci
274262306a36Sopenharmony_ci	poll_hdr = (struct qla8044_minidump_entry_pollrdmwr *) entry_hdr;
274362306a36Sopenharmony_ci	addr_1 = poll_hdr->addr_1;
274462306a36Sopenharmony_ci	addr_2 = poll_hdr->addr_2;
274562306a36Sopenharmony_ci	value_1 = poll_hdr->value_1;
274662306a36Sopenharmony_ci	value_2 = poll_hdr->value_2;
274762306a36Sopenharmony_ci	poll_mask = poll_hdr->poll_mask;
274862306a36Sopenharmony_ci
274962306a36Sopenharmony_ci	qla8044_wr_reg_indirect(vha, addr_1, value_1);
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_ci	poll_wait = poll_hdr->poll_wait;
275262306a36Sopenharmony_ci	while (1) {
275362306a36Sopenharmony_ci		qla8044_rd_reg_indirect(vha, addr_1, &r_value);
275462306a36Sopenharmony_ci
275562306a36Sopenharmony_ci		if ((r_value & poll_mask) != 0) {
275662306a36Sopenharmony_ci			break;
275762306a36Sopenharmony_ci		} else {
275862306a36Sopenharmony_ci			usleep_range(1000, 1100);
275962306a36Sopenharmony_ci			if (--poll_wait == 0) {
276062306a36Sopenharmony_ci				ql_log(ql_log_fatal, vha, 0xb0ff,
276162306a36Sopenharmony_ci				    "%s: TIMEOUT\n", __func__);
276262306a36Sopenharmony_ci				goto error;
276362306a36Sopenharmony_ci			}
276462306a36Sopenharmony_ci		}
276562306a36Sopenharmony_ci	}
276662306a36Sopenharmony_ci
276762306a36Sopenharmony_ci	qla8044_rd_reg_indirect(vha, addr_2, &data);
276862306a36Sopenharmony_ci	data &= poll_hdr->modify_mask;
276962306a36Sopenharmony_ci	qla8044_wr_reg_indirect(vha, addr_2, data);
277062306a36Sopenharmony_ci	qla8044_wr_reg_indirect(vha, addr_1, value_2);
277162306a36Sopenharmony_ci
277262306a36Sopenharmony_ci	poll_wait = poll_hdr->poll_wait;
277362306a36Sopenharmony_ci	while (1) {
277462306a36Sopenharmony_ci		qla8044_rd_reg_indirect(vha, addr_1, &r_value);
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_ci		if ((r_value & poll_mask) != 0) {
277762306a36Sopenharmony_ci			break;
277862306a36Sopenharmony_ci		} else {
277962306a36Sopenharmony_ci			usleep_range(1000, 1100);
278062306a36Sopenharmony_ci			if (--poll_wait == 0) {
278162306a36Sopenharmony_ci				ql_log(ql_log_fatal, vha, 0xb100,
278262306a36Sopenharmony_ci				    "%s: TIMEOUT2\n", __func__);
278362306a36Sopenharmony_ci				goto error;
278462306a36Sopenharmony_ci			}
278562306a36Sopenharmony_ci		}
278662306a36Sopenharmony_ci	}
278762306a36Sopenharmony_ci
278862306a36Sopenharmony_ci	*data_ptr++ = addr_2;
278962306a36Sopenharmony_ci	*data_ptr++ = data;
279062306a36Sopenharmony_ci
279162306a36Sopenharmony_ci	*d_ptr = data_ptr;
279262306a36Sopenharmony_ci
279362306a36Sopenharmony_ci	return QLA_SUCCESS;
279462306a36Sopenharmony_ci
279562306a36Sopenharmony_cierror:
279662306a36Sopenharmony_ci	return QLA_FUNCTION_FAILED;
279762306a36Sopenharmony_ci}
279862306a36Sopenharmony_ci
279962306a36Sopenharmony_ci#define ISP8044_PEX_DMA_ENGINE_INDEX		8
280062306a36Sopenharmony_ci#define ISP8044_PEX_DMA_BASE_ADDRESS		0x77320000
280162306a36Sopenharmony_ci#define ISP8044_PEX_DMA_NUM_OFFSET		0x10000UL
280262306a36Sopenharmony_ci#define ISP8044_PEX_DMA_CMD_ADDR_LOW		0x0
280362306a36Sopenharmony_ci#define ISP8044_PEX_DMA_CMD_ADDR_HIGH		0x04
280462306a36Sopenharmony_ci#define ISP8044_PEX_DMA_CMD_STS_AND_CNTRL	0x08
280562306a36Sopenharmony_ci
280662306a36Sopenharmony_ci#define ISP8044_PEX_DMA_READ_SIZE	(16 * 1024)
280762306a36Sopenharmony_ci#define ISP8044_PEX_DMA_MAX_WAIT	(100 * 100) /* Max wait of 100 msecs */
280862306a36Sopenharmony_ci
280962306a36Sopenharmony_cistatic int
281062306a36Sopenharmony_ciqla8044_check_dma_engine_state(struct scsi_qla_host *vha)
281162306a36Sopenharmony_ci{
281262306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
281362306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
281462306a36Sopenharmony_ci	uint32_t dma_eng_num = 0, cmd_sts_and_cntrl = 0;
281562306a36Sopenharmony_ci	uint64_t dma_base_addr = 0;
281662306a36Sopenharmony_ci	struct qla8044_minidump_template_hdr *tmplt_hdr = NULL;
281762306a36Sopenharmony_ci
281862306a36Sopenharmony_ci	tmplt_hdr = ha->md_tmplt_hdr;
281962306a36Sopenharmony_ci	dma_eng_num =
282062306a36Sopenharmony_ci	    tmplt_hdr->saved_state_array[ISP8044_PEX_DMA_ENGINE_INDEX];
282162306a36Sopenharmony_ci	dma_base_addr = ISP8044_PEX_DMA_BASE_ADDRESS +
282262306a36Sopenharmony_ci		(dma_eng_num * ISP8044_PEX_DMA_NUM_OFFSET);
282362306a36Sopenharmony_ci
282462306a36Sopenharmony_ci	/* Read the pex-dma's command-status-and-control register. */
282562306a36Sopenharmony_ci	rval = qla8044_rd_reg_indirect(vha,
282662306a36Sopenharmony_ci	    (dma_base_addr + ISP8044_PEX_DMA_CMD_STS_AND_CNTRL),
282762306a36Sopenharmony_ci	    &cmd_sts_and_cntrl);
282862306a36Sopenharmony_ci	if (rval)
282962306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
283062306a36Sopenharmony_ci
283162306a36Sopenharmony_ci	/* Check if requested pex-dma engine is available. */
283262306a36Sopenharmony_ci	if (cmd_sts_and_cntrl & BIT_31)
283362306a36Sopenharmony_ci		return QLA_SUCCESS;
283462306a36Sopenharmony_ci
283562306a36Sopenharmony_ci	return QLA_FUNCTION_FAILED;
283662306a36Sopenharmony_ci}
283762306a36Sopenharmony_ci
283862306a36Sopenharmony_cistatic int
283962306a36Sopenharmony_ciqla8044_start_pex_dma(struct scsi_qla_host *vha,
284062306a36Sopenharmony_ci	struct qla8044_minidump_entry_rdmem_pex_dma *m_hdr)
284162306a36Sopenharmony_ci{
284262306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
284362306a36Sopenharmony_ci	int rval = QLA_SUCCESS, wait = 0;
284462306a36Sopenharmony_ci	uint32_t dma_eng_num = 0, cmd_sts_and_cntrl = 0;
284562306a36Sopenharmony_ci	uint64_t dma_base_addr = 0;
284662306a36Sopenharmony_ci	struct qla8044_minidump_template_hdr *tmplt_hdr = NULL;
284762306a36Sopenharmony_ci
284862306a36Sopenharmony_ci	tmplt_hdr = ha->md_tmplt_hdr;
284962306a36Sopenharmony_ci	dma_eng_num =
285062306a36Sopenharmony_ci	    tmplt_hdr->saved_state_array[ISP8044_PEX_DMA_ENGINE_INDEX];
285162306a36Sopenharmony_ci	dma_base_addr = ISP8044_PEX_DMA_BASE_ADDRESS +
285262306a36Sopenharmony_ci		(dma_eng_num * ISP8044_PEX_DMA_NUM_OFFSET);
285362306a36Sopenharmony_ci
285462306a36Sopenharmony_ci	rval = qla8044_wr_reg_indirect(vha,
285562306a36Sopenharmony_ci	    dma_base_addr + ISP8044_PEX_DMA_CMD_ADDR_LOW,
285662306a36Sopenharmony_ci	    m_hdr->desc_card_addr);
285762306a36Sopenharmony_ci	if (rval)
285862306a36Sopenharmony_ci		goto error_exit;
285962306a36Sopenharmony_ci
286062306a36Sopenharmony_ci	rval = qla8044_wr_reg_indirect(vha,
286162306a36Sopenharmony_ci	    dma_base_addr + ISP8044_PEX_DMA_CMD_ADDR_HIGH, 0);
286262306a36Sopenharmony_ci	if (rval)
286362306a36Sopenharmony_ci		goto error_exit;
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci	rval = qla8044_wr_reg_indirect(vha,
286662306a36Sopenharmony_ci	    dma_base_addr + ISP8044_PEX_DMA_CMD_STS_AND_CNTRL,
286762306a36Sopenharmony_ci	    m_hdr->start_dma_cmd);
286862306a36Sopenharmony_ci	if (rval)
286962306a36Sopenharmony_ci		goto error_exit;
287062306a36Sopenharmony_ci
287162306a36Sopenharmony_ci	/* Wait for dma operation to complete. */
287262306a36Sopenharmony_ci	for (wait = 0; wait < ISP8044_PEX_DMA_MAX_WAIT; wait++) {
287362306a36Sopenharmony_ci		rval = qla8044_rd_reg_indirect(vha,
287462306a36Sopenharmony_ci		    (dma_base_addr + ISP8044_PEX_DMA_CMD_STS_AND_CNTRL),
287562306a36Sopenharmony_ci		    &cmd_sts_and_cntrl);
287662306a36Sopenharmony_ci		if (rval)
287762306a36Sopenharmony_ci			goto error_exit;
287862306a36Sopenharmony_ci
287962306a36Sopenharmony_ci		if ((cmd_sts_and_cntrl & BIT_1) == 0)
288062306a36Sopenharmony_ci			break;
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_ci		udelay(10);
288362306a36Sopenharmony_ci	}
288462306a36Sopenharmony_ci
288562306a36Sopenharmony_ci	/* Wait a max of 100 ms, otherwise fallback to rdmem entry read */
288662306a36Sopenharmony_ci	if (wait >= ISP8044_PEX_DMA_MAX_WAIT) {
288762306a36Sopenharmony_ci		rval = QLA_FUNCTION_FAILED;
288862306a36Sopenharmony_ci		goto error_exit;
288962306a36Sopenharmony_ci	}
289062306a36Sopenharmony_ci
289162306a36Sopenharmony_cierror_exit:
289262306a36Sopenharmony_ci	return rval;
289362306a36Sopenharmony_ci}
289462306a36Sopenharmony_ci
289562306a36Sopenharmony_cistatic int
289662306a36Sopenharmony_ciqla8044_minidump_pex_dma_read(struct scsi_qla_host *vha,
289762306a36Sopenharmony_ci	struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
289862306a36Sopenharmony_ci{
289962306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
290062306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
290162306a36Sopenharmony_ci	struct qla8044_minidump_entry_rdmem_pex_dma *m_hdr = NULL;
290262306a36Sopenharmony_ci	uint32_t chunk_size, read_size;
290362306a36Sopenharmony_ci	uint8_t *data_ptr = (uint8_t *)*d_ptr;
290462306a36Sopenharmony_ci	void *rdmem_buffer = NULL;
290562306a36Sopenharmony_ci	dma_addr_t rdmem_dma;
290662306a36Sopenharmony_ci	struct qla8044_pex_dma_descriptor dma_desc;
290762306a36Sopenharmony_ci
290862306a36Sopenharmony_ci	rval = qla8044_check_dma_engine_state(vha);
290962306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
291062306a36Sopenharmony_ci		ql_dbg(ql_dbg_p3p, vha, 0xb147,
291162306a36Sopenharmony_ci		    "DMA engine not available. Fallback to rdmem-read.\n");
291262306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
291362306a36Sopenharmony_ci	}
291462306a36Sopenharmony_ci
291562306a36Sopenharmony_ci	m_hdr = (void *)entry_hdr;
291662306a36Sopenharmony_ci
291762306a36Sopenharmony_ci	rdmem_buffer = dma_alloc_coherent(&ha->pdev->dev,
291862306a36Sopenharmony_ci	    ISP8044_PEX_DMA_READ_SIZE, &rdmem_dma, GFP_KERNEL);
291962306a36Sopenharmony_ci	if (!rdmem_buffer) {
292062306a36Sopenharmony_ci		ql_dbg(ql_dbg_p3p, vha, 0xb148,
292162306a36Sopenharmony_ci		    "Unable to allocate rdmem dma buffer\n");
292262306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
292362306a36Sopenharmony_ci	}
292462306a36Sopenharmony_ci
292562306a36Sopenharmony_ci	/* Prepare pex-dma descriptor to be written to MS memory. */
292662306a36Sopenharmony_ci	/* dma-desc-cmd layout:
292762306a36Sopenharmony_ci	 *		0-3: dma-desc-cmd 0-3
292862306a36Sopenharmony_ci	 *		4-7: pcid function number
292962306a36Sopenharmony_ci	 *		8-15: dma-desc-cmd 8-15
293062306a36Sopenharmony_ci	 * dma_bus_addr: dma buffer address
293162306a36Sopenharmony_ci	 * cmd.read_data_size: amount of data-chunk to be read.
293262306a36Sopenharmony_ci	 */
293362306a36Sopenharmony_ci	dma_desc.cmd.dma_desc_cmd = (m_hdr->dma_desc_cmd & 0xff0f);
293462306a36Sopenharmony_ci	dma_desc.cmd.dma_desc_cmd |=
293562306a36Sopenharmony_ci	    ((PCI_FUNC(ha->pdev->devfn) & 0xf) << 0x4);
293662306a36Sopenharmony_ci
293762306a36Sopenharmony_ci	dma_desc.dma_bus_addr = rdmem_dma;
293862306a36Sopenharmony_ci	dma_desc.cmd.read_data_size = chunk_size = ISP8044_PEX_DMA_READ_SIZE;
293962306a36Sopenharmony_ci	read_size = 0;
294062306a36Sopenharmony_ci
294162306a36Sopenharmony_ci	/*
294262306a36Sopenharmony_ci	 * Perform rdmem operation using pex-dma.
294362306a36Sopenharmony_ci	 * Prepare dma in chunks of ISP8044_PEX_DMA_READ_SIZE.
294462306a36Sopenharmony_ci	 */
294562306a36Sopenharmony_ci	while (read_size < m_hdr->read_data_size) {
294662306a36Sopenharmony_ci		if (m_hdr->read_data_size - read_size <
294762306a36Sopenharmony_ci		    ISP8044_PEX_DMA_READ_SIZE) {
294862306a36Sopenharmony_ci			chunk_size = (m_hdr->read_data_size - read_size);
294962306a36Sopenharmony_ci			dma_desc.cmd.read_data_size = chunk_size;
295062306a36Sopenharmony_ci		}
295162306a36Sopenharmony_ci
295262306a36Sopenharmony_ci		dma_desc.src_addr = m_hdr->read_addr + read_size;
295362306a36Sopenharmony_ci
295462306a36Sopenharmony_ci		/* Prepare: Write pex-dma descriptor to MS memory. */
295562306a36Sopenharmony_ci		rval = qla8044_ms_mem_write_128b(vha,
295662306a36Sopenharmony_ci		    m_hdr->desc_card_addr, (uint32_t *)&dma_desc,
295762306a36Sopenharmony_ci		    (sizeof(struct qla8044_pex_dma_descriptor)/16));
295862306a36Sopenharmony_ci		if (rval) {
295962306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb14a,
296062306a36Sopenharmony_ci			    "%s: Error writing rdmem-dma-init to MS !!!\n",
296162306a36Sopenharmony_ci			    __func__);
296262306a36Sopenharmony_ci			goto error_exit;
296362306a36Sopenharmony_ci		}
296462306a36Sopenharmony_ci		ql_dbg(ql_dbg_p3p, vha, 0xb14b,
296562306a36Sopenharmony_ci		    "%s: Dma-descriptor: Instruct for rdmem dma "
296662306a36Sopenharmony_ci		    "(chunk_size 0x%x).\n", __func__, chunk_size);
296762306a36Sopenharmony_ci
296862306a36Sopenharmony_ci		/* Execute: Start pex-dma operation. */
296962306a36Sopenharmony_ci		rval = qla8044_start_pex_dma(vha, m_hdr);
297062306a36Sopenharmony_ci		if (rval)
297162306a36Sopenharmony_ci			goto error_exit;
297262306a36Sopenharmony_ci
297362306a36Sopenharmony_ci		memcpy(data_ptr, rdmem_buffer, chunk_size);
297462306a36Sopenharmony_ci		data_ptr += chunk_size;
297562306a36Sopenharmony_ci		read_size += chunk_size;
297662306a36Sopenharmony_ci	}
297762306a36Sopenharmony_ci
297862306a36Sopenharmony_ci	*d_ptr = (uint32_t *)data_ptr;
297962306a36Sopenharmony_ci
298062306a36Sopenharmony_cierror_exit:
298162306a36Sopenharmony_ci	if (rdmem_buffer)
298262306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, ISP8044_PEX_DMA_READ_SIZE,
298362306a36Sopenharmony_ci		    rdmem_buffer, rdmem_dma);
298462306a36Sopenharmony_ci
298562306a36Sopenharmony_ci	return rval;
298662306a36Sopenharmony_ci}
298762306a36Sopenharmony_ci
298862306a36Sopenharmony_cistatic uint32_t
298962306a36Sopenharmony_ciqla8044_minidump_process_rddfe(struct scsi_qla_host *vha,
299062306a36Sopenharmony_ci	struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
299162306a36Sopenharmony_ci{
299262306a36Sopenharmony_ci	int loop_cnt;
299362306a36Sopenharmony_ci	uint32_t addr1, addr2, value, data, temp, wrVal;
299462306a36Sopenharmony_ci	uint8_t stride, stride2;
299562306a36Sopenharmony_ci	uint16_t count;
299662306a36Sopenharmony_ci	uint32_t poll, mask, modify_mask;
299762306a36Sopenharmony_ci	uint32_t wait_count = 0;
299862306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
299962306a36Sopenharmony_ci	struct qla8044_minidump_entry_rddfe *rddfe;
300062306a36Sopenharmony_ci
300162306a36Sopenharmony_ci	rddfe = (struct qla8044_minidump_entry_rddfe *) entry_hdr;
300262306a36Sopenharmony_ci
300362306a36Sopenharmony_ci	addr1 = rddfe->addr_1;
300462306a36Sopenharmony_ci	value = rddfe->value;
300562306a36Sopenharmony_ci	stride = rddfe->stride;
300662306a36Sopenharmony_ci	stride2 = rddfe->stride2;
300762306a36Sopenharmony_ci	count = rddfe->count;
300862306a36Sopenharmony_ci
300962306a36Sopenharmony_ci	poll = rddfe->poll;
301062306a36Sopenharmony_ci	mask = rddfe->mask;
301162306a36Sopenharmony_ci	modify_mask = rddfe->modify_mask;
301262306a36Sopenharmony_ci
301362306a36Sopenharmony_ci	addr2 = addr1 + stride;
301462306a36Sopenharmony_ci
301562306a36Sopenharmony_ci	for (loop_cnt = 0x0; loop_cnt < count; loop_cnt++) {
301662306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha, addr1, (0x40000000 | value));
301762306a36Sopenharmony_ci
301862306a36Sopenharmony_ci		wait_count = 0;
301962306a36Sopenharmony_ci		while (wait_count < poll) {
302062306a36Sopenharmony_ci			qla8044_rd_reg_indirect(vha, addr1, &temp);
302162306a36Sopenharmony_ci			if ((temp & mask) != 0)
302262306a36Sopenharmony_ci				break;
302362306a36Sopenharmony_ci			wait_count++;
302462306a36Sopenharmony_ci		}
302562306a36Sopenharmony_ci
302662306a36Sopenharmony_ci		if (wait_count == poll) {
302762306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb153,
302862306a36Sopenharmony_ci			    "%s: TIMEOUT\n", __func__);
302962306a36Sopenharmony_ci			goto error;
303062306a36Sopenharmony_ci		} else {
303162306a36Sopenharmony_ci			qla8044_rd_reg_indirect(vha, addr2, &temp);
303262306a36Sopenharmony_ci			temp = temp & modify_mask;
303362306a36Sopenharmony_ci			temp = (temp | ((loop_cnt << 16) | loop_cnt));
303462306a36Sopenharmony_ci			wrVal = ((temp << 16) | temp);
303562306a36Sopenharmony_ci
303662306a36Sopenharmony_ci			qla8044_wr_reg_indirect(vha, addr2, wrVal);
303762306a36Sopenharmony_ci			qla8044_wr_reg_indirect(vha, addr1, value);
303862306a36Sopenharmony_ci
303962306a36Sopenharmony_ci			wait_count = 0;
304062306a36Sopenharmony_ci			while (wait_count < poll) {
304162306a36Sopenharmony_ci				qla8044_rd_reg_indirect(vha, addr1, &temp);
304262306a36Sopenharmony_ci				if ((temp & mask) != 0)
304362306a36Sopenharmony_ci					break;
304462306a36Sopenharmony_ci				wait_count++;
304562306a36Sopenharmony_ci			}
304662306a36Sopenharmony_ci			if (wait_count == poll) {
304762306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0xb154,
304862306a36Sopenharmony_ci				    "%s: TIMEOUT\n", __func__);
304962306a36Sopenharmony_ci				goto error;
305062306a36Sopenharmony_ci			}
305162306a36Sopenharmony_ci
305262306a36Sopenharmony_ci			qla8044_wr_reg_indirect(vha, addr1,
305362306a36Sopenharmony_ci			    ((0x40000000 | value) + stride2));
305462306a36Sopenharmony_ci			wait_count = 0;
305562306a36Sopenharmony_ci			while (wait_count < poll) {
305662306a36Sopenharmony_ci				qla8044_rd_reg_indirect(vha, addr1, &temp);
305762306a36Sopenharmony_ci				if ((temp & mask) != 0)
305862306a36Sopenharmony_ci					break;
305962306a36Sopenharmony_ci				wait_count++;
306062306a36Sopenharmony_ci			}
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci			if (wait_count == poll) {
306362306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0xb155,
306462306a36Sopenharmony_ci				    "%s: TIMEOUT\n", __func__);
306562306a36Sopenharmony_ci				goto error;
306662306a36Sopenharmony_ci			}
306762306a36Sopenharmony_ci
306862306a36Sopenharmony_ci			qla8044_rd_reg_indirect(vha, addr2, &data);
306962306a36Sopenharmony_ci
307062306a36Sopenharmony_ci			*data_ptr++ = wrVal;
307162306a36Sopenharmony_ci			*data_ptr++ = data;
307262306a36Sopenharmony_ci		}
307362306a36Sopenharmony_ci
307462306a36Sopenharmony_ci	}
307562306a36Sopenharmony_ci
307662306a36Sopenharmony_ci	*d_ptr = data_ptr;
307762306a36Sopenharmony_ci	return QLA_SUCCESS;
307862306a36Sopenharmony_ci
307962306a36Sopenharmony_cierror:
308062306a36Sopenharmony_ci	return -1;
308162306a36Sopenharmony_ci
308262306a36Sopenharmony_ci}
308362306a36Sopenharmony_ci
308462306a36Sopenharmony_cistatic uint32_t
308562306a36Sopenharmony_ciqla8044_minidump_process_rdmdio(struct scsi_qla_host *vha,
308662306a36Sopenharmony_ci	struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
308762306a36Sopenharmony_ci{
308862306a36Sopenharmony_ci	int ret = 0;
308962306a36Sopenharmony_ci	uint32_t addr1, addr2, value1, value2, data, selVal;
309062306a36Sopenharmony_ci	uint8_t stride1, stride2;
309162306a36Sopenharmony_ci	uint32_t addr3, addr4, addr5, addr6, addr7;
309262306a36Sopenharmony_ci	uint16_t count, loop_cnt;
309362306a36Sopenharmony_ci	uint32_t mask;
309462306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
309562306a36Sopenharmony_ci
309662306a36Sopenharmony_ci	struct qla8044_minidump_entry_rdmdio *rdmdio;
309762306a36Sopenharmony_ci
309862306a36Sopenharmony_ci	rdmdio = (struct qla8044_minidump_entry_rdmdio *) entry_hdr;
309962306a36Sopenharmony_ci
310062306a36Sopenharmony_ci	addr1 = rdmdio->addr_1;
310162306a36Sopenharmony_ci	addr2 = rdmdio->addr_2;
310262306a36Sopenharmony_ci	value1 = rdmdio->value_1;
310362306a36Sopenharmony_ci	stride1 = rdmdio->stride_1;
310462306a36Sopenharmony_ci	stride2 = rdmdio->stride_2;
310562306a36Sopenharmony_ci	count = rdmdio->count;
310662306a36Sopenharmony_ci
310762306a36Sopenharmony_ci	mask = rdmdio->mask;
310862306a36Sopenharmony_ci	value2 = rdmdio->value_2;
310962306a36Sopenharmony_ci
311062306a36Sopenharmony_ci	addr3 = addr1 + stride1;
311162306a36Sopenharmony_ci
311262306a36Sopenharmony_ci	for (loop_cnt = 0; loop_cnt < count; loop_cnt++) {
311362306a36Sopenharmony_ci		ret = qla8044_poll_wait_ipmdio_bus_idle(vha, addr1, addr2,
311462306a36Sopenharmony_ci		    addr3, mask);
311562306a36Sopenharmony_ci		if (ret == -1)
311662306a36Sopenharmony_ci			goto error;
311762306a36Sopenharmony_ci
311862306a36Sopenharmony_ci		addr4 = addr2 - stride1;
311962306a36Sopenharmony_ci		ret = qla8044_ipmdio_wr_reg(vha, addr1, addr3, mask, addr4,
312062306a36Sopenharmony_ci		    value2);
312162306a36Sopenharmony_ci		if (ret == -1)
312262306a36Sopenharmony_ci			goto error;
312362306a36Sopenharmony_ci
312462306a36Sopenharmony_ci		addr5 = addr2 - (2 * stride1);
312562306a36Sopenharmony_ci		ret = qla8044_ipmdio_wr_reg(vha, addr1, addr3, mask, addr5,
312662306a36Sopenharmony_ci		    value1);
312762306a36Sopenharmony_ci		if (ret == -1)
312862306a36Sopenharmony_ci			goto error;
312962306a36Sopenharmony_ci
313062306a36Sopenharmony_ci		addr6 = addr2 - (3 * stride1);
313162306a36Sopenharmony_ci		ret = qla8044_ipmdio_wr_reg(vha, addr1, addr3, mask,
313262306a36Sopenharmony_ci		    addr6, 0x2);
313362306a36Sopenharmony_ci		if (ret == -1)
313462306a36Sopenharmony_ci			goto error;
313562306a36Sopenharmony_ci
313662306a36Sopenharmony_ci		ret = qla8044_poll_wait_ipmdio_bus_idle(vha, addr1, addr2,
313762306a36Sopenharmony_ci		    addr3, mask);
313862306a36Sopenharmony_ci		if (ret == -1)
313962306a36Sopenharmony_ci			goto error;
314062306a36Sopenharmony_ci
314162306a36Sopenharmony_ci		addr7 = addr2 - (4 * stride1);
314262306a36Sopenharmony_ci		data = qla8044_ipmdio_rd_reg(vha, addr1, addr3, mask, addr7);
314362306a36Sopenharmony_ci		if (data == -1)
314462306a36Sopenharmony_ci			goto error;
314562306a36Sopenharmony_ci
314662306a36Sopenharmony_ci		selVal = (value2 << 18) | (value1 << 2) | 2;
314762306a36Sopenharmony_ci
314862306a36Sopenharmony_ci		stride2 = rdmdio->stride_2;
314962306a36Sopenharmony_ci		*data_ptr++ = selVal;
315062306a36Sopenharmony_ci		*data_ptr++ = data;
315162306a36Sopenharmony_ci
315262306a36Sopenharmony_ci		value1 = value1 + stride2;
315362306a36Sopenharmony_ci		*d_ptr = data_ptr;
315462306a36Sopenharmony_ci	}
315562306a36Sopenharmony_ci
315662306a36Sopenharmony_ci	return 0;
315762306a36Sopenharmony_ci
315862306a36Sopenharmony_cierror:
315962306a36Sopenharmony_ci	return -1;
316062306a36Sopenharmony_ci}
316162306a36Sopenharmony_ci
316262306a36Sopenharmony_cistatic uint32_t qla8044_minidump_process_pollwr(struct scsi_qla_host *vha,
316362306a36Sopenharmony_ci		struct qla8044_minidump_entry_hdr *entry_hdr, uint32_t **d_ptr)
316462306a36Sopenharmony_ci{
316562306a36Sopenharmony_ci	uint32_t addr1, addr2, value1, value2, poll, r_value;
316662306a36Sopenharmony_ci	uint32_t wait_count = 0;
316762306a36Sopenharmony_ci	struct qla8044_minidump_entry_pollwr *pollwr_hdr;
316862306a36Sopenharmony_ci
316962306a36Sopenharmony_ci	pollwr_hdr = (struct qla8044_minidump_entry_pollwr *)entry_hdr;
317062306a36Sopenharmony_ci	addr1 = pollwr_hdr->addr_1;
317162306a36Sopenharmony_ci	addr2 = pollwr_hdr->addr_2;
317262306a36Sopenharmony_ci	value1 = pollwr_hdr->value_1;
317362306a36Sopenharmony_ci	value2 = pollwr_hdr->value_2;
317462306a36Sopenharmony_ci
317562306a36Sopenharmony_ci	poll = pollwr_hdr->poll;
317662306a36Sopenharmony_ci
317762306a36Sopenharmony_ci	while (wait_count < poll) {
317862306a36Sopenharmony_ci		qla8044_rd_reg_indirect(vha, addr1, &r_value);
317962306a36Sopenharmony_ci
318062306a36Sopenharmony_ci		if ((r_value & poll) != 0)
318162306a36Sopenharmony_ci			break;
318262306a36Sopenharmony_ci		wait_count++;
318362306a36Sopenharmony_ci	}
318462306a36Sopenharmony_ci
318562306a36Sopenharmony_ci	if (wait_count == poll) {
318662306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb156, "%s: TIMEOUT\n", __func__);
318762306a36Sopenharmony_ci		goto error;
318862306a36Sopenharmony_ci	}
318962306a36Sopenharmony_ci
319062306a36Sopenharmony_ci	qla8044_wr_reg_indirect(vha, addr2, value2);
319162306a36Sopenharmony_ci	qla8044_wr_reg_indirect(vha, addr1, value1);
319262306a36Sopenharmony_ci
319362306a36Sopenharmony_ci	wait_count = 0;
319462306a36Sopenharmony_ci	while (wait_count < poll) {
319562306a36Sopenharmony_ci		qla8044_rd_reg_indirect(vha, addr1, &r_value);
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_ci		if ((r_value & poll) != 0)
319862306a36Sopenharmony_ci			break;
319962306a36Sopenharmony_ci		wait_count++;
320062306a36Sopenharmony_ci	}
320162306a36Sopenharmony_ci
320262306a36Sopenharmony_ci	return QLA_SUCCESS;
320362306a36Sopenharmony_ci
320462306a36Sopenharmony_cierror:
320562306a36Sopenharmony_ci	return -1;
320662306a36Sopenharmony_ci}
320762306a36Sopenharmony_ci
320862306a36Sopenharmony_ci/*
320962306a36Sopenharmony_ci *
321062306a36Sopenharmony_ci * qla8044_collect_md_data - Retrieve firmware minidump data.
321162306a36Sopenharmony_ci * @ha: pointer to adapter structure
321262306a36Sopenharmony_ci **/
321362306a36Sopenharmony_ciint
321462306a36Sopenharmony_ciqla8044_collect_md_data(struct scsi_qla_host *vha)
321562306a36Sopenharmony_ci{
321662306a36Sopenharmony_ci	int num_entry_hdr = 0;
321762306a36Sopenharmony_ci	struct qla8044_minidump_entry_hdr *entry_hdr;
321862306a36Sopenharmony_ci	struct qla8044_minidump_template_hdr *tmplt_hdr;
321962306a36Sopenharmony_ci	uint32_t *data_ptr;
322062306a36Sopenharmony_ci	uint32_t data_collected = 0, f_capture_mask;
322162306a36Sopenharmony_ci	int i, rval = QLA_FUNCTION_FAILED;
322262306a36Sopenharmony_ci	uint64_t now;
322362306a36Sopenharmony_ci	uint32_t timestamp, idc_control;
322462306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
322562306a36Sopenharmony_ci
322662306a36Sopenharmony_ci	if (!ha->md_dump) {
322762306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0xb101,
322862306a36Sopenharmony_ci		    "%s(%ld) No buffer to dump\n",
322962306a36Sopenharmony_ci		    __func__, vha->host_no);
323062306a36Sopenharmony_ci		return rval;
323162306a36Sopenharmony_ci	}
323262306a36Sopenharmony_ci
323362306a36Sopenharmony_ci	if (ha->fw_dumped) {
323462306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb10d,
323562306a36Sopenharmony_ci		    "Firmware has been previously dumped (%p) "
323662306a36Sopenharmony_ci		    "-- ignoring request.\n", ha->fw_dump);
323762306a36Sopenharmony_ci		goto md_failed;
323862306a36Sopenharmony_ci	}
323962306a36Sopenharmony_ci
324062306a36Sopenharmony_ci	ha->fw_dumped = false;
324162306a36Sopenharmony_ci
324262306a36Sopenharmony_ci	if (!ha->md_tmplt_hdr || !ha->md_dump) {
324362306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb10e,
324462306a36Sopenharmony_ci		    "Memory not allocated for minidump capture\n");
324562306a36Sopenharmony_ci		goto md_failed;
324662306a36Sopenharmony_ci	}
324762306a36Sopenharmony_ci
324862306a36Sopenharmony_ci	qla8044_idc_lock(ha);
324962306a36Sopenharmony_ci	idc_control = qla8044_rd_reg(ha, QLA8044_IDC_DRV_CTRL);
325062306a36Sopenharmony_ci	if (idc_control & GRACEFUL_RESET_BIT1) {
325162306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb112,
325262306a36Sopenharmony_ci		    "Forced reset from application, "
325362306a36Sopenharmony_ci		    "ignore minidump capture\n");
325462306a36Sopenharmony_ci		qla8044_wr_reg(ha, QLA8044_IDC_DRV_CTRL,
325562306a36Sopenharmony_ci		    (idc_control & ~GRACEFUL_RESET_BIT1));
325662306a36Sopenharmony_ci		qla8044_idc_unlock(ha);
325762306a36Sopenharmony_ci
325862306a36Sopenharmony_ci		goto md_failed;
325962306a36Sopenharmony_ci	}
326062306a36Sopenharmony_ci	qla8044_idc_unlock(ha);
326162306a36Sopenharmony_ci
326262306a36Sopenharmony_ci	if (qla82xx_validate_template_chksum(vha)) {
326362306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0xb109,
326462306a36Sopenharmony_ci		    "Template checksum validation error\n");
326562306a36Sopenharmony_ci		goto md_failed;
326662306a36Sopenharmony_ci	}
326762306a36Sopenharmony_ci
326862306a36Sopenharmony_ci	tmplt_hdr = (struct qla8044_minidump_template_hdr *)
326962306a36Sopenharmony_ci		ha->md_tmplt_hdr;
327062306a36Sopenharmony_ci	data_ptr = (uint32_t *)((uint8_t *)ha->md_dump);
327162306a36Sopenharmony_ci	num_entry_hdr = tmplt_hdr->num_of_entries;
327262306a36Sopenharmony_ci
327362306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb11a,
327462306a36Sopenharmony_ci	    "Capture Mask obtained: 0x%x\n", tmplt_hdr->capture_debug_level);
327562306a36Sopenharmony_ci
327662306a36Sopenharmony_ci	f_capture_mask = tmplt_hdr->capture_debug_level & 0xFF;
327762306a36Sopenharmony_ci
327862306a36Sopenharmony_ci	/* Validate whether required debug level is set */
327962306a36Sopenharmony_ci	if ((f_capture_mask & 0x3) != 0x3) {
328062306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb10f,
328162306a36Sopenharmony_ci		    "Minimum required capture mask[0x%x] level not set\n",
328262306a36Sopenharmony_ci		    f_capture_mask);
328362306a36Sopenharmony_ci
328462306a36Sopenharmony_ci	}
328562306a36Sopenharmony_ci	tmplt_hdr->driver_capture_mask = ql2xmdcapmask;
328662306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0xb102,
328762306a36Sopenharmony_ci	    "[%s]: starting data ptr: %p\n",
328862306a36Sopenharmony_ci	   __func__, data_ptr);
328962306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0xb10b,
329062306a36Sopenharmony_ci	   "[%s]: no of entry headers in Template: 0x%x\n",
329162306a36Sopenharmony_ci	   __func__, num_entry_hdr);
329262306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0xb10c,
329362306a36Sopenharmony_ci	    "[%s]: Total_data_size 0x%x, %d obtained\n",
329462306a36Sopenharmony_ci	   __func__, ha->md_dump_size, ha->md_dump_size);
329562306a36Sopenharmony_ci
329662306a36Sopenharmony_ci	/* Update current timestamp before taking dump */
329762306a36Sopenharmony_ci	now = get_jiffies_64();
329862306a36Sopenharmony_ci	timestamp = (u32)(jiffies_to_msecs(now) / 1000);
329962306a36Sopenharmony_ci	tmplt_hdr->driver_timestamp = timestamp;
330062306a36Sopenharmony_ci
330162306a36Sopenharmony_ci	entry_hdr = (struct qla8044_minidump_entry_hdr *)
330262306a36Sopenharmony_ci		(((uint8_t *)ha->md_tmplt_hdr) + tmplt_hdr->first_entry_offset);
330362306a36Sopenharmony_ci	tmplt_hdr->saved_state_array[QLA8044_SS_OCM_WNDREG_INDEX] =
330462306a36Sopenharmony_ci	    tmplt_hdr->ocm_window_reg[ha->portnum];
330562306a36Sopenharmony_ci
330662306a36Sopenharmony_ci	/* Walk through the entry headers - validate/perform required action */
330762306a36Sopenharmony_ci	for (i = 0; i < num_entry_hdr; i++) {
330862306a36Sopenharmony_ci		if (data_collected > ha->md_dump_size) {
330962306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0xb103,
331062306a36Sopenharmony_ci			    "Data collected: [0x%x], "
331162306a36Sopenharmony_ci			    "Total Dump size: [0x%x]\n",
331262306a36Sopenharmony_ci			    data_collected, ha->md_dump_size);
331362306a36Sopenharmony_ci			return rval;
331462306a36Sopenharmony_ci		}
331562306a36Sopenharmony_ci
331662306a36Sopenharmony_ci		if (!(entry_hdr->d_ctrl.entry_capture_mask &
331762306a36Sopenharmony_ci		      ql2xmdcapmask)) {
331862306a36Sopenharmony_ci			entry_hdr->d_ctrl.driver_flags |=
331962306a36Sopenharmony_ci			    QLA82XX_DBG_SKIPPED_FLAG;
332062306a36Sopenharmony_ci			goto skip_nxt_entry;
332162306a36Sopenharmony_ci		}
332262306a36Sopenharmony_ci
332362306a36Sopenharmony_ci		ql_dbg(ql_dbg_p3p, vha, 0xb104,
332462306a36Sopenharmony_ci		    "Data collected: [0x%x], Dump size left:[0x%x]\n",
332562306a36Sopenharmony_ci		    data_collected,
332662306a36Sopenharmony_ci		    (ha->md_dump_size - data_collected));
332762306a36Sopenharmony_ci
332862306a36Sopenharmony_ci		/* Decode the entry type and take required action to capture
332962306a36Sopenharmony_ci		 * debug data
333062306a36Sopenharmony_ci		 */
333162306a36Sopenharmony_ci		switch (entry_hdr->entry_type) {
333262306a36Sopenharmony_ci		case QLA82XX_RDEND:
333362306a36Sopenharmony_ci			qla8044_mark_entry_skipped(vha, entry_hdr, i);
333462306a36Sopenharmony_ci			break;
333562306a36Sopenharmony_ci		case QLA82XX_CNTRL:
333662306a36Sopenharmony_ci			rval = qla8044_minidump_process_control(vha,
333762306a36Sopenharmony_ci			    entry_hdr);
333862306a36Sopenharmony_ci			if (rval != QLA_SUCCESS) {
333962306a36Sopenharmony_ci				qla8044_mark_entry_skipped(vha, entry_hdr, i);
334062306a36Sopenharmony_ci				goto md_failed;
334162306a36Sopenharmony_ci			}
334262306a36Sopenharmony_ci			break;
334362306a36Sopenharmony_ci		case QLA82XX_RDCRB:
334462306a36Sopenharmony_ci			qla8044_minidump_process_rdcrb(vha,
334562306a36Sopenharmony_ci			    entry_hdr, &data_ptr);
334662306a36Sopenharmony_ci			break;
334762306a36Sopenharmony_ci		case QLA82XX_RDMEM:
334862306a36Sopenharmony_ci			rval = qla8044_minidump_pex_dma_read(vha,
334962306a36Sopenharmony_ci			    entry_hdr, &data_ptr);
335062306a36Sopenharmony_ci			if (rval != QLA_SUCCESS) {
335162306a36Sopenharmony_ci				rval = qla8044_minidump_process_rdmem(vha,
335262306a36Sopenharmony_ci				    entry_hdr, &data_ptr);
335362306a36Sopenharmony_ci				if (rval != QLA_SUCCESS) {
335462306a36Sopenharmony_ci					qla8044_mark_entry_skipped(vha,
335562306a36Sopenharmony_ci					    entry_hdr, i);
335662306a36Sopenharmony_ci					goto md_failed;
335762306a36Sopenharmony_ci				}
335862306a36Sopenharmony_ci			}
335962306a36Sopenharmony_ci			break;
336062306a36Sopenharmony_ci		case QLA82XX_BOARD:
336162306a36Sopenharmony_ci		case QLA82XX_RDROM:
336262306a36Sopenharmony_ci			rval = qla8044_minidump_process_rdrom(vha,
336362306a36Sopenharmony_ci			    entry_hdr, &data_ptr);
336462306a36Sopenharmony_ci			if (rval != QLA_SUCCESS) {
336562306a36Sopenharmony_ci				qla8044_mark_entry_skipped(vha,
336662306a36Sopenharmony_ci				    entry_hdr, i);
336762306a36Sopenharmony_ci			}
336862306a36Sopenharmony_ci			break;
336962306a36Sopenharmony_ci		case QLA82XX_L2DTG:
337062306a36Sopenharmony_ci		case QLA82XX_L2ITG:
337162306a36Sopenharmony_ci		case QLA82XX_L2DAT:
337262306a36Sopenharmony_ci		case QLA82XX_L2INS:
337362306a36Sopenharmony_ci			rval = qla8044_minidump_process_l2tag(vha,
337462306a36Sopenharmony_ci			    entry_hdr, &data_ptr);
337562306a36Sopenharmony_ci			if (rval != QLA_SUCCESS) {
337662306a36Sopenharmony_ci				qla8044_mark_entry_skipped(vha, entry_hdr, i);
337762306a36Sopenharmony_ci				goto md_failed;
337862306a36Sopenharmony_ci			}
337962306a36Sopenharmony_ci			break;
338062306a36Sopenharmony_ci		case QLA8044_L1DTG:
338162306a36Sopenharmony_ci		case QLA8044_L1ITG:
338262306a36Sopenharmony_ci		case QLA82XX_L1DAT:
338362306a36Sopenharmony_ci		case QLA82XX_L1INS:
338462306a36Sopenharmony_ci			qla8044_minidump_process_l1cache(vha,
338562306a36Sopenharmony_ci			    entry_hdr, &data_ptr);
338662306a36Sopenharmony_ci			break;
338762306a36Sopenharmony_ci		case QLA82XX_RDOCM:
338862306a36Sopenharmony_ci			qla8044_minidump_process_rdocm(vha,
338962306a36Sopenharmony_ci			    entry_hdr, &data_ptr);
339062306a36Sopenharmony_ci			break;
339162306a36Sopenharmony_ci		case QLA82XX_RDMUX:
339262306a36Sopenharmony_ci			qla8044_minidump_process_rdmux(vha,
339362306a36Sopenharmony_ci			    entry_hdr, &data_ptr);
339462306a36Sopenharmony_ci			break;
339562306a36Sopenharmony_ci		case QLA82XX_QUEUE:
339662306a36Sopenharmony_ci			qla8044_minidump_process_queue(vha,
339762306a36Sopenharmony_ci			    entry_hdr, &data_ptr);
339862306a36Sopenharmony_ci			break;
339962306a36Sopenharmony_ci		case QLA8044_POLLRD:
340062306a36Sopenharmony_ci			rval = qla8044_minidump_process_pollrd(vha,
340162306a36Sopenharmony_ci			    entry_hdr, &data_ptr);
340262306a36Sopenharmony_ci			if (rval != QLA_SUCCESS)
340362306a36Sopenharmony_ci				qla8044_mark_entry_skipped(vha, entry_hdr, i);
340462306a36Sopenharmony_ci			break;
340562306a36Sopenharmony_ci		case QLA8044_RDMUX2:
340662306a36Sopenharmony_ci			qla8044_minidump_process_rdmux2(vha,
340762306a36Sopenharmony_ci			    entry_hdr, &data_ptr);
340862306a36Sopenharmony_ci			break;
340962306a36Sopenharmony_ci		case QLA8044_POLLRDMWR:
341062306a36Sopenharmony_ci			rval = qla8044_minidump_process_pollrdmwr(vha,
341162306a36Sopenharmony_ci			    entry_hdr, &data_ptr);
341262306a36Sopenharmony_ci			if (rval != QLA_SUCCESS)
341362306a36Sopenharmony_ci				qla8044_mark_entry_skipped(vha, entry_hdr, i);
341462306a36Sopenharmony_ci			break;
341562306a36Sopenharmony_ci		case QLA8044_RDDFE:
341662306a36Sopenharmony_ci			rval = qla8044_minidump_process_rddfe(vha, entry_hdr,
341762306a36Sopenharmony_ci			    &data_ptr);
341862306a36Sopenharmony_ci			if (rval != QLA_SUCCESS)
341962306a36Sopenharmony_ci				qla8044_mark_entry_skipped(vha, entry_hdr, i);
342062306a36Sopenharmony_ci			break;
342162306a36Sopenharmony_ci		case QLA8044_RDMDIO:
342262306a36Sopenharmony_ci			rval = qla8044_minidump_process_rdmdio(vha, entry_hdr,
342362306a36Sopenharmony_ci			    &data_ptr);
342462306a36Sopenharmony_ci			if (rval != QLA_SUCCESS)
342562306a36Sopenharmony_ci				qla8044_mark_entry_skipped(vha, entry_hdr, i);
342662306a36Sopenharmony_ci			break;
342762306a36Sopenharmony_ci		case QLA8044_POLLWR:
342862306a36Sopenharmony_ci			rval = qla8044_minidump_process_pollwr(vha, entry_hdr,
342962306a36Sopenharmony_ci			    &data_ptr);
343062306a36Sopenharmony_ci			if (rval != QLA_SUCCESS)
343162306a36Sopenharmony_ci				qla8044_mark_entry_skipped(vha, entry_hdr, i);
343262306a36Sopenharmony_ci			break;
343362306a36Sopenharmony_ci		case QLA82XX_RDNOP:
343462306a36Sopenharmony_ci		default:
343562306a36Sopenharmony_ci			qla8044_mark_entry_skipped(vha, entry_hdr, i);
343662306a36Sopenharmony_ci			break;
343762306a36Sopenharmony_ci		}
343862306a36Sopenharmony_ci
343962306a36Sopenharmony_ci		data_collected = (uint8_t *)data_ptr -
344062306a36Sopenharmony_ci		    (uint8_t *)((uint8_t *)ha->md_dump);
344162306a36Sopenharmony_ciskip_nxt_entry:
344262306a36Sopenharmony_ci		/*
344362306a36Sopenharmony_ci		 * next entry in the template
344462306a36Sopenharmony_ci		 */
344562306a36Sopenharmony_ci		entry_hdr = (struct qla8044_minidump_entry_hdr *)
344662306a36Sopenharmony_ci		    (((uint8_t *)entry_hdr) + entry_hdr->entry_size);
344762306a36Sopenharmony_ci	}
344862306a36Sopenharmony_ci
344962306a36Sopenharmony_ci	if (data_collected != ha->md_dump_size) {
345062306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0xb105,
345162306a36Sopenharmony_ci		    "Dump data mismatch: Data collected: "
345262306a36Sopenharmony_ci		    "[0x%x], total_data_size:[0x%x]\n",
345362306a36Sopenharmony_ci		    data_collected, ha->md_dump_size);
345462306a36Sopenharmony_ci		rval = QLA_FUNCTION_FAILED;
345562306a36Sopenharmony_ci		goto md_failed;
345662306a36Sopenharmony_ci	}
345762306a36Sopenharmony_ci
345862306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0xb110,
345962306a36Sopenharmony_ci	    "Firmware dump saved to temp buffer (%ld/%p %ld/%p).\n",
346062306a36Sopenharmony_ci	    vha->host_no, ha->md_tmplt_hdr, vha->host_no, ha->md_dump);
346162306a36Sopenharmony_ci	ha->fw_dumped = true;
346262306a36Sopenharmony_ci	qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP);
346362306a36Sopenharmony_ci
346462306a36Sopenharmony_ci
346562306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0xb106,
346662306a36Sopenharmony_ci	    "Leaving fn: %s Last entry: 0x%x\n",
346762306a36Sopenharmony_ci	    __func__, i);
346862306a36Sopenharmony_cimd_failed:
346962306a36Sopenharmony_ci	return rval;
347062306a36Sopenharmony_ci}
347162306a36Sopenharmony_ci
347262306a36Sopenharmony_civoid
347362306a36Sopenharmony_ciqla8044_get_minidump(struct scsi_qla_host *vha)
347462306a36Sopenharmony_ci{
347562306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
347662306a36Sopenharmony_ci
347762306a36Sopenharmony_ci	if (!qla8044_collect_md_data(vha)) {
347862306a36Sopenharmony_ci		ha->fw_dumped = true;
347962306a36Sopenharmony_ci		ha->prev_minidump_failed = 0;
348062306a36Sopenharmony_ci	} else {
348162306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb0db,
348262306a36Sopenharmony_ci		    "%s: Unable to collect minidump\n",
348362306a36Sopenharmony_ci		    __func__);
348462306a36Sopenharmony_ci		ha->prev_minidump_failed = 1;
348562306a36Sopenharmony_ci	}
348662306a36Sopenharmony_ci}
348762306a36Sopenharmony_ci
348862306a36Sopenharmony_cistatic int
348962306a36Sopenharmony_ciqla8044_poll_flash_status_reg(struct scsi_qla_host *vha)
349062306a36Sopenharmony_ci{
349162306a36Sopenharmony_ci	uint32_t flash_status;
349262306a36Sopenharmony_ci	int retries = QLA8044_FLASH_READ_RETRY_COUNT;
349362306a36Sopenharmony_ci	int ret_val = QLA_SUCCESS;
349462306a36Sopenharmony_ci
349562306a36Sopenharmony_ci	while (retries--) {
349662306a36Sopenharmony_ci		ret_val = qla8044_rd_reg_indirect(vha, QLA8044_FLASH_STATUS,
349762306a36Sopenharmony_ci		    &flash_status);
349862306a36Sopenharmony_ci		if (ret_val) {
349962306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb13c,
350062306a36Sopenharmony_ci			    "%s: Failed to read FLASH_STATUS reg.\n",
350162306a36Sopenharmony_ci			    __func__);
350262306a36Sopenharmony_ci			break;
350362306a36Sopenharmony_ci		}
350462306a36Sopenharmony_ci		if ((flash_status & QLA8044_FLASH_STATUS_READY) ==
350562306a36Sopenharmony_ci		    QLA8044_FLASH_STATUS_READY)
350662306a36Sopenharmony_ci			break;
350762306a36Sopenharmony_ci		msleep(QLA8044_FLASH_STATUS_REG_POLL_DELAY);
350862306a36Sopenharmony_ci	}
350962306a36Sopenharmony_ci
351062306a36Sopenharmony_ci	if (!retries)
351162306a36Sopenharmony_ci		ret_val = QLA_FUNCTION_FAILED;
351262306a36Sopenharmony_ci
351362306a36Sopenharmony_ci	return ret_val;
351462306a36Sopenharmony_ci}
351562306a36Sopenharmony_ci
351662306a36Sopenharmony_cistatic int
351762306a36Sopenharmony_ciqla8044_write_flash_status_reg(struct scsi_qla_host *vha,
351862306a36Sopenharmony_ci			       uint32_t data)
351962306a36Sopenharmony_ci{
352062306a36Sopenharmony_ci	int ret_val = QLA_SUCCESS;
352162306a36Sopenharmony_ci	uint32_t cmd;
352262306a36Sopenharmony_ci
352362306a36Sopenharmony_ci	cmd = vha->hw->fdt_wrt_sts_reg_cmd;
352462306a36Sopenharmony_ci
352562306a36Sopenharmony_ci	ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR,
352662306a36Sopenharmony_ci	    QLA8044_FLASH_STATUS_WRITE_DEF_SIG | cmd);
352762306a36Sopenharmony_ci	if (ret_val) {
352862306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb125,
352962306a36Sopenharmony_ci		    "%s: Failed to write to FLASH_ADDR.\n", __func__);
353062306a36Sopenharmony_ci		goto exit_func;
353162306a36Sopenharmony_ci	}
353262306a36Sopenharmony_ci
353362306a36Sopenharmony_ci	ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_WRDATA, data);
353462306a36Sopenharmony_ci	if (ret_val) {
353562306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb126,
353662306a36Sopenharmony_ci		    "%s: Failed to write to FLASH_WRDATA.\n", __func__);
353762306a36Sopenharmony_ci		goto exit_func;
353862306a36Sopenharmony_ci	}
353962306a36Sopenharmony_ci
354062306a36Sopenharmony_ci	ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL,
354162306a36Sopenharmony_ci	    QLA8044_FLASH_SECOND_ERASE_MS_VAL);
354262306a36Sopenharmony_ci	if (ret_val) {
354362306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb127,
354462306a36Sopenharmony_ci		    "%s: Failed to write to FLASH_CONTROL.\n", __func__);
354562306a36Sopenharmony_ci		goto exit_func;
354662306a36Sopenharmony_ci	}
354762306a36Sopenharmony_ci
354862306a36Sopenharmony_ci	ret_val = qla8044_poll_flash_status_reg(vha);
354962306a36Sopenharmony_ci	if (ret_val)
355062306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb128,
355162306a36Sopenharmony_ci		    "%s: Error polling flash status reg.\n", __func__);
355262306a36Sopenharmony_ci
355362306a36Sopenharmony_ciexit_func:
355462306a36Sopenharmony_ci	return ret_val;
355562306a36Sopenharmony_ci}
355662306a36Sopenharmony_ci
355762306a36Sopenharmony_ci/*
355862306a36Sopenharmony_ci * This function assumes that the flash lock is held.
355962306a36Sopenharmony_ci */
356062306a36Sopenharmony_cistatic int
356162306a36Sopenharmony_ciqla8044_unprotect_flash(scsi_qla_host_t *vha)
356262306a36Sopenharmony_ci{
356362306a36Sopenharmony_ci	int ret_val;
356462306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
356562306a36Sopenharmony_ci
356662306a36Sopenharmony_ci	ret_val = qla8044_write_flash_status_reg(vha, ha->fdt_wrt_enable);
356762306a36Sopenharmony_ci	if (ret_val)
356862306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb139,
356962306a36Sopenharmony_ci		    "%s: Write flash status failed.\n", __func__);
357062306a36Sopenharmony_ci
357162306a36Sopenharmony_ci	return ret_val;
357262306a36Sopenharmony_ci}
357362306a36Sopenharmony_ci
357462306a36Sopenharmony_ci/*
357562306a36Sopenharmony_ci * This function assumes that the flash lock is held.
357662306a36Sopenharmony_ci */
357762306a36Sopenharmony_cistatic int
357862306a36Sopenharmony_ciqla8044_protect_flash(scsi_qla_host_t *vha)
357962306a36Sopenharmony_ci{
358062306a36Sopenharmony_ci	int ret_val;
358162306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
358262306a36Sopenharmony_ci
358362306a36Sopenharmony_ci	ret_val = qla8044_write_flash_status_reg(vha, ha->fdt_wrt_disable);
358462306a36Sopenharmony_ci	if (ret_val)
358562306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb13b,
358662306a36Sopenharmony_ci		    "%s: Write flash status failed.\n", __func__);
358762306a36Sopenharmony_ci
358862306a36Sopenharmony_ci	return ret_val;
358962306a36Sopenharmony_ci}
359062306a36Sopenharmony_ci
359162306a36Sopenharmony_ci
359262306a36Sopenharmony_cistatic int
359362306a36Sopenharmony_ciqla8044_erase_flash_sector(struct scsi_qla_host *vha,
359462306a36Sopenharmony_ci			   uint32_t sector_start_addr)
359562306a36Sopenharmony_ci{
359662306a36Sopenharmony_ci	uint32_t reversed_addr;
359762306a36Sopenharmony_ci	int ret_val = QLA_SUCCESS;
359862306a36Sopenharmony_ci
359962306a36Sopenharmony_ci	ret_val = qla8044_poll_flash_status_reg(vha);
360062306a36Sopenharmony_ci	if (ret_val) {
360162306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb12e,
360262306a36Sopenharmony_ci		    "%s: Poll flash status after erase failed..\n", __func__);
360362306a36Sopenharmony_ci	}
360462306a36Sopenharmony_ci
360562306a36Sopenharmony_ci	reversed_addr = (((sector_start_addr & 0xFF) << 16) |
360662306a36Sopenharmony_ci	    (sector_start_addr & 0xFF00) |
360762306a36Sopenharmony_ci	    ((sector_start_addr & 0xFF0000) >> 16));
360862306a36Sopenharmony_ci
360962306a36Sopenharmony_ci	ret_val = qla8044_wr_reg_indirect(vha,
361062306a36Sopenharmony_ci	    QLA8044_FLASH_WRDATA, reversed_addr);
361162306a36Sopenharmony_ci	if (ret_val) {
361262306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb12f,
361362306a36Sopenharmony_ci		    "%s: Failed to write to FLASH_WRDATA.\n", __func__);
361462306a36Sopenharmony_ci	}
361562306a36Sopenharmony_ci	ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR,
361662306a36Sopenharmony_ci	   QLA8044_FLASH_ERASE_SIG | vha->hw->fdt_erase_cmd);
361762306a36Sopenharmony_ci	if (ret_val) {
361862306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb130,
361962306a36Sopenharmony_ci		    "%s: Failed to write to FLASH_ADDR.\n", __func__);
362062306a36Sopenharmony_ci	}
362162306a36Sopenharmony_ci	ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL,
362262306a36Sopenharmony_ci	    QLA8044_FLASH_LAST_ERASE_MS_VAL);
362362306a36Sopenharmony_ci	if (ret_val) {
362462306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb131,
362562306a36Sopenharmony_ci		    "%s: Failed write to FLASH_CONTROL.\n", __func__);
362662306a36Sopenharmony_ci	}
362762306a36Sopenharmony_ci	ret_val = qla8044_poll_flash_status_reg(vha);
362862306a36Sopenharmony_ci	if (ret_val) {
362962306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb132,
363062306a36Sopenharmony_ci		    "%s: Poll flash status failed.\n", __func__);
363162306a36Sopenharmony_ci	}
363262306a36Sopenharmony_ci
363362306a36Sopenharmony_ci
363462306a36Sopenharmony_ci	return ret_val;
363562306a36Sopenharmony_ci}
363662306a36Sopenharmony_ci
363762306a36Sopenharmony_ci/*
363862306a36Sopenharmony_ci * qla8044_flash_write_u32 - Write data to flash
363962306a36Sopenharmony_ci *
364062306a36Sopenharmony_ci * @ha : Pointer to adapter structure
364162306a36Sopenharmony_ci * addr : Flash address to write to
364262306a36Sopenharmony_ci * p_data : Data to be written
364362306a36Sopenharmony_ci *
364462306a36Sopenharmony_ci * Return Value - QLA_SUCCESS/QLA_FUNCTION_FAILED
364562306a36Sopenharmony_ci *
364662306a36Sopenharmony_ci * NOTE: Lock should be held on entry
364762306a36Sopenharmony_ci */
364862306a36Sopenharmony_cistatic int
364962306a36Sopenharmony_ciqla8044_flash_write_u32(struct scsi_qla_host *vha, uint32_t addr,
365062306a36Sopenharmony_ci			uint32_t *p_data)
365162306a36Sopenharmony_ci{
365262306a36Sopenharmony_ci	int ret_val = QLA_SUCCESS;
365362306a36Sopenharmony_ci
365462306a36Sopenharmony_ci	ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR,
365562306a36Sopenharmony_ci	    0x00800000 | (addr >> 2));
365662306a36Sopenharmony_ci	if (ret_val) {
365762306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb134,
365862306a36Sopenharmony_ci		    "%s: Failed write to FLASH_ADDR.\n", __func__);
365962306a36Sopenharmony_ci		goto exit_func;
366062306a36Sopenharmony_ci	}
366162306a36Sopenharmony_ci	ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_WRDATA, *p_data);
366262306a36Sopenharmony_ci	if (ret_val) {
366362306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb135,
366462306a36Sopenharmony_ci		    "%s: Failed write to FLASH_WRDATA.\n", __func__);
366562306a36Sopenharmony_ci		goto exit_func;
366662306a36Sopenharmony_ci	}
366762306a36Sopenharmony_ci	ret_val = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL, 0x3D);
366862306a36Sopenharmony_ci	if (ret_val) {
366962306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb136,
367062306a36Sopenharmony_ci		    "%s: Failed write to FLASH_CONTROL.\n", __func__);
367162306a36Sopenharmony_ci		goto exit_func;
367262306a36Sopenharmony_ci	}
367362306a36Sopenharmony_ci	ret_val = qla8044_poll_flash_status_reg(vha);
367462306a36Sopenharmony_ci	if (ret_val) {
367562306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb137,
367662306a36Sopenharmony_ci		    "%s: Poll flash status failed.\n", __func__);
367762306a36Sopenharmony_ci	}
367862306a36Sopenharmony_ci
367962306a36Sopenharmony_ciexit_func:
368062306a36Sopenharmony_ci	return ret_val;
368162306a36Sopenharmony_ci}
368262306a36Sopenharmony_ci
368362306a36Sopenharmony_cistatic int
368462306a36Sopenharmony_ciqla8044_write_flash_buffer_mode(scsi_qla_host_t *vha, uint32_t *dwptr,
368562306a36Sopenharmony_ci				uint32_t faddr, uint32_t dwords)
368662306a36Sopenharmony_ci{
368762306a36Sopenharmony_ci	int ret = QLA_FUNCTION_FAILED;
368862306a36Sopenharmony_ci	uint32_t spi_val;
368962306a36Sopenharmony_ci
369062306a36Sopenharmony_ci	if (dwords < QLA8044_MIN_OPTROM_BURST_DWORDS ||
369162306a36Sopenharmony_ci	    dwords > QLA8044_MAX_OPTROM_BURST_DWORDS) {
369262306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0xb123,
369362306a36Sopenharmony_ci		    "Got unsupported dwords = 0x%x.\n",
369462306a36Sopenharmony_ci		    dwords);
369562306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
369662306a36Sopenharmony_ci	}
369762306a36Sopenharmony_ci
369862306a36Sopenharmony_ci	qla8044_rd_reg_indirect(vha, QLA8044_FLASH_SPI_CONTROL, &spi_val);
369962306a36Sopenharmony_ci	qla8044_wr_reg_indirect(vha, QLA8044_FLASH_SPI_CONTROL,
370062306a36Sopenharmony_ci	    spi_val | QLA8044_FLASH_SPI_CTL);
370162306a36Sopenharmony_ci	qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR,
370262306a36Sopenharmony_ci	    QLA8044_FLASH_FIRST_TEMP_VAL);
370362306a36Sopenharmony_ci
370462306a36Sopenharmony_ci	/* First DWORD write to FLASH_WRDATA */
370562306a36Sopenharmony_ci	ret = qla8044_wr_reg_indirect(vha, QLA8044_FLASH_WRDATA,
370662306a36Sopenharmony_ci	    *dwptr++);
370762306a36Sopenharmony_ci	qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL,
370862306a36Sopenharmony_ci	    QLA8044_FLASH_FIRST_MS_PATTERN);
370962306a36Sopenharmony_ci
371062306a36Sopenharmony_ci	ret = qla8044_poll_flash_status_reg(vha);
371162306a36Sopenharmony_ci	if (ret) {
371262306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb124,
371362306a36Sopenharmony_ci		    "%s: Failed.\n", __func__);
371462306a36Sopenharmony_ci		goto exit_func;
371562306a36Sopenharmony_ci	}
371662306a36Sopenharmony_ci
371762306a36Sopenharmony_ci	dwords--;
371862306a36Sopenharmony_ci
371962306a36Sopenharmony_ci	qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR,
372062306a36Sopenharmony_ci	    QLA8044_FLASH_SECOND_TEMP_VAL);
372162306a36Sopenharmony_ci
372262306a36Sopenharmony_ci
372362306a36Sopenharmony_ci	/* Second to N-1 DWORDS writes */
372462306a36Sopenharmony_ci	while (dwords != 1) {
372562306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha, QLA8044_FLASH_WRDATA, *dwptr++);
372662306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL,
372762306a36Sopenharmony_ci		    QLA8044_FLASH_SECOND_MS_PATTERN);
372862306a36Sopenharmony_ci		ret = qla8044_poll_flash_status_reg(vha);
372962306a36Sopenharmony_ci		if (ret) {
373062306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb129,
373162306a36Sopenharmony_ci			    "%s: Failed.\n", __func__);
373262306a36Sopenharmony_ci			goto exit_func;
373362306a36Sopenharmony_ci		}
373462306a36Sopenharmony_ci		dwords--;
373562306a36Sopenharmony_ci	}
373662306a36Sopenharmony_ci
373762306a36Sopenharmony_ci	qla8044_wr_reg_indirect(vha, QLA8044_FLASH_ADDR,
373862306a36Sopenharmony_ci	    QLA8044_FLASH_FIRST_TEMP_VAL | (faddr >> 2));
373962306a36Sopenharmony_ci
374062306a36Sopenharmony_ci	/* Last DWORD write */
374162306a36Sopenharmony_ci	qla8044_wr_reg_indirect(vha, QLA8044_FLASH_WRDATA, *dwptr++);
374262306a36Sopenharmony_ci	qla8044_wr_reg_indirect(vha, QLA8044_FLASH_CONTROL,
374362306a36Sopenharmony_ci	    QLA8044_FLASH_LAST_MS_PATTERN);
374462306a36Sopenharmony_ci	ret = qla8044_poll_flash_status_reg(vha);
374562306a36Sopenharmony_ci	if (ret) {
374662306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb12a,
374762306a36Sopenharmony_ci		    "%s: Failed.\n", __func__);
374862306a36Sopenharmony_ci		goto exit_func;
374962306a36Sopenharmony_ci	}
375062306a36Sopenharmony_ci	qla8044_rd_reg_indirect(vha, QLA8044_FLASH_SPI_STATUS, &spi_val);
375162306a36Sopenharmony_ci
375262306a36Sopenharmony_ci	if ((spi_val & QLA8044_FLASH_SPI_CTL) == QLA8044_FLASH_SPI_CTL) {
375362306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb12b,
375462306a36Sopenharmony_ci		    "%s: Failed.\n", __func__);
375562306a36Sopenharmony_ci		spi_val = 0;
375662306a36Sopenharmony_ci		/* Operation failed, clear error bit. */
375762306a36Sopenharmony_ci		qla8044_rd_reg_indirect(vha, QLA8044_FLASH_SPI_CONTROL,
375862306a36Sopenharmony_ci		    &spi_val);
375962306a36Sopenharmony_ci		qla8044_wr_reg_indirect(vha, QLA8044_FLASH_SPI_CONTROL,
376062306a36Sopenharmony_ci		    spi_val | QLA8044_FLASH_SPI_CTL);
376162306a36Sopenharmony_ci	}
376262306a36Sopenharmony_ciexit_func:
376362306a36Sopenharmony_ci	return ret;
376462306a36Sopenharmony_ci}
376562306a36Sopenharmony_ci
376662306a36Sopenharmony_cistatic int
376762306a36Sopenharmony_ciqla8044_write_flash_dword_mode(scsi_qla_host_t *vha, uint32_t *dwptr,
376862306a36Sopenharmony_ci			       uint32_t faddr, uint32_t dwords)
376962306a36Sopenharmony_ci{
377062306a36Sopenharmony_ci	int ret = QLA_FUNCTION_FAILED;
377162306a36Sopenharmony_ci	uint32_t liter;
377262306a36Sopenharmony_ci
377362306a36Sopenharmony_ci	for (liter = 0; liter < dwords; liter++, faddr += 4, dwptr++) {
377462306a36Sopenharmony_ci		ret = qla8044_flash_write_u32(vha, faddr, dwptr);
377562306a36Sopenharmony_ci		if (ret) {
377662306a36Sopenharmony_ci			ql_dbg(ql_dbg_p3p, vha, 0xb141,
377762306a36Sopenharmony_ci			    "%s: flash address=%x data=%x.\n", __func__,
377862306a36Sopenharmony_ci			     faddr, *dwptr);
377962306a36Sopenharmony_ci			break;
378062306a36Sopenharmony_ci		}
378162306a36Sopenharmony_ci	}
378262306a36Sopenharmony_ci
378362306a36Sopenharmony_ci	return ret;
378462306a36Sopenharmony_ci}
378562306a36Sopenharmony_ci
378662306a36Sopenharmony_ciint
378762306a36Sopenharmony_ciqla8044_write_optrom_data(struct scsi_qla_host *vha, void *buf,
378862306a36Sopenharmony_ci			  uint32_t offset, uint32_t length)
378962306a36Sopenharmony_ci{
379062306a36Sopenharmony_ci	int rval = QLA_FUNCTION_FAILED, i, burst_iter_count;
379162306a36Sopenharmony_ci	int dword_count, erase_sec_count;
379262306a36Sopenharmony_ci	uint32_t erase_offset;
379362306a36Sopenharmony_ci	uint8_t *p_cache, *p_src;
379462306a36Sopenharmony_ci
379562306a36Sopenharmony_ci	erase_offset = offset;
379662306a36Sopenharmony_ci
379762306a36Sopenharmony_ci	p_cache = kcalloc(length, sizeof(uint8_t), GFP_KERNEL);
379862306a36Sopenharmony_ci	if (!p_cache)
379962306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
380062306a36Sopenharmony_ci
380162306a36Sopenharmony_ci	memcpy(p_cache, buf, length);
380262306a36Sopenharmony_ci	p_src = p_cache;
380362306a36Sopenharmony_ci	dword_count = length / sizeof(uint32_t);
380462306a36Sopenharmony_ci	/* Since the offset and legth are sector aligned, it will be always
380562306a36Sopenharmony_ci	 * multiple of burst_iter_count (64)
380662306a36Sopenharmony_ci	 */
380762306a36Sopenharmony_ci	burst_iter_count = dword_count / QLA8044_MAX_OPTROM_BURST_DWORDS;
380862306a36Sopenharmony_ci	erase_sec_count = length / QLA8044_SECTOR_SIZE;
380962306a36Sopenharmony_ci
381062306a36Sopenharmony_ci	/* Suspend HBA. */
381162306a36Sopenharmony_ci	scsi_block_requests(vha->host);
381262306a36Sopenharmony_ci	/* Lock and enable write for whole operation. */
381362306a36Sopenharmony_ci	qla8044_flash_lock(vha);
381462306a36Sopenharmony_ci	qla8044_unprotect_flash(vha);
381562306a36Sopenharmony_ci
381662306a36Sopenharmony_ci	/* Erasing the sectors */
381762306a36Sopenharmony_ci	for (i = 0; i < erase_sec_count; i++) {
381862306a36Sopenharmony_ci		rval = qla8044_erase_flash_sector(vha, erase_offset);
381962306a36Sopenharmony_ci		ql_dbg(ql_dbg_user, vha, 0xb138,
382062306a36Sopenharmony_ci		    "Done erase of sector=0x%x.\n",
382162306a36Sopenharmony_ci		    erase_offset);
382262306a36Sopenharmony_ci		if (rval) {
382362306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb121,
382462306a36Sopenharmony_ci			    "Failed to erase the sector having address: "
382562306a36Sopenharmony_ci			    "0x%x.\n", erase_offset);
382662306a36Sopenharmony_ci			goto out;
382762306a36Sopenharmony_ci		}
382862306a36Sopenharmony_ci		erase_offset += QLA8044_SECTOR_SIZE;
382962306a36Sopenharmony_ci	}
383062306a36Sopenharmony_ci	ql_dbg(ql_dbg_user, vha, 0xb13f,
383162306a36Sopenharmony_ci	    "Got write for addr = 0x%x length=0x%x.\n",
383262306a36Sopenharmony_ci	    offset, length);
383362306a36Sopenharmony_ci
383462306a36Sopenharmony_ci	for (i = 0; i < burst_iter_count; i++) {
383562306a36Sopenharmony_ci
383662306a36Sopenharmony_ci		/* Go with write. */
383762306a36Sopenharmony_ci		rval = qla8044_write_flash_buffer_mode(vha, (uint32_t *)p_src,
383862306a36Sopenharmony_ci		    offset, QLA8044_MAX_OPTROM_BURST_DWORDS);
383962306a36Sopenharmony_ci		if (rval) {
384062306a36Sopenharmony_ci			/* Buffer Mode failed skip to dword mode */
384162306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb122,
384262306a36Sopenharmony_ci			    "Failed to write flash in buffer mode, "
384362306a36Sopenharmony_ci			    "Reverting to slow-write.\n");
384462306a36Sopenharmony_ci			rval = qla8044_write_flash_dword_mode(vha,
384562306a36Sopenharmony_ci			    (uint32_t *)p_src, offset,
384662306a36Sopenharmony_ci			    QLA8044_MAX_OPTROM_BURST_DWORDS);
384762306a36Sopenharmony_ci		}
384862306a36Sopenharmony_ci		p_src +=  sizeof(uint32_t) * QLA8044_MAX_OPTROM_BURST_DWORDS;
384962306a36Sopenharmony_ci		offset += sizeof(uint32_t) * QLA8044_MAX_OPTROM_BURST_DWORDS;
385062306a36Sopenharmony_ci	}
385162306a36Sopenharmony_ci	ql_dbg(ql_dbg_user, vha, 0xb133,
385262306a36Sopenharmony_ci	    "Done writing.\n");
385362306a36Sopenharmony_ci
385462306a36Sopenharmony_ciout:
385562306a36Sopenharmony_ci	qla8044_protect_flash(vha);
385662306a36Sopenharmony_ci	qla8044_flash_unlock(vha);
385762306a36Sopenharmony_ci	scsi_unblock_requests(vha->host);
385862306a36Sopenharmony_ci	kfree(p_cache);
385962306a36Sopenharmony_ci
386062306a36Sopenharmony_ci	return rval;
386162306a36Sopenharmony_ci}
386262306a36Sopenharmony_ci
386362306a36Sopenharmony_ci#define LEG_INT_PTR_B31		(1 << 31)
386462306a36Sopenharmony_ci#define LEG_INT_PTR_B30		(1 << 30)
386562306a36Sopenharmony_ci#define PF_BITS_MASK		(0xF << 16)
386662306a36Sopenharmony_ci/**
386762306a36Sopenharmony_ci * qla8044_intr_handler() - Process interrupts for the ISP8044
386862306a36Sopenharmony_ci * @irq: interrupt number
386962306a36Sopenharmony_ci * @dev_id: SCSI driver HA context
387062306a36Sopenharmony_ci *
387162306a36Sopenharmony_ci * Called by system whenever the host adapter generates an interrupt.
387262306a36Sopenharmony_ci *
387362306a36Sopenharmony_ci * Returns handled flag.
387462306a36Sopenharmony_ci */
387562306a36Sopenharmony_ciirqreturn_t
387662306a36Sopenharmony_ciqla8044_intr_handler(int irq, void *dev_id)
387762306a36Sopenharmony_ci{
387862306a36Sopenharmony_ci	scsi_qla_host_t	*vha;
387962306a36Sopenharmony_ci	struct qla_hw_data *ha;
388062306a36Sopenharmony_ci	struct rsp_que *rsp;
388162306a36Sopenharmony_ci	struct device_reg_82xx __iomem *reg;
388262306a36Sopenharmony_ci	int		status = 0;
388362306a36Sopenharmony_ci	unsigned long	flags;
388462306a36Sopenharmony_ci	unsigned long	iter;
388562306a36Sopenharmony_ci	uint32_t	stat;
388662306a36Sopenharmony_ci	uint16_t	mb[8];
388762306a36Sopenharmony_ci	uint32_t leg_int_ptr = 0, pf_bit;
388862306a36Sopenharmony_ci
388962306a36Sopenharmony_ci	rsp = (struct rsp_que *) dev_id;
389062306a36Sopenharmony_ci	if (!rsp) {
389162306a36Sopenharmony_ci		ql_log(ql_log_info, NULL, 0xb143,
389262306a36Sopenharmony_ci		    "%s(): NULL response queue pointer\n", __func__);
389362306a36Sopenharmony_ci		return IRQ_NONE;
389462306a36Sopenharmony_ci	}
389562306a36Sopenharmony_ci	ha = rsp->hw;
389662306a36Sopenharmony_ci	vha = pci_get_drvdata(ha->pdev);
389762306a36Sopenharmony_ci
389862306a36Sopenharmony_ci	if (unlikely(pci_channel_offline(ha->pdev)))
389962306a36Sopenharmony_ci		return IRQ_HANDLED;
390062306a36Sopenharmony_ci
390162306a36Sopenharmony_ci	leg_int_ptr = qla8044_rd_reg(ha, LEG_INTR_PTR_OFFSET);
390262306a36Sopenharmony_ci
390362306a36Sopenharmony_ci	/* Legacy interrupt is valid if bit31 of leg_int_ptr is set */
390462306a36Sopenharmony_ci	if (!(leg_int_ptr & (LEG_INT_PTR_B31))) {
390562306a36Sopenharmony_ci		ql_dbg(ql_dbg_p3p, vha, 0xb144,
390662306a36Sopenharmony_ci		    "%s: Legacy Interrupt Bit 31 not set, "
390762306a36Sopenharmony_ci		    "spurious interrupt!\n", __func__);
390862306a36Sopenharmony_ci		return IRQ_NONE;
390962306a36Sopenharmony_ci	}
391062306a36Sopenharmony_ci
391162306a36Sopenharmony_ci	pf_bit = ha->portnum << 16;
391262306a36Sopenharmony_ci	/* Validate the PCIE function ID set in leg_int_ptr bits [19..16] */
391362306a36Sopenharmony_ci	if ((leg_int_ptr & (PF_BITS_MASK)) != pf_bit) {
391462306a36Sopenharmony_ci		ql_dbg(ql_dbg_p3p, vha, 0xb145,
391562306a36Sopenharmony_ci		    "%s: Incorrect function ID 0x%x in "
391662306a36Sopenharmony_ci		    "legacy interrupt register, "
391762306a36Sopenharmony_ci		    "ha->pf_bit = 0x%x\n", __func__,
391862306a36Sopenharmony_ci		    (leg_int_ptr & (PF_BITS_MASK)), pf_bit);
391962306a36Sopenharmony_ci		return IRQ_NONE;
392062306a36Sopenharmony_ci	}
392162306a36Sopenharmony_ci
392262306a36Sopenharmony_ci	/* To de-assert legacy interrupt, write 0 to Legacy Interrupt Trigger
392362306a36Sopenharmony_ci	 * Control register and poll till Legacy Interrupt Pointer register
392462306a36Sopenharmony_ci	 * bit32 is 0.
392562306a36Sopenharmony_ci	 */
392662306a36Sopenharmony_ci	qla8044_wr_reg(ha, LEG_INTR_TRIG_OFFSET, 0);
392762306a36Sopenharmony_ci	do {
392862306a36Sopenharmony_ci		leg_int_ptr = qla8044_rd_reg(ha, LEG_INTR_PTR_OFFSET);
392962306a36Sopenharmony_ci		if ((leg_int_ptr & (PF_BITS_MASK)) != pf_bit)
393062306a36Sopenharmony_ci			break;
393162306a36Sopenharmony_ci	} while (leg_int_ptr & (LEG_INT_PTR_B30));
393262306a36Sopenharmony_ci
393362306a36Sopenharmony_ci	reg = &ha->iobase->isp82;
393462306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
393562306a36Sopenharmony_ci	for (iter = 1; iter--; ) {
393662306a36Sopenharmony_ci
393762306a36Sopenharmony_ci		if (rd_reg_dword(&reg->host_int)) {
393862306a36Sopenharmony_ci			stat = rd_reg_dword(&reg->host_status);
393962306a36Sopenharmony_ci			if ((stat & HSRX_RISC_INT) == 0)
394062306a36Sopenharmony_ci				break;
394162306a36Sopenharmony_ci
394262306a36Sopenharmony_ci			switch (stat & 0xff) {
394362306a36Sopenharmony_ci			case 0x1:
394462306a36Sopenharmony_ci			case 0x2:
394562306a36Sopenharmony_ci			case 0x10:
394662306a36Sopenharmony_ci			case 0x11:
394762306a36Sopenharmony_ci				qla82xx_mbx_completion(vha, MSW(stat));
394862306a36Sopenharmony_ci				status |= MBX_INTERRUPT;
394962306a36Sopenharmony_ci				break;
395062306a36Sopenharmony_ci			case 0x12:
395162306a36Sopenharmony_ci				mb[0] = MSW(stat);
395262306a36Sopenharmony_ci				mb[1] = rd_reg_word(&reg->mailbox_out[1]);
395362306a36Sopenharmony_ci				mb[2] = rd_reg_word(&reg->mailbox_out[2]);
395462306a36Sopenharmony_ci				mb[3] = rd_reg_word(&reg->mailbox_out[3]);
395562306a36Sopenharmony_ci				qla2x00_async_event(vha, rsp, mb);
395662306a36Sopenharmony_ci				break;
395762306a36Sopenharmony_ci			case 0x13:
395862306a36Sopenharmony_ci				qla24xx_process_response_queue(vha, rsp);
395962306a36Sopenharmony_ci				break;
396062306a36Sopenharmony_ci			default:
396162306a36Sopenharmony_ci				ql_dbg(ql_dbg_p3p, vha, 0xb146,
396262306a36Sopenharmony_ci				    "Unrecognized interrupt type "
396362306a36Sopenharmony_ci				    "(%d).\n", stat & 0xff);
396462306a36Sopenharmony_ci				break;
396562306a36Sopenharmony_ci			}
396662306a36Sopenharmony_ci		}
396762306a36Sopenharmony_ci		wrt_reg_dword(&reg->host_int, 0);
396862306a36Sopenharmony_ci	}
396962306a36Sopenharmony_ci
397062306a36Sopenharmony_ci	qla2x00_handle_mbx_completion(ha, status);
397162306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
397262306a36Sopenharmony_ci
397362306a36Sopenharmony_ci	return IRQ_HANDLED;
397462306a36Sopenharmony_ci}
397562306a36Sopenharmony_ci
397662306a36Sopenharmony_cistatic int
397762306a36Sopenharmony_ciqla8044_idc_dontreset(struct qla_hw_data *ha)
397862306a36Sopenharmony_ci{
397962306a36Sopenharmony_ci	uint32_t idc_ctrl;
398062306a36Sopenharmony_ci
398162306a36Sopenharmony_ci	idc_ctrl = qla8044_rd_reg(ha, QLA8044_IDC_DRV_CTRL);
398262306a36Sopenharmony_ci	return idc_ctrl & DONTRESET_BIT0;
398362306a36Sopenharmony_ci}
398462306a36Sopenharmony_ci
398562306a36Sopenharmony_cistatic void
398662306a36Sopenharmony_ciqla8044_clear_rst_ready(scsi_qla_host_t *vha)
398762306a36Sopenharmony_ci{
398862306a36Sopenharmony_ci	uint32_t drv_state;
398962306a36Sopenharmony_ci
399062306a36Sopenharmony_ci	drv_state = qla8044_rd_direct(vha, QLA8044_CRB_DRV_STATE_INDEX);
399162306a36Sopenharmony_ci
399262306a36Sopenharmony_ci	/*
399362306a36Sopenharmony_ci	 * For ISP8044, drv_active register has 1 bit per function,
399462306a36Sopenharmony_ci	 * shift 1 by func_num to set a bit for the function.
399562306a36Sopenharmony_ci	 * For ISP82xx, drv_active has 4 bits per function
399662306a36Sopenharmony_ci	 */
399762306a36Sopenharmony_ci	drv_state &= ~(1 << vha->hw->portnum);
399862306a36Sopenharmony_ci
399962306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb13d,
400062306a36Sopenharmony_ci	    "drv_state: 0x%08x\n", drv_state);
400162306a36Sopenharmony_ci	qla8044_wr_direct(vha, QLA8044_CRB_DRV_STATE_INDEX, drv_state);
400262306a36Sopenharmony_ci}
400362306a36Sopenharmony_ci
400462306a36Sopenharmony_ciint
400562306a36Sopenharmony_ciqla8044_abort_isp(scsi_qla_host_t *vha)
400662306a36Sopenharmony_ci{
400762306a36Sopenharmony_ci	int rval;
400862306a36Sopenharmony_ci	uint32_t dev_state;
400962306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
401062306a36Sopenharmony_ci
401162306a36Sopenharmony_ci	qla8044_idc_lock(ha);
401262306a36Sopenharmony_ci	dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX);
401362306a36Sopenharmony_ci
401462306a36Sopenharmony_ci	if (ql2xdontresethba)
401562306a36Sopenharmony_ci		qla8044_set_idc_dontreset(vha);
401662306a36Sopenharmony_ci
401762306a36Sopenharmony_ci	/* If device_state is NEED_RESET, go ahead with
401862306a36Sopenharmony_ci	 * Reset,irrespective of ql2xdontresethba. This is to allow a
401962306a36Sopenharmony_ci	 * non-reset-owner to force a reset. Non-reset-owner sets
402062306a36Sopenharmony_ci	 * the IDC_CTRL BIT0 to prevent Reset-owner from doing a Reset
402162306a36Sopenharmony_ci	 * and then forces a Reset by setting device_state to
402262306a36Sopenharmony_ci	 * NEED_RESET. */
402362306a36Sopenharmony_ci	if (dev_state == QLA8XXX_DEV_READY) {
402462306a36Sopenharmony_ci		/* If IDC_CTRL DONTRESETHBA_BIT0 is set don't do reset
402562306a36Sopenharmony_ci		 * recovery */
402662306a36Sopenharmony_ci		if (qla8044_idc_dontreset(ha) == DONTRESET_BIT0) {
402762306a36Sopenharmony_ci			ql_dbg(ql_dbg_p3p, vha, 0xb13e,
402862306a36Sopenharmony_ci			    "Reset recovery disabled\n");
402962306a36Sopenharmony_ci			rval = QLA_FUNCTION_FAILED;
403062306a36Sopenharmony_ci			goto exit_isp_reset;
403162306a36Sopenharmony_ci		}
403262306a36Sopenharmony_ci
403362306a36Sopenharmony_ci		ql_dbg(ql_dbg_p3p, vha, 0xb140,
403462306a36Sopenharmony_ci		    "HW State: NEED RESET\n");
403562306a36Sopenharmony_ci		qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
403662306a36Sopenharmony_ci		    QLA8XXX_DEV_NEED_RESET);
403762306a36Sopenharmony_ci	}
403862306a36Sopenharmony_ci
403962306a36Sopenharmony_ci	/* For ISP8044, Reset owner is NIC, iSCSI or FCOE based on priority
404062306a36Sopenharmony_ci	 * and which drivers are present. Unlike ISP82XX, the function setting
404162306a36Sopenharmony_ci	 * NEED_RESET, may not be the Reset owner. */
404262306a36Sopenharmony_ci	qla83xx_reset_ownership(vha);
404362306a36Sopenharmony_ci
404462306a36Sopenharmony_ci	qla8044_idc_unlock(ha);
404562306a36Sopenharmony_ci	rval = qla8044_device_state_handler(vha);
404662306a36Sopenharmony_ci	qla8044_idc_lock(ha);
404762306a36Sopenharmony_ci	qla8044_clear_rst_ready(vha);
404862306a36Sopenharmony_ci
404962306a36Sopenharmony_ciexit_isp_reset:
405062306a36Sopenharmony_ci	qla8044_idc_unlock(ha);
405162306a36Sopenharmony_ci	if (rval == QLA_SUCCESS) {
405262306a36Sopenharmony_ci		ha->flags.isp82xx_fw_hung = 0;
405362306a36Sopenharmony_ci		ha->flags.nic_core_reset_hdlr_active = 0;
405462306a36Sopenharmony_ci		rval = qla82xx_restart_isp(vha);
405562306a36Sopenharmony_ci	}
405662306a36Sopenharmony_ci
405762306a36Sopenharmony_ci	return rval;
405862306a36Sopenharmony_ci}
405962306a36Sopenharmony_ci
406062306a36Sopenharmony_civoid
406162306a36Sopenharmony_ciqla8044_fw_dump(scsi_qla_host_t *vha)
406262306a36Sopenharmony_ci{
406362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
406462306a36Sopenharmony_ci
406562306a36Sopenharmony_ci	if (!ha->allow_cna_fw_dump)
406662306a36Sopenharmony_ci		return;
406762306a36Sopenharmony_ci
406862306a36Sopenharmony_ci	scsi_block_requests(vha->host);
406962306a36Sopenharmony_ci	ha->flags.isp82xx_no_md_cap = 1;
407062306a36Sopenharmony_ci	qla8044_idc_lock(ha);
407162306a36Sopenharmony_ci	qla82xx_set_reset_owner(vha);
407262306a36Sopenharmony_ci	qla8044_idc_unlock(ha);
407362306a36Sopenharmony_ci	qla2x00_wait_for_chip_reset(vha);
407462306a36Sopenharmony_ci	scsi_unblock_requests(vha->host);
407562306a36Sopenharmony_ci}
4076