162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * QLogic iSCSI HBA Driver
462306a36Sopenharmony_ci * Copyright (c)  2003-2013 QLogic Corporation
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include <linux/delay.h>
762306a36Sopenharmony_ci#include <linux/io.h>
862306a36Sopenharmony_ci#include <linux/pci.h>
962306a36Sopenharmony_ci#include <linux/ratelimit.h>
1062306a36Sopenharmony_ci#include "ql4_def.h"
1162306a36Sopenharmony_ci#include "ql4_glbl.h"
1262306a36Sopenharmony_ci#include "ql4_inline.h"
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <linux/io-64-nonatomic-lo-hi.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#define TIMEOUT_100_MS	100
1762306a36Sopenharmony_ci#define MASK(n)		DMA_BIT_MASK(n)
1862306a36Sopenharmony_ci#define MN_WIN(addr)	(((addr & 0x1fc0000) >> 1) | ((addr >> 25) & 0x3ff))
1962306a36Sopenharmony_ci#define OCM_WIN(addr)	(((addr & 0x1ff0000) >> 1) | ((addr >> 25) & 0x3ff))
2062306a36Sopenharmony_ci#define MS_WIN(addr)	(addr & 0x0ffc0000)
2162306a36Sopenharmony_ci#define QLA82XX_PCI_MN_2M	(0)
2262306a36Sopenharmony_ci#define QLA82XX_PCI_MS_2M	(0x80000)
2362306a36Sopenharmony_ci#define QLA82XX_PCI_OCM0_2M	(0xc0000)
2462306a36Sopenharmony_ci#define VALID_OCM_ADDR(addr)	(((addr) & 0x3f800) != 0x3f800)
2562306a36Sopenharmony_ci#define GET_MEM_OFFS_2M(addr)	(addr & MASK(18))
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/* CRB window related */
2862306a36Sopenharmony_ci#define CRB_BLK(off)	((off >> 20) & 0x3f)
2962306a36Sopenharmony_ci#define CRB_SUBBLK(off)	((off >> 16) & 0xf)
3062306a36Sopenharmony_ci#define CRB_WINDOW_2M	(0x130060)
3162306a36Sopenharmony_ci#define CRB_HI(off)	((qla4_82xx_crb_hub_agt[CRB_BLK(off)] << 20) | \
3262306a36Sopenharmony_ci			((off) & 0xf0000))
3362306a36Sopenharmony_ci#define QLA82XX_PCI_CAMQM_2M_END	(0x04800800UL)
3462306a36Sopenharmony_ci#define QLA82XX_PCI_CAMQM_2M_BASE	(0x000ff800UL)
3562306a36Sopenharmony_ci#define CRB_INDIRECT_2M			(0x1e0000UL)
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic inline void __iomem *
3862306a36Sopenharmony_ciqla4_8xxx_pci_base_offsetfset(struct scsi_qla_host *ha, unsigned long off)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	if ((off < ha->first_page_group_end) &&
4162306a36Sopenharmony_ci	    (off >= ha->first_page_group_start))
4262306a36Sopenharmony_ci		return (void __iomem *)(ha->nx_pcibase + off);
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci	return NULL;
4562306a36Sopenharmony_ci}
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_cistatic const int MD_MIU_TEST_AGT_RDDATA[] = { 0x410000A8,
4862306a36Sopenharmony_ci				0x410000AC, 0x410000B8, 0x410000BC };
4962306a36Sopenharmony_ci#define MAX_CRB_XFORM 60
5062306a36Sopenharmony_cistatic unsigned long crb_addr_xform[MAX_CRB_XFORM];
5162306a36Sopenharmony_cistatic int qla4_8xxx_crb_table_initialized;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci#define qla4_8xxx_crb_addr_transform(name) \
5462306a36Sopenharmony_ci	(crb_addr_xform[QLA82XX_HW_PX_MAP_CRB_##name] = \
5562306a36Sopenharmony_ci	 QLA82XX_HW_CRB_HUB_AGT_ADR_##name << 20)
5662306a36Sopenharmony_cistatic void
5762306a36Sopenharmony_ciqla4_82xx_crb_addr_transform_setup(void)
5862306a36Sopenharmony_ci{
5962306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(XDMA);
6062306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(TIMR);
6162306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(SRE);
6262306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(SQN3);
6362306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(SQN2);
6462306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(SQN1);
6562306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(SQN0);
6662306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(SQS3);
6762306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(SQS2);
6862306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(SQS1);
6962306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(SQS0);
7062306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(RPMX7);
7162306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(RPMX6);
7262306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(RPMX5);
7362306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(RPMX4);
7462306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(RPMX3);
7562306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(RPMX2);
7662306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(RPMX1);
7762306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(RPMX0);
7862306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(ROMUSB);
7962306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(SN);
8062306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(QMN);
8162306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(QMS);
8262306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(PGNI);
8362306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(PGND);
8462306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(PGN3);
8562306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(PGN2);
8662306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(PGN1);
8762306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(PGN0);
8862306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(PGSI);
8962306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(PGSD);
9062306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(PGS3);
9162306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(PGS2);
9262306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(PGS1);
9362306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(PGS0);
9462306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(PS);
9562306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(PH);
9662306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(NIU);
9762306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(I2Q);
9862306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(EG);
9962306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(MN);
10062306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(MS);
10162306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(CAS2);
10262306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(CAS1);
10362306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(CAS0);
10462306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(CAM);
10562306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(C2C1);
10662306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(C2C0);
10762306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(SMB);
10862306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(OCM0);
10962306a36Sopenharmony_ci	qla4_8xxx_crb_addr_transform(I2C0);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	qla4_8xxx_crb_table_initialized = 1;
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic struct crb_128M_2M_block_map crb_128M_2M_map[64] = {
11562306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },		/* 0: PCI */
11662306a36Sopenharmony_ci	{{{1, 0x0100000, 0x0102000, 0x120000},	/* 1: PCIE */
11762306a36Sopenharmony_ci		{1, 0x0110000, 0x0120000, 0x130000},
11862306a36Sopenharmony_ci		{1, 0x0120000, 0x0122000, 0x124000},
11962306a36Sopenharmony_ci		{1, 0x0130000, 0x0132000, 0x126000},
12062306a36Sopenharmony_ci		{1, 0x0140000, 0x0142000, 0x128000},
12162306a36Sopenharmony_ci		{1, 0x0150000, 0x0152000, 0x12a000},
12262306a36Sopenharmony_ci		{1, 0x0160000, 0x0170000, 0x110000},
12362306a36Sopenharmony_ci		{1, 0x0170000, 0x0172000, 0x12e000},
12462306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
12562306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
12662306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
12762306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
12862306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
12962306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
13062306a36Sopenharmony_ci		{1, 0x01e0000, 0x01e0800, 0x122000},
13162306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000} } },
13262306a36Sopenharmony_ci	{{{1, 0x0200000, 0x0210000, 0x180000} } },/* 2: MN */
13362306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },	    /* 3: */
13462306a36Sopenharmony_ci	{{{1, 0x0400000, 0x0401000, 0x169000} } },/* 4: P2NR1 */
13562306a36Sopenharmony_ci	{{{1, 0x0500000, 0x0510000, 0x140000} } },/* 5: SRE   */
13662306a36Sopenharmony_ci	{{{1, 0x0600000, 0x0610000, 0x1c0000} } },/* 6: NIU   */
13762306a36Sopenharmony_ci	{{{1, 0x0700000, 0x0704000, 0x1b8000} } },/* 7: QM    */
13862306a36Sopenharmony_ci	{{{1, 0x0800000, 0x0802000, 0x170000},  /* 8: SQM0  */
13962306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
14062306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
14162306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
14262306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
14362306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
14462306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
14562306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
14662306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
14762306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
14862306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
14962306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
15062306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
15162306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
15262306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
15362306a36Sopenharmony_ci		{1, 0x08f0000, 0x08f2000, 0x172000} } },
15462306a36Sopenharmony_ci	{{{1, 0x0900000, 0x0902000, 0x174000},	/* 9: SQM1*/
15562306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
15662306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
15762306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
15862306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
15962306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
16062306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
16162306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
16262306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
16362306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
16462306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
16562306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
16662306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
16762306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
16862306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
16962306a36Sopenharmony_ci		{1, 0x09f0000, 0x09f2000, 0x176000} } },
17062306a36Sopenharmony_ci	{{{0, 0x0a00000, 0x0a02000, 0x178000},	/* 10: SQM2*/
17162306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
17262306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
17362306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
17462306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
17562306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
17662306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
17762306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
17862306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
17962306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
18062306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
18162306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
18262306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
18362306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
18462306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
18562306a36Sopenharmony_ci		{1, 0x0af0000, 0x0af2000, 0x17a000} } },
18662306a36Sopenharmony_ci	{{{0, 0x0b00000, 0x0b02000, 0x17c000},	/* 11: SQM3*/
18762306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
18862306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
18962306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
19062306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
19162306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
19262306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
19362306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
19462306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
19562306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
19662306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
19762306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
19862306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
19962306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
20062306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
20162306a36Sopenharmony_ci		{1, 0x0bf0000, 0x0bf2000, 0x17e000} } },
20262306a36Sopenharmony_ci	{{{1, 0x0c00000, 0x0c04000, 0x1d4000} } },/* 12: I2Q */
20362306a36Sopenharmony_ci	{{{1, 0x0d00000, 0x0d04000, 0x1a4000} } },/* 13: TMR */
20462306a36Sopenharmony_ci	{{{1, 0x0e00000, 0x0e04000, 0x1a0000} } },/* 14: ROMUSB */
20562306a36Sopenharmony_ci	{{{1, 0x0f00000, 0x0f01000, 0x164000} } },/* 15: PEG4 */
20662306a36Sopenharmony_ci	{{{0, 0x1000000, 0x1004000, 0x1a8000} } },/* 16: XDMA */
20762306a36Sopenharmony_ci	{{{1, 0x1100000, 0x1101000, 0x160000} } },/* 17: PEG0 */
20862306a36Sopenharmony_ci	{{{1, 0x1200000, 0x1201000, 0x161000} } },/* 18: PEG1 */
20962306a36Sopenharmony_ci	{{{1, 0x1300000, 0x1301000, 0x162000} } },/* 19: PEG2 */
21062306a36Sopenharmony_ci	{{{1, 0x1400000, 0x1401000, 0x163000} } },/* 20: PEG3 */
21162306a36Sopenharmony_ci	{{{1, 0x1500000, 0x1501000, 0x165000} } },/* 21: P2ND */
21262306a36Sopenharmony_ci	{{{1, 0x1600000, 0x1601000, 0x166000} } },/* 22: P2NI */
21362306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },	/* 23: */
21462306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },	/* 24: */
21562306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },	/* 25: */
21662306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },	/* 26: */
21762306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },	/* 27: */
21862306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },	/* 28: */
21962306a36Sopenharmony_ci	{{{1, 0x1d00000, 0x1d10000, 0x190000} } },/* 29: MS */
22062306a36Sopenharmony_ci	{{{1, 0x1e00000, 0x1e01000, 0x16a000} } },/* 30: P2NR2 */
22162306a36Sopenharmony_ci	{{{1, 0x1f00000, 0x1f10000, 0x150000} } },/* 31: EPG */
22262306a36Sopenharmony_ci	{{{0} } },				/* 32: PCI */
22362306a36Sopenharmony_ci	{{{1, 0x2100000, 0x2102000, 0x120000},	/* 33: PCIE */
22462306a36Sopenharmony_ci		{1, 0x2110000, 0x2120000, 0x130000},
22562306a36Sopenharmony_ci		{1, 0x2120000, 0x2122000, 0x124000},
22662306a36Sopenharmony_ci		{1, 0x2130000, 0x2132000, 0x126000},
22762306a36Sopenharmony_ci		{1, 0x2140000, 0x2142000, 0x128000},
22862306a36Sopenharmony_ci		{1, 0x2150000, 0x2152000, 0x12a000},
22962306a36Sopenharmony_ci		{1, 0x2160000, 0x2170000, 0x110000},
23062306a36Sopenharmony_ci		{1, 0x2170000, 0x2172000, 0x12e000},
23162306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
23262306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
23362306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
23462306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
23562306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
23662306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
23762306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000},
23862306a36Sopenharmony_ci		{0, 0x0000000, 0x0000000, 0x000000} } },
23962306a36Sopenharmony_ci	{{{1, 0x2200000, 0x2204000, 0x1b0000} } },/* 34: CAM */
24062306a36Sopenharmony_ci	{{{0} } },				/* 35: */
24162306a36Sopenharmony_ci	{{{0} } },				/* 36: */
24262306a36Sopenharmony_ci	{{{0} } },				/* 37: */
24362306a36Sopenharmony_ci	{{{0} } },				/* 38: */
24462306a36Sopenharmony_ci	{{{0} } },				/* 39: */
24562306a36Sopenharmony_ci	{{{1, 0x2800000, 0x2804000, 0x1a4000} } },/* 40: TMR */
24662306a36Sopenharmony_ci	{{{1, 0x2900000, 0x2901000, 0x16b000} } },/* 41: P2NR3 */
24762306a36Sopenharmony_ci	{{{1, 0x2a00000, 0x2a00400, 0x1ac400} } },/* 42: RPMX1 */
24862306a36Sopenharmony_ci	{{{1, 0x2b00000, 0x2b00400, 0x1ac800} } },/* 43: RPMX2 */
24962306a36Sopenharmony_ci	{{{1, 0x2c00000, 0x2c00400, 0x1acc00} } },/* 44: RPMX3 */
25062306a36Sopenharmony_ci	{{{1, 0x2d00000, 0x2d00400, 0x1ad000} } },/* 45: RPMX4 */
25162306a36Sopenharmony_ci	{{{1, 0x2e00000, 0x2e00400, 0x1ad400} } },/* 46: RPMX5 */
25262306a36Sopenharmony_ci	{{{1, 0x2f00000, 0x2f00400, 0x1ad800} } },/* 47: RPMX6 */
25362306a36Sopenharmony_ci	{{{1, 0x3000000, 0x3000400, 0x1adc00} } },/* 48: RPMX7 */
25462306a36Sopenharmony_ci	{{{0, 0x3100000, 0x3104000, 0x1a8000} } },/* 49: XDMA */
25562306a36Sopenharmony_ci	{{{1, 0x3200000, 0x3204000, 0x1d4000} } },/* 50: I2Q */
25662306a36Sopenharmony_ci	{{{1, 0x3300000, 0x3304000, 0x1a0000} } },/* 51: ROMUSB */
25762306a36Sopenharmony_ci	{{{0} } },				/* 52: */
25862306a36Sopenharmony_ci	{{{1, 0x3500000, 0x3500400, 0x1ac000} } },/* 53: RPMX0 */
25962306a36Sopenharmony_ci	{{{1, 0x3600000, 0x3600400, 0x1ae000} } },/* 54: RPMX8 */
26062306a36Sopenharmony_ci	{{{1, 0x3700000, 0x3700400, 0x1ae400} } },/* 55: RPMX9 */
26162306a36Sopenharmony_ci	{{{1, 0x3800000, 0x3804000, 0x1d0000} } },/* 56: OCM0 */
26262306a36Sopenharmony_ci	{{{1, 0x3900000, 0x3904000, 0x1b4000} } },/* 57: CRYPTO */
26362306a36Sopenharmony_ci	{{{1, 0x3a00000, 0x3a04000, 0x1d8000} } },/* 58: SMB */
26462306a36Sopenharmony_ci	{{{0} } },				/* 59: I2C0 */
26562306a36Sopenharmony_ci	{{{0} } },				/* 60: I2C1 */
26662306a36Sopenharmony_ci	{{{1, 0x3d00000, 0x3d04000, 0x1dc000} } },/* 61: LPC */
26762306a36Sopenharmony_ci	{{{1, 0x3e00000, 0x3e01000, 0x167000} } },/* 62: P2NC */
26862306a36Sopenharmony_ci	{{{1, 0x3f00000, 0x3f01000, 0x168000} } }	/* 63: P2NR0 */
26962306a36Sopenharmony_ci};
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci/*
27262306a36Sopenharmony_ci * top 12 bits of crb internal address (hub, agent)
27362306a36Sopenharmony_ci */
27462306a36Sopenharmony_cistatic unsigned qla4_82xx_crb_hub_agt[64] = {
27562306a36Sopenharmony_ci	0,
27662306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PS,
27762306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_MN,
27862306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_MS,
27962306a36Sopenharmony_ci	0,
28062306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_SRE,
28162306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_NIU,
28262306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_QMN,
28362306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_SQN0,
28462306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_SQN1,
28562306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_SQN2,
28662306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_SQN3,
28762306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q,
28862306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR,
28962306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB,
29062306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGN4,
29162306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA,
29262306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGN0,
29362306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGN1,
29462306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGN2,
29562306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGN3,
29662306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGND,
29762306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGNI,
29862306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGS0,
29962306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGS1,
30062306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGS2,
30162306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGS3,
30262306a36Sopenharmony_ci	0,
30362306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGSI,
30462306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_SN,
30562306a36Sopenharmony_ci	0,
30662306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_EG,
30762306a36Sopenharmony_ci	0,
30862306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PS,
30962306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_CAM,
31062306a36Sopenharmony_ci	0,
31162306a36Sopenharmony_ci	0,
31262306a36Sopenharmony_ci	0,
31362306a36Sopenharmony_ci	0,
31462306a36Sopenharmony_ci	0,
31562306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR,
31662306a36Sopenharmony_ci	0,
31762306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX1,
31862306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX2,
31962306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX3,
32062306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX4,
32162306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX5,
32262306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX6,
32362306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX7,
32462306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA,
32562306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q,
32662306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB,
32762306a36Sopenharmony_ci	0,
32862306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX0,
32962306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX8,
33062306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX9,
33162306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_OCM0,
33262306a36Sopenharmony_ci	0,
33362306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_SMB,
33462306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_I2C0,
33562306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_I2C1,
33662306a36Sopenharmony_ci	0,
33762306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGNC,
33862306a36Sopenharmony_ci	0,
33962306a36Sopenharmony_ci};
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ci/* Device states */
34262306a36Sopenharmony_cistatic char *qdev_state[] = {
34362306a36Sopenharmony_ci	"Unknown",
34462306a36Sopenharmony_ci	"Cold",
34562306a36Sopenharmony_ci	"Initializing",
34662306a36Sopenharmony_ci	"Ready",
34762306a36Sopenharmony_ci	"Need Reset",
34862306a36Sopenharmony_ci	"Need Quiescent",
34962306a36Sopenharmony_ci	"Failed",
35062306a36Sopenharmony_ci	"Quiescent",
35162306a36Sopenharmony_ci};
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci/*
35462306a36Sopenharmony_ci * In: 'off' is offset from CRB space in 128M pci map
35562306a36Sopenharmony_ci * Out: 'off' is 2M pci map addr
35662306a36Sopenharmony_ci * side effect: lock crb window
35762306a36Sopenharmony_ci */
35862306a36Sopenharmony_cistatic void
35962306a36Sopenharmony_ciqla4_82xx_pci_set_crbwindow_2M(struct scsi_qla_host *ha, ulong *off)
36062306a36Sopenharmony_ci{
36162306a36Sopenharmony_ci	u32 win_read;
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci	ha->crb_win = CRB_HI(*off);
36462306a36Sopenharmony_ci	writel(ha->crb_win,
36562306a36Sopenharmony_ci		(void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase));
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci	/* Read back value to make sure write has gone through before trying
36862306a36Sopenharmony_ci	* to use it. */
36962306a36Sopenharmony_ci	win_read = readl((void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase));
37062306a36Sopenharmony_ci	if (win_read != ha->crb_win) {
37162306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
37262306a36Sopenharmony_ci		    "%s: Written crbwin (0x%x) != Read crbwin (0x%x),"
37362306a36Sopenharmony_ci		    " off=0x%lx\n", __func__, ha->crb_win, win_read, *off));
37462306a36Sopenharmony_ci	}
37562306a36Sopenharmony_ci	*off = (*off & MASK(16)) + CRB_INDIRECT_2M + ha->nx_pcibase;
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci#define CRB_WIN_LOCK_TIMEOUT 100000000
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci/*
38162306a36Sopenharmony_ci * Context: atomic
38262306a36Sopenharmony_ci */
38362306a36Sopenharmony_cistatic int qla4_82xx_crb_win_lock(struct scsi_qla_host *ha)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	int done = 0, timeout = 0;
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	while (!done) {
38862306a36Sopenharmony_ci		/* acquire semaphore3 from PCI HW block */
38962306a36Sopenharmony_ci		done = qla4_82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_LOCK));
39062306a36Sopenharmony_ci		if (done == 1)
39162306a36Sopenharmony_ci			break;
39262306a36Sopenharmony_ci		if (timeout >= CRB_WIN_LOCK_TIMEOUT)
39362306a36Sopenharmony_ci			return -1;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci		timeout++;
39662306a36Sopenharmony_ci		udelay(10);
39762306a36Sopenharmony_ci	}
39862306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_WIN_LOCK_ID, ha->func_num);
39962306a36Sopenharmony_ci	return 0;
40062306a36Sopenharmony_ci}
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_civoid qla4_82xx_crb_win_unlock(struct scsi_qla_host *ha)
40362306a36Sopenharmony_ci{
40462306a36Sopenharmony_ci	qla4_82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK));
40562306a36Sopenharmony_ci}
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_civoid
40862306a36Sopenharmony_ciqla4_82xx_wr_32(struct scsi_qla_host *ha, ulong off, u32 data)
40962306a36Sopenharmony_ci{
41062306a36Sopenharmony_ci	unsigned long flags = 0;
41162306a36Sopenharmony_ci	int rv;
41262306a36Sopenharmony_ci
41362306a36Sopenharmony_ci	rv = qla4_82xx_pci_get_crb_addr_2M(ha, &off);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	BUG_ON(rv == -1);
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	if (rv == 1) {
41862306a36Sopenharmony_ci		write_lock_irqsave(&ha->hw_lock, flags);
41962306a36Sopenharmony_ci		qla4_82xx_crb_win_lock(ha);
42062306a36Sopenharmony_ci		qla4_82xx_pci_set_crbwindow_2M(ha, &off);
42162306a36Sopenharmony_ci	}
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ci	writel(data, (void __iomem *)off);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	if (rv == 1) {
42662306a36Sopenharmony_ci		qla4_82xx_crb_win_unlock(ha);
42762306a36Sopenharmony_ci		write_unlock_irqrestore(&ha->hw_lock, flags);
42862306a36Sopenharmony_ci	}
42962306a36Sopenharmony_ci}
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ciuint32_t qla4_82xx_rd_32(struct scsi_qla_host *ha, ulong off)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	unsigned long flags = 0;
43462306a36Sopenharmony_ci	int rv;
43562306a36Sopenharmony_ci	u32 data;
43662306a36Sopenharmony_ci
43762306a36Sopenharmony_ci	rv = qla4_82xx_pci_get_crb_addr_2M(ha, &off);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	BUG_ON(rv == -1);
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	if (rv == 1) {
44262306a36Sopenharmony_ci		write_lock_irqsave(&ha->hw_lock, flags);
44362306a36Sopenharmony_ci		qla4_82xx_crb_win_lock(ha);
44462306a36Sopenharmony_ci		qla4_82xx_pci_set_crbwindow_2M(ha, &off);
44562306a36Sopenharmony_ci	}
44662306a36Sopenharmony_ci	data = readl((void __iomem *)off);
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	if (rv == 1) {
44962306a36Sopenharmony_ci		qla4_82xx_crb_win_unlock(ha);
45062306a36Sopenharmony_ci		write_unlock_irqrestore(&ha->hw_lock, flags);
45162306a36Sopenharmony_ci	}
45262306a36Sopenharmony_ci	return data;
45362306a36Sopenharmony_ci}
45462306a36Sopenharmony_ci
45562306a36Sopenharmony_ci/* Minidump related functions */
45662306a36Sopenharmony_ciint qla4_82xx_md_rd_32(struct scsi_qla_host *ha, uint32_t off, uint32_t *data)
45762306a36Sopenharmony_ci{
45862306a36Sopenharmony_ci	uint32_t win_read, off_value;
45962306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	off_value  = off & 0xFFFF0000;
46262306a36Sopenharmony_ci	writel(off_value, (void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase));
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	/*
46562306a36Sopenharmony_ci	 * Read back value to make sure write has gone through before trying
46662306a36Sopenharmony_ci	 * to use it.
46762306a36Sopenharmony_ci	 */
46862306a36Sopenharmony_ci	win_read = readl((void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase));
46962306a36Sopenharmony_ci	if (win_read != off_value) {
47062306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
47162306a36Sopenharmony_ci				  "%s: Written (0x%x) != Read (0x%x), off=0x%x\n",
47262306a36Sopenharmony_ci				  __func__, off_value, win_read, off));
47362306a36Sopenharmony_ci		rval = QLA_ERROR;
47462306a36Sopenharmony_ci	} else {
47562306a36Sopenharmony_ci		off_value  = off & 0x0000FFFF;
47662306a36Sopenharmony_ci		*data = readl((void __iomem *)(off_value + CRB_INDIRECT_2M +
47762306a36Sopenharmony_ci					       ha->nx_pcibase));
47862306a36Sopenharmony_ci	}
47962306a36Sopenharmony_ci	return rval;
48062306a36Sopenharmony_ci}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ciint qla4_82xx_md_wr_32(struct scsi_qla_host *ha, uint32_t off, uint32_t data)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	uint32_t win_read, off_value;
48562306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
48662306a36Sopenharmony_ci
48762306a36Sopenharmony_ci	off_value  = off & 0xFFFF0000;
48862306a36Sopenharmony_ci	writel(off_value, (void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase));
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci	/* Read back value to make sure write has gone through before trying
49162306a36Sopenharmony_ci	 * to use it.
49262306a36Sopenharmony_ci	 */
49362306a36Sopenharmony_ci	win_read = readl((void __iomem *)(CRB_WINDOW_2M + ha->nx_pcibase));
49462306a36Sopenharmony_ci	if (win_read != off_value) {
49562306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
49662306a36Sopenharmony_ci				  "%s: Written (0x%x) != Read (0x%x), off=0x%x\n",
49762306a36Sopenharmony_ci				  __func__, off_value, win_read, off));
49862306a36Sopenharmony_ci		rval = QLA_ERROR;
49962306a36Sopenharmony_ci	} else {
50062306a36Sopenharmony_ci		off_value  = off & 0x0000FFFF;
50162306a36Sopenharmony_ci		writel(data, (void __iomem *)(off_value + CRB_INDIRECT_2M +
50262306a36Sopenharmony_ci					      ha->nx_pcibase));
50362306a36Sopenharmony_ci	}
50462306a36Sopenharmony_ci	return rval;
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci#define IDC_LOCK_TIMEOUT 100000000
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci/**
51062306a36Sopenharmony_ci * qla4_82xx_idc_lock - hw_lock
51162306a36Sopenharmony_ci * @ha: pointer to adapter structure
51262306a36Sopenharmony_ci *
51362306a36Sopenharmony_ci * General purpose lock used to synchronize access to
51462306a36Sopenharmony_ci * CRB_DEV_STATE, CRB_DEV_REF_COUNT, etc.
51562306a36Sopenharmony_ci *
51662306a36Sopenharmony_ci * Context: task, can sleep
51762306a36Sopenharmony_ci **/
51862306a36Sopenharmony_ciint qla4_82xx_idc_lock(struct scsi_qla_host *ha)
51962306a36Sopenharmony_ci{
52062306a36Sopenharmony_ci	int done = 0, timeout = 0;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	might_sleep();
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	while (!done) {
52562306a36Sopenharmony_ci		/* acquire semaphore5 from PCI HW block */
52662306a36Sopenharmony_ci		done = qla4_82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_LOCK));
52762306a36Sopenharmony_ci		if (done == 1)
52862306a36Sopenharmony_ci			break;
52962306a36Sopenharmony_ci		if (timeout >= IDC_LOCK_TIMEOUT)
53062306a36Sopenharmony_ci			return -1;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci		timeout++;
53362306a36Sopenharmony_ci		msleep(100);
53462306a36Sopenharmony_ci	}
53562306a36Sopenharmony_ci	return 0;
53662306a36Sopenharmony_ci}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_civoid qla4_82xx_idc_unlock(struct scsi_qla_host *ha)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	qla4_82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_UNLOCK));
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_ciint
54462306a36Sopenharmony_ciqla4_82xx_pci_get_crb_addr_2M(struct scsi_qla_host *ha, ulong *off)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	struct crb_128M_2M_sub_block_map *m;
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	if (*off >= QLA82XX_CRB_MAX)
54962306a36Sopenharmony_ci		return -1;
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	if (*off >= QLA82XX_PCI_CAMQM && (*off < QLA82XX_PCI_CAMQM_2M_END)) {
55262306a36Sopenharmony_ci		*off = (*off - QLA82XX_PCI_CAMQM) +
55362306a36Sopenharmony_ci		    QLA82XX_PCI_CAMQM_2M_BASE + ha->nx_pcibase;
55462306a36Sopenharmony_ci		return 0;
55562306a36Sopenharmony_ci	}
55662306a36Sopenharmony_ci
55762306a36Sopenharmony_ci	if (*off < QLA82XX_PCI_CRBSPACE)
55862306a36Sopenharmony_ci		return -1;
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	*off -= QLA82XX_PCI_CRBSPACE;
56162306a36Sopenharmony_ci	/*
56262306a36Sopenharmony_ci	 * Try direct map
56362306a36Sopenharmony_ci	 */
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	m = &crb_128M_2M_map[CRB_BLK(*off)].sub_block[CRB_SUBBLK(*off)];
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	if (m->valid && (m->start_128M <= *off) && (m->end_128M > *off)) {
56862306a36Sopenharmony_ci		*off = *off + m->start_2M - m->start_128M + ha->nx_pcibase;
56962306a36Sopenharmony_ci		return 0;
57062306a36Sopenharmony_ci	}
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	/*
57362306a36Sopenharmony_ci	 * Not in direct map, use crb window
57462306a36Sopenharmony_ci	 */
57562306a36Sopenharmony_ci	return 1;
57662306a36Sopenharmony_ci}
57762306a36Sopenharmony_ci
57862306a36Sopenharmony_ci/*
57962306a36Sopenharmony_ci* check memory access boundary.
58062306a36Sopenharmony_ci* used by test agent. support ddr access only for now
58162306a36Sopenharmony_ci*/
58262306a36Sopenharmony_cistatic unsigned long
58362306a36Sopenharmony_ciqla4_82xx_pci_mem_bound_check(struct scsi_qla_host *ha,
58462306a36Sopenharmony_ci		unsigned long long addr, int size)
58562306a36Sopenharmony_ci{
58662306a36Sopenharmony_ci	if (!QLA8XXX_ADDR_IN_RANGE(addr, QLA8XXX_ADDR_DDR_NET,
58762306a36Sopenharmony_ci	    QLA8XXX_ADDR_DDR_NET_MAX) ||
58862306a36Sopenharmony_ci	    !QLA8XXX_ADDR_IN_RANGE(addr + size - 1,
58962306a36Sopenharmony_ci	    QLA8XXX_ADDR_DDR_NET, QLA8XXX_ADDR_DDR_NET_MAX) ||
59062306a36Sopenharmony_ci	    ((size != 1) && (size != 2) && (size != 4) && (size != 8))) {
59162306a36Sopenharmony_ci		return 0;
59262306a36Sopenharmony_ci	}
59362306a36Sopenharmony_ci	return 1;
59462306a36Sopenharmony_ci}
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_cistatic int qla4_82xx_pci_set_window_warning_count;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cistatic unsigned long
59962306a36Sopenharmony_ciqla4_82xx_pci_set_window(struct scsi_qla_host *ha, unsigned long long addr)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	int window;
60262306a36Sopenharmony_ci	u32 win_read;
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_ci	if (QLA8XXX_ADDR_IN_RANGE(addr, QLA8XXX_ADDR_DDR_NET,
60562306a36Sopenharmony_ci	    QLA8XXX_ADDR_DDR_NET_MAX)) {
60662306a36Sopenharmony_ci		/* DDR network side */
60762306a36Sopenharmony_ci		window = MN_WIN(addr);
60862306a36Sopenharmony_ci		ha->ddr_mn_window = window;
60962306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, ha->mn_win_crb |
61062306a36Sopenharmony_ci		    QLA82XX_PCI_CRBSPACE, window);
61162306a36Sopenharmony_ci		win_read = qla4_82xx_rd_32(ha, ha->mn_win_crb |
61262306a36Sopenharmony_ci		    QLA82XX_PCI_CRBSPACE);
61362306a36Sopenharmony_ci		if ((win_read << 17) != window) {
61462306a36Sopenharmony_ci			ql4_printk(KERN_WARNING, ha,
61562306a36Sopenharmony_ci			"%s: Written MNwin (0x%x) != Read MNwin (0x%x)\n",
61662306a36Sopenharmony_ci			__func__, window, win_read);
61762306a36Sopenharmony_ci		}
61862306a36Sopenharmony_ci		addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_DDR_NET;
61962306a36Sopenharmony_ci	} else if (QLA8XXX_ADDR_IN_RANGE(addr, QLA8XXX_ADDR_OCM0,
62062306a36Sopenharmony_ci				QLA8XXX_ADDR_OCM0_MAX)) {
62162306a36Sopenharmony_ci		unsigned int temp1;
62262306a36Sopenharmony_ci		/* if bits 19:18&17:11 are on */
62362306a36Sopenharmony_ci		if ((addr & 0x00ff800) == 0xff800) {
62462306a36Sopenharmony_ci			printk("%s: QM access not handled.\n", __func__);
62562306a36Sopenharmony_ci			addr = -1UL;
62662306a36Sopenharmony_ci		}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci		window = OCM_WIN(addr);
62962306a36Sopenharmony_ci		ha->ddr_mn_window = window;
63062306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, ha->mn_win_crb |
63162306a36Sopenharmony_ci		    QLA82XX_PCI_CRBSPACE, window);
63262306a36Sopenharmony_ci		win_read = qla4_82xx_rd_32(ha, ha->mn_win_crb |
63362306a36Sopenharmony_ci		    QLA82XX_PCI_CRBSPACE);
63462306a36Sopenharmony_ci		temp1 = ((window & 0x1FF) << 7) |
63562306a36Sopenharmony_ci		    ((window & 0x0FFFE0000) >> 17);
63662306a36Sopenharmony_ci		if (win_read != temp1) {
63762306a36Sopenharmony_ci			printk("%s: Written OCMwin (0x%x) != Read"
63862306a36Sopenharmony_ci			    " OCMwin (0x%x)\n", __func__, temp1, win_read);
63962306a36Sopenharmony_ci		}
64062306a36Sopenharmony_ci		addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_OCM0_2M;
64162306a36Sopenharmony_ci
64262306a36Sopenharmony_ci	} else if (QLA8XXX_ADDR_IN_RANGE(addr, QLA8XXX_ADDR_QDR_NET,
64362306a36Sopenharmony_ci				QLA82XX_P3_ADDR_QDR_NET_MAX)) {
64462306a36Sopenharmony_ci		/* QDR network side */
64562306a36Sopenharmony_ci		window = MS_WIN(addr);
64662306a36Sopenharmony_ci		ha->qdr_sn_window = window;
64762306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, ha->ms_win_crb |
64862306a36Sopenharmony_ci		    QLA82XX_PCI_CRBSPACE, window);
64962306a36Sopenharmony_ci		win_read = qla4_82xx_rd_32(ha,
65062306a36Sopenharmony_ci		     ha->ms_win_crb | QLA82XX_PCI_CRBSPACE);
65162306a36Sopenharmony_ci		if (win_read != window) {
65262306a36Sopenharmony_ci			printk("%s: Written MSwin (0x%x) != Read "
65362306a36Sopenharmony_ci			    "MSwin (0x%x)\n", __func__, window, win_read);
65462306a36Sopenharmony_ci		}
65562306a36Sopenharmony_ci		addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_QDR_NET;
65662306a36Sopenharmony_ci
65762306a36Sopenharmony_ci	} else {
65862306a36Sopenharmony_ci		/*
65962306a36Sopenharmony_ci		 * peg gdb frequently accesses memory that doesn't exist,
66062306a36Sopenharmony_ci		 * this limits the chit chat so debugging isn't slowed down.
66162306a36Sopenharmony_ci		 */
66262306a36Sopenharmony_ci		if ((qla4_82xx_pci_set_window_warning_count++ < 8) ||
66362306a36Sopenharmony_ci		    (qla4_82xx_pci_set_window_warning_count%64 == 0)) {
66462306a36Sopenharmony_ci			printk("%s: Warning:%s Unknown address range!\n",
66562306a36Sopenharmony_ci			    __func__, DRIVER_NAME);
66662306a36Sopenharmony_ci		}
66762306a36Sopenharmony_ci		addr = -1UL;
66862306a36Sopenharmony_ci	}
66962306a36Sopenharmony_ci	return addr;
67062306a36Sopenharmony_ci}
67162306a36Sopenharmony_ci
67262306a36Sopenharmony_ci/* check if address is in the same windows as the previous access */
67362306a36Sopenharmony_cistatic int qla4_82xx_pci_is_same_window(struct scsi_qla_host *ha,
67462306a36Sopenharmony_ci		unsigned long long addr)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	int window;
67762306a36Sopenharmony_ci	unsigned long long qdr_max;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	qdr_max = QLA82XX_P3_ADDR_QDR_NET_MAX;
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	if (QLA8XXX_ADDR_IN_RANGE(addr, QLA8XXX_ADDR_DDR_NET,
68262306a36Sopenharmony_ci	    QLA8XXX_ADDR_DDR_NET_MAX)) {
68362306a36Sopenharmony_ci		/* DDR network side */
68462306a36Sopenharmony_ci		BUG();	/* MN access can not come here */
68562306a36Sopenharmony_ci	} else if (QLA8XXX_ADDR_IN_RANGE(addr, QLA8XXX_ADDR_OCM0,
68662306a36Sopenharmony_ci	     QLA8XXX_ADDR_OCM0_MAX)) {
68762306a36Sopenharmony_ci		return 1;
68862306a36Sopenharmony_ci	} else if (QLA8XXX_ADDR_IN_RANGE(addr, QLA8XXX_ADDR_OCM1,
68962306a36Sopenharmony_ci	     QLA8XXX_ADDR_OCM1_MAX)) {
69062306a36Sopenharmony_ci		return 1;
69162306a36Sopenharmony_ci	} else if (QLA8XXX_ADDR_IN_RANGE(addr, QLA8XXX_ADDR_QDR_NET,
69262306a36Sopenharmony_ci	    qdr_max)) {
69362306a36Sopenharmony_ci		/* QDR network side */
69462306a36Sopenharmony_ci		window = ((addr - QLA8XXX_ADDR_QDR_NET) >> 22) & 0x3f;
69562306a36Sopenharmony_ci		if (ha->qdr_sn_window == window)
69662306a36Sopenharmony_ci			return 1;
69762306a36Sopenharmony_ci	}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	return 0;
70062306a36Sopenharmony_ci}
70162306a36Sopenharmony_ci
70262306a36Sopenharmony_cistatic int qla4_82xx_pci_mem_read_direct(struct scsi_qla_host *ha,
70362306a36Sopenharmony_ci		u64 off, void *data, int size)
70462306a36Sopenharmony_ci{
70562306a36Sopenharmony_ci	unsigned long flags;
70662306a36Sopenharmony_ci	void __iomem *addr;
70762306a36Sopenharmony_ci	int ret = 0;
70862306a36Sopenharmony_ci	u64 start;
70962306a36Sopenharmony_ci	void __iomem *mem_ptr = NULL;
71062306a36Sopenharmony_ci	unsigned long mem_base;
71162306a36Sopenharmony_ci	unsigned long mem_page;
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	write_lock_irqsave(&ha->hw_lock, flags);
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	/*
71662306a36Sopenharmony_ci	 * If attempting to access unknown address or straddle hw windows,
71762306a36Sopenharmony_ci	 * do not access.
71862306a36Sopenharmony_ci	 */
71962306a36Sopenharmony_ci	start = qla4_82xx_pci_set_window(ha, off);
72062306a36Sopenharmony_ci	if ((start == -1UL) ||
72162306a36Sopenharmony_ci	    (qla4_82xx_pci_is_same_window(ha, off + size - 1) == 0)) {
72262306a36Sopenharmony_ci		write_unlock_irqrestore(&ha->hw_lock, flags);
72362306a36Sopenharmony_ci		printk(KERN_ERR"%s out of bound pci memory access. "
72462306a36Sopenharmony_ci				"offset is 0x%llx\n", DRIVER_NAME, off);
72562306a36Sopenharmony_ci		return -1;
72662306a36Sopenharmony_ci	}
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	addr = qla4_8xxx_pci_base_offsetfset(ha, start);
72962306a36Sopenharmony_ci	if (!addr) {
73062306a36Sopenharmony_ci		write_unlock_irqrestore(&ha->hw_lock, flags);
73162306a36Sopenharmony_ci		mem_base = pci_resource_start(ha->pdev, 0);
73262306a36Sopenharmony_ci		mem_page = start & PAGE_MASK;
73362306a36Sopenharmony_ci		/* Map two pages whenever user tries to access addresses in two
73462306a36Sopenharmony_ci		   consecutive pages.
73562306a36Sopenharmony_ci		 */
73662306a36Sopenharmony_ci		if (mem_page != ((start + size - 1) & PAGE_MASK))
73762306a36Sopenharmony_ci			mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2);
73862306a36Sopenharmony_ci		else
73962306a36Sopenharmony_ci			mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE);
74062306a36Sopenharmony_ci
74162306a36Sopenharmony_ci		if (mem_ptr == NULL) {
74262306a36Sopenharmony_ci			*(u8 *)data = 0;
74362306a36Sopenharmony_ci			return -1;
74462306a36Sopenharmony_ci		}
74562306a36Sopenharmony_ci		addr = mem_ptr;
74662306a36Sopenharmony_ci		addr += start & (PAGE_SIZE - 1);
74762306a36Sopenharmony_ci		write_lock_irqsave(&ha->hw_lock, flags);
74862306a36Sopenharmony_ci	}
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	switch (size) {
75162306a36Sopenharmony_ci	case 1:
75262306a36Sopenharmony_ci		*(u8  *)data = readb(addr);
75362306a36Sopenharmony_ci		break;
75462306a36Sopenharmony_ci	case 2:
75562306a36Sopenharmony_ci		*(u16 *)data = readw(addr);
75662306a36Sopenharmony_ci		break;
75762306a36Sopenharmony_ci	case 4:
75862306a36Sopenharmony_ci		*(u32 *)data = readl(addr);
75962306a36Sopenharmony_ci		break;
76062306a36Sopenharmony_ci	case 8:
76162306a36Sopenharmony_ci		*(u64 *)data = readq(addr);
76262306a36Sopenharmony_ci		break;
76362306a36Sopenharmony_ci	default:
76462306a36Sopenharmony_ci		ret = -1;
76562306a36Sopenharmony_ci		break;
76662306a36Sopenharmony_ci	}
76762306a36Sopenharmony_ci	write_unlock_irqrestore(&ha->hw_lock, flags);
76862306a36Sopenharmony_ci
76962306a36Sopenharmony_ci	if (mem_ptr)
77062306a36Sopenharmony_ci		iounmap(mem_ptr);
77162306a36Sopenharmony_ci	return ret;
77262306a36Sopenharmony_ci}
77362306a36Sopenharmony_ci
77462306a36Sopenharmony_cistatic int
77562306a36Sopenharmony_ciqla4_82xx_pci_mem_write_direct(struct scsi_qla_host *ha, u64 off,
77662306a36Sopenharmony_ci		void *data, int size)
77762306a36Sopenharmony_ci{
77862306a36Sopenharmony_ci	unsigned long flags;
77962306a36Sopenharmony_ci	void __iomem *addr;
78062306a36Sopenharmony_ci	int ret = 0;
78162306a36Sopenharmony_ci	u64 start;
78262306a36Sopenharmony_ci	void __iomem *mem_ptr = NULL;
78362306a36Sopenharmony_ci	unsigned long mem_base;
78462306a36Sopenharmony_ci	unsigned long mem_page;
78562306a36Sopenharmony_ci
78662306a36Sopenharmony_ci	write_lock_irqsave(&ha->hw_lock, flags);
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci	/*
78962306a36Sopenharmony_ci	 * If attempting to access unknown address or straddle hw windows,
79062306a36Sopenharmony_ci	 * do not access.
79162306a36Sopenharmony_ci	 */
79262306a36Sopenharmony_ci	start = qla4_82xx_pci_set_window(ha, off);
79362306a36Sopenharmony_ci	if ((start == -1UL) ||
79462306a36Sopenharmony_ci	    (qla4_82xx_pci_is_same_window(ha, off + size - 1) == 0)) {
79562306a36Sopenharmony_ci		write_unlock_irqrestore(&ha->hw_lock, flags);
79662306a36Sopenharmony_ci		printk(KERN_ERR"%s out of bound pci memory access. "
79762306a36Sopenharmony_ci				"offset is 0x%llx\n", DRIVER_NAME, off);
79862306a36Sopenharmony_ci		return -1;
79962306a36Sopenharmony_ci	}
80062306a36Sopenharmony_ci
80162306a36Sopenharmony_ci	addr = qla4_8xxx_pci_base_offsetfset(ha, start);
80262306a36Sopenharmony_ci	if (!addr) {
80362306a36Sopenharmony_ci		write_unlock_irqrestore(&ha->hw_lock, flags);
80462306a36Sopenharmony_ci		mem_base = pci_resource_start(ha->pdev, 0);
80562306a36Sopenharmony_ci		mem_page = start & PAGE_MASK;
80662306a36Sopenharmony_ci		/* Map two pages whenever user tries to access addresses in two
80762306a36Sopenharmony_ci		   consecutive pages.
80862306a36Sopenharmony_ci		 */
80962306a36Sopenharmony_ci		if (mem_page != ((start + size - 1) & PAGE_MASK))
81062306a36Sopenharmony_ci			mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE*2);
81162306a36Sopenharmony_ci		else
81262306a36Sopenharmony_ci			mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE);
81362306a36Sopenharmony_ci		if (mem_ptr == NULL)
81462306a36Sopenharmony_ci			return -1;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_ci		addr = mem_ptr;
81762306a36Sopenharmony_ci		addr += start & (PAGE_SIZE - 1);
81862306a36Sopenharmony_ci		write_lock_irqsave(&ha->hw_lock, flags);
81962306a36Sopenharmony_ci	}
82062306a36Sopenharmony_ci
82162306a36Sopenharmony_ci	switch (size) {
82262306a36Sopenharmony_ci	case 1:
82362306a36Sopenharmony_ci		writeb(*(u8 *)data, addr);
82462306a36Sopenharmony_ci		break;
82562306a36Sopenharmony_ci	case 2:
82662306a36Sopenharmony_ci		writew(*(u16 *)data, addr);
82762306a36Sopenharmony_ci		break;
82862306a36Sopenharmony_ci	case 4:
82962306a36Sopenharmony_ci		writel(*(u32 *)data, addr);
83062306a36Sopenharmony_ci		break;
83162306a36Sopenharmony_ci	case 8:
83262306a36Sopenharmony_ci		writeq(*(u64 *)data, addr);
83362306a36Sopenharmony_ci		break;
83462306a36Sopenharmony_ci	default:
83562306a36Sopenharmony_ci		ret = -1;
83662306a36Sopenharmony_ci		break;
83762306a36Sopenharmony_ci	}
83862306a36Sopenharmony_ci	write_unlock_irqrestore(&ha->hw_lock, flags);
83962306a36Sopenharmony_ci	if (mem_ptr)
84062306a36Sopenharmony_ci		iounmap(mem_ptr);
84162306a36Sopenharmony_ci	return ret;
84262306a36Sopenharmony_ci}
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci#define MTU_FUDGE_FACTOR 100
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_cistatic unsigned long
84762306a36Sopenharmony_ciqla4_82xx_decode_crb_addr(unsigned long addr)
84862306a36Sopenharmony_ci{
84962306a36Sopenharmony_ci	int i;
85062306a36Sopenharmony_ci	unsigned long base_addr, offset, pci_base;
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	if (!qla4_8xxx_crb_table_initialized)
85362306a36Sopenharmony_ci		qla4_82xx_crb_addr_transform_setup();
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	pci_base = ADDR_ERROR;
85662306a36Sopenharmony_ci	base_addr = addr & 0xfff00000;
85762306a36Sopenharmony_ci	offset = addr & 0x000fffff;
85862306a36Sopenharmony_ci
85962306a36Sopenharmony_ci	for (i = 0; i < MAX_CRB_XFORM; i++) {
86062306a36Sopenharmony_ci		if (crb_addr_xform[i] == base_addr) {
86162306a36Sopenharmony_ci			pci_base = i << 20;
86262306a36Sopenharmony_ci			break;
86362306a36Sopenharmony_ci		}
86462306a36Sopenharmony_ci	}
86562306a36Sopenharmony_ci	if (pci_base == ADDR_ERROR)
86662306a36Sopenharmony_ci		return pci_base;
86762306a36Sopenharmony_ci	else
86862306a36Sopenharmony_ci		return pci_base + offset;
86962306a36Sopenharmony_ci}
87062306a36Sopenharmony_ci
87162306a36Sopenharmony_cistatic long rom_max_timeout = 100;
87262306a36Sopenharmony_cistatic long qla4_82xx_rom_lock_timeout = 100;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci/*
87562306a36Sopenharmony_ci * Context: task, can_sleep
87662306a36Sopenharmony_ci */
87762306a36Sopenharmony_cistatic int
87862306a36Sopenharmony_ciqla4_82xx_rom_lock(struct scsi_qla_host *ha)
87962306a36Sopenharmony_ci{
88062306a36Sopenharmony_ci	int done = 0, timeout = 0;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci	might_sleep();
88362306a36Sopenharmony_ci
88462306a36Sopenharmony_ci	while (!done) {
88562306a36Sopenharmony_ci		/* acquire semaphore2 from PCI HW block */
88662306a36Sopenharmony_ci		done = qla4_82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_LOCK));
88762306a36Sopenharmony_ci		if (done == 1)
88862306a36Sopenharmony_ci			break;
88962306a36Sopenharmony_ci		if (timeout >= qla4_82xx_rom_lock_timeout)
89062306a36Sopenharmony_ci			return -1;
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci		timeout++;
89362306a36Sopenharmony_ci		msleep(20);
89462306a36Sopenharmony_ci	}
89562306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_ROM_LOCK_ID, ROM_LOCK_DRIVER);
89662306a36Sopenharmony_ci	return 0;
89762306a36Sopenharmony_ci}
89862306a36Sopenharmony_ci
89962306a36Sopenharmony_cistatic void
90062306a36Sopenharmony_ciqla4_82xx_rom_unlock(struct scsi_qla_host *ha)
90162306a36Sopenharmony_ci{
90262306a36Sopenharmony_ci	qla4_82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK));
90362306a36Sopenharmony_ci}
90462306a36Sopenharmony_ci
90562306a36Sopenharmony_cistatic int
90662306a36Sopenharmony_ciqla4_82xx_wait_rom_done(struct scsi_qla_host *ha)
90762306a36Sopenharmony_ci{
90862306a36Sopenharmony_ci	long timeout = 0;
90962306a36Sopenharmony_ci	long done = 0 ;
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	while (done == 0) {
91262306a36Sopenharmony_ci		done = qla4_82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_STATUS);
91362306a36Sopenharmony_ci		done &= 2;
91462306a36Sopenharmony_ci		timeout++;
91562306a36Sopenharmony_ci		if (timeout >= rom_max_timeout) {
91662306a36Sopenharmony_ci			printk("%s: Timeout reached  waiting for rom done",
91762306a36Sopenharmony_ci					DRIVER_NAME);
91862306a36Sopenharmony_ci			return -1;
91962306a36Sopenharmony_ci		}
92062306a36Sopenharmony_ci	}
92162306a36Sopenharmony_ci	return 0;
92262306a36Sopenharmony_ci}
92362306a36Sopenharmony_ci
92462306a36Sopenharmony_cistatic int
92562306a36Sopenharmony_ciqla4_82xx_do_rom_fast_read(struct scsi_qla_host *ha, int addr, int *valp)
92662306a36Sopenharmony_ci{
92762306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, addr);
92862306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
92962306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 3);
93062306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, 0xb);
93162306a36Sopenharmony_ci	if (qla4_82xx_wait_rom_done(ha)) {
93262306a36Sopenharmony_ci		printk("%s: Error waiting for rom done\n", DRIVER_NAME);
93362306a36Sopenharmony_ci		return -1;
93462306a36Sopenharmony_ci	}
93562306a36Sopenharmony_ci	/* reset abyte_cnt and dummy_byte_cnt */
93662306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
93762306a36Sopenharmony_ci	udelay(10);
93862306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0);
93962306a36Sopenharmony_ci
94062306a36Sopenharmony_ci	*valp = qla4_82xx_rd_32(ha, QLA82XX_ROMUSB_ROM_RDATA);
94162306a36Sopenharmony_ci	return 0;
94262306a36Sopenharmony_ci}
94362306a36Sopenharmony_ci
94462306a36Sopenharmony_cistatic int
94562306a36Sopenharmony_ciqla4_82xx_rom_fast_read(struct scsi_qla_host *ha, int addr, int *valp)
94662306a36Sopenharmony_ci{
94762306a36Sopenharmony_ci	int ret, loops = 0;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	while ((qla4_82xx_rom_lock(ha) != 0) && (loops < 50000)) {
95062306a36Sopenharmony_ci		udelay(100);
95162306a36Sopenharmony_ci		loops++;
95262306a36Sopenharmony_ci	}
95362306a36Sopenharmony_ci	if (loops >= 50000) {
95462306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha, "%s: qla4_82xx_rom_lock failed\n",
95562306a36Sopenharmony_ci			   DRIVER_NAME);
95662306a36Sopenharmony_ci		return -1;
95762306a36Sopenharmony_ci	}
95862306a36Sopenharmony_ci	ret = qla4_82xx_do_rom_fast_read(ha, addr, valp);
95962306a36Sopenharmony_ci	qla4_82xx_rom_unlock(ha);
96062306a36Sopenharmony_ci	return ret;
96162306a36Sopenharmony_ci}
96262306a36Sopenharmony_ci
96362306a36Sopenharmony_ci/*
96462306a36Sopenharmony_ci * This routine does CRB initialize sequence
96562306a36Sopenharmony_ci * to put the ISP into operational state
96662306a36Sopenharmony_ci */
96762306a36Sopenharmony_cistatic int
96862306a36Sopenharmony_ciqla4_82xx_pinit_from_rom(struct scsi_qla_host *ha, int verbose)
96962306a36Sopenharmony_ci{
97062306a36Sopenharmony_ci	int addr, val;
97162306a36Sopenharmony_ci	int i ;
97262306a36Sopenharmony_ci	struct crb_addr_pair *buf;
97362306a36Sopenharmony_ci	unsigned long off;
97462306a36Sopenharmony_ci	unsigned offset, n;
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	struct crb_addr_pair {
97762306a36Sopenharmony_ci		long addr;
97862306a36Sopenharmony_ci		long data;
97962306a36Sopenharmony_ci	};
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	/* Halt all the indiviual PEGs and other blocks of the ISP */
98262306a36Sopenharmony_ci	qla4_82xx_rom_lock(ha);
98362306a36Sopenharmony_ci
98462306a36Sopenharmony_ci	/* disable all I2Q */
98562306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x10, 0x0);
98662306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x14, 0x0);
98762306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x18, 0x0);
98862306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x1c, 0x0);
98962306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x20, 0x0);
99062306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x24, 0x0);
99162306a36Sopenharmony_ci
99262306a36Sopenharmony_ci	/* disable all niu interrupts */
99362306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x40, 0xff);
99462306a36Sopenharmony_ci	/* disable xge rx/tx */
99562306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x70000, 0x00);
99662306a36Sopenharmony_ci	/* disable xg1 rx/tx */
99762306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x80000, 0x00);
99862306a36Sopenharmony_ci	/* disable sideband mac */
99962306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x90000, 0x00);
100062306a36Sopenharmony_ci	/* disable ap0 mac */
100162306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0xa0000, 0x00);
100262306a36Sopenharmony_ci	/* disable ap1 mac */
100362306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_NIU + 0xb0000, 0x00);
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	/* halt sre */
100662306a36Sopenharmony_ci	val = qla4_82xx_rd_32(ha, QLA82XX_CRB_SRE + 0x1000);
100762306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_SRE + 0x1000, val & (~(0x1)));
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	/* halt epg */
101062306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_EPG + 0x1300, 0x1);
101162306a36Sopenharmony_ci
101262306a36Sopenharmony_ci	/* halt timers */
101362306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x0, 0x0);
101462306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x8, 0x0);
101562306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x10, 0x0);
101662306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x18, 0x0);
101762306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x100, 0x0);
101862306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x200, 0x0);
101962306a36Sopenharmony_ci
102062306a36Sopenharmony_ci	/* halt pegs */
102162306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x3c, 1);
102262306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_1 + 0x3c, 1);
102362306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_2 + 0x3c, 1);
102462306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_3 + 0x3c, 1);
102562306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_4 + 0x3c, 1);
102662306a36Sopenharmony_ci	msleep(5);
102762306a36Sopenharmony_ci
102862306a36Sopenharmony_ci	/* big hammer */
102962306a36Sopenharmony_ci	if (test_bit(DPC_RESET_HA, &ha->dpc_flags))
103062306a36Sopenharmony_ci		/* don't reset CAM block on reset */
103162306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xfeffffff);
103262306a36Sopenharmony_ci	else
103362306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xffffffff);
103462306a36Sopenharmony_ci
103562306a36Sopenharmony_ci	qla4_82xx_rom_unlock(ha);
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	/* Read the signature value from the flash.
103862306a36Sopenharmony_ci	 * Offset 0: Contain signature (0xcafecafe)
103962306a36Sopenharmony_ci	 * Offset 4: Offset and number of addr/value pairs
104062306a36Sopenharmony_ci	 * that present in CRB initialize sequence
104162306a36Sopenharmony_ci	 */
104262306a36Sopenharmony_ci	if (qla4_82xx_rom_fast_read(ha, 0, &n) != 0 || n != 0xcafecafeUL ||
104362306a36Sopenharmony_ci	    qla4_82xx_rom_fast_read(ha, 4, &n) != 0) {
104462306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
104562306a36Sopenharmony_ci			"[ERROR] Reading crb_init area: n: %08x\n", n);
104662306a36Sopenharmony_ci		return -1;
104762306a36Sopenharmony_ci	}
104862306a36Sopenharmony_ci
104962306a36Sopenharmony_ci	/* Offset in flash = lower 16 bits
105062306a36Sopenharmony_ci	 * Number of enteries = upper 16 bits
105162306a36Sopenharmony_ci	 */
105262306a36Sopenharmony_ci	offset = n & 0xffffU;
105362306a36Sopenharmony_ci	n = (n >> 16) & 0xffffU;
105462306a36Sopenharmony_ci
105562306a36Sopenharmony_ci	/* number of addr/value pair should not exceed 1024 enteries */
105662306a36Sopenharmony_ci	if (n  >= 1024) {
105762306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
105862306a36Sopenharmony_ci		    "%s: %s:n=0x%x [ERROR] Card flash not initialized.\n",
105962306a36Sopenharmony_ci		    DRIVER_NAME, __func__, n);
106062306a36Sopenharmony_ci		return -1;
106162306a36Sopenharmony_ci	}
106262306a36Sopenharmony_ci
106362306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha,
106462306a36Sopenharmony_ci		"%s: %d CRB init values found in ROM.\n", DRIVER_NAME, n);
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	buf = kmalloc_array(n, sizeof(struct crb_addr_pair), GFP_KERNEL);
106762306a36Sopenharmony_ci	if (buf == NULL) {
106862306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
106962306a36Sopenharmony_ci		    "%s: [ERROR] Unable to malloc memory.\n", DRIVER_NAME);
107062306a36Sopenharmony_ci		return -1;
107162306a36Sopenharmony_ci	}
107262306a36Sopenharmony_ci
107362306a36Sopenharmony_ci	for (i = 0; i < n; i++) {
107462306a36Sopenharmony_ci		if (qla4_82xx_rom_fast_read(ha, 8*i + 4*offset, &val) != 0 ||
107562306a36Sopenharmony_ci		    qla4_82xx_rom_fast_read(ha, 8*i + 4*offset + 4, &addr) !=
107662306a36Sopenharmony_ci		    0) {
107762306a36Sopenharmony_ci			kfree(buf);
107862306a36Sopenharmony_ci			return -1;
107962306a36Sopenharmony_ci		}
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci		buf[i].addr = addr;
108262306a36Sopenharmony_ci		buf[i].data = val;
108362306a36Sopenharmony_ci	}
108462306a36Sopenharmony_ci
108562306a36Sopenharmony_ci	for (i = 0; i < n; i++) {
108662306a36Sopenharmony_ci		/* Translate internal CRB initialization
108762306a36Sopenharmony_ci		 * address to PCI bus address
108862306a36Sopenharmony_ci		 */
108962306a36Sopenharmony_ci		off = qla4_82xx_decode_crb_addr((unsigned long)buf[i].addr) +
109062306a36Sopenharmony_ci		    QLA82XX_PCI_CRBSPACE;
109162306a36Sopenharmony_ci		/* Not all CRB  addr/value pair to be written,
109262306a36Sopenharmony_ci		 * some of them are skipped
109362306a36Sopenharmony_ci		 */
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci		/* skip if LS bit is set*/
109662306a36Sopenharmony_ci		if (off & 0x1) {
109762306a36Sopenharmony_ci			DEBUG2(ql4_printk(KERN_WARNING, ha,
109862306a36Sopenharmony_ci			    "Skip CRB init replay for offset = 0x%lx\n", off));
109962306a36Sopenharmony_ci			continue;
110062306a36Sopenharmony_ci		}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci		/* skipping cold reboot MAGIC */
110362306a36Sopenharmony_ci		if (off == QLA82XX_CAM_RAM(0x1fc))
110462306a36Sopenharmony_ci			continue;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci		/* do not reset PCI */
110762306a36Sopenharmony_ci		if (off == (ROMUSB_GLB + 0xbc))
110862306a36Sopenharmony_ci			continue;
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci		/* skip core clock, so that firmware can increase the clock */
111162306a36Sopenharmony_ci		if (off == (ROMUSB_GLB + 0xc8))
111262306a36Sopenharmony_ci			continue;
111362306a36Sopenharmony_ci
111462306a36Sopenharmony_ci		/* skip the function enable register */
111562306a36Sopenharmony_ci		if (off == QLA82XX_PCIE_REG(PCIE_SETUP_FUNCTION))
111662306a36Sopenharmony_ci			continue;
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci		if (off == QLA82XX_PCIE_REG(PCIE_SETUP_FUNCTION2))
111962306a36Sopenharmony_ci			continue;
112062306a36Sopenharmony_ci
112162306a36Sopenharmony_ci		if ((off & 0x0ff00000) == QLA82XX_CRB_SMB)
112262306a36Sopenharmony_ci			continue;
112362306a36Sopenharmony_ci
112462306a36Sopenharmony_ci		if ((off & 0x0ff00000) == QLA82XX_CRB_DDR_NET)
112562306a36Sopenharmony_ci			continue;
112662306a36Sopenharmony_ci
112762306a36Sopenharmony_ci		if (off == ADDR_ERROR) {
112862306a36Sopenharmony_ci			ql4_printk(KERN_WARNING, ha,
112962306a36Sopenharmony_ci			    "%s: [ERROR] Unknown addr: 0x%08lx\n",
113062306a36Sopenharmony_ci			    DRIVER_NAME, buf[i].addr);
113162306a36Sopenharmony_ci			continue;
113262306a36Sopenharmony_ci		}
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, off, buf[i].data);
113562306a36Sopenharmony_ci
113662306a36Sopenharmony_ci		/* ISP requires much bigger delay to settle down,
113762306a36Sopenharmony_ci		 * else crb_window returns 0xffffffff
113862306a36Sopenharmony_ci		 */
113962306a36Sopenharmony_ci		if (off == QLA82XX_ROMUSB_GLB_SW_RESET)
114062306a36Sopenharmony_ci			msleep(1000);
114162306a36Sopenharmony_ci
114262306a36Sopenharmony_ci		/* ISP requires millisec delay between
114362306a36Sopenharmony_ci		 * successive CRB register updation
114462306a36Sopenharmony_ci		 */
114562306a36Sopenharmony_ci		msleep(1);
114662306a36Sopenharmony_ci	}
114762306a36Sopenharmony_ci
114862306a36Sopenharmony_ci	kfree(buf);
114962306a36Sopenharmony_ci
115062306a36Sopenharmony_ci	/* Resetting the data and instruction cache */
115162306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_D+0xec, 0x1e);
115262306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_D+0x4c, 8);
115362306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_I+0x4c, 8);
115462306a36Sopenharmony_ci
115562306a36Sopenharmony_ci	/* Clear all protocol processing engines */
115662306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0+0x8, 0);
115762306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0+0xc, 0);
115862306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_1+0x8, 0);
115962306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_1+0xc, 0);
116062306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_2+0x8, 0);
116162306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_2+0xc, 0);
116262306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_3+0x8, 0);
116362306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_3+0xc, 0);
116462306a36Sopenharmony_ci
116562306a36Sopenharmony_ci	return 0;
116662306a36Sopenharmony_ci}
116762306a36Sopenharmony_ci
116862306a36Sopenharmony_ci/**
116962306a36Sopenharmony_ci * qla4_8xxx_ms_mem_write_128b - Writes data to MS/off-chip memory
117062306a36Sopenharmony_ci * @ha: Pointer to adapter structure
117162306a36Sopenharmony_ci * @addr: Flash address to write to
117262306a36Sopenharmony_ci * @data: Data to be written
117362306a36Sopenharmony_ci * @count: word_count to be written
117462306a36Sopenharmony_ci *
117562306a36Sopenharmony_ci * Return: On success return QLA_SUCCESS
117662306a36Sopenharmony_ci *         On error return QLA_ERROR
117762306a36Sopenharmony_ci **/
117862306a36Sopenharmony_ciint qla4_8xxx_ms_mem_write_128b(struct scsi_qla_host *ha, uint64_t addr,
117962306a36Sopenharmony_ci				uint32_t *data, uint32_t count)
118062306a36Sopenharmony_ci{
118162306a36Sopenharmony_ci	int i, j;
118262306a36Sopenharmony_ci	uint32_t agt_ctrl;
118362306a36Sopenharmony_ci	unsigned long flags;
118462306a36Sopenharmony_ci	int ret_val = QLA_SUCCESS;
118562306a36Sopenharmony_ci
118662306a36Sopenharmony_ci	/* Only 128-bit aligned access */
118762306a36Sopenharmony_ci	if (addr & 0xF) {
118862306a36Sopenharmony_ci		ret_val = QLA_ERROR;
118962306a36Sopenharmony_ci		goto exit_ms_mem_write;
119062306a36Sopenharmony_ci	}
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	write_lock_irqsave(&ha->hw_lock, flags);
119362306a36Sopenharmony_ci
119462306a36Sopenharmony_ci	/* Write address */
119562306a36Sopenharmony_ci	ret_val = ha->isp_ops->wr_reg_indirect(ha, MD_MIU_TEST_AGT_ADDR_HI, 0);
119662306a36Sopenharmony_ci	if (ret_val == QLA_ERROR) {
119762306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: write to AGT_ADDR_HI failed\n",
119862306a36Sopenharmony_ci			   __func__);
119962306a36Sopenharmony_ci		goto exit_ms_mem_write_unlock;
120062306a36Sopenharmony_ci	}
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	for (i = 0; i < count; i++, addr += 16) {
120362306a36Sopenharmony_ci		if (!((QLA8XXX_ADDR_IN_RANGE(addr, QLA8XXX_ADDR_QDR_NET,
120462306a36Sopenharmony_ci					     QLA8XXX_ADDR_QDR_NET_MAX)) ||
120562306a36Sopenharmony_ci		      (QLA8XXX_ADDR_IN_RANGE(addr, QLA8XXX_ADDR_DDR_NET,
120662306a36Sopenharmony_ci					     QLA8XXX_ADDR_DDR_NET_MAX)))) {
120762306a36Sopenharmony_ci			ret_val = QLA_ERROR;
120862306a36Sopenharmony_ci			goto exit_ms_mem_write_unlock;
120962306a36Sopenharmony_ci		}
121062306a36Sopenharmony_ci
121162306a36Sopenharmony_ci		ret_val = ha->isp_ops->wr_reg_indirect(ha,
121262306a36Sopenharmony_ci						       MD_MIU_TEST_AGT_ADDR_LO,
121362306a36Sopenharmony_ci						       addr);
121462306a36Sopenharmony_ci		/* Write data */
121562306a36Sopenharmony_ci		ret_val |= ha->isp_ops->wr_reg_indirect(ha,
121662306a36Sopenharmony_ci						MD_MIU_TEST_AGT_WRDATA_LO,
121762306a36Sopenharmony_ci						*data++);
121862306a36Sopenharmony_ci		ret_val |= ha->isp_ops->wr_reg_indirect(ha,
121962306a36Sopenharmony_ci						MD_MIU_TEST_AGT_WRDATA_HI,
122062306a36Sopenharmony_ci						*data++);
122162306a36Sopenharmony_ci		ret_val |= ha->isp_ops->wr_reg_indirect(ha,
122262306a36Sopenharmony_ci						MD_MIU_TEST_AGT_WRDATA_ULO,
122362306a36Sopenharmony_ci						*data++);
122462306a36Sopenharmony_ci		ret_val |= ha->isp_ops->wr_reg_indirect(ha,
122562306a36Sopenharmony_ci						MD_MIU_TEST_AGT_WRDATA_UHI,
122662306a36Sopenharmony_ci						*data++);
122762306a36Sopenharmony_ci		if (ret_val == QLA_ERROR) {
122862306a36Sopenharmony_ci			ql4_printk(KERN_ERR, ha, "%s: write to AGT_WRDATA failed\n",
122962306a36Sopenharmony_ci				   __func__);
123062306a36Sopenharmony_ci			goto exit_ms_mem_write_unlock;
123162306a36Sopenharmony_ci		}
123262306a36Sopenharmony_ci
123362306a36Sopenharmony_ci		/* Check write status */
123462306a36Sopenharmony_ci		ret_val = ha->isp_ops->wr_reg_indirect(ha, MD_MIU_TEST_AGT_CTRL,
123562306a36Sopenharmony_ci						       MIU_TA_CTL_WRITE_ENABLE);
123662306a36Sopenharmony_ci		ret_val |= ha->isp_ops->wr_reg_indirect(ha,
123762306a36Sopenharmony_ci							MD_MIU_TEST_AGT_CTRL,
123862306a36Sopenharmony_ci							MIU_TA_CTL_WRITE_START);
123962306a36Sopenharmony_ci		if (ret_val == QLA_ERROR) {
124062306a36Sopenharmony_ci			ql4_printk(KERN_ERR, ha, "%s: write to AGT_CTRL failed\n",
124162306a36Sopenharmony_ci				   __func__);
124262306a36Sopenharmony_ci			goto exit_ms_mem_write_unlock;
124362306a36Sopenharmony_ci		}
124462306a36Sopenharmony_ci
124562306a36Sopenharmony_ci		for (j = 0; j < MAX_CTL_CHECK; j++) {
124662306a36Sopenharmony_ci			ret_val = ha->isp_ops->rd_reg_indirect(ha,
124762306a36Sopenharmony_ci							MD_MIU_TEST_AGT_CTRL,
124862306a36Sopenharmony_ci							&agt_ctrl);
124962306a36Sopenharmony_ci			if (ret_val == QLA_ERROR) {
125062306a36Sopenharmony_ci				ql4_printk(KERN_ERR, ha, "%s: failed to read MD_MIU_TEST_AGT_CTRL\n",
125162306a36Sopenharmony_ci					   __func__);
125262306a36Sopenharmony_ci				goto exit_ms_mem_write_unlock;
125362306a36Sopenharmony_ci			}
125462306a36Sopenharmony_ci			if ((agt_ctrl & MIU_TA_CTL_BUSY) == 0)
125562306a36Sopenharmony_ci				break;
125662306a36Sopenharmony_ci		}
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci		/* Status check failed */
125962306a36Sopenharmony_ci		if (j >= MAX_CTL_CHECK) {
126062306a36Sopenharmony_ci			printk_ratelimited(KERN_ERR "%s: MS memory write failed!\n",
126162306a36Sopenharmony_ci					   __func__);
126262306a36Sopenharmony_ci			ret_val = QLA_ERROR;
126362306a36Sopenharmony_ci			goto exit_ms_mem_write_unlock;
126462306a36Sopenharmony_ci		}
126562306a36Sopenharmony_ci	}
126662306a36Sopenharmony_ci
126762306a36Sopenharmony_ciexit_ms_mem_write_unlock:
126862306a36Sopenharmony_ci	write_unlock_irqrestore(&ha->hw_lock, flags);
126962306a36Sopenharmony_ci
127062306a36Sopenharmony_ciexit_ms_mem_write:
127162306a36Sopenharmony_ci	return ret_val;
127262306a36Sopenharmony_ci}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_cistatic int
127562306a36Sopenharmony_ciqla4_82xx_load_from_flash(struct scsi_qla_host *ha, uint32_t image_start)
127662306a36Sopenharmony_ci{
127762306a36Sopenharmony_ci	int  i, rval = 0;
127862306a36Sopenharmony_ci	long size = 0;
127962306a36Sopenharmony_ci	long flashaddr, memaddr;
128062306a36Sopenharmony_ci	u64 data;
128162306a36Sopenharmony_ci	u32 high, low;
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_ci	flashaddr = memaddr = ha->hw.flt_region_bootload;
128462306a36Sopenharmony_ci	size = (image_start - flashaddr) / 8;
128562306a36Sopenharmony_ci
128662306a36Sopenharmony_ci	DEBUG2(printk("scsi%ld: %s: bootldr=0x%lx, fw_image=0x%x\n",
128762306a36Sopenharmony_ci	    ha->host_no, __func__, flashaddr, image_start));
128862306a36Sopenharmony_ci
128962306a36Sopenharmony_ci	for (i = 0; i < size; i++) {
129062306a36Sopenharmony_ci		if ((qla4_82xx_rom_fast_read(ha, flashaddr, (int *)&low)) ||
129162306a36Sopenharmony_ci		    (qla4_82xx_rom_fast_read(ha, flashaddr + 4,
129262306a36Sopenharmony_ci		    (int *)&high))) {
129362306a36Sopenharmony_ci			rval = -1;
129462306a36Sopenharmony_ci			goto exit_load_from_flash;
129562306a36Sopenharmony_ci		}
129662306a36Sopenharmony_ci		data = ((u64)high << 32) | low ;
129762306a36Sopenharmony_ci		rval = qla4_82xx_pci_mem_write_2M(ha, memaddr, &data, 8);
129862306a36Sopenharmony_ci		if (rval)
129962306a36Sopenharmony_ci			goto exit_load_from_flash;
130062306a36Sopenharmony_ci
130162306a36Sopenharmony_ci		flashaddr += 8;
130262306a36Sopenharmony_ci		memaddr   += 8;
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci		if (i % 0x1000 == 0)
130562306a36Sopenharmony_ci			msleep(1);
130662306a36Sopenharmony_ci
130762306a36Sopenharmony_ci	}
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	udelay(100);
131062306a36Sopenharmony_ci
131162306a36Sopenharmony_ci	read_lock(&ha->hw_lock);
131262306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020);
131362306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
131462306a36Sopenharmony_ci	read_unlock(&ha->hw_lock);
131562306a36Sopenharmony_ci
131662306a36Sopenharmony_ciexit_load_from_flash:
131762306a36Sopenharmony_ci	return rval;
131862306a36Sopenharmony_ci}
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_cistatic int qla4_82xx_load_fw(struct scsi_qla_host *ha, uint32_t image_start)
132162306a36Sopenharmony_ci{
132262306a36Sopenharmony_ci	u32 rst;
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, CRB_CMDPEG_STATE, 0);
132562306a36Sopenharmony_ci	if (qla4_82xx_pinit_from_rom(ha, 0) != QLA_SUCCESS) {
132662306a36Sopenharmony_ci		printk(KERN_WARNING "%s: Error during CRB Initialization\n",
132762306a36Sopenharmony_ci		    __func__);
132862306a36Sopenharmony_ci		return QLA_ERROR;
132962306a36Sopenharmony_ci	}
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	udelay(500);
133262306a36Sopenharmony_ci
133362306a36Sopenharmony_ci	/* at this point, QM is in reset. This could be a problem if there are
133462306a36Sopenharmony_ci	 * incoming d* transition queue messages. QM/PCIE could wedge.
133562306a36Sopenharmony_ci	 * To get around this, QM is brought out of reset.
133662306a36Sopenharmony_ci	 */
133762306a36Sopenharmony_ci
133862306a36Sopenharmony_ci	rst = qla4_82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET);
133962306a36Sopenharmony_ci	/* unreset qm */
134062306a36Sopenharmony_ci	rst &= ~(1 << 28);
134162306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, rst);
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	if (qla4_82xx_load_from_flash(ha, image_start)) {
134462306a36Sopenharmony_ci		printk("%s: Error trying to load fw from flash!\n", __func__);
134562306a36Sopenharmony_ci		return QLA_ERROR;
134662306a36Sopenharmony_ci	}
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	return QLA_SUCCESS;
134962306a36Sopenharmony_ci}
135062306a36Sopenharmony_ci
135162306a36Sopenharmony_ciint
135262306a36Sopenharmony_ciqla4_82xx_pci_mem_read_2M(struct scsi_qla_host *ha,
135362306a36Sopenharmony_ci		u64 off, void *data, int size)
135462306a36Sopenharmony_ci{
135562306a36Sopenharmony_ci	int i, j = 0, k, start, end, loop, sz[2], off0[2];
135662306a36Sopenharmony_ci	int shift_amount;
135762306a36Sopenharmony_ci	uint32_t temp;
135862306a36Sopenharmony_ci	uint64_t off8, val, mem_crb, word[2] = {0, 0};
135962306a36Sopenharmony_ci
136062306a36Sopenharmony_ci	/*
136162306a36Sopenharmony_ci	 * If not MN, go check for MS or invalid.
136262306a36Sopenharmony_ci	 */
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci	if (off >= QLA8XXX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX)
136562306a36Sopenharmony_ci		mem_crb = QLA82XX_CRB_QDR_NET;
136662306a36Sopenharmony_ci	else {
136762306a36Sopenharmony_ci		mem_crb = QLA82XX_CRB_DDR_NET;
136862306a36Sopenharmony_ci		if (qla4_82xx_pci_mem_bound_check(ha, off, size) == 0)
136962306a36Sopenharmony_ci			return qla4_82xx_pci_mem_read_direct(ha,
137062306a36Sopenharmony_ci					off, data, size);
137162306a36Sopenharmony_ci	}
137262306a36Sopenharmony_ci
137362306a36Sopenharmony_ci
137462306a36Sopenharmony_ci	off8 = off & 0xfffffff0;
137562306a36Sopenharmony_ci	off0[0] = off & 0xf;
137662306a36Sopenharmony_ci	sz[0] = (size < (16 - off0[0])) ? size : (16 - off0[0]);
137762306a36Sopenharmony_ci	shift_amount = 4;
137862306a36Sopenharmony_ci
137962306a36Sopenharmony_ci	loop = ((off0[0] + size - 1) >> shift_amount) + 1;
138062306a36Sopenharmony_ci	off0[1] = 0;
138162306a36Sopenharmony_ci	sz[1] = size - sz[0];
138262306a36Sopenharmony_ci
138362306a36Sopenharmony_ci	for (i = 0; i < loop; i++) {
138462306a36Sopenharmony_ci		temp = off8 + (i << shift_amount);
138562306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_LO, temp);
138662306a36Sopenharmony_ci		temp = 0;
138762306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_HI, temp);
138862306a36Sopenharmony_ci		temp = MIU_TA_CTL_ENABLE;
138962306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
139062306a36Sopenharmony_ci		temp = MIU_TA_CTL_START_ENABLE;
139162306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
139262306a36Sopenharmony_ci
139362306a36Sopenharmony_ci		for (j = 0; j < MAX_CTL_CHECK; j++) {
139462306a36Sopenharmony_ci			temp = qla4_82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL);
139562306a36Sopenharmony_ci			if ((temp & MIU_TA_CTL_BUSY) == 0)
139662306a36Sopenharmony_ci				break;
139762306a36Sopenharmony_ci		}
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci		if (j >= MAX_CTL_CHECK) {
140062306a36Sopenharmony_ci			printk_ratelimited(KERN_ERR
140162306a36Sopenharmony_ci					   "%s: failed to read through agent\n",
140262306a36Sopenharmony_ci					   __func__);
140362306a36Sopenharmony_ci			break;
140462306a36Sopenharmony_ci		}
140562306a36Sopenharmony_ci
140662306a36Sopenharmony_ci		start = off0[i] >> 2;
140762306a36Sopenharmony_ci		end   = (off0[i] + sz[i] - 1) >> 2;
140862306a36Sopenharmony_ci		for (k = start; k <= end; k++) {
140962306a36Sopenharmony_ci			temp = qla4_82xx_rd_32(ha,
141062306a36Sopenharmony_ci				mem_crb + MIU_TEST_AGT_RDDATA(k));
141162306a36Sopenharmony_ci			word[i] |= ((uint64_t)temp << (32 * (k & 1)));
141262306a36Sopenharmony_ci		}
141362306a36Sopenharmony_ci	}
141462306a36Sopenharmony_ci
141562306a36Sopenharmony_ci	if (j >= MAX_CTL_CHECK)
141662306a36Sopenharmony_ci		return -1;
141762306a36Sopenharmony_ci
141862306a36Sopenharmony_ci	if ((off0[0] & 7) == 0) {
141962306a36Sopenharmony_ci		val = word[0];
142062306a36Sopenharmony_ci	} else {
142162306a36Sopenharmony_ci		val = ((word[0] >> (off0[0] * 8)) & (~(~0ULL << (sz[0] * 8)))) |
142262306a36Sopenharmony_ci		((word[1] & (~(~0ULL << (sz[1] * 8)))) << (sz[0] * 8));
142362306a36Sopenharmony_ci	}
142462306a36Sopenharmony_ci
142562306a36Sopenharmony_ci	switch (size) {
142662306a36Sopenharmony_ci	case 1:
142762306a36Sopenharmony_ci		*(uint8_t  *)data = val;
142862306a36Sopenharmony_ci		break;
142962306a36Sopenharmony_ci	case 2:
143062306a36Sopenharmony_ci		*(uint16_t *)data = val;
143162306a36Sopenharmony_ci		break;
143262306a36Sopenharmony_ci	case 4:
143362306a36Sopenharmony_ci		*(uint32_t *)data = val;
143462306a36Sopenharmony_ci		break;
143562306a36Sopenharmony_ci	case 8:
143662306a36Sopenharmony_ci		*(uint64_t *)data = val;
143762306a36Sopenharmony_ci		break;
143862306a36Sopenharmony_ci	}
143962306a36Sopenharmony_ci	return 0;
144062306a36Sopenharmony_ci}
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ciint
144362306a36Sopenharmony_ciqla4_82xx_pci_mem_write_2M(struct scsi_qla_host *ha,
144462306a36Sopenharmony_ci		u64 off, void *data, int size)
144562306a36Sopenharmony_ci{
144662306a36Sopenharmony_ci	int i, j, ret = 0, loop, sz[2], off0;
144762306a36Sopenharmony_ci	int scale, shift_amount, startword;
144862306a36Sopenharmony_ci	uint32_t temp;
144962306a36Sopenharmony_ci	uint64_t off8, mem_crb, tmpw, word[2] = {0, 0};
145062306a36Sopenharmony_ci
145162306a36Sopenharmony_ci	/*
145262306a36Sopenharmony_ci	 * If not MN, go check for MS or invalid.
145362306a36Sopenharmony_ci	 */
145462306a36Sopenharmony_ci	if (off >= QLA8XXX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX)
145562306a36Sopenharmony_ci		mem_crb = QLA82XX_CRB_QDR_NET;
145662306a36Sopenharmony_ci	else {
145762306a36Sopenharmony_ci		mem_crb = QLA82XX_CRB_DDR_NET;
145862306a36Sopenharmony_ci		if (qla4_82xx_pci_mem_bound_check(ha, off, size) == 0)
145962306a36Sopenharmony_ci			return qla4_82xx_pci_mem_write_direct(ha,
146062306a36Sopenharmony_ci					off, data, size);
146162306a36Sopenharmony_ci	}
146262306a36Sopenharmony_ci
146362306a36Sopenharmony_ci	off0 = off & 0x7;
146462306a36Sopenharmony_ci	sz[0] = (size < (8 - off0)) ? size : (8 - off0);
146562306a36Sopenharmony_ci	sz[1] = size - sz[0];
146662306a36Sopenharmony_ci
146762306a36Sopenharmony_ci	off8 = off & 0xfffffff0;
146862306a36Sopenharmony_ci	loop = (((off & 0xf) + size - 1) >> 4) + 1;
146962306a36Sopenharmony_ci	shift_amount = 4;
147062306a36Sopenharmony_ci	scale = 2;
147162306a36Sopenharmony_ci	startword = (off & 0xf)/8;
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci	for (i = 0; i < loop; i++) {
147462306a36Sopenharmony_ci		if (qla4_82xx_pci_mem_read_2M(ha, off8 +
147562306a36Sopenharmony_ci		    (i << shift_amount), &word[i * scale], 8))
147662306a36Sopenharmony_ci			return -1;
147762306a36Sopenharmony_ci	}
147862306a36Sopenharmony_ci
147962306a36Sopenharmony_ci	switch (size) {
148062306a36Sopenharmony_ci	case 1:
148162306a36Sopenharmony_ci		tmpw = *((uint8_t *)data);
148262306a36Sopenharmony_ci		break;
148362306a36Sopenharmony_ci	case 2:
148462306a36Sopenharmony_ci		tmpw = *((uint16_t *)data);
148562306a36Sopenharmony_ci		break;
148662306a36Sopenharmony_ci	case 4:
148762306a36Sopenharmony_ci		tmpw = *((uint32_t *)data);
148862306a36Sopenharmony_ci		break;
148962306a36Sopenharmony_ci	case 8:
149062306a36Sopenharmony_ci	default:
149162306a36Sopenharmony_ci		tmpw = *((uint64_t *)data);
149262306a36Sopenharmony_ci		break;
149362306a36Sopenharmony_ci	}
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	if (sz[0] == 8)
149662306a36Sopenharmony_ci		word[startword] = tmpw;
149762306a36Sopenharmony_ci	else {
149862306a36Sopenharmony_ci		word[startword] &=
149962306a36Sopenharmony_ci		    ~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
150062306a36Sopenharmony_ci		word[startword] |= tmpw << (off0 * 8);
150162306a36Sopenharmony_ci	}
150262306a36Sopenharmony_ci
150362306a36Sopenharmony_ci	if (sz[1] != 0) {
150462306a36Sopenharmony_ci		word[startword+1] &= ~(~0ULL << (sz[1] * 8));
150562306a36Sopenharmony_ci		word[startword+1] |= tmpw >> (sz[0] * 8);
150662306a36Sopenharmony_ci	}
150762306a36Sopenharmony_ci
150862306a36Sopenharmony_ci	for (i = 0; i < loop; i++) {
150962306a36Sopenharmony_ci		temp = off8 + (i << shift_amount);
151062306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp);
151162306a36Sopenharmony_ci		temp = 0;
151262306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_HI, temp);
151362306a36Sopenharmony_ci		temp = word[i * scale] & 0xffffffff;
151462306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp);
151562306a36Sopenharmony_ci		temp = (word[i * scale] >> 32) & 0xffffffff;
151662306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp);
151762306a36Sopenharmony_ci		temp = word[i*scale + 1] & 0xffffffff;
151862306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_WRDATA_UPPER_LO,
151962306a36Sopenharmony_ci		    temp);
152062306a36Sopenharmony_ci		temp = (word[i*scale + 1] >> 32) & 0xffffffff;
152162306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_WRDATA_UPPER_HI,
152262306a36Sopenharmony_ci		    temp);
152362306a36Sopenharmony_ci
152462306a36Sopenharmony_ci		temp = MIU_TA_CTL_WRITE_ENABLE;
152562306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp);
152662306a36Sopenharmony_ci		temp = MIU_TA_CTL_WRITE_START;
152762306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_CTRL, temp);
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci		for (j = 0; j < MAX_CTL_CHECK; j++) {
153062306a36Sopenharmony_ci			temp = qla4_82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL);
153162306a36Sopenharmony_ci			if ((temp & MIU_TA_CTL_BUSY) == 0)
153262306a36Sopenharmony_ci				break;
153362306a36Sopenharmony_ci		}
153462306a36Sopenharmony_ci
153562306a36Sopenharmony_ci		if (j >= MAX_CTL_CHECK) {
153662306a36Sopenharmony_ci			if (printk_ratelimit())
153762306a36Sopenharmony_ci				ql4_printk(KERN_ERR, ha,
153862306a36Sopenharmony_ci					   "%s: failed to read through agent\n",
153962306a36Sopenharmony_ci					   __func__);
154062306a36Sopenharmony_ci			ret = -1;
154162306a36Sopenharmony_ci			break;
154262306a36Sopenharmony_ci		}
154362306a36Sopenharmony_ci	}
154462306a36Sopenharmony_ci
154562306a36Sopenharmony_ci	return ret;
154662306a36Sopenharmony_ci}
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_cistatic int qla4_82xx_cmdpeg_ready(struct scsi_qla_host *ha, int pegtune_val)
154962306a36Sopenharmony_ci{
155062306a36Sopenharmony_ci	u32 val = 0;
155162306a36Sopenharmony_ci	int retries = 60;
155262306a36Sopenharmony_ci
155362306a36Sopenharmony_ci	if (!pegtune_val) {
155462306a36Sopenharmony_ci		do {
155562306a36Sopenharmony_ci			val = qla4_82xx_rd_32(ha, CRB_CMDPEG_STATE);
155662306a36Sopenharmony_ci			if ((val == PHAN_INITIALIZE_COMPLETE) ||
155762306a36Sopenharmony_ci			    (val == PHAN_INITIALIZE_ACK))
155862306a36Sopenharmony_ci				return 0;
155962306a36Sopenharmony_ci			set_current_state(TASK_UNINTERRUPTIBLE);
156062306a36Sopenharmony_ci			schedule_timeout(500);
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci		} while (--retries);
156362306a36Sopenharmony_ci
156462306a36Sopenharmony_ci		if (!retries) {
156562306a36Sopenharmony_ci			pegtune_val = qla4_82xx_rd_32(ha,
156662306a36Sopenharmony_ci				QLA82XX_ROMUSB_GLB_PEGTUNE_DONE);
156762306a36Sopenharmony_ci			printk(KERN_WARNING "%s: init failed, "
156862306a36Sopenharmony_ci				"pegtune_val = %x\n", __func__, pegtune_val);
156962306a36Sopenharmony_ci			return -1;
157062306a36Sopenharmony_ci		}
157162306a36Sopenharmony_ci	}
157262306a36Sopenharmony_ci	return 0;
157362306a36Sopenharmony_ci}
157462306a36Sopenharmony_ci
157562306a36Sopenharmony_cistatic int qla4_82xx_rcvpeg_ready(struct scsi_qla_host *ha)
157662306a36Sopenharmony_ci{
157762306a36Sopenharmony_ci	uint32_t state = 0;
157862306a36Sopenharmony_ci	int loops = 0;
157962306a36Sopenharmony_ci
158062306a36Sopenharmony_ci	/* Window 1 call */
158162306a36Sopenharmony_ci	read_lock(&ha->hw_lock);
158262306a36Sopenharmony_ci	state = qla4_82xx_rd_32(ha, CRB_RCVPEG_STATE);
158362306a36Sopenharmony_ci	read_unlock(&ha->hw_lock);
158462306a36Sopenharmony_ci
158562306a36Sopenharmony_ci	while ((state != PHAN_PEG_RCV_INITIALIZED) && (loops < 30000)) {
158662306a36Sopenharmony_ci		udelay(100);
158762306a36Sopenharmony_ci		/* Window 1 call */
158862306a36Sopenharmony_ci		read_lock(&ha->hw_lock);
158962306a36Sopenharmony_ci		state = qla4_82xx_rd_32(ha, CRB_RCVPEG_STATE);
159062306a36Sopenharmony_ci		read_unlock(&ha->hw_lock);
159162306a36Sopenharmony_ci
159262306a36Sopenharmony_ci		loops++;
159362306a36Sopenharmony_ci	}
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	if (loops >= 30000) {
159662306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
159762306a36Sopenharmony_ci		    "Receive Peg initialization not complete: 0x%x.\n", state));
159862306a36Sopenharmony_ci		return QLA_ERROR;
159962306a36Sopenharmony_ci	}
160062306a36Sopenharmony_ci
160162306a36Sopenharmony_ci	return QLA_SUCCESS;
160262306a36Sopenharmony_ci}
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_civoid
160562306a36Sopenharmony_ciqla4_8xxx_set_drv_active(struct scsi_qla_host *ha)
160662306a36Sopenharmony_ci{
160762306a36Sopenharmony_ci	uint32_t drv_active;
160862306a36Sopenharmony_ci
160962306a36Sopenharmony_ci	drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
161062306a36Sopenharmony_ci
161162306a36Sopenharmony_ci	/*
161262306a36Sopenharmony_ci	 * For ISP8324 and ISP8042, drv_active register has 1 bit per function,
161362306a36Sopenharmony_ci	 * shift 1 by func_num to set a bit for the function.
161462306a36Sopenharmony_ci	 * For ISP8022, drv_active has 4 bits per function
161562306a36Sopenharmony_ci	 */
161662306a36Sopenharmony_ci	if (is_qla8032(ha) || is_qla8042(ha))
161762306a36Sopenharmony_ci		drv_active |= (1 << ha->func_num);
161862306a36Sopenharmony_ci	else
161962306a36Sopenharmony_ci		drv_active |= (1 << (ha->func_num * 4));
162062306a36Sopenharmony_ci
162162306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "%s(%ld): drv_active: 0x%08x\n",
162262306a36Sopenharmony_ci		   __func__, ha->host_no, drv_active);
162362306a36Sopenharmony_ci	qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_ACTIVE, drv_active);
162462306a36Sopenharmony_ci}
162562306a36Sopenharmony_ci
162662306a36Sopenharmony_civoid
162762306a36Sopenharmony_ciqla4_8xxx_clear_drv_active(struct scsi_qla_host *ha)
162862306a36Sopenharmony_ci{
162962306a36Sopenharmony_ci	uint32_t drv_active;
163062306a36Sopenharmony_ci
163162306a36Sopenharmony_ci	drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
163262306a36Sopenharmony_ci
163362306a36Sopenharmony_ci	/*
163462306a36Sopenharmony_ci	 * For ISP8324 and ISP8042, drv_active register has 1 bit per function,
163562306a36Sopenharmony_ci	 * shift 1 by func_num to set a bit for the function.
163662306a36Sopenharmony_ci	 * For ISP8022, drv_active has 4 bits per function
163762306a36Sopenharmony_ci	 */
163862306a36Sopenharmony_ci	if (is_qla8032(ha) || is_qla8042(ha))
163962306a36Sopenharmony_ci		drv_active &= ~(1 << (ha->func_num));
164062306a36Sopenharmony_ci	else
164162306a36Sopenharmony_ci		drv_active &= ~(1 << (ha->func_num * 4));
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "%s(%ld): drv_active: 0x%08x\n",
164462306a36Sopenharmony_ci		   __func__, ha->host_no, drv_active);
164562306a36Sopenharmony_ci	qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_ACTIVE, drv_active);
164662306a36Sopenharmony_ci}
164762306a36Sopenharmony_ci
164862306a36Sopenharmony_ciinline int qla4_8xxx_need_reset(struct scsi_qla_host *ha)
164962306a36Sopenharmony_ci{
165062306a36Sopenharmony_ci	uint32_t drv_state, drv_active;
165162306a36Sopenharmony_ci	int rval;
165262306a36Sopenharmony_ci
165362306a36Sopenharmony_ci	drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
165462306a36Sopenharmony_ci	drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE);
165562306a36Sopenharmony_ci
165662306a36Sopenharmony_ci	/*
165762306a36Sopenharmony_ci	 * For ISP8324 and ISP8042, drv_active register has 1 bit per function,
165862306a36Sopenharmony_ci	 * shift 1 by func_num to set a bit for the function.
165962306a36Sopenharmony_ci	 * For ISP8022, drv_active has 4 bits per function
166062306a36Sopenharmony_ci	 */
166162306a36Sopenharmony_ci	if (is_qla8032(ha) || is_qla8042(ha))
166262306a36Sopenharmony_ci		rval = drv_state & (1 << ha->func_num);
166362306a36Sopenharmony_ci	else
166462306a36Sopenharmony_ci		rval = drv_state & (1 << (ha->func_num * 4));
166562306a36Sopenharmony_ci
166662306a36Sopenharmony_ci	if ((test_bit(AF_EEH_BUSY, &ha->flags)) && drv_active)
166762306a36Sopenharmony_ci		rval = 1;
166862306a36Sopenharmony_ci
166962306a36Sopenharmony_ci	return rval;
167062306a36Sopenharmony_ci}
167162306a36Sopenharmony_ci
167262306a36Sopenharmony_civoid qla4_8xxx_set_rst_ready(struct scsi_qla_host *ha)
167362306a36Sopenharmony_ci{
167462306a36Sopenharmony_ci	uint32_t drv_state;
167562306a36Sopenharmony_ci
167662306a36Sopenharmony_ci	drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE);
167762306a36Sopenharmony_ci
167862306a36Sopenharmony_ci	/*
167962306a36Sopenharmony_ci	 * For ISP8324 and ISP8042, drv_active register has 1 bit per function,
168062306a36Sopenharmony_ci	 * shift 1 by func_num to set a bit for the function.
168162306a36Sopenharmony_ci	 * For ISP8022, drv_active has 4 bits per function
168262306a36Sopenharmony_ci	 */
168362306a36Sopenharmony_ci	if (is_qla8032(ha) || is_qla8042(ha))
168462306a36Sopenharmony_ci		drv_state |= (1 << ha->func_num);
168562306a36Sopenharmony_ci	else
168662306a36Sopenharmony_ci		drv_state |= (1 << (ha->func_num * 4));
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "%s(%ld): drv_state: 0x%08x\n",
168962306a36Sopenharmony_ci		   __func__, ha->host_no, drv_state);
169062306a36Sopenharmony_ci	qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_STATE, drv_state);
169162306a36Sopenharmony_ci}
169262306a36Sopenharmony_ci
169362306a36Sopenharmony_civoid qla4_8xxx_clear_rst_ready(struct scsi_qla_host *ha)
169462306a36Sopenharmony_ci{
169562306a36Sopenharmony_ci	uint32_t drv_state;
169662306a36Sopenharmony_ci
169762306a36Sopenharmony_ci	drv_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE);
169862306a36Sopenharmony_ci
169962306a36Sopenharmony_ci	/*
170062306a36Sopenharmony_ci	 * For ISP8324 and ISP8042, drv_active register has 1 bit per function,
170162306a36Sopenharmony_ci	 * shift 1 by func_num to set a bit for the function.
170262306a36Sopenharmony_ci	 * For ISP8022, drv_active has 4 bits per function
170362306a36Sopenharmony_ci	 */
170462306a36Sopenharmony_ci	if (is_qla8032(ha) || is_qla8042(ha))
170562306a36Sopenharmony_ci		drv_state &= ~(1 << ha->func_num);
170662306a36Sopenharmony_ci	else
170762306a36Sopenharmony_ci		drv_state &= ~(1 << (ha->func_num * 4));
170862306a36Sopenharmony_ci
170962306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "%s(%ld): drv_state: 0x%08x\n",
171062306a36Sopenharmony_ci		   __func__, ha->host_no, drv_state);
171162306a36Sopenharmony_ci	qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_STATE, drv_state);
171262306a36Sopenharmony_ci}
171362306a36Sopenharmony_ci
171462306a36Sopenharmony_cistatic inline void
171562306a36Sopenharmony_ciqla4_8xxx_set_qsnt_ready(struct scsi_qla_host *ha)
171662306a36Sopenharmony_ci{
171762306a36Sopenharmony_ci	uint32_t qsnt_state;
171862306a36Sopenharmony_ci
171962306a36Sopenharmony_ci	qsnt_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_STATE);
172062306a36Sopenharmony_ci
172162306a36Sopenharmony_ci	/*
172262306a36Sopenharmony_ci	 * For ISP8324 and ISP8042, drv_active register has 1 bit per function,
172362306a36Sopenharmony_ci	 * shift 1 by func_num to set a bit for the function.
172462306a36Sopenharmony_ci	 * For ISP8022, drv_active has 4 bits per function.
172562306a36Sopenharmony_ci	 */
172662306a36Sopenharmony_ci	if (is_qla8032(ha) || is_qla8042(ha))
172762306a36Sopenharmony_ci		qsnt_state |= (1 << ha->func_num);
172862306a36Sopenharmony_ci	else
172962306a36Sopenharmony_ci		qsnt_state |= (2 << (ha->func_num * 4));
173062306a36Sopenharmony_ci
173162306a36Sopenharmony_ci	qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_STATE, qsnt_state);
173262306a36Sopenharmony_ci}
173362306a36Sopenharmony_ci
173462306a36Sopenharmony_ci
173562306a36Sopenharmony_cistatic int
173662306a36Sopenharmony_ciqla4_82xx_start_firmware(struct scsi_qla_host *ha, uint32_t image_start)
173762306a36Sopenharmony_ci{
173862306a36Sopenharmony_ci	uint16_t lnk;
173962306a36Sopenharmony_ci
174062306a36Sopenharmony_ci	/* scrub dma mask expansion register */
174162306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, CRB_DMA_SHIFT, 0x55555555);
174262306a36Sopenharmony_ci
174362306a36Sopenharmony_ci	/* Overwrite stale initialization register values */
174462306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, CRB_CMDPEG_STATE, 0);
174562306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, CRB_RCVPEG_STATE, 0);
174662306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS1, 0);
174762306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS2, 0);
174862306a36Sopenharmony_ci
174962306a36Sopenharmony_ci	if (qla4_82xx_load_fw(ha, image_start) != QLA_SUCCESS) {
175062306a36Sopenharmony_ci		printk("%s: Error trying to start fw!\n", __func__);
175162306a36Sopenharmony_ci		return QLA_ERROR;
175262306a36Sopenharmony_ci	}
175362306a36Sopenharmony_ci
175462306a36Sopenharmony_ci	/* Handshake with the card before we register the devices. */
175562306a36Sopenharmony_ci	if (qla4_82xx_cmdpeg_ready(ha, 0) != QLA_SUCCESS) {
175662306a36Sopenharmony_ci		printk("%s: Error during card handshake!\n", __func__);
175762306a36Sopenharmony_ci		return QLA_ERROR;
175862306a36Sopenharmony_ci	}
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	/* Negotiated Link width */
176162306a36Sopenharmony_ci	pcie_capability_read_word(ha->pdev, PCI_EXP_LNKSTA, &lnk);
176262306a36Sopenharmony_ci	ha->link_width = (lnk >> 4) & 0x3f;
176362306a36Sopenharmony_ci
176462306a36Sopenharmony_ci	/* Synchronize with Receive peg */
176562306a36Sopenharmony_ci	return qla4_82xx_rcvpeg_ready(ha);
176662306a36Sopenharmony_ci}
176762306a36Sopenharmony_ci
176862306a36Sopenharmony_ciint qla4_82xx_try_start_fw(struct scsi_qla_host *ha)
176962306a36Sopenharmony_ci{
177062306a36Sopenharmony_ci	int rval;
177162306a36Sopenharmony_ci
177262306a36Sopenharmony_ci	/*
177362306a36Sopenharmony_ci	 * FW Load priority:
177462306a36Sopenharmony_ci	 * 1) Operational firmware residing in flash.
177562306a36Sopenharmony_ci	 * 2) Fail
177662306a36Sopenharmony_ci	 */
177762306a36Sopenharmony_ci
177862306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha,
177962306a36Sopenharmony_ci	    "FW: Retrieving flash offsets from FLT/FDT ...\n");
178062306a36Sopenharmony_ci	rval = qla4_8xxx_get_flash_info(ha);
178162306a36Sopenharmony_ci	if (rval != QLA_SUCCESS)
178262306a36Sopenharmony_ci		return rval;
178362306a36Sopenharmony_ci
178462306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha,
178562306a36Sopenharmony_ci	    "FW: Attempting to load firmware from flash...\n");
178662306a36Sopenharmony_ci	rval = qla4_82xx_start_firmware(ha, ha->hw.flt_region_fw);
178762306a36Sopenharmony_ci
178862306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
178962306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "FW: Load firmware from flash"
179062306a36Sopenharmony_ci		    " FAILED...\n");
179162306a36Sopenharmony_ci		return rval;
179262306a36Sopenharmony_ci	}
179362306a36Sopenharmony_ci
179462306a36Sopenharmony_ci	return rval;
179562306a36Sopenharmony_ci}
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_civoid qla4_82xx_rom_lock_recovery(struct scsi_qla_host *ha)
179862306a36Sopenharmony_ci{
179962306a36Sopenharmony_ci	if (qla4_82xx_rom_lock(ha)) {
180062306a36Sopenharmony_ci		/* Someone else is holding the lock. */
180162306a36Sopenharmony_ci		dev_info(&ha->pdev->dev, "Resetting rom_lock\n");
180262306a36Sopenharmony_ci	}
180362306a36Sopenharmony_ci
180462306a36Sopenharmony_ci	/*
180562306a36Sopenharmony_ci	 * Either we got the lock, or someone
180662306a36Sopenharmony_ci	 * else died while holding it.
180762306a36Sopenharmony_ci	 * In either case, unlock.
180862306a36Sopenharmony_ci	 */
180962306a36Sopenharmony_ci	qla4_82xx_rom_unlock(ha);
181062306a36Sopenharmony_ci}
181162306a36Sopenharmony_ci
181262306a36Sopenharmony_cistatic uint32_t ql4_84xx_poll_wait_for_ready(struct scsi_qla_host *ha,
181362306a36Sopenharmony_ci					     uint32_t addr1, uint32_t mask)
181462306a36Sopenharmony_ci{
181562306a36Sopenharmony_ci	unsigned long timeout;
181662306a36Sopenharmony_ci	uint32_t rval = QLA_SUCCESS;
181762306a36Sopenharmony_ci	uint32_t temp;
181862306a36Sopenharmony_ci
181962306a36Sopenharmony_ci	timeout = jiffies + msecs_to_jiffies(TIMEOUT_100_MS);
182062306a36Sopenharmony_ci	do {
182162306a36Sopenharmony_ci		ha->isp_ops->rd_reg_indirect(ha, addr1, &temp);
182262306a36Sopenharmony_ci		if ((temp & mask) != 0)
182362306a36Sopenharmony_ci			break;
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci		if (time_after_eq(jiffies, timeout)) {
182662306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "Error in processing rdmdio entry\n");
182762306a36Sopenharmony_ci			return QLA_ERROR;
182862306a36Sopenharmony_ci		}
182962306a36Sopenharmony_ci	} while (1);
183062306a36Sopenharmony_ci
183162306a36Sopenharmony_ci	return rval;
183262306a36Sopenharmony_ci}
183362306a36Sopenharmony_ci
183462306a36Sopenharmony_cistatic uint32_t ql4_84xx_ipmdio_rd_reg(struct scsi_qla_host *ha, uint32_t addr1,
183562306a36Sopenharmony_ci				uint32_t addr3, uint32_t mask, uint32_t addr,
183662306a36Sopenharmony_ci				uint32_t *data_ptr)
183762306a36Sopenharmony_ci{
183862306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
183962306a36Sopenharmony_ci	uint32_t temp;
184062306a36Sopenharmony_ci	uint32_t data;
184162306a36Sopenharmony_ci
184262306a36Sopenharmony_ci	rval = ql4_84xx_poll_wait_for_ready(ha, addr1, mask);
184362306a36Sopenharmony_ci	if (rval)
184462306a36Sopenharmony_ci		goto exit_ipmdio_rd_reg;
184562306a36Sopenharmony_ci
184662306a36Sopenharmony_ci	temp = (0x40000000 | addr);
184762306a36Sopenharmony_ci	ha->isp_ops->wr_reg_indirect(ha, addr1, temp);
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci	rval = ql4_84xx_poll_wait_for_ready(ha, addr1, mask);
185062306a36Sopenharmony_ci	if (rval)
185162306a36Sopenharmony_ci		goto exit_ipmdio_rd_reg;
185262306a36Sopenharmony_ci
185362306a36Sopenharmony_ci	ha->isp_ops->rd_reg_indirect(ha, addr3, &data);
185462306a36Sopenharmony_ci	*data_ptr = data;
185562306a36Sopenharmony_ci
185662306a36Sopenharmony_ciexit_ipmdio_rd_reg:
185762306a36Sopenharmony_ci	return rval;
185862306a36Sopenharmony_ci}
185962306a36Sopenharmony_ci
186062306a36Sopenharmony_ci
186162306a36Sopenharmony_cistatic uint32_t ql4_84xx_poll_wait_ipmdio_bus_idle(struct scsi_qla_host *ha,
186262306a36Sopenharmony_ci						    uint32_t addr1,
186362306a36Sopenharmony_ci						    uint32_t addr2,
186462306a36Sopenharmony_ci						    uint32_t addr3,
186562306a36Sopenharmony_ci						    uint32_t mask)
186662306a36Sopenharmony_ci{
186762306a36Sopenharmony_ci	unsigned long timeout;
186862306a36Sopenharmony_ci	uint32_t temp;
186962306a36Sopenharmony_ci	uint32_t rval = QLA_SUCCESS;
187062306a36Sopenharmony_ci
187162306a36Sopenharmony_ci	timeout = jiffies + msecs_to_jiffies(TIMEOUT_100_MS);
187262306a36Sopenharmony_ci	do {
187362306a36Sopenharmony_ci		ql4_84xx_ipmdio_rd_reg(ha, addr1, addr3, mask, addr2, &temp);
187462306a36Sopenharmony_ci		if ((temp & 0x1) != 1)
187562306a36Sopenharmony_ci			break;
187662306a36Sopenharmony_ci		if (time_after_eq(jiffies, timeout)) {
187762306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "Error in processing mdiobus idle\n");
187862306a36Sopenharmony_ci			return QLA_ERROR;
187962306a36Sopenharmony_ci		}
188062306a36Sopenharmony_ci	} while (1);
188162306a36Sopenharmony_ci
188262306a36Sopenharmony_ci	return rval;
188362306a36Sopenharmony_ci}
188462306a36Sopenharmony_ci
188562306a36Sopenharmony_cistatic int ql4_84xx_ipmdio_wr_reg(struct scsi_qla_host *ha,
188662306a36Sopenharmony_ci				  uint32_t addr1, uint32_t addr3,
188762306a36Sopenharmony_ci				  uint32_t mask, uint32_t addr,
188862306a36Sopenharmony_ci				  uint32_t value)
188962306a36Sopenharmony_ci{
189062306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	rval = ql4_84xx_poll_wait_for_ready(ha, addr1, mask);
189362306a36Sopenharmony_ci	if (rval)
189462306a36Sopenharmony_ci		goto exit_ipmdio_wr_reg;
189562306a36Sopenharmony_ci
189662306a36Sopenharmony_ci	ha->isp_ops->wr_reg_indirect(ha, addr3, value);
189762306a36Sopenharmony_ci	ha->isp_ops->wr_reg_indirect(ha, addr1, addr);
189862306a36Sopenharmony_ci
189962306a36Sopenharmony_ci	rval = ql4_84xx_poll_wait_for_ready(ha, addr1, mask);
190062306a36Sopenharmony_ci	if (rval)
190162306a36Sopenharmony_ci		goto exit_ipmdio_wr_reg;
190262306a36Sopenharmony_ci
190362306a36Sopenharmony_ciexit_ipmdio_wr_reg:
190462306a36Sopenharmony_ci	return rval;
190562306a36Sopenharmony_ci}
190662306a36Sopenharmony_ci
190762306a36Sopenharmony_cistatic void qla4_8xxx_minidump_process_rdcrb(struct scsi_qla_host *ha,
190862306a36Sopenharmony_ci				struct qla8xxx_minidump_entry_hdr *entry_hdr,
190962306a36Sopenharmony_ci				uint32_t **d_ptr)
191062306a36Sopenharmony_ci{
191162306a36Sopenharmony_ci	uint32_t r_addr, r_stride, loop_cnt, i, r_value;
191262306a36Sopenharmony_ci	struct qla8xxx_minidump_entry_crb *crb_hdr;
191362306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
191462306a36Sopenharmony_ci
191562306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__));
191662306a36Sopenharmony_ci	crb_hdr = (struct qla8xxx_minidump_entry_crb *)entry_hdr;
191762306a36Sopenharmony_ci	r_addr = crb_hdr->addr;
191862306a36Sopenharmony_ci	r_stride = crb_hdr->crb_strd.addr_stride;
191962306a36Sopenharmony_ci	loop_cnt = crb_hdr->op_count;
192062306a36Sopenharmony_ci
192162306a36Sopenharmony_ci	for (i = 0; i < loop_cnt; i++) {
192262306a36Sopenharmony_ci		ha->isp_ops->rd_reg_indirect(ha, r_addr, &r_value);
192362306a36Sopenharmony_ci		*data_ptr++ = cpu_to_le32(r_addr);
192462306a36Sopenharmony_ci		*data_ptr++ = cpu_to_le32(r_value);
192562306a36Sopenharmony_ci		r_addr += r_stride;
192662306a36Sopenharmony_ci	}
192762306a36Sopenharmony_ci	*d_ptr = data_ptr;
192862306a36Sopenharmony_ci}
192962306a36Sopenharmony_ci
193062306a36Sopenharmony_cistatic int qla4_83xx_check_dma_engine_state(struct scsi_qla_host *ha)
193162306a36Sopenharmony_ci{
193262306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
193362306a36Sopenharmony_ci	uint32_t dma_eng_num = 0, cmd_sts_and_cntrl = 0;
193462306a36Sopenharmony_ci	uint64_t dma_base_addr = 0;
193562306a36Sopenharmony_ci	struct qla4_8xxx_minidump_template_hdr *tmplt_hdr = NULL;
193662306a36Sopenharmony_ci
193762306a36Sopenharmony_ci	tmplt_hdr = (struct qla4_8xxx_minidump_template_hdr *)
193862306a36Sopenharmony_ci							ha->fw_dump_tmplt_hdr;
193962306a36Sopenharmony_ci	dma_eng_num =
194062306a36Sopenharmony_ci		tmplt_hdr->saved_state_array[QLA83XX_PEX_DMA_ENGINE_INDEX];
194162306a36Sopenharmony_ci	dma_base_addr = QLA83XX_PEX_DMA_BASE_ADDRESS +
194262306a36Sopenharmony_ci				(dma_eng_num * QLA83XX_PEX_DMA_NUM_OFFSET);
194362306a36Sopenharmony_ci
194462306a36Sopenharmony_ci	/* Read the pex-dma's command-status-and-control register. */
194562306a36Sopenharmony_ci	rval = ha->isp_ops->rd_reg_indirect(ha,
194662306a36Sopenharmony_ci			(dma_base_addr + QLA83XX_PEX_DMA_CMD_STS_AND_CNTRL),
194762306a36Sopenharmony_ci			&cmd_sts_and_cntrl);
194862306a36Sopenharmony_ci
194962306a36Sopenharmony_ci	if (rval)
195062306a36Sopenharmony_ci		return QLA_ERROR;
195162306a36Sopenharmony_ci
195262306a36Sopenharmony_ci	/* Check if requested pex-dma engine is available. */
195362306a36Sopenharmony_ci	if (cmd_sts_and_cntrl & BIT_31)
195462306a36Sopenharmony_ci		return QLA_SUCCESS;
195562306a36Sopenharmony_ci	else
195662306a36Sopenharmony_ci		return QLA_ERROR;
195762306a36Sopenharmony_ci}
195862306a36Sopenharmony_ci
195962306a36Sopenharmony_cistatic int qla4_83xx_start_pex_dma(struct scsi_qla_host *ha,
196062306a36Sopenharmony_ci			   struct qla4_83xx_minidump_entry_rdmem_pex_dma *m_hdr)
196162306a36Sopenharmony_ci{
196262306a36Sopenharmony_ci	int rval = QLA_SUCCESS, wait = 0;
196362306a36Sopenharmony_ci	uint32_t dma_eng_num = 0, cmd_sts_and_cntrl = 0;
196462306a36Sopenharmony_ci	uint64_t dma_base_addr = 0;
196562306a36Sopenharmony_ci	struct qla4_8xxx_minidump_template_hdr *tmplt_hdr = NULL;
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	tmplt_hdr = (struct qla4_8xxx_minidump_template_hdr *)
196862306a36Sopenharmony_ci							ha->fw_dump_tmplt_hdr;
196962306a36Sopenharmony_ci	dma_eng_num =
197062306a36Sopenharmony_ci		tmplt_hdr->saved_state_array[QLA83XX_PEX_DMA_ENGINE_INDEX];
197162306a36Sopenharmony_ci	dma_base_addr = QLA83XX_PEX_DMA_BASE_ADDRESS +
197262306a36Sopenharmony_ci				(dma_eng_num * QLA83XX_PEX_DMA_NUM_OFFSET);
197362306a36Sopenharmony_ci
197462306a36Sopenharmony_ci	rval = ha->isp_ops->wr_reg_indirect(ha,
197562306a36Sopenharmony_ci				dma_base_addr + QLA83XX_PEX_DMA_CMD_ADDR_LOW,
197662306a36Sopenharmony_ci				m_hdr->desc_card_addr);
197762306a36Sopenharmony_ci	if (rval)
197862306a36Sopenharmony_ci		goto error_exit;
197962306a36Sopenharmony_ci
198062306a36Sopenharmony_ci	rval = ha->isp_ops->wr_reg_indirect(ha,
198162306a36Sopenharmony_ci			      dma_base_addr + QLA83XX_PEX_DMA_CMD_ADDR_HIGH, 0);
198262306a36Sopenharmony_ci	if (rval)
198362306a36Sopenharmony_ci		goto error_exit;
198462306a36Sopenharmony_ci
198562306a36Sopenharmony_ci	rval = ha->isp_ops->wr_reg_indirect(ha,
198662306a36Sopenharmony_ci			      dma_base_addr + QLA83XX_PEX_DMA_CMD_STS_AND_CNTRL,
198762306a36Sopenharmony_ci			      m_hdr->start_dma_cmd);
198862306a36Sopenharmony_ci	if (rval)
198962306a36Sopenharmony_ci		goto error_exit;
199062306a36Sopenharmony_ci
199162306a36Sopenharmony_ci	/* Wait for dma operation to complete. */
199262306a36Sopenharmony_ci	for (wait = 0; wait < QLA83XX_PEX_DMA_MAX_WAIT; wait++) {
199362306a36Sopenharmony_ci		rval = ha->isp_ops->rd_reg_indirect(ha,
199462306a36Sopenharmony_ci			    (dma_base_addr + QLA83XX_PEX_DMA_CMD_STS_AND_CNTRL),
199562306a36Sopenharmony_ci			    &cmd_sts_and_cntrl);
199662306a36Sopenharmony_ci		if (rval)
199762306a36Sopenharmony_ci			goto error_exit;
199862306a36Sopenharmony_ci
199962306a36Sopenharmony_ci		if ((cmd_sts_and_cntrl & BIT_1) == 0)
200062306a36Sopenharmony_ci			break;
200162306a36Sopenharmony_ci		else
200262306a36Sopenharmony_ci			udelay(10);
200362306a36Sopenharmony_ci	}
200462306a36Sopenharmony_ci
200562306a36Sopenharmony_ci	/* Wait a max of 100 ms, otherwise fallback to rdmem entry read */
200662306a36Sopenharmony_ci	if (wait >= QLA83XX_PEX_DMA_MAX_WAIT) {
200762306a36Sopenharmony_ci		rval = QLA_ERROR;
200862306a36Sopenharmony_ci		goto error_exit;
200962306a36Sopenharmony_ci	}
201062306a36Sopenharmony_ci
201162306a36Sopenharmony_cierror_exit:
201262306a36Sopenharmony_ci	return rval;
201362306a36Sopenharmony_ci}
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_cistatic int qla4_8xxx_minidump_pex_dma_read(struct scsi_qla_host *ha,
201662306a36Sopenharmony_ci				struct qla8xxx_minidump_entry_hdr *entry_hdr,
201762306a36Sopenharmony_ci				uint32_t **d_ptr)
201862306a36Sopenharmony_ci{
201962306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
202062306a36Sopenharmony_ci	struct qla4_83xx_minidump_entry_rdmem_pex_dma *m_hdr = NULL;
202162306a36Sopenharmony_ci	uint32_t size, read_size;
202262306a36Sopenharmony_ci	uint8_t *data_ptr = (uint8_t *)*d_ptr;
202362306a36Sopenharmony_ci	void *rdmem_buffer = NULL;
202462306a36Sopenharmony_ci	dma_addr_t rdmem_dma;
202562306a36Sopenharmony_ci	struct qla4_83xx_pex_dma_descriptor dma_desc;
202662306a36Sopenharmony_ci
202762306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__));
202862306a36Sopenharmony_ci
202962306a36Sopenharmony_ci	rval = qla4_83xx_check_dma_engine_state(ha);
203062306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
203162306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
203262306a36Sopenharmony_ci				  "%s: DMA engine not available. Fallback to rdmem-read.\n",
203362306a36Sopenharmony_ci				  __func__));
203462306a36Sopenharmony_ci		return QLA_ERROR;
203562306a36Sopenharmony_ci	}
203662306a36Sopenharmony_ci
203762306a36Sopenharmony_ci	m_hdr = (struct qla4_83xx_minidump_entry_rdmem_pex_dma *)entry_hdr;
203862306a36Sopenharmony_ci	rdmem_buffer = dma_alloc_coherent(&ha->pdev->dev,
203962306a36Sopenharmony_ci					  QLA83XX_PEX_DMA_READ_SIZE,
204062306a36Sopenharmony_ci					  &rdmem_dma, GFP_KERNEL);
204162306a36Sopenharmony_ci	if (!rdmem_buffer) {
204262306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
204362306a36Sopenharmony_ci				  "%s: Unable to allocate rdmem dma buffer\n",
204462306a36Sopenharmony_ci				  __func__));
204562306a36Sopenharmony_ci		return QLA_ERROR;
204662306a36Sopenharmony_ci	}
204762306a36Sopenharmony_ci
204862306a36Sopenharmony_ci	/* Prepare pex-dma descriptor to be written to MS memory. */
204962306a36Sopenharmony_ci	/* dma-desc-cmd layout:
205062306a36Sopenharmony_ci	 *              0-3: dma-desc-cmd 0-3
205162306a36Sopenharmony_ci	 *              4-7: pcid function number
205262306a36Sopenharmony_ci	 *              8-15: dma-desc-cmd 8-15
205362306a36Sopenharmony_ci	 */
205462306a36Sopenharmony_ci	dma_desc.cmd.dma_desc_cmd = (m_hdr->dma_desc_cmd & 0xff0f);
205562306a36Sopenharmony_ci	dma_desc.cmd.dma_desc_cmd |= ((PCI_FUNC(ha->pdev->devfn) & 0xf) << 0x4);
205662306a36Sopenharmony_ci	dma_desc.dma_bus_addr = rdmem_dma;
205762306a36Sopenharmony_ci
205862306a36Sopenharmony_ci	size = 0;
205962306a36Sopenharmony_ci	read_size = 0;
206062306a36Sopenharmony_ci	/*
206162306a36Sopenharmony_ci	 * Perform rdmem operation using pex-dma.
206262306a36Sopenharmony_ci	 * Prepare dma in chunks of QLA83XX_PEX_DMA_READ_SIZE.
206362306a36Sopenharmony_ci	 */
206462306a36Sopenharmony_ci	while (read_size < m_hdr->read_data_size) {
206562306a36Sopenharmony_ci		if (m_hdr->read_data_size - read_size >=
206662306a36Sopenharmony_ci		    QLA83XX_PEX_DMA_READ_SIZE)
206762306a36Sopenharmony_ci			size = QLA83XX_PEX_DMA_READ_SIZE;
206862306a36Sopenharmony_ci		else {
206962306a36Sopenharmony_ci			size = (m_hdr->read_data_size - read_size);
207062306a36Sopenharmony_ci
207162306a36Sopenharmony_ci			if (rdmem_buffer)
207262306a36Sopenharmony_ci				dma_free_coherent(&ha->pdev->dev,
207362306a36Sopenharmony_ci						  QLA83XX_PEX_DMA_READ_SIZE,
207462306a36Sopenharmony_ci						  rdmem_buffer, rdmem_dma);
207562306a36Sopenharmony_ci
207662306a36Sopenharmony_ci			rdmem_buffer = dma_alloc_coherent(&ha->pdev->dev, size,
207762306a36Sopenharmony_ci							  &rdmem_dma,
207862306a36Sopenharmony_ci							  GFP_KERNEL);
207962306a36Sopenharmony_ci			if (!rdmem_buffer) {
208062306a36Sopenharmony_ci				DEBUG2(ql4_printk(KERN_INFO, ha,
208162306a36Sopenharmony_ci						  "%s: Unable to allocate rdmem dma buffer\n",
208262306a36Sopenharmony_ci						  __func__));
208362306a36Sopenharmony_ci				return QLA_ERROR;
208462306a36Sopenharmony_ci			}
208562306a36Sopenharmony_ci			dma_desc.dma_bus_addr = rdmem_dma;
208662306a36Sopenharmony_ci		}
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci		dma_desc.src_addr = m_hdr->read_addr + read_size;
208962306a36Sopenharmony_ci		dma_desc.cmd.read_data_size = size;
209062306a36Sopenharmony_ci
209162306a36Sopenharmony_ci		/* Prepare: Write pex-dma descriptor to MS memory. */
209262306a36Sopenharmony_ci		rval = qla4_8xxx_ms_mem_write_128b(ha,
209362306a36Sopenharmony_ci			      (uint64_t)m_hdr->desc_card_addr,
209462306a36Sopenharmony_ci			      (uint32_t *)&dma_desc,
209562306a36Sopenharmony_ci			      (sizeof(struct qla4_83xx_pex_dma_descriptor)/16));
209662306a36Sopenharmony_ci		if (rval != QLA_SUCCESS) {
209762306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha,
209862306a36Sopenharmony_ci				   "%s: Error writing rdmem-dma-init to MS !!!\n",
209962306a36Sopenharmony_ci				   __func__);
210062306a36Sopenharmony_ci			goto error_exit;
210162306a36Sopenharmony_ci		}
210262306a36Sopenharmony_ci
210362306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
210462306a36Sopenharmony_ci				  "%s: Dma-desc: Instruct for rdmem dma (size 0x%x).\n",
210562306a36Sopenharmony_ci				  __func__, size));
210662306a36Sopenharmony_ci		/* Execute: Start pex-dma operation. */
210762306a36Sopenharmony_ci		rval = qla4_83xx_start_pex_dma(ha, m_hdr);
210862306a36Sopenharmony_ci		if (rval != QLA_SUCCESS) {
210962306a36Sopenharmony_ci			DEBUG2(ql4_printk(KERN_INFO, ha,
211062306a36Sopenharmony_ci					  "scsi(%ld): start-pex-dma failed rval=0x%x\n",
211162306a36Sopenharmony_ci					  ha->host_no, rval));
211262306a36Sopenharmony_ci			goto error_exit;
211362306a36Sopenharmony_ci		}
211462306a36Sopenharmony_ci
211562306a36Sopenharmony_ci		memcpy(data_ptr, rdmem_buffer, size);
211662306a36Sopenharmony_ci		data_ptr += size;
211762306a36Sopenharmony_ci		read_size += size;
211862306a36Sopenharmony_ci	}
211962306a36Sopenharmony_ci
212062306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "Leaving fn: %s\n", __func__));
212162306a36Sopenharmony_ci
212262306a36Sopenharmony_ci	*d_ptr = (uint32_t *)data_ptr;
212362306a36Sopenharmony_ci
212462306a36Sopenharmony_cierror_exit:
212562306a36Sopenharmony_ci	if (rdmem_buffer)
212662306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, size, rdmem_buffer,
212762306a36Sopenharmony_ci				  rdmem_dma);
212862306a36Sopenharmony_ci
212962306a36Sopenharmony_ci	return rval;
213062306a36Sopenharmony_ci}
213162306a36Sopenharmony_ci
213262306a36Sopenharmony_cistatic int qla4_8xxx_minidump_process_l2tag(struct scsi_qla_host *ha,
213362306a36Sopenharmony_ci				 struct qla8xxx_minidump_entry_hdr *entry_hdr,
213462306a36Sopenharmony_ci				 uint32_t **d_ptr)
213562306a36Sopenharmony_ci{
213662306a36Sopenharmony_ci	uint32_t addr, r_addr, c_addr, t_r_addr;
213762306a36Sopenharmony_ci	uint32_t i, k, loop_count, t_value, r_cnt, r_value;
213862306a36Sopenharmony_ci	unsigned long p_wait, w_time, p_mask;
213962306a36Sopenharmony_ci	uint32_t c_value_w, c_value_r;
214062306a36Sopenharmony_ci	struct qla8xxx_minidump_entry_cache *cache_hdr;
214162306a36Sopenharmony_ci	int rval = QLA_ERROR;
214262306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
214362306a36Sopenharmony_ci
214462306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__));
214562306a36Sopenharmony_ci	cache_hdr = (struct qla8xxx_minidump_entry_cache *)entry_hdr;
214662306a36Sopenharmony_ci
214762306a36Sopenharmony_ci	loop_count = cache_hdr->op_count;
214862306a36Sopenharmony_ci	r_addr = cache_hdr->read_addr;
214962306a36Sopenharmony_ci	c_addr = cache_hdr->control_addr;
215062306a36Sopenharmony_ci	c_value_w = cache_hdr->cache_ctrl.write_value;
215162306a36Sopenharmony_ci
215262306a36Sopenharmony_ci	t_r_addr = cache_hdr->tag_reg_addr;
215362306a36Sopenharmony_ci	t_value = cache_hdr->addr_ctrl.init_tag_value;
215462306a36Sopenharmony_ci	r_cnt = cache_hdr->read_ctrl.read_addr_cnt;
215562306a36Sopenharmony_ci	p_wait = cache_hdr->cache_ctrl.poll_wait;
215662306a36Sopenharmony_ci	p_mask = cache_hdr->cache_ctrl.poll_mask;
215762306a36Sopenharmony_ci
215862306a36Sopenharmony_ci	for (i = 0; i < loop_count; i++) {
215962306a36Sopenharmony_ci		ha->isp_ops->wr_reg_indirect(ha, t_r_addr, t_value);
216062306a36Sopenharmony_ci
216162306a36Sopenharmony_ci		if (c_value_w)
216262306a36Sopenharmony_ci			ha->isp_ops->wr_reg_indirect(ha, c_addr, c_value_w);
216362306a36Sopenharmony_ci
216462306a36Sopenharmony_ci		if (p_mask) {
216562306a36Sopenharmony_ci			w_time = jiffies + p_wait;
216662306a36Sopenharmony_ci			do {
216762306a36Sopenharmony_ci				ha->isp_ops->rd_reg_indirect(ha, c_addr,
216862306a36Sopenharmony_ci							     &c_value_r);
216962306a36Sopenharmony_ci				if ((c_value_r & p_mask) == 0) {
217062306a36Sopenharmony_ci					break;
217162306a36Sopenharmony_ci				} else if (time_after_eq(jiffies, w_time)) {
217262306a36Sopenharmony_ci					/* capturing dump failed */
217362306a36Sopenharmony_ci					return rval;
217462306a36Sopenharmony_ci				}
217562306a36Sopenharmony_ci			} while (1);
217662306a36Sopenharmony_ci		}
217762306a36Sopenharmony_ci
217862306a36Sopenharmony_ci		addr = r_addr;
217962306a36Sopenharmony_ci		for (k = 0; k < r_cnt; k++) {
218062306a36Sopenharmony_ci			ha->isp_ops->rd_reg_indirect(ha, addr, &r_value);
218162306a36Sopenharmony_ci			*data_ptr++ = cpu_to_le32(r_value);
218262306a36Sopenharmony_ci			addr += cache_hdr->read_ctrl.read_addr_stride;
218362306a36Sopenharmony_ci		}
218462306a36Sopenharmony_ci
218562306a36Sopenharmony_ci		t_value += cache_hdr->addr_ctrl.tag_value_stride;
218662306a36Sopenharmony_ci	}
218762306a36Sopenharmony_ci	*d_ptr = data_ptr;
218862306a36Sopenharmony_ci	return QLA_SUCCESS;
218962306a36Sopenharmony_ci}
219062306a36Sopenharmony_ci
219162306a36Sopenharmony_cistatic int qla4_8xxx_minidump_process_control(struct scsi_qla_host *ha,
219262306a36Sopenharmony_ci				struct qla8xxx_minidump_entry_hdr *entry_hdr)
219362306a36Sopenharmony_ci{
219462306a36Sopenharmony_ci	struct qla8xxx_minidump_entry_crb *crb_entry;
219562306a36Sopenharmony_ci	uint32_t read_value, opcode, poll_time, addr, index, rval = QLA_SUCCESS;
219662306a36Sopenharmony_ci	uint32_t crb_addr;
219762306a36Sopenharmony_ci	unsigned long wtime;
219862306a36Sopenharmony_ci	struct qla4_8xxx_minidump_template_hdr *tmplt_hdr;
219962306a36Sopenharmony_ci	int i;
220062306a36Sopenharmony_ci
220162306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__));
220262306a36Sopenharmony_ci	tmplt_hdr = (struct qla4_8xxx_minidump_template_hdr *)
220362306a36Sopenharmony_ci						ha->fw_dump_tmplt_hdr;
220462306a36Sopenharmony_ci	crb_entry = (struct qla8xxx_minidump_entry_crb *)entry_hdr;
220562306a36Sopenharmony_ci
220662306a36Sopenharmony_ci	crb_addr = crb_entry->addr;
220762306a36Sopenharmony_ci	for (i = 0; i < crb_entry->op_count; i++) {
220862306a36Sopenharmony_ci		opcode = crb_entry->crb_ctrl.opcode;
220962306a36Sopenharmony_ci		if (opcode & QLA8XXX_DBG_OPCODE_WR) {
221062306a36Sopenharmony_ci			ha->isp_ops->wr_reg_indirect(ha, crb_addr,
221162306a36Sopenharmony_ci						     crb_entry->value_1);
221262306a36Sopenharmony_ci			opcode &= ~QLA8XXX_DBG_OPCODE_WR;
221362306a36Sopenharmony_ci		}
221462306a36Sopenharmony_ci		if (opcode & QLA8XXX_DBG_OPCODE_RW) {
221562306a36Sopenharmony_ci			ha->isp_ops->rd_reg_indirect(ha, crb_addr, &read_value);
221662306a36Sopenharmony_ci			ha->isp_ops->wr_reg_indirect(ha, crb_addr, read_value);
221762306a36Sopenharmony_ci			opcode &= ~QLA8XXX_DBG_OPCODE_RW;
221862306a36Sopenharmony_ci		}
221962306a36Sopenharmony_ci		if (opcode & QLA8XXX_DBG_OPCODE_AND) {
222062306a36Sopenharmony_ci			ha->isp_ops->rd_reg_indirect(ha, crb_addr, &read_value);
222162306a36Sopenharmony_ci			read_value &= crb_entry->value_2;
222262306a36Sopenharmony_ci			opcode &= ~QLA8XXX_DBG_OPCODE_AND;
222362306a36Sopenharmony_ci			if (opcode & QLA8XXX_DBG_OPCODE_OR) {
222462306a36Sopenharmony_ci				read_value |= crb_entry->value_3;
222562306a36Sopenharmony_ci				opcode &= ~QLA8XXX_DBG_OPCODE_OR;
222662306a36Sopenharmony_ci			}
222762306a36Sopenharmony_ci			ha->isp_ops->wr_reg_indirect(ha, crb_addr, read_value);
222862306a36Sopenharmony_ci		}
222962306a36Sopenharmony_ci		if (opcode & QLA8XXX_DBG_OPCODE_OR) {
223062306a36Sopenharmony_ci			ha->isp_ops->rd_reg_indirect(ha, crb_addr, &read_value);
223162306a36Sopenharmony_ci			read_value |= crb_entry->value_3;
223262306a36Sopenharmony_ci			ha->isp_ops->wr_reg_indirect(ha, crb_addr, read_value);
223362306a36Sopenharmony_ci			opcode &= ~QLA8XXX_DBG_OPCODE_OR;
223462306a36Sopenharmony_ci		}
223562306a36Sopenharmony_ci		if (opcode & QLA8XXX_DBG_OPCODE_POLL) {
223662306a36Sopenharmony_ci			poll_time = crb_entry->crb_strd.poll_timeout;
223762306a36Sopenharmony_ci			wtime = jiffies + poll_time;
223862306a36Sopenharmony_ci			ha->isp_ops->rd_reg_indirect(ha, crb_addr, &read_value);
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci			do {
224162306a36Sopenharmony_ci				if ((read_value & crb_entry->value_2) ==
224262306a36Sopenharmony_ci				    crb_entry->value_1) {
224362306a36Sopenharmony_ci					break;
224462306a36Sopenharmony_ci				} else if (time_after_eq(jiffies, wtime)) {
224562306a36Sopenharmony_ci					/* capturing dump failed */
224662306a36Sopenharmony_ci					rval = QLA_ERROR;
224762306a36Sopenharmony_ci					break;
224862306a36Sopenharmony_ci				} else {
224962306a36Sopenharmony_ci					ha->isp_ops->rd_reg_indirect(ha,
225062306a36Sopenharmony_ci							crb_addr, &read_value);
225162306a36Sopenharmony_ci				}
225262306a36Sopenharmony_ci			} while (1);
225362306a36Sopenharmony_ci			opcode &= ~QLA8XXX_DBG_OPCODE_POLL;
225462306a36Sopenharmony_ci		}
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci		if (opcode & QLA8XXX_DBG_OPCODE_RDSTATE) {
225762306a36Sopenharmony_ci			if (crb_entry->crb_strd.state_index_a) {
225862306a36Sopenharmony_ci				index = crb_entry->crb_strd.state_index_a;
225962306a36Sopenharmony_ci				addr = tmplt_hdr->saved_state_array[index];
226062306a36Sopenharmony_ci			} else {
226162306a36Sopenharmony_ci				addr = crb_addr;
226262306a36Sopenharmony_ci			}
226362306a36Sopenharmony_ci
226462306a36Sopenharmony_ci			ha->isp_ops->rd_reg_indirect(ha, addr, &read_value);
226562306a36Sopenharmony_ci			index = crb_entry->crb_ctrl.state_index_v;
226662306a36Sopenharmony_ci			tmplt_hdr->saved_state_array[index] = read_value;
226762306a36Sopenharmony_ci			opcode &= ~QLA8XXX_DBG_OPCODE_RDSTATE;
226862306a36Sopenharmony_ci		}
226962306a36Sopenharmony_ci
227062306a36Sopenharmony_ci		if (opcode & QLA8XXX_DBG_OPCODE_WRSTATE) {
227162306a36Sopenharmony_ci			if (crb_entry->crb_strd.state_index_a) {
227262306a36Sopenharmony_ci				index = crb_entry->crb_strd.state_index_a;
227362306a36Sopenharmony_ci				addr = tmplt_hdr->saved_state_array[index];
227462306a36Sopenharmony_ci			} else {
227562306a36Sopenharmony_ci				addr = crb_addr;
227662306a36Sopenharmony_ci			}
227762306a36Sopenharmony_ci
227862306a36Sopenharmony_ci			if (crb_entry->crb_ctrl.state_index_v) {
227962306a36Sopenharmony_ci				index = crb_entry->crb_ctrl.state_index_v;
228062306a36Sopenharmony_ci				read_value =
228162306a36Sopenharmony_ci					tmplt_hdr->saved_state_array[index];
228262306a36Sopenharmony_ci			} else {
228362306a36Sopenharmony_ci				read_value = crb_entry->value_1;
228462306a36Sopenharmony_ci			}
228562306a36Sopenharmony_ci
228662306a36Sopenharmony_ci			ha->isp_ops->wr_reg_indirect(ha, addr, read_value);
228762306a36Sopenharmony_ci			opcode &= ~QLA8XXX_DBG_OPCODE_WRSTATE;
228862306a36Sopenharmony_ci		}
228962306a36Sopenharmony_ci
229062306a36Sopenharmony_ci		if (opcode & QLA8XXX_DBG_OPCODE_MDSTATE) {
229162306a36Sopenharmony_ci			index = crb_entry->crb_ctrl.state_index_v;
229262306a36Sopenharmony_ci			read_value = tmplt_hdr->saved_state_array[index];
229362306a36Sopenharmony_ci			read_value <<= crb_entry->crb_ctrl.shl;
229462306a36Sopenharmony_ci			read_value >>= crb_entry->crb_ctrl.shr;
229562306a36Sopenharmony_ci			if (crb_entry->value_2)
229662306a36Sopenharmony_ci				read_value &= crb_entry->value_2;
229762306a36Sopenharmony_ci			read_value |= crb_entry->value_3;
229862306a36Sopenharmony_ci			read_value += crb_entry->value_1;
229962306a36Sopenharmony_ci			tmplt_hdr->saved_state_array[index] = read_value;
230062306a36Sopenharmony_ci			opcode &= ~QLA8XXX_DBG_OPCODE_MDSTATE;
230162306a36Sopenharmony_ci		}
230262306a36Sopenharmony_ci		crb_addr += crb_entry->crb_strd.addr_stride;
230362306a36Sopenharmony_ci	}
230462306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "Leaving fn: %s\n", __func__));
230562306a36Sopenharmony_ci	return rval;
230662306a36Sopenharmony_ci}
230762306a36Sopenharmony_ci
230862306a36Sopenharmony_cistatic void qla4_8xxx_minidump_process_rdocm(struct scsi_qla_host *ha,
230962306a36Sopenharmony_ci				struct qla8xxx_minidump_entry_hdr *entry_hdr,
231062306a36Sopenharmony_ci				uint32_t **d_ptr)
231162306a36Sopenharmony_ci{
231262306a36Sopenharmony_ci	uint32_t r_addr, r_stride, loop_cnt, i, r_value;
231362306a36Sopenharmony_ci	struct qla8xxx_minidump_entry_rdocm *ocm_hdr;
231462306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
231562306a36Sopenharmony_ci
231662306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__));
231762306a36Sopenharmony_ci	ocm_hdr = (struct qla8xxx_minidump_entry_rdocm *)entry_hdr;
231862306a36Sopenharmony_ci	r_addr = ocm_hdr->read_addr;
231962306a36Sopenharmony_ci	r_stride = ocm_hdr->read_addr_stride;
232062306a36Sopenharmony_ci	loop_cnt = ocm_hdr->op_count;
232162306a36Sopenharmony_ci
232262306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
232362306a36Sopenharmony_ci			  "[%s]: r_addr: 0x%x, r_stride: 0x%x, loop_cnt: 0x%x\n",
232462306a36Sopenharmony_ci			  __func__, r_addr, r_stride, loop_cnt));
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci	for (i = 0; i < loop_cnt; i++) {
232762306a36Sopenharmony_ci		r_value = readl((void __iomem *)(r_addr + ha->nx_pcibase));
232862306a36Sopenharmony_ci		*data_ptr++ = cpu_to_le32(r_value);
232962306a36Sopenharmony_ci		r_addr += r_stride;
233062306a36Sopenharmony_ci	}
233162306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "Leaving fn: %s datacount: 0x%lx\n",
233262306a36Sopenharmony_ci		__func__, (long unsigned int) (loop_cnt * sizeof(uint32_t))));
233362306a36Sopenharmony_ci	*d_ptr = data_ptr;
233462306a36Sopenharmony_ci}
233562306a36Sopenharmony_ci
233662306a36Sopenharmony_cistatic void qla4_8xxx_minidump_process_rdmux(struct scsi_qla_host *ha,
233762306a36Sopenharmony_ci				struct qla8xxx_minidump_entry_hdr *entry_hdr,
233862306a36Sopenharmony_ci				uint32_t **d_ptr)
233962306a36Sopenharmony_ci{
234062306a36Sopenharmony_ci	uint32_t r_addr, s_stride, s_addr, s_value, loop_cnt, i, r_value;
234162306a36Sopenharmony_ci	struct qla8xxx_minidump_entry_mux *mux_hdr;
234262306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
234362306a36Sopenharmony_ci
234462306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__));
234562306a36Sopenharmony_ci	mux_hdr = (struct qla8xxx_minidump_entry_mux *)entry_hdr;
234662306a36Sopenharmony_ci	r_addr = mux_hdr->read_addr;
234762306a36Sopenharmony_ci	s_addr = mux_hdr->select_addr;
234862306a36Sopenharmony_ci	s_stride = mux_hdr->select_value_stride;
234962306a36Sopenharmony_ci	s_value = mux_hdr->select_value;
235062306a36Sopenharmony_ci	loop_cnt = mux_hdr->op_count;
235162306a36Sopenharmony_ci
235262306a36Sopenharmony_ci	for (i = 0; i < loop_cnt; i++) {
235362306a36Sopenharmony_ci		ha->isp_ops->wr_reg_indirect(ha, s_addr, s_value);
235462306a36Sopenharmony_ci		ha->isp_ops->rd_reg_indirect(ha, r_addr, &r_value);
235562306a36Sopenharmony_ci		*data_ptr++ = cpu_to_le32(s_value);
235662306a36Sopenharmony_ci		*data_ptr++ = cpu_to_le32(r_value);
235762306a36Sopenharmony_ci		s_value += s_stride;
235862306a36Sopenharmony_ci	}
235962306a36Sopenharmony_ci	*d_ptr = data_ptr;
236062306a36Sopenharmony_ci}
236162306a36Sopenharmony_ci
236262306a36Sopenharmony_cistatic void qla4_8xxx_minidump_process_l1cache(struct scsi_qla_host *ha,
236362306a36Sopenharmony_ci				struct qla8xxx_minidump_entry_hdr *entry_hdr,
236462306a36Sopenharmony_ci				uint32_t **d_ptr)
236562306a36Sopenharmony_ci{
236662306a36Sopenharmony_ci	uint32_t addr, r_addr, c_addr, t_r_addr;
236762306a36Sopenharmony_ci	uint32_t i, k, loop_count, t_value, r_cnt, r_value;
236862306a36Sopenharmony_ci	uint32_t c_value_w;
236962306a36Sopenharmony_ci	struct qla8xxx_minidump_entry_cache *cache_hdr;
237062306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
237162306a36Sopenharmony_ci
237262306a36Sopenharmony_ci	cache_hdr = (struct qla8xxx_minidump_entry_cache *)entry_hdr;
237362306a36Sopenharmony_ci	loop_count = cache_hdr->op_count;
237462306a36Sopenharmony_ci	r_addr = cache_hdr->read_addr;
237562306a36Sopenharmony_ci	c_addr = cache_hdr->control_addr;
237662306a36Sopenharmony_ci	c_value_w = cache_hdr->cache_ctrl.write_value;
237762306a36Sopenharmony_ci
237862306a36Sopenharmony_ci	t_r_addr = cache_hdr->tag_reg_addr;
237962306a36Sopenharmony_ci	t_value = cache_hdr->addr_ctrl.init_tag_value;
238062306a36Sopenharmony_ci	r_cnt = cache_hdr->read_ctrl.read_addr_cnt;
238162306a36Sopenharmony_ci
238262306a36Sopenharmony_ci	for (i = 0; i < loop_count; i++) {
238362306a36Sopenharmony_ci		ha->isp_ops->wr_reg_indirect(ha, t_r_addr, t_value);
238462306a36Sopenharmony_ci		ha->isp_ops->wr_reg_indirect(ha, c_addr, c_value_w);
238562306a36Sopenharmony_ci		addr = r_addr;
238662306a36Sopenharmony_ci		for (k = 0; k < r_cnt; k++) {
238762306a36Sopenharmony_ci			ha->isp_ops->rd_reg_indirect(ha, addr, &r_value);
238862306a36Sopenharmony_ci			*data_ptr++ = cpu_to_le32(r_value);
238962306a36Sopenharmony_ci			addr += cache_hdr->read_ctrl.read_addr_stride;
239062306a36Sopenharmony_ci		}
239162306a36Sopenharmony_ci		t_value += cache_hdr->addr_ctrl.tag_value_stride;
239262306a36Sopenharmony_ci	}
239362306a36Sopenharmony_ci	*d_ptr = data_ptr;
239462306a36Sopenharmony_ci}
239562306a36Sopenharmony_ci
239662306a36Sopenharmony_cistatic void qla4_8xxx_minidump_process_queue(struct scsi_qla_host *ha,
239762306a36Sopenharmony_ci				struct qla8xxx_minidump_entry_hdr *entry_hdr,
239862306a36Sopenharmony_ci				uint32_t **d_ptr)
239962306a36Sopenharmony_ci{
240062306a36Sopenharmony_ci	uint32_t s_addr, r_addr;
240162306a36Sopenharmony_ci	uint32_t r_stride, r_value, r_cnt, qid = 0;
240262306a36Sopenharmony_ci	uint32_t i, k, loop_cnt;
240362306a36Sopenharmony_ci	struct qla8xxx_minidump_entry_queue *q_hdr;
240462306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
240562306a36Sopenharmony_ci
240662306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__));
240762306a36Sopenharmony_ci	q_hdr = (struct qla8xxx_minidump_entry_queue *)entry_hdr;
240862306a36Sopenharmony_ci	s_addr = q_hdr->select_addr;
240962306a36Sopenharmony_ci	r_cnt = q_hdr->rd_strd.read_addr_cnt;
241062306a36Sopenharmony_ci	r_stride = q_hdr->rd_strd.read_addr_stride;
241162306a36Sopenharmony_ci	loop_cnt = q_hdr->op_count;
241262306a36Sopenharmony_ci
241362306a36Sopenharmony_ci	for (i = 0; i < loop_cnt; i++) {
241462306a36Sopenharmony_ci		ha->isp_ops->wr_reg_indirect(ha, s_addr, qid);
241562306a36Sopenharmony_ci		r_addr = q_hdr->read_addr;
241662306a36Sopenharmony_ci		for (k = 0; k < r_cnt; k++) {
241762306a36Sopenharmony_ci			ha->isp_ops->rd_reg_indirect(ha, r_addr, &r_value);
241862306a36Sopenharmony_ci			*data_ptr++ = cpu_to_le32(r_value);
241962306a36Sopenharmony_ci			r_addr += r_stride;
242062306a36Sopenharmony_ci		}
242162306a36Sopenharmony_ci		qid += q_hdr->q_strd.queue_id_stride;
242262306a36Sopenharmony_ci	}
242362306a36Sopenharmony_ci	*d_ptr = data_ptr;
242462306a36Sopenharmony_ci}
242562306a36Sopenharmony_ci
242662306a36Sopenharmony_ci#define MD_DIRECT_ROM_WINDOW		0x42110030
242762306a36Sopenharmony_ci#define MD_DIRECT_ROM_READ_BASE		0x42150000
242862306a36Sopenharmony_ci
242962306a36Sopenharmony_cistatic void qla4_82xx_minidump_process_rdrom(struct scsi_qla_host *ha,
243062306a36Sopenharmony_ci				struct qla8xxx_minidump_entry_hdr *entry_hdr,
243162306a36Sopenharmony_ci				uint32_t **d_ptr)
243262306a36Sopenharmony_ci{
243362306a36Sopenharmony_ci	uint32_t r_addr, r_value;
243462306a36Sopenharmony_ci	uint32_t i, loop_cnt;
243562306a36Sopenharmony_ci	struct qla8xxx_minidump_entry_rdrom *rom_hdr;
243662306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
243762306a36Sopenharmony_ci
243862306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__));
243962306a36Sopenharmony_ci	rom_hdr = (struct qla8xxx_minidump_entry_rdrom *)entry_hdr;
244062306a36Sopenharmony_ci	r_addr = rom_hdr->read_addr;
244162306a36Sopenharmony_ci	loop_cnt = rom_hdr->read_data_size/sizeof(uint32_t);
244262306a36Sopenharmony_ci
244362306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
244462306a36Sopenharmony_ci			  "[%s]: flash_addr: 0x%x, read_data_size: 0x%x\n",
244562306a36Sopenharmony_ci			   __func__, r_addr, loop_cnt));
244662306a36Sopenharmony_ci
244762306a36Sopenharmony_ci	for (i = 0; i < loop_cnt; i++) {
244862306a36Sopenharmony_ci		ha->isp_ops->wr_reg_indirect(ha, MD_DIRECT_ROM_WINDOW,
244962306a36Sopenharmony_ci					     (r_addr & 0xFFFF0000));
245062306a36Sopenharmony_ci		ha->isp_ops->rd_reg_indirect(ha,
245162306a36Sopenharmony_ci				MD_DIRECT_ROM_READ_BASE + (r_addr & 0x0000FFFF),
245262306a36Sopenharmony_ci				&r_value);
245362306a36Sopenharmony_ci		*data_ptr++ = cpu_to_le32(r_value);
245462306a36Sopenharmony_ci		r_addr += sizeof(uint32_t);
245562306a36Sopenharmony_ci	}
245662306a36Sopenharmony_ci	*d_ptr = data_ptr;
245762306a36Sopenharmony_ci}
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_ci#define MD_MIU_TEST_AGT_CTRL		0x41000090
246062306a36Sopenharmony_ci#define MD_MIU_TEST_AGT_ADDR_LO		0x41000094
246162306a36Sopenharmony_ci#define MD_MIU_TEST_AGT_ADDR_HI		0x41000098
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_cistatic int __qla4_8xxx_minidump_process_rdmem(struct scsi_qla_host *ha,
246462306a36Sopenharmony_ci				struct qla8xxx_minidump_entry_hdr *entry_hdr,
246562306a36Sopenharmony_ci				uint32_t **d_ptr)
246662306a36Sopenharmony_ci{
246762306a36Sopenharmony_ci	uint32_t r_addr, r_value, r_data;
246862306a36Sopenharmony_ci	uint32_t i, j, loop_cnt;
246962306a36Sopenharmony_ci	struct qla8xxx_minidump_entry_rdmem *m_hdr;
247062306a36Sopenharmony_ci	unsigned long flags;
247162306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
247262306a36Sopenharmony_ci
247362306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "Entering fn: %s\n", __func__));
247462306a36Sopenharmony_ci	m_hdr = (struct qla8xxx_minidump_entry_rdmem *)entry_hdr;
247562306a36Sopenharmony_ci	r_addr = m_hdr->read_addr;
247662306a36Sopenharmony_ci	loop_cnt = m_hdr->read_data_size/16;
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
247962306a36Sopenharmony_ci			  "[%s]: Read addr: 0x%x, read_data_size: 0x%x\n",
248062306a36Sopenharmony_ci			  __func__, r_addr, m_hdr->read_data_size));
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	if (r_addr & 0xf) {
248362306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
248462306a36Sopenharmony_ci				  "[%s]: Read addr 0x%x not 16 bytes aligned\n",
248562306a36Sopenharmony_ci				  __func__, r_addr));
248662306a36Sopenharmony_ci		return QLA_ERROR;
248762306a36Sopenharmony_ci	}
248862306a36Sopenharmony_ci
248962306a36Sopenharmony_ci	if (m_hdr->read_data_size % 16) {
249062306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
249162306a36Sopenharmony_ci				  "[%s]: Read data[0x%x] not multiple of 16 bytes\n",
249262306a36Sopenharmony_ci				  __func__, m_hdr->read_data_size));
249362306a36Sopenharmony_ci		return QLA_ERROR;
249462306a36Sopenharmony_ci	}
249562306a36Sopenharmony_ci
249662306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
249762306a36Sopenharmony_ci			  "[%s]: rdmem_addr: 0x%x, read_data_size: 0x%x, loop_cnt: 0x%x\n",
249862306a36Sopenharmony_ci			  __func__, r_addr, m_hdr->read_data_size, loop_cnt));
249962306a36Sopenharmony_ci
250062306a36Sopenharmony_ci	write_lock_irqsave(&ha->hw_lock, flags);
250162306a36Sopenharmony_ci	for (i = 0; i < loop_cnt; i++) {
250262306a36Sopenharmony_ci		ha->isp_ops->wr_reg_indirect(ha, MD_MIU_TEST_AGT_ADDR_LO,
250362306a36Sopenharmony_ci					     r_addr);
250462306a36Sopenharmony_ci		r_value = 0;
250562306a36Sopenharmony_ci		ha->isp_ops->wr_reg_indirect(ha, MD_MIU_TEST_AGT_ADDR_HI,
250662306a36Sopenharmony_ci					     r_value);
250762306a36Sopenharmony_ci		r_value = MIU_TA_CTL_ENABLE;
250862306a36Sopenharmony_ci		ha->isp_ops->wr_reg_indirect(ha, MD_MIU_TEST_AGT_CTRL, r_value);
250962306a36Sopenharmony_ci		r_value = MIU_TA_CTL_START_ENABLE;
251062306a36Sopenharmony_ci		ha->isp_ops->wr_reg_indirect(ha, MD_MIU_TEST_AGT_CTRL, r_value);
251162306a36Sopenharmony_ci
251262306a36Sopenharmony_ci		for (j = 0; j < MAX_CTL_CHECK; j++) {
251362306a36Sopenharmony_ci			ha->isp_ops->rd_reg_indirect(ha, MD_MIU_TEST_AGT_CTRL,
251462306a36Sopenharmony_ci						     &r_value);
251562306a36Sopenharmony_ci			if ((r_value & MIU_TA_CTL_BUSY) == 0)
251662306a36Sopenharmony_ci				break;
251762306a36Sopenharmony_ci		}
251862306a36Sopenharmony_ci
251962306a36Sopenharmony_ci		if (j >= MAX_CTL_CHECK) {
252062306a36Sopenharmony_ci			printk_ratelimited(KERN_ERR
252162306a36Sopenharmony_ci					   "%s: failed to read through agent\n",
252262306a36Sopenharmony_ci					    __func__);
252362306a36Sopenharmony_ci			write_unlock_irqrestore(&ha->hw_lock, flags);
252462306a36Sopenharmony_ci			return QLA_SUCCESS;
252562306a36Sopenharmony_ci		}
252662306a36Sopenharmony_ci
252762306a36Sopenharmony_ci		for (j = 0; j < 4; j++) {
252862306a36Sopenharmony_ci			ha->isp_ops->rd_reg_indirect(ha,
252962306a36Sopenharmony_ci						     MD_MIU_TEST_AGT_RDDATA[j],
253062306a36Sopenharmony_ci						     &r_data);
253162306a36Sopenharmony_ci			*data_ptr++ = cpu_to_le32(r_data);
253262306a36Sopenharmony_ci		}
253362306a36Sopenharmony_ci
253462306a36Sopenharmony_ci		r_addr += 16;
253562306a36Sopenharmony_ci	}
253662306a36Sopenharmony_ci	write_unlock_irqrestore(&ha->hw_lock, flags);
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "Leaving fn: %s datacount: 0x%x\n",
253962306a36Sopenharmony_ci			  __func__, (loop_cnt * 16)));
254062306a36Sopenharmony_ci
254162306a36Sopenharmony_ci	*d_ptr = data_ptr;
254262306a36Sopenharmony_ci	return QLA_SUCCESS;
254362306a36Sopenharmony_ci}
254462306a36Sopenharmony_ci
254562306a36Sopenharmony_cistatic int qla4_8xxx_minidump_process_rdmem(struct scsi_qla_host *ha,
254662306a36Sopenharmony_ci				struct qla8xxx_minidump_entry_hdr *entry_hdr,
254762306a36Sopenharmony_ci				uint32_t **d_ptr)
254862306a36Sopenharmony_ci{
254962306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
255062306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
255162306a36Sopenharmony_ci
255262306a36Sopenharmony_ci	rval = qla4_8xxx_minidump_pex_dma_read(ha, entry_hdr, &data_ptr);
255362306a36Sopenharmony_ci	if (rval != QLA_SUCCESS)
255462306a36Sopenharmony_ci		rval = __qla4_8xxx_minidump_process_rdmem(ha, entry_hdr,
255562306a36Sopenharmony_ci							  &data_ptr);
255662306a36Sopenharmony_ci	*d_ptr = data_ptr;
255762306a36Sopenharmony_ci	return rval;
255862306a36Sopenharmony_ci}
255962306a36Sopenharmony_ci
256062306a36Sopenharmony_cistatic void qla4_8xxx_mark_entry_skipped(struct scsi_qla_host *ha,
256162306a36Sopenharmony_ci				struct qla8xxx_minidump_entry_hdr *entry_hdr,
256262306a36Sopenharmony_ci				int index)
256362306a36Sopenharmony_ci{
256462306a36Sopenharmony_ci	entry_hdr->d_ctrl.driver_flags |= QLA8XXX_DBG_SKIPPED_FLAG;
256562306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
256662306a36Sopenharmony_ci			  "scsi(%ld): Skipping entry[%d]: ETYPE[0x%x]-ELEVEL[0x%x]\n",
256762306a36Sopenharmony_ci			  ha->host_no, index, entry_hdr->entry_type,
256862306a36Sopenharmony_ci			  entry_hdr->d_ctrl.entry_capture_mask));
256962306a36Sopenharmony_ci	/* If driver encounters a new entry type that it cannot process,
257062306a36Sopenharmony_ci	 * it should just skip the entry and adjust the total buffer size by
257162306a36Sopenharmony_ci	 * from subtracting the skipped bytes from it
257262306a36Sopenharmony_ci	 */
257362306a36Sopenharmony_ci	ha->fw_dump_skip_size += entry_hdr->entry_capture_size;
257462306a36Sopenharmony_ci}
257562306a36Sopenharmony_ci
257662306a36Sopenharmony_ci/* ISP83xx functions to process new minidump entries... */
257762306a36Sopenharmony_cistatic uint32_t qla83xx_minidump_process_pollrd(struct scsi_qla_host *ha,
257862306a36Sopenharmony_ci				struct qla8xxx_minidump_entry_hdr *entry_hdr,
257962306a36Sopenharmony_ci				uint32_t **d_ptr)
258062306a36Sopenharmony_ci{
258162306a36Sopenharmony_ci	uint32_t r_addr, s_addr, s_value, r_value, poll_wait, poll_mask;
258262306a36Sopenharmony_ci	uint16_t s_stride, i;
258362306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
258462306a36Sopenharmony_ci	uint32_t rval = QLA_SUCCESS;
258562306a36Sopenharmony_ci	struct qla83xx_minidump_entry_pollrd *pollrd_hdr;
258662306a36Sopenharmony_ci
258762306a36Sopenharmony_ci	pollrd_hdr = (struct qla83xx_minidump_entry_pollrd *)entry_hdr;
258862306a36Sopenharmony_ci	s_addr = le32_to_cpu(pollrd_hdr->select_addr);
258962306a36Sopenharmony_ci	r_addr = le32_to_cpu(pollrd_hdr->read_addr);
259062306a36Sopenharmony_ci	s_value = le32_to_cpu(pollrd_hdr->select_value);
259162306a36Sopenharmony_ci	s_stride = le32_to_cpu(pollrd_hdr->select_value_stride);
259262306a36Sopenharmony_ci
259362306a36Sopenharmony_ci	poll_wait = le32_to_cpu(pollrd_hdr->poll_wait);
259462306a36Sopenharmony_ci	poll_mask = le32_to_cpu(pollrd_hdr->poll_mask);
259562306a36Sopenharmony_ci
259662306a36Sopenharmony_ci	for (i = 0; i < le32_to_cpu(pollrd_hdr->op_count); i++) {
259762306a36Sopenharmony_ci		ha->isp_ops->wr_reg_indirect(ha, s_addr, s_value);
259862306a36Sopenharmony_ci		poll_wait = le32_to_cpu(pollrd_hdr->poll_wait);
259962306a36Sopenharmony_ci		while (1) {
260062306a36Sopenharmony_ci			ha->isp_ops->rd_reg_indirect(ha, s_addr, &r_value);
260162306a36Sopenharmony_ci
260262306a36Sopenharmony_ci			if ((r_value & poll_mask) != 0) {
260362306a36Sopenharmony_ci				break;
260462306a36Sopenharmony_ci			} else {
260562306a36Sopenharmony_ci				msleep(1);
260662306a36Sopenharmony_ci				if (--poll_wait == 0) {
260762306a36Sopenharmony_ci					ql4_printk(KERN_ERR, ha, "%s: TIMEOUT\n",
260862306a36Sopenharmony_ci						   __func__);
260962306a36Sopenharmony_ci					rval = QLA_ERROR;
261062306a36Sopenharmony_ci					goto exit_process_pollrd;
261162306a36Sopenharmony_ci				}
261262306a36Sopenharmony_ci			}
261362306a36Sopenharmony_ci		}
261462306a36Sopenharmony_ci		ha->isp_ops->rd_reg_indirect(ha, r_addr, &r_value);
261562306a36Sopenharmony_ci		*data_ptr++ = cpu_to_le32(s_value);
261662306a36Sopenharmony_ci		*data_ptr++ = cpu_to_le32(r_value);
261762306a36Sopenharmony_ci		s_value += s_stride;
261862306a36Sopenharmony_ci	}
261962306a36Sopenharmony_ci
262062306a36Sopenharmony_ci	*d_ptr = data_ptr;
262162306a36Sopenharmony_ci
262262306a36Sopenharmony_ciexit_process_pollrd:
262362306a36Sopenharmony_ci	return rval;
262462306a36Sopenharmony_ci}
262562306a36Sopenharmony_ci
262662306a36Sopenharmony_cistatic uint32_t qla4_84xx_minidump_process_rddfe(struct scsi_qla_host *ha,
262762306a36Sopenharmony_ci				struct qla8xxx_minidump_entry_hdr *entry_hdr,
262862306a36Sopenharmony_ci				uint32_t **d_ptr)
262962306a36Sopenharmony_ci{
263062306a36Sopenharmony_ci	int loop_cnt;
263162306a36Sopenharmony_ci	uint32_t addr1, addr2, value, data, temp, wrval;
263262306a36Sopenharmony_ci	uint8_t stride, stride2;
263362306a36Sopenharmony_ci	uint16_t count;
263462306a36Sopenharmony_ci	uint32_t poll, mask, modify_mask;
263562306a36Sopenharmony_ci	uint32_t wait_count = 0;
263662306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
263762306a36Sopenharmony_ci	struct qla8044_minidump_entry_rddfe *rddfe;
263862306a36Sopenharmony_ci	uint32_t rval = QLA_SUCCESS;
263962306a36Sopenharmony_ci
264062306a36Sopenharmony_ci	rddfe = (struct qla8044_minidump_entry_rddfe *)entry_hdr;
264162306a36Sopenharmony_ci	addr1 = le32_to_cpu(rddfe->addr_1);
264262306a36Sopenharmony_ci	value = le32_to_cpu(rddfe->value);
264362306a36Sopenharmony_ci	stride = le32_to_cpu(rddfe->stride);
264462306a36Sopenharmony_ci	stride2 = le32_to_cpu(rddfe->stride2);
264562306a36Sopenharmony_ci	count = le32_to_cpu(rddfe->count);
264662306a36Sopenharmony_ci
264762306a36Sopenharmony_ci	poll = le32_to_cpu(rddfe->poll);
264862306a36Sopenharmony_ci	mask = le32_to_cpu(rddfe->mask);
264962306a36Sopenharmony_ci	modify_mask = le32_to_cpu(rddfe->modify_mask);
265062306a36Sopenharmony_ci
265162306a36Sopenharmony_ci	addr2 = addr1 + stride;
265262306a36Sopenharmony_ci
265362306a36Sopenharmony_ci	for (loop_cnt = 0x0; loop_cnt < count; loop_cnt++) {
265462306a36Sopenharmony_ci		ha->isp_ops->wr_reg_indirect(ha, addr1, (0x40000000 | value));
265562306a36Sopenharmony_ci
265662306a36Sopenharmony_ci		wait_count = 0;
265762306a36Sopenharmony_ci		while (wait_count < poll) {
265862306a36Sopenharmony_ci			ha->isp_ops->rd_reg_indirect(ha, addr1, &temp);
265962306a36Sopenharmony_ci			if ((temp & mask) != 0)
266062306a36Sopenharmony_ci				break;
266162306a36Sopenharmony_ci			wait_count++;
266262306a36Sopenharmony_ci		}
266362306a36Sopenharmony_ci
266462306a36Sopenharmony_ci		if (wait_count == poll) {
266562306a36Sopenharmony_ci			ql4_printk(KERN_ERR, ha, "%s: TIMEOUT\n", __func__);
266662306a36Sopenharmony_ci			rval = QLA_ERROR;
266762306a36Sopenharmony_ci			goto exit_process_rddfe;
266862306a36Sopenharmony_ci		} else {
266962306a36Sopenharmony_ci			ha->isp_ops->rd_reg_indirect(ha, addr2, &temp);
267062306a36Sopenharmony_ci			temp = temp & modify_mask;
267162306a36Sopenharmony_ci			temp = (temp | ((loop_cnt << 16) | loop_cnt));
267262306a36Sopenharmony_ci			wrval = ((temp << 16) | temp);
267362306a36Sopenharmony_ci
267462306a36Sopenharmony_ci			ha->isp_ops->wr_reg_indirect(ha, addr2, wrval);
267562306a36Sopenharmony_ci			ha->isp_ops->wr_reg_indirect(ha, addr1, value);
267662306a36Sopenharmony_ci
267762306a36Sopenharmony_ci			wait_count = 0;
267862306a36Sopenharmony_ci			while (wait_count < poll) {
267962306a36Sopenharmony_ci				ha->isp_ops->rd_reg_indirect(ha, addr1, &temp);
268062306a36Sopenharmony_ci				if ((temp & mask) != 0)
268162306a36Sopenharmony_ci					break;
268262306a36Sopenharmony_ci				wait_count++;
268362306a36Sopenharmony_ci			}
268462306a36Sopenharmony_ci			if (wait_count == poll) {
268562306a36Sopenharmony_ci				ql4_printk(KERN_ERR, ha, "%s: TIMEOUT\n",
268662306a36Sopenharmony_ci					   __func__);
268762306a36Sopenharmony_ci				rval = QLA_ERROR;
268862306a36Sopenharmony_ci				goto exit_process_rddfe;
268962306a36Sopenharmony_ci			}
269062306a36Sopenharmony_ci
269162306a36Sopenharmony_ci			ha->isp_ops->wr_reg_indirect(ha, addr1,
269262306a36Sopenharmony_ci						     ((0x40000000 | value) +
269362306a36Sopenharmony_ci						     stride2));
269462306a36Sopenharmony_ci			wait_count = 0;
269562306a36Sopenharmony_ci			while (wait_count < poll) {
269662306a36Sopenharmony_ci				ha->isp_ops->rd_reg_indirect(ha, addr1, &temp);
269762306a36Sopenharmony_ci				if ((temp & mask) != 0)
269862306a36Sopenharmony_ci					break;
269962306a36Sopenharmony_ci				wait_count++;
270062306a36Sopenharmony_ci			}
270162306a36Sopenharmony_ci
270262306a36Sopenharmony_ci			if (wait_count == poll) {
270362306a36Sopenharmony_ci				ql4_printk(KERN_ERR, ha, "%s: TIMEOUT\n",
270462306a36Sopenharmony_ci					   __func__);
270562306a36Sopenharmony_ci				rval = QLA_ERROR;
270662306a36Sopenharmony_ci				goto exit_process_rddfe;
270762306a36Sopenharmony_ci			}
270862306a36Sopenharmony_ci
270962306a36Sopenharmony_ci			ha->isp_ops->rd_reg_indirect(ha, addr2, &data);
271062306a36Sopenharmony_ci
271162306a36Sopenharmony_ci			*data_ptr++ = cpu_to_le32(wrval);
271262306a36Sopenharmony_ci			*data_ptr++ = cpu_to_le32(data);
271362306a36Sopenharmony_ci		}
271462306a36Sopenharmony_ci	}
271562306a36Sopenharmony_ci
271662306a36Sopenharmony_ci	*d_ptr = data_ptr;
271762306a36Sopenharmony_ciexit_process_rddfe:
271862306a36Sopenharmony_ci	return rval;
271962306a36Sopenharmony_ci}
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_cistatic uint32_t qla4_84xx_minidump_process_rdmdio(struct scsi_qla_host *ha,
272262306a36Sopenharmony_ci				struct qla8xxx_minidump_entry_hdr *entry_hdr,
272362306a36Sopenharmony_ci				uint32_t **d_ptr)
272462306a36Sopenharmony_ci{
272562306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
272662306a36Sopenharmony_ci	uint32_t addr1, addr2, value1, value2, data, selval;
272762306a36Sopenharmony_ci	uint8_t stride1, stride2;
272862306a36Sopenharmony_ci	uint32_t addr3, addr4, addr5, addr6, addr7;
272962306a36Sopenharmony_ci	uint16_t count, loop_cnt;
273062306a36Sopenharmony_ci	uint32_t mask;
273162306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
273262306a36Sopenharmony_ci	struct qla8044_minidump_entry_rdmdio *rdmdio;
273362306a36Sopenharmony_ci
273462306a36Sopenharmony_ci	rdmdio = (struct qla8044_minidump_entry_rdmdio *)entry_hdr;
273562306a36Sopenharmony_ci	addr1 = le32_to_cpu(rdmdio->addr_1);
273662306a36Sopenharmony_ci	addr2 = le32_to_cpu(rdmdio->addr_2);
273762306a36Sopenharmony_ci	value1 = le32_to_cpu(rdmdio->value_1);
273862306a36Sopenharmony_ci	stride1 = le32_to_cpu(rdmdio->stride_1);
273962306a36Sopenharmony_ci	stride2 = le32_to_cpu(rdmdio->stride_2);
274062306a36Sopenharmony_ci	count = le32_to_cpu(rdmdio->count);
274162306a36Sopenharmony_ci
274262306a36Sopenharmony_ci	mask = le32_to_cpu(rdmdio->mask);
274362306a36Sopenharmony_ci	value2 = le32_to_cpu(rdmdio->value_2);
274462306a36Sopenharmony_ci
274562306a36Sopenharmony_ci	addr3 = addr1 + stride1;
274662306a36Sopenharmony_ci
274762306a36Sopenharmony_ci	for (loop_cnt = 0; loop_cnt < count; loop_cnt++) {
274862306a36Sopenharmony_ci		rval = ql4_84xx_poll_wait_ipmdio_bus_idle(ha, addr1, addr2,
274962306a36Sopenharmony_ci							 addr3, mask);
275062306a36Sopenharmony_ci		if (rval)
275162306a36Sopenharmony_ci			goto exit_process_rdmdio;
275262306a36Sopenharmony_ci
275362306a36Sopenharmony_ci		addr4 = addr2 - stride1;
275462306a36Sopenharmony_ci		rval = ql4_84xx_ipmdio_wr_reg(ha, addr1, addr3, mask, addr4,
275562306a36Sopenharmony_ci					     value2);
275662306a36Sopenharmony_ci		if (rval)
275762306a36Sopenharmony_ci			goto exit_process_rdmdio;
275862306a36Sopenharmony_ci
275962306a36Sopenharmony_ci		addr5 = addr2 - (2 * stride1);
276062306a36Sopenharmony_ci		rval = ql4_84xx_ipmdio_wr_reg(ha, addr1, addr3, mask, addr5,
276162306a36Sopenharmony_ci					     value1);
276262306a36Sopenharmony_ci		if (rval)
276362306a36Sopenharmony_ci			goto exit_process_rdmdio;
276462306a36Sopenharmony_ci
276562306a36Sopenharmony_ci		addr6 = addr2 - (3 * stride1);
276662306a36Sopenharmony_ci		rval = ql4_84xx_ipmdio_wr_reg(ha, addr1, addr3, mask,
276762306a36Sopenharmony_ci					     addr6, 0x2);
276862306a36Sopenharmony_ci		if (rval)
276962306a36Sopenharmony_ci			goto exit_process_rdmdio;
277062306a36Sopenharmony_ci
277162306a36Sopenharmony_ci		rval = ql4_84xx_poll_wait_ipmdio_bus_idle(ha, addr1, addr2,
277262306a36Sopenharmony_ci							 addr3, mask);
277362306a36Sopenharmony_ci		if (rval)
277462306a36Sopenharmony_ci			goto exit_process_rdmdio;
277562306a36Sopenharmony_ci
277662306a36Sopenharmony_ci		addr7 = addr2 - (4 * stride1);
277762306a36Sopenharmony_ci		rval = ql4_84xx_ipmdio_rd_reg(ha, addr1, addr3,
277862306a36Sopenharmony_ci						      mask, addr7, &data);
277962306a36Sopenharmony_ci		if (rval)
278062306a36Sopenharmony_ci			goto exit_process_rdmdio;
278162306a36Sopenharmony_ci
278262306a36Sopenharmony_ci		selval = (value2 << 18) | (value1 << 2) | 2;
278362306a36Sopenharmony_ci
278462306a36Sopenharmony_ci		stride2 = le32_to_cpu(rdmdio->stride_2);
278562306a36Sopenharmony_ci		*data_ptr++ = cpu_to_le32(selval);
278662306a36Sopenharmony_ci		*data_ptr++ = cpu_to_le32(data);
278762306a36Sopenharmony_ci
278862306a36Sopenharmony_ci		value1 = value1 + stride2;
278962306a36Sopenharmony_ci		*d_ptr = data_ptr;
279062306a36Sopenharmony_ci	}
279162306a36Sopenharmony_ci
279262306a36Sopenharmony_ciexit_process_rdmdio:
279362306a36Sopenharmony_ci	return rval;
279462306a36Sopenharmony_ci}
279562306a36Sopenharmony_ci
279662306a36Sopenharmony_cistatic uint32_t qla4_84xx_minidump_process_pollwr(struct scsi_qla_host *ha,
279762306a36Sopenharmony_ci				struct qla8xxx_minidump_entry_hdr *entry_hdr,
279862306a36Sopenharmony_ci				uint32_t **d_ptr)
279962306a36Sopenharmony_ci{
280062306a36Sopenharmony_ci	uint32_t addr1, addr2, value1, value2, poll, r_value;
280162306a36Sopenharmony_ci	struct qla8044_minidump_entry_pollwr *pollwr_hdr;
280262306a36Sopenharmony_ci	uint32_t wait_count = 0;
280362306a36Sopenharmony_ci	uint32_t rval = QLA_SUCCESS;
280462306a36Sopenharmony_ci
280562306a36Sopenharmony_ci	pollwr_hdr = (struct qla8044_minidump_entry_pollwr *)entry_hdr;
280662306a36Sopenharmony_ci	addr1 = le32_to_cpu(pollwr_hdr->addr_1);
280762306a36Sopenharmony_ci	addr2 = le32_to_cpu(pollwr_hdr->addr_2);
280862306a36Sopenharmony_ci	value1 = le32_to_cpu(pollwr_hdr->value_1);
280962306a36Sopenharmony_ci	value2 = le32_to_cpu(pollwr_hdr->value_2);
281062306a36Sopenharmony_ci
281162306a36Sopenharmony_ci	poll = le32_to_cpu(pollwr_hdr->poll);
281262306a36Sopenharmony_ci
281362306a36Sopenharmony_ci	while (wait_count < poll) {
281462306a36Sopenharmony_ci		ha->isp_ops->rd_reg_indirect(ha, addr1, &r_value);
281562306a36Sopenharmony_ci
281662306a36Sopenharmony_ci		if ((r_value & poll) != 0)
281762306a36Sopenharmony_ci			break;
281862306a36Sopenharmony_ci
281962306a36Sopenharmony_ci		wait_count++;
282062306a36Sopenharmony_ci	}
282162306a36Sopenharmony_ci
282262306a36Sopenharmony_ci	if (wait_count == poll) {
282362306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: TIMEOUT\n", __func__);
282462306a36Sopenharmony_ci		rval = QLA_ERROR;
282562306a36Sopenharmony_ci		goto exit_process_pollwr;
282662306a36Sopenharmony_ci	}
282762306a36Sopenharmony_ci
282862306a36Sopenharmony_ci	ha->isp_ops->wr_reg_indirect(ha, addr2, value2);
282962306a36Sopenharmony_ci	ha->isp_ops->wr_reg_indirect(ha, addr1, value1);
283062306a36Sopenharmony_ci
283162306a36Sopenharmony_ci	wait_count = 0;
283262306a36Sopenharmony_ci	while (wait_count < poll) {
283362306a36Sopenharmony_ci		ha->isp_ops->rd_reg_indirect(ha, addr1, &r_value);
283462306a36Sopenharmony_ci
283562306a36Sopenharmony_ci		if ((r_value & poll) != 0)
283662306a36Sopenharmony_ci			break;
283762306a36Sopenharmony_ci		wait_count++;
283862306a36Sopenharmony_ci	}
283962306a36Sopenharmony_ci
284062306a36Sopenharmony_ciexit_process_pollwr:
284162306a36Sopenharmony_ci	return rval;
284262306a36Sopenharmony_ci}
284362306a36Sopenharmony_ci
284462306a36Sopenharmony_cistatic void qla83xx_minidump_process_rdmux2(struct scsi_qla_host *ha,
284562306a36Sopenharmony_ci				struct qla8xxx_minidump_entry_hdr *entry_hdr,
284662306a36Sopenharmony_ci				uint32_t **d_ptr)
284762306a36Sopenharmony_ci{
284862306a36Sopenharmony_ci	uint32_t sel_val1, sel_val2, t_sel_val, data, i;
284962306a36Sopenharmony_ci	uint32_t sel_addr1, sel_addr2, sel_val_mask, read_addr;
285062306a36Sopenharmony_ci	struct qla83xx_minidump_entry_rdmux2 *rdmux2_hdr;
285162306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
285262306a36Sopenharmony_ci
285362306a36Sopenharmony_ci	rdmux2_hdr = (struct qla83xx_minidump_entry_rdmux2 *)entry_hdr;
285462306a36Sopenharmony_ci	sel_val1 = le32_to_cpu(rdmux2_hdr->select_value_1);
285562306a36Sopenharmony_ci	sel_val2 = le32_to_cpu(rdmux2_hdr->select_value_2);
285662306a36Sopenharmony_ci	sel_addr1 = le32_to_cpu(rdmux2_hdr->select_addr_1);
285762306a36Sopenharmony_ci	sel_addr2 = le32_to_cpu(rdmux2_hdr->select_addr_2);
285862306a36Sopenharmony_ci	sel_val_mask = le32_to_cpu(rdmux2_hdr->select_value_mask);
285962306a36Sopenharmony_ci	read_addr = le32_to_cpu(rdmux2_hdr->read_addr);
286062306a36Sopenharmony_ci
286162306a36Sopenharmony_ci	for (i = 0; i < rdmux2_hdr->op_count; i++) {
286262306a36Sopenharmony_ci		ha->isp_ops->wr_reg_indirect(ha, sel_addr1, sel_val1);
286362306a36Sopenharmony_ci		t_sel_val = sel_val1 & sel_val_mask;
286462306a36Sopenharmony_ci		*data_ptr++ = cpu_to_le32(t_sel_val);
286562306a36Sopenharmony_ci
286662306a36Sopenharmony_ci		ha->isp_ops->wr_reg_indirect(ha, sel_addr2, t_sel_val);
286762306a36Sopenharmony_ci		ha->isp_ops->rd_reg_indirect(ha, read_addr, &data);
286862306a36Sopenharmony_ci
286962306a36Sopenharmony_ci		*data_ptr++ = cpu_to_le32(data);
287062306a36Sopenharmony_ci
287162306a36Sopenharmony_ci		ha->isp_ops->wr_reg_indirect(ha, sel_addr1, sel_val2);
287262306a36Sopenharmony_ci		t_sel_val = sel_val2 & sel_val_mask;
287362306a36Sopenharmony_ci		*data_ptr++ = cpu_to_le32(t_sel_val);
287462306a36Sopenharmony_ci
287562306a36Sopenharmony_ci		ha->isp_ops->wr_reg_indirect(ha, sel_addr2, t_sel_val);
287662306a36Sopenharmony_ci		ha->isp_ops->rd_reg_indirect(ha, read_addr, &data);
287762306a36Sopenharmony_ci
287862306a36Sopenharmony_ci		*data_ptr++ = cpu_to_le32(data);
287962306a36Sopenharmony_ci
288062306a36Sopenharmony_ci		sel_val1 += rdmux2_hdr->select_value_stride;
288162306a36Sopenharmony_ci		sel_val2 += rdmux2_hdr->select_value_stride;
288262306a36Sopenharmony_ci	}
288362306a36Sopenharmony_ci
288462306a36Sopenharmony_ci	*d_ptr = data_ptr;
288562306a36Sopenharmony_ci}
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_cistatic uint32_t qla83xx_minidump_process_pollrdmwr(struct scsi_qla_host *ha,
288862306a36Sopenharmony_ci				struct qla8xxx_minidump_entry_hdr *entry_hdr,
288962306a36Sopenharmony_ci				uint32_t **d_ptr)
289062306a36Sopenharmony_ci{
289162306a36Sopenharmony_ci	uint32_t poll_wait, poll_mask, r_value, data;
289262306a36Sopenharmony_ci	uint32_t addr_1, addr_2, value_1, value_2;
289362306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
289462306a36Sopenharmony_ci	uint32_t rval = QLA_SUCCESS;
289562306a36Sopenharmony_ci	struct qla83xx_minidump_entry_pollrdmwr *poll_hdr;
289662306a36Sopenharmony_ci
289762306a36Sopenharmony_ci	poll_hdr = (struct qla83xx_minidump_entry_pollrdmwr *)entry_hdr;
289862306a36Sopenharmony_ci	addr_1 = le32_to_cpu(poll_hdr->addr_1);
289962306a36Sopenharmony_ci	addr_2 = le32_to_cpu(poll_hdr->addr_2);
290062306a36Sopenharmony_ci	value_1 = le32_to_cpu(poll_hdr->value_1);
290162306a36Sopenharmony_ci	value_2 = le32_to_cpu(poll_hdr->value_2);
290262306a36Sopenharmony_ci	poll_mask = le32_to_cpu(poll_hdr->poll_mask);
290362306a36Sopenharmony_ci
290462306a36Sopenharmony_ci	ha->isp_ops->wr_reg_indirect(ha, addr_1, value_1);
290562306a36Sopenharmony_ci
290662306a36Sopenharmony_ci	poll_wait = le32_to_cpu(poll_hdr->poll_wait);
290762306a36Sopenharmony_ci	while (1) {
290862306a36Sopenharmony_ci		ha->isp_ops->rd_reg_indirect(ha, addr_1, &r_value);
290962306a36Sopenharmony_ci
291062306a36Sopenharmony_ci		if ((r_value & poll_mask) != 0) {
291162306a36Sopenharmony_ci			break;
291262306a36Sopenharmony_ci		} else {
291362306a36Sopenharmony_ci			msleep(1);
291462306a36Sopenharmony_ci			if (--poll_wait == 0) {
291562306a36Sopenharmony_ci				ql4_printk(KERN_ERR, ha, "%s: TIMEOUT_1\n",
291662306a36Sopenharmony_ci					   __func__);
291762306a36Sopenharmony_ci				rval = QLA_ERROR;
291862306a36Sopenharmony_ci				goto exit_process_pollrdmwr;
291962306a36Sopenharmony_ci			}
292062306a36Sopenharmony_ci		}
292162306a36Sopenharmony_ci	}
292262306a36Sopenharmony_ci
292362306a36Sopenharmony_ci	ha->isp_ops->rd_reg_indirect(ha, addr_2, &data);
292462306a36Sopenharmony_ci	data &= le32_to_cpu(poll_hdr->modify_mask);
292562306a36Sopenharmony_ci	ha->isp_ops->wr_reg_indirect(ha, addr_2, data);
292662306a36Sopenharmony_ci	ha->isp_ops->wr_reg_indirect(ha, addr_1, value_2);
292762306a36Sopenharmony_ci
292862306a36Sopenharmony_ci	poll_wait = le32_to_cpu(poll_hdr->poll_wait);
292962306a36Sopenharmony_ci	while (1) {
293062306a36Sopenharmony_ci		ha->isp_ops->rd_reg_indirect(ha, addr_1, &r_value);
293162306a36Sopenharmony_ci
293262306a36Sopenharmony_ci		if ((r_value & poll_mask) != 0) {
293362306a36Sopenharmony_ci			break;
293462306a36Sopenharmony_ci		} else {
293562306a36Sopenharmony_ci			msleep(1);
293662306a36Sopenharmony_ci			if (--poll_wait == 0) {
293762306a36Sopenharmony_ci				ql4_printk(KERN_ERR, ha, "%s: TIMEOUT_2\n",
293862306a36Sopenharmony_ci					   __func__);
293962306a36Sopenharmony_ci				rval = QLA_ERROR;
294062306a36Sopenharmony_ci				goto exit_process_pollrdmwr;
294162306a36Sopenharmony_ci			}
294262306a36Sopenharmony_ci		}
294362306a36Sopenharmony_ci	}
294462306a36Sopenharmony_ci
294562306a36Sopenharmony_ci	*data_ptr++ = cpu_to_le32(addr_2);
294662306a36Sopenharmony_ci	*data_ptr++ = cpu_to_le32(data);
294762306a36Sopenharmony_ci	*d_ptr = data_ptr;
294862306a36Sopenharmony_ci
294962306a36Sopenharmony_ciexit_process_pollrdmwr:
295062306a36Sopenharmony_ci	return rval;
295162306a36Sopenharmony_ci}
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_cistatic uint32_t qla4_83xx_minidump_process_rdrom(struct scsi_qla_host *ha,
295462306a36Sopenharmony_ci				struct qla8xxx_minidump_entry_hdr *entry_hdr,
295562306a36Sopenharmony_ci				uint32_t **d_ptr)
295662306a36Sopenharmony_ci{
295762306a36Sopenharmony_ci	uint32_t fl_addr, u32_count, rval;
295862306a36Sopenharmony_ci	struct qla8xxx_minidump_entry_rdrom *rom_hdr;
295962306a36Sopenharmony_ci	uint32_t *data_ptr = *d_ptr;
296062306a36Sopenharmony_ci
296162306a36Sopenharmony_ci	rom_hdr = (struct qla8xxx_minidump_entry_rdrom *)entry_hdr;
296262306a36Sopenharmony_ci	fl_addr = le32_to_cpu(rom_hdr->read_addr);
296362306a36Sopenharmony_ci	u32_count = le32_to_cpu(rom_hdr->read_data_size)/sizeof(uint32_t);
296462306a36Sopenharmony_ci
296562306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "[%s]: fl_addr: 0x%x, count: 0x%x\n",
296662306a36Sopenharmony_ci			  __func__, fl_addr, u32_count));
296762306a36Sopenharmony_ci
296862306a36Sopenharmony_ci	rval = qla4_83xx_lockless_flash_read_u32(ha, fl_addr,
296962306a36Sopenharmony_ci						 (u8 *)(data_ptr), u32_count);
297062306a36Sopenharmony_ci
297162306a36Sopenharmony_ci	if (rval == QLA_ERROR) {
297262306a36Sopenharmony_ci		ql4_printk(KERN_ERR, ha, "%s: Flash Read Error,Count=%d\n",
297362306a36Sopenharmony_ci			   __func__, u32_count);
297462306a36Sopenharmony_ci		goto exit_process_rdrom;
297562306a36Sopenharmony_ci	}
297662306a36Sopenharmony_ci
297762306a36Sopenharmony_ci	data_ptr += u32_count;
297862306a36Sopenharmony_ci	*d_ptr = data_ptr;
297962306a36Sopenharmony_ci
298062306a36Sopenharmony_ciexit_process_rdrom:
298162306a36Sopenharmony_ci	return rval;
298262306a36Sopenharmony_ci}
298362306a36Sopenharmony_ci
298462306a36Sopenharmony_ci/**
298562306a36Sopenharmony_ci * qla4_8xxx_collect_md_data - Retrieve firmware minidump data.
298662306a36Sopenharmony_ci * @ha: pointer to adapter structure
298762306a36Sopenharmony_ci **/
298862306a36Sopenharmony_cistatic int qla4_8xxx_collect_md_data(struct scsi_qla_host *ha)
298962306a36Sopenharmony_ci{
299062306a36Sopenharmony_ci	int num_entry_hdr = 0;
299162306a36Sopenharmony_ci	struct qla8xxx_minidump_entry_hdr *entry_hdr;
299262306a36Sopenharmony_ci	struct qla4_8xxx_minidump_template_hdr *tmplt_hdr;
299362306a36Sopenharmony_ci	uint32_t *data_ptr;
299462306a36Sopenharmony_ci	uint32_t data_collected = 0;
299562306a36Sopenharmony_ci	int i, rval = QLA_ERROR;
299662306a36Sopenharmony_ci	uint64_t now;
299762306a36Sopenharmony_ci	uint32_t timestamp;
299862306a36Sopenharmony_ci
299962306a36Sopenharmony_ci	ha->fw_dump_skip_size = 0;
300062306a36Sopenharmony_ci	if (!ha->fw_dump) {
300162306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "%s(%ld) No buffer to dump\n",
300262306a36Sopenharmony_ci			   __func__, ha->host_no);
300362306a36Sopenharmony_ci		return rval;
300462306a36Sopenharmony_ci	}
300562306a36Sopenharmony_ci
300662306a36Sopenharmony_ci	tmplt_hdr = (struct qla4_8xxx_minidump_template_hdr *)
300762306a36Sopenharmony_ci						ha->fw_dump_tmplt_hdr;
300862306a36Sopenharmony_ci	data_ptr = (uint32_t *)((uint8_t *)ha->fw_dump +
300962306a36Sopenharmony_ci						ha->fw_dump_tmplt_size);
301062306a36Sopenharmony_ci	data_collected += ha->fw_dump_tmplt_size;
301162306a36Sopenharmony_ci
301262306a36Sopenharmony_ci	num_entry_hdr = tmplt_hdr->num_of_entries;
301362306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "[%s]: starting data ptr: %p\n",
301462306a36Sopenharmony_ci		   __func__, data_ptr);
301562306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha,
301662306a36Sopenharmony_ci		   "[%s]: no of entry headers in Template: 0x%x\n",
301762306a36Sopenharmony_ci		   __func__, num_entry_hdr);
301862306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "[%s]: Capture Mask obtained: 0x%x\n",
301962306a36Sopenharmony_ci		   __func__, ha->fw_dump_capture_mask);
302062306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "[%s]: Total_data_size 0x%x, %d obtained\n",
302162306a36Sopenharmony_ci		   __func__, ha->fw_dump_size, ha->fw_dump_size);
302262306a36Sopenharmony_ci
302362306a36Sopenharmony_ci	/* Update current timestamp before taking dump */
302462306a36Sopenharmony_ci	now = get_jiffies_64();
302562306a36Sopenharmony_ci	timestamp = (u32)(jiffies_to_msecs(now) / 1000);
302662306a36Sopenharmony_ci	tmplt_hdr->driver_timestamp = timestamp;
302762306a36Sopenharmony_ci
302862306a36Sopenharmony_ci	entry_hdr = (struct qla8xxx_minidump_entry_hdr *)
302962306a36Sopenharmony_ci					(((uint8_t *)ha->fw_dump_tmplt_hdr) +
303062306a36Sopenharmony_ci					 tmplt_hdr->first_entry_offset);
303162306a36Sopenharmony_ci
303262306a36Sopenharmony_ci	if (is_qla8032(ha) || is_qla8042(ha))
303362306a36Sopenharmony_ci		tmplt_hdr->saved_state_array[QLA83XX_SS_OCM_WNDREG_INDEX] =
303462306a36Sopenharmony_ci					tmplt_hdr->ocm_window_reg[ha->func_num];
303562306a36Sopenharmony_ci
303662306a36Sopenharmony_ci	/* Walk through the entry headers - validate/perform required action */
303762306a36Sopenharmony_ci	for (i = 0; i < num_entry_hdr; i++) {
303862306a36Sopenharmony_ci		if (data_collected > ha->fw_dump_size) {
303962306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha,
304062306a36Sopenharmony_ci				   "Data collected: [0x%x], Total Dump size: [0x%x]\n",
304162306a36Sopenharmony_ci				   data_collected, ha->fw_dump_size);
304262306a36Sopenharmony_ci			return rval;
304362306a36Sopenharmony_ci		}
304462306a36Sopenharmony_ci
304562306a36Sopenharmony_ci		if (!(entry_hdr->d_ctrl.entry_capture_mask &
304662306a36Sopenharmony_ci		      ha->fw_dump_capture_mask)) {
304762306a36Sopenharmony_ci			entry_hdr->d_ctrl.driver_flags |=
304862306a36Sopenharmony_ci						QLA8XXX_DBG_SKIPPED_FLAG;
304962306a36Sopenharmony_ci			goto skip_nxt_entry;
305062306a36Sopenharmony_ci		}
305162306a36Sopenharmony_ci
305262306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
305362306a36Sopenharmony_ci				  "Data collected: [0x%x], Dump size left:[0x%x]\n",
305462306a36Sopenharmony_ci				  data_collected,
305562306a36Sopenharmony_ci				  (ha->fw_dump_size - data_collected)));
305662306a36Sopenharmony_ci
305762306a36Sopenharmony_ci		/* Decode the entry type and take required action to capture
305862306a36Sopenharmony_ci		 * debug data
305962306a36Sopenharmony_ci		 */
306062306a36Sopenharmony_ci		switch (entry_hdr->entry_type) {
306162306a36Sopenharmony_ci		case QLA8XXX_RDEND:
306262306a36Sopenharmony_ci			qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
306362306a36Sopenharmony_ci			break;
306462306a36Sopenharmony_ci		case QLA8XXX_CNTRL:
306562306a36Sopenharmony_ci			rval = qla4_8xxx_minidump_process_control(ha,
306662306a36Sopenharmony_ci								  entry_hdr);
306762306a36Sopenharmony_ci			if (rval != QLA_SUCCESS) {
306862306a36Sopenharmony_ci				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
306962306a36Sopenharmony_ci				goto md_failed;
307062306a36Sopenharmony_ci			}
307162306a36Sopenharmony_ci			break;
307262306a36Sopenharmony_ci		case QLA8XXX_RDCRB:
307362306a36Sopenharmony_ci			qla4_8xxx_minidump_process_rdcrb(ha, entry_hdr,
307462306a36Sopenharmony_ci							 &data_ptr);
307562306a36Sopenharmony_ci			break;
307662306a36Sopenharmony_ci		case QLA8XXX_RDMEM:
307762306a36Sopenharmony_ci			rval = qla4_8xxx_minidump_process_rdmem(ha, entry_hdr,
307862306a36Sopenharmony_ci								&data_ptr);
307962306a36Sopenharmony_ci			if (rval != QLA_SUCCESS) {
308062306a36Sopenharmony_ci				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
308162306a36Sopenharmony_ci				goto md_failed;
308262306a36Sopenharmony_ci			}
308362306a36Sopenharmony_ci			break;
308462306a36Sopenharmony_ci		case QLA8XXX_BOARD:
308562306a36Sopenharmony_ci		case QLA8XXX_RDROM:
308662306a36Sopenharmony_ci			if (is_qla8022(ha)) {
308762306a36Sopenharmony_ci				qla4_82xx_minidump_process_rdrom(ha, entry_hdr,
308862306a36Sopenharmony_ci								 &data_ptr);
308962306a36Sopenharmony_ci			} else if (is_qla8032(ha) || is_qla8042(ha)) {
309062306a36Sopenharmony_ci				rval = qla4_83xx_minidump_process_rdrom(ha,
309162306a36Sopenharmony_ci								    entry_hdr,
309262306a36Sopenharmony_ci								    &data_ptr);
309362306a36Sopenharmony_ci				if (rval != QLA_SUCCESS)
309462306a36Sopenharmony_ci					qla4_8xxx_mark_entry_skipped(ha,
309562306a36Sopenharmony_ci								     entry_hdr,
309662306a36Sopenharmony_ci								     i);
309762306a36Sopenharmony_ci			}
309862306a36Sopenharmony_ci			break;
309962306a36Sopenharmony_ci		case QLA8XXX_L2DTG:
310062306a36Sopenharmony_ci		case QLA8XXX_L2ITG:
310162306a36Sopenharmony_ci		case QLA8XXX_L2DAT:
310262306a36Sopenharmony_ci		case QLA8XXX_L2INS:
310362306a36Sopenharmony_ci			rval = qla4_8xxx_minidump_process_l2tag(ha, entry_hdr,
310462306a36Sopenharmony_ci								&data_ptr);
310562306a36Sopenharmony_ci			if (rval != QLA_SUCCESS) {
310662306a36Sopenharmony_ci				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
310762306a36Sopenharmony_ci				goto md_failed;
310862306a36Sopenharmony_ci			}
310962306a36Sopenharmony_ci			break;
311062306a36Sopenharmony_ci		case QLA8XXX_L1DTG:
311162306a36Sopenharmony_ci		case QLA8XXX_L1ITG:
311262306a36Sopenharmony_ci		case QLA8XXX_L1DAT:
311362306a36Sopenharmony_ci		case QLA8XXX_L1INS:
311462306a36Sopenharmony_ci			qla4_8xxx_minidump_process_l1cache(ha, entry_hdr,
311562306a36Sopenharmony_ci							   &data_ptr);
311662306a36Sopenharmony_ci			break;
311762306a36Sopenharmony_ci		case QLA8XXX_RDOCM:
311862306a36Sopenharmony_ci			qla4_8xxx_minidump_process_rdocm(ha, entry_hdr,
311962306a36Sopenharmony_ci							 &data_ptr);
312062306a36Sopenharmony_ci			break;
312162306a36Sopenharmony_ci		case QLA8XXX_RDMUX:
312262306a36Sopenharmony_ci			qla4_8xxx_minidump_process_rdmux(ha, entry_hdr,
312362306a36Sopenharmony_ci							 &data_ptr);
312462306a36Sopenharmony_ci			break;
312562306a36Sopenharmony_ci		case QLA8XXX_QUEUE:
312662306a36Sopenharmony_ci			qla4_8xxx_minidump_process_queue(ha, entry_hdr,
312762306a36Sopenharmony_ci							 &data_ptr);
312862306a36Sopenharmony_ci			break;
312962306a36Sopenharmony_ci		case QLA83XX_POLLRD:
313062306a36Sopenharmony_ci			if (is_qla8022(ha)) {
313162306a36Sopenharmony_ci				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
313262306a36Sopenharmony_ci				break;
313362306a36Sopenharmony_ci			}
313462306a36Sopenharmony_ci			rval = qla83xx_minidump_process_pollrd(ha, entry_hdr,
313562306a36Sopenharmony_ci							       &data_ptr);
313662306a36Sopenharmony_ci			if (rval != QLA_SUCCESS)
313762306a36Sopenharmony_ci				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
313862306a36Sopenharmony_ci			break;
313962306a36Sopenharmony_ci		case QLA83XX_RDMUX2:
314062306a36Sopenharmony_ci			if (is_qla8022(ha)) {
314162306a36Sopenharmony_ci				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
314262306a36Sopenharmony_ci				break;
314362306a36Sopenharmony_ci			}
314462306a36Sopenharmony_ci			qla83xx_minidump_process_rdmux2(ha, entry_hdr,
314562306a36Sopenharmony_ci							&data_ptr);
314662306a36Sopenharmony_ci			break;
314762306a36Sopenharmony_ci		case QLA83XX_POLLRDMWR:
314862306a36Sopenharmony_ci			if (is_qla8022(ha)) {
314962306a36Sopenharmony_ci				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
315062306a36Sopenharmony_ci				break;
315162306a36Sopenharmony_ci			}
315262306a36Sopenharmony_ci			rval = qla83xx_minidump_process_pollrdmwr(ha, entry_hdr,
315362306a36Sopenharmony_ci								  &data_ptr);
315462306a36Sopenharmony_ci			if (rval != QLA_SUCCESS)
315562306a36Sopenharmony_ci				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
315662306a36Sopenharmony_ci			break;
315762306a36Sopenharmony_ci		case QLA8044_RDDFE:
315862306a36Sopenharmony_ci			rval = qla4_84xx_minidump_process_rddfe(ha, entry_hdr,
315962306a36Sopenharmony_ci								&data_ptr);
316062306a36Sopenharmony_ci			if (rval != QLA_SUCCESS)
316162306a36Sopenharmony_ci				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
316262306a36Sopenharmony_ci			break;
316362306a36Sopenharmony_ci		case QLA8044_RDMDIO:
316462306a36Sopenharmony_ci			rval = qla4_84xx_minidump_process_rdmdio(ha, entry_hdr,
316562306a36Sopenharmony_ci								 &data_ptr);
316662306a36Sopenharmony_ci			if (rval != QLA_SUCCESS)
316762306a36Sopenharmony_ci				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
316862306a36Sopenharmony_ci			break;
316962306a36Sopenharmony_ci		case QLA8044_POLLWR:
317062306a36Sopenharmony_ci			rval = qla4_84xx_minidump_process_pollwr(ha, entry_hdr,
317162306a36Sopenharmony_ci								 &data_ptr);
317262306a36Sopenharmony_ci			if (rval != QLA_SUCCESS)
317362306a36Sopenharmony_ci				qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
317462306a36Sopenharmony_ci			break;
317562306a36Sopenharmony_ci		case QLA8XXX_RDNOP:
317662306a36Sopenharmony_ci		default:
317762306a36Sopenharmony_ci			qla4_8xxx_mark_entry_skipped(ha, entry_hdr, i);
317862306a36Sopenharmony_ci			break;
317962306a36Sopenharmony_ci		}
318062306a36Sopenharmony_ci
318162306a36Sopenharmony_ci		data_collected = (uint8_t *)data_ptr - (uint8_t *)ha->fw_dump;
318262306a36Sopenharmony_ciskip_nxt_entry:
318362306a36Sopenharmony_ci		/*  next entry in the template */
318462306a36Sopenharmony_ci		entry_hdr = (struct qla8xxx_minidump_entry_hdr *)
318562306a36Sopenharmony_ci				(((uint8_t *)entry_hdr) +
318662306a36Sopenharmony_ci				 entry_hdr->entry_size);
318762306a36Sopenharmony_ci	}
318862306a36Sopenharmony_ci
318962306a36Sopenharmony_ci	if ((data_collected + ha->fw_dump_skip_size) != ha->fw_dump_size) {
319062306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha,
319162306a36Sopenharmony_ci			   "Dump data mismatch: Data collected: [0x%x], total_data_size:[0x%x]\n",
319262306a36Sopenharmony_ci			   data_collected, ha->fw_dump_size);
319362306a36Sopenharmony_ci		rval = QLA_ERROR;
319462306a36Sopenharmony_ci		goto md_failed;
319562306a36Sopenharmony_ci	}
319662306a36Sopenharmony_ci
319762306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "Leaving fn: %s Last entry: 0x%x\n",
319862306a36Sopenharmony_ci			  __func__, i));
319962306a36Sopenharmony_cimd_failed:
320062306a36Sopenharmony_ci	return rval;
320162306a36Sopenharmony_ci}
320262306a36Sopenharmony_ci
320362306a36Sopenharmony_ci/**
320462306a36Sopenharmony_ci * qla4_8xxx_uevent_emit - Send uevent when the firmware dump is ready.
320562306a36Sopenharmony_ci * @ha: pointer to adapter structure
320662306a36Sopenharmony_ci * @code: uevent code to act upon
320762306a36Sopenharmony_ci **/
320862306a36Sopenharmony_cistatic void qla4_8xxx_uevent_emit(struct scsi_qla_host *ha, u32 code)
320962306a36Sopenharmony_ci{
321062306a36Sopenharmony_ci	char event_string[40];
321162306a36Sopenharmony_ci	char *envp[] = { event_string, NULL };
321262306a36Sopenharmony_ci
321362306a36Sopenharmony_ci	switch (code) {
321462306a36Sopenharmony_ci	case QL4_UEVENT_CODE_FW_DUMP:
321562306a36Sopenharmony_ci		snprintf(event_string, sizeof(event_string), "FW_DUMP=%lu",
321662306a36Sopenharmony_ci			 ha->host_no);
321762306a36Sopenharmony_ci		break;
321862306a36Sopenharmony_ci	default:
321962306a36Sopenharmony_ci		/*do nothing*/
322062306a36Sopenharmony_ci		break;
322162306a36Sopenharmony_ci	}
322262306a36Sopenharmony_ci
322362306a36Sopenharmony_ci	kobject_uevent_env(&(&ha->pdev->dev)->kobj, KOBJ_CHANGE, envp);
322462306a36Sopenharmony_ci}
322562306a36Sopenharmony_ci
322662306a36Sopenharmony_civoid qla4_8xxx_get_minidump(struct scsi_qla_host *ha)
322762306a36Sopenharmony_ci{
322862306a36Sopenharmony_ci	if (ql4xenablemd && test_bit(AF_FW_RECOVERY, &ha->flags) &&
322962306a36Sopenharmony_ci	    !test_bit(AF_82XX_FW_DUMPED, &ha->flags)) {
323062306a36Sopenharmony_ci		if (!qla4_8xxx_collect_md_data(ha)) {
323162306a36Sopenharmony_ci			qla4_8xxx_uevent_emit(ha, QL4_UEVENT_CODE_FW_DUMP);
323262306a36Sopenharmony_ci			set_bit(AF_82XX_FW_DUMPED, &ha->flags);
323362306a36Sopenharmony_ci		} else {
323462306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha, "%s: Unable to collect minidump\n",
323562306a36Sopenharmony_ci				   __func__);
323662306a36Sopenharmony_ci		}
323762306a36Sopenharmony_ci	}
323862306a36Sopenharmony_ci}
323962306a36Sopenharmony_ci
324062306a36Sopenharmony_ci/**
324162306a36Sopenharmony_ci * qla4_8xxx_device_bootstrap - Initialize device, set DEV_READY, start fw
324262306a36Sopenharmony_ci * @ha: pointer to adapter structure
324362306a36Sopenharmony_ci *
324462306a36Sopenharmony_ci * Note: IDC lock must be held upon entry
324562306a36Sopenharmony_ci **/
324662306a36Sopenharmony_ciint qla4_8xxx_device_bootstrap(struct scsi_qla_host *ha)
324762306a36Sopenharmony_ci{
324862306a36Sopenharmony_ci	int rval = QLA_ERROR;
324962306a36Sopenharmony_ci	int i;
325062306a36Sopenharmony_ci	uint32_t old_count, count;
325162306a36Sopenharmony_ci	int need_reset = 0;
325262306a36Sopenharmony_ci
325362306a36Sopenharmony_ci	need_reset = ha->isp_ops->need_reset(ha);
325462306a36Sopenharmony_ci
325562306a36Sopenharmony_ci	if (need_reset) {
325662306a36Sopenharmony_ci		/* We are trying to perform a recovery here. */
325762306a36Sopenharmony_ci		if (test_bit(AF_FW_RECOVERY, &ha->flags))
325862306a36Sopenharmony_ci			ha->isp_ops->rom_lock_recovery(ha);
325962306a36Sopenharmony_ci	} else  {
326062306a36Sopenharmony_ci		old_count = qla4_8xxx_rd_direct(ha, QLA8XXX_PEG_ALIVE_COUNTER);
326162306a36Sopenharmony_ci		for (i = 0; i < 10; i++) {
326262306a36Sopenharmony_ci			msleep(200);
326362306a36Sopenharmony_ci			count = qla4_8xxx_rd_direct(ha,
326462306a36Sopenharmony_ci						    QLA8XXX_PEG_ALIVE_COUNTER);
326562306a36Sopenharmony_ci			if (count != old_count) {
326662306a36Sopenharmony_ci				rval = QLA_SUCCESS;
326762306a36Sopenharmony_ci				goto dev_ready;
326862306a36Sopenharmony_ci			}
326962306a36Sopenharmony_ci		}
327062306a36Sopenharmony_ci		ha->isp_ops->rom_lock_recovery(ha);
327162306a36Sopenharmony_ci	}
327262306a36Sopenharmony_ci
327362306a36Sopenharmony_ci	/* set to DEV_INITIALIZING */
327462306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "HW State: INITIALIZING\n");
327562306a36Sopenharmony_ci	qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
327662306a36Sopenharmony_ci			    QLA8XXX_DEV_INITIALIZING);
327762306a36Sopenharmony_ci
327862306a36Sopenharmony_ci	ha->isp_ops->idc_unlock(ha);
327962306a36Sopenharmony_ci
328062306a36Sopenharmony_ci	if (is_qla8022(ha))
328162306a36Sopenharmony_ci		qla4_8xxx_get_minidump(ha);
328262306a36Sopenharmony_ci
328362306a36Sopenharmony_ci	rval = ha->isp_ops->restart_firmware(ha);
328462306a36Sopenharmony_ci	ha->isp_ops->idc_lock(ha);
328562306a36Sopenharmony_ci
328662306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
328762306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "HW State: FAILED\n");
328862306a36Sopenharmony_ci		qla4_8xxx_clear_drv_active(ha);
328962306a36Sopenharmony_ci		qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
329062306a36Sopenharmony_ci				    QLA8XXX_DEV_FAILED);
329162306a36Sopenharmony_ci		return rval;
329262306a36Sopenharmony_ci	}
329362306a36Sopenharmony_ci
329462306a36Sopenharmony_cidev_ready:
329562306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "HW State: READY\n");
329662306a36Sopenharmony_ci	qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE, QLA8XXX_DEV_READY);
329762306a36Sopenharmony_ci
329862306a36Sopenharmony_ci	return rval;
329962306a36Sopenharmony_ci}
330062306a36Sopenharmony_ci
330162306a36Sopenharmony_ci/**
330262306a36Sopenharmony_ci * qla4_82xx_need_reset_handler - Code to start reset sequence
330362306a36Sopenharmony_ci * @ha: pointer to adapter structure
330462306a36Sopenharmony_ci *
330562306a36Sopenharmony_ci * Note: IDC lock must be held upon entry
330662306a36Sopenharmony_ci **/
330762306a36Sopenharmony_cistatic void
330862306a36Sopenharmony_ciqla4_82xx_need_reset_handler(struct scsi_qla_host *ha)
330962306a36Sopenharmony_ci{
331062306a36Sopenharmony_ci	uint32_t dev_state, drv_state, drv_active;
331162306a36Sopenharmony_ci	uint32_t active_mask = 0xFFFFFFFF;
331262306a36Sopenharmony_ci	unsigned long reset_timeout;
331362306a36Sopenharmony_ci
331462306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha,
331562306a36Sopenharmony_ci		"Performing ISP error recovery\n");
331662306a36Sopenharmony_ci
331762306a36Sopenharmony_ci	if (test_and_clear_bit(AF_ONLINE, &ha->flags)) {
331862306a36Sopenharmony_ci		qla4_82xx_idc_unlock(ha);
331962306a36Sopenharmony_ci		ha->isp_ops->disable_intrs(ha);
332062306a36Sopenharmony_ci		qla4_82xx_idc_lock(ha);
332162306a36Sopenharmony_ci	}
332262306a36Sopenharmony_ci
332362306a36Sopenharmony_ci	if (!test_bit(AF_8XXX_RST_OWNER, &ha->flags)) {
332462306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
332562306a36Sopenharmony_ci				  "%s(%ld): reset acknowledged\n",
332662306a36Sopenharmony_ci				  __func__, ha->host_no));
332762306a36Sopenharmony_ci		qla4_8xxx_set_rst_ready(ha);
332862306a36Sopenharmony_ci	} else {
332962306a36Sopenharmony_ci		active_mask = (~(1 << (ha->func_num * 4)));
333062306a36Sopenharmony_ci	}
333162306a36Sopenharmony_ci
333262306a36Sopenharmony_ci	/* wait for 10 seconds for reset ack from all functions */
333362306a36Sopenharmony_ci	reset_timeout = jiffies + (ha->nx_reset_timeout * HZ);
333462306a36Sopenharmony_ci
333562306a36Sopenharmony_ci	drv_state = qla4_82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
333662306a36Sopenharmony_ci	drv_active = qla4_82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
333762306a36Sopenharmony_ci
333862306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha,
333962306a36Sopenharmony_ci		"%s(%ld): drv_state = 0x%x, drv_active = 0x%x\n",
334062306a36Sopenharmony_ci		__func__, ha->host_no, drv_state, drv_active);
334162306a36Sopenharmony_ci
334262306a36Sopenharmony_ci	while (drv_state != (drv_active & active_mask)) {
334362306a36Sopenharmony_ci		if (time_after_eq(jiffies, reset_timeout)) {
334462306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha,
334562306a36Sopenharmony_ci				   "%s: RESET TIMEOUT! drv_state: 0x%08x, drv_active: 0x%08x\n",
334662306a36Sopenharmony_ci				   DRIVER_NAME, drv_state, drv_active);
334762306a36Sopenharmony_ci			break;
334862306a36Sopenharmony_ci		}
334962306a36Sopenharmony_ci
335062306a36Sopenharmony_ci		/*
335162306a36Sopenharmony_ci		 * When reset_owner times out, check which functions
335262306a36Sopenharmony_ci		 * acked/did not ack
335362306a36Sopenharmony_ci		 */
335462306a36Sopenharmony_ci		if (test_bit(AF_8XXX_RST_OWNER, &ha->flags)) {
335562306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha,
335662306a36Sopenharmony_ci				   "%s(%ld): drv_state = 0x%x, drv_active = 0x%x\n",
335762306a36Sopenharmony_ci				   __func__, ha->host_no, drv_state,
335862306a36Sopenharmony_ci				   drv_active);
335962306a36Sopenharmony_ci		}
336062306a36Sopenharmony_ci		qla4_82xx_idc_unlock(ha);
336162306a36Sopenharmony_ci		msleep(1000);
336262306a36Sopenharmony_ci		qla4_82xx_idc_lock(ha);
336362306a36Sopenharmony_ci
336462306a36Sopenharmony_ci		drv_state = qla4_82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
336562306a36Sopenharmony_ci		drv_active = qla4_82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
336662306a36Sopenharmony_ci	}
336762306a36Sopenharmony_ci
336862306a36Sopenharmony_ci	/* Clear RESET OWNER as we are not going to use it any further */
336962306a36Sopenharmony_ci	clear_bit(AF_8XXX_RST_OWNER, &ha->flags);
337062306a36Sopenharmony_ci
337162306a36Sopenharmony_ci	dev_state = qla4_82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
337262306a36Sopenharmony_ci	ql4_printk(KERN_INFO, ha, "Device state is 0x%x = %s\n", dev_state,
337362306a36Sopenharmony_ci		   dev_state < MAX_STATES ? qdev_state[dev_state] : "Unknown");
337462306a36Sopenharmony_ci
337562306a36Sopenharmony_ci	/* Force to DEV_COLD unless someone else is starting a reset */
337662306a36Sopenharmony_ci	if (dev_state != QLA8XXX_DEV_INITIALIZING) {
337762306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "HW State: COLD/RE-INIT\n");
337862306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA8XXX_DEV_COLD);
337962306a36Sopenharmony_ci		qla4_8xxx_set_rst_ready(ha);
338062306a36Sopenharmony_ci	}
338162306a36Sopenharmony_ci}
338262306a36Sopenharmony_ci
338362306a36Sopenharmony_ci/**
338462306a36Sopenharmony_ci * qla4_8xxx_need_qsnt_handler - Code to start qsnt
338562306a36Sopenharmony_ci * @ha: pointer to adapter structure
338662306a36Sopenharmony_ci **/
338762306a36Sopenharmony_civoid
338862306a36Sopenharmony_ciqla4_8xxx_need_qsnt_handler(struct scsi_qla_host *ha)
338962306a36Sopenharmony_ci{
339062306a36Sopenharmony_ci	ha->isp_ops->idc_lock(ha);
339162306a36Sopenharmony_ci	qla4_8xxx_set_qsnt_ready(ha);
339262306a36Sopenharmony_ci	ha->isp_ops->idc_unlock(ha);
339362306a36Sopenharmony_ci}
339462306a36Sopenharmony_ci
339562306a36Sopenharmony_cistatic void qla4_82xx_set_idc_ver(struct scsi_qla_host *ha)
339662306a36Sopenharmony_ci{
339762306a36Sopenharmony_ci	int idc_ver;
339862306a36Sopenharmony_ci	uint32_t drv_active;
339962306a36Sopenharmony_ci
340062306a36Sopenharmony_ci	drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
340162306a36Sopenharmony_ci	if (drv_active == (1 << (ha->func_num * 4))) {
340262306a36Sopenharmony_ci		qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_IDC_VERSION,
340362306a36Sopenharmony_ci				    QLA82XX_IDC_VERSION);
340462306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha,
340562306a36Sopenharmony_ci			   "%s: IDC version updated to %d\n", __func__,
340662306a36Sopenharmony_ci			   QLA82XX_IDC_VERSION);
340762306a36Sopenharmony_ci	} else {
340862306a36Sopenharmony_ci		idc_ver = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_IDC_VERSION);
340962306a36Sopenharmony_ci		if (QLA82XX_IDC_VERSION != idc_ver) {
341062306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha,
341162306a36Sopenharmony_ci				   "%s: qla4xxx driver IDC version %d is not compatible with IDC version %d of other drivers!\n",
341262306a36Sopenharmony_ci				   __func__, QLA82XX_IDC_VERSION, idc_ver);
341362306a36Sopenharmony_ci		}
341462306a36Sopenharmony_ci	}
341562306a36Sopenharmony_ci}
341662306a36Sopenharmony_ci
341762306a36Sopenharmony_cistatic int qla4_83xx_set_idc_ver(struct scsi_qla_host *ha)
341862306a36Sopenharmony_ci{
341962306a36Sopenharmony_ci	int idc_ver;
342062306a36Sopenharmony_ci	uint32_t drv_active;
342162306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
342262306a36Sopenharmony_ci
342362306a36Sopenharmony_ci	drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
342462306a36Sopenharmony_ci	if (drv_active == (1 << ha->func_num)) {
342562306a36Sopenharmony_ci		idc_ver = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_IDC_VERSION);
342662306a36Sopenharmony_ci		idc_ver &= (~0xFF);
342762306a36Sopenharmony_ci		idc_ver |= QLA83XX_IDC_VER_MAJ_VALUE;
342862306a36Sopenharmony_ci		qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DRV_IDC_VERSION, idc_ver);
342962306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha,
343062306a36Sopenharmony_ci			   "%s: IDC version updated to %d\n", __func__,
343162306a36Sopenharmony_ci			   idc_ver);
343262306a36Sopenharmony_ci	} else {
343362306a36Sopenharmony_ci		idc_ver = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_IDC_VERSION);
343462306a36Sopenharmony_ci		idc_ver &= 0xFF;
343562306a36Sopenharmony_ci		if (QLA83XX_IDC_VER_MAJ_VALUE != idc_ver) {
343662306a36Sopenharmony_ci			ql4_printk(KERN_INFO, ha,
343762306a36Sopenharmony_ci				   "%s: qla4xxx driver IDC version %d is not compatible with IDC version %d of other drivers!\n",
343862306a36Sopenharmony_ci				   __func__, QLA83XX_IDC_VER_MAJ_VALUE,
343962306a36Sopenharmony_ci				   idc_ver);
344062306a36Sopenharmony_ci			rval = QLA_ERROR;
344162306a36Sopenharmony_ci			goto exit_set_idc_ver;
344262306a36Sopenharmony_ci		}
344362306a36Sopenharmony_ci	}
344462306a36Sopenharmony_ci
344562306a36Sopenharmony_ci	/* Update IDC_MINOR_VERSION */
344662306a36Sopenharmony_ci	idc_ver = qla4_83xx_rd_reg(ha, QLA83XX_CRB_IDC_VER_MINOR);
344762306a36Sopenharmony_ci	idc_ver &= ~(0x03 << (ha->func_num * 2));
344862306a36Sopenharmony_ci	idc_ver |= (QLA83XX_IDC_VER_MIN_VALUE << (ha->func_num * 2));
344962306a36Sopenharmony_ci	qla4_83xx_wr_reg(ha, QLA83XX_CRB_IDC_VER_MINOR, idc_ver);
345062306a36Sopenharmony_ci
345162306a36Sopenharmony_ciexit_set_idc_ver:
345262306a36Sopenharmony_ci	return rval;
345362306a36Sopenharmony_ci}
345462306a36Sopenharmony_ci
345562306a36Sopenharmony_ciint qla4_8xxx_update_idc_reg(struct scsi_qla_host *ha)
345662306a36Sopenharmony_ci{
345762306a36Sopenharmony_ci	uint32_t drv_active;
345862306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
345962306a36Sopenharmony_ci
346062306a36Sopenharmony_ci	if (test_bit(AF_INIT_DONE, &ha->flags))
346162306a36Sopenharmony_ci		goto exit_update_idc_reg;
346262306a36Sopenharmony_ci
346362306a36Sopenharmony_ci	ha->isp_ops->idc_lock(ha);
346462306a36Sopenharmony_ci	qla4_8xxx_set_drv_active(ha);
346562306a36Sopenharmony_ci
346662306a36Sopenharmony_ci	/*
346762306a36Sopenharmony_ci	 * If we are the first driver to load and
346862306a36Sopenharmony_ci	 * ql4xdontresethba is not set, clear IDC_CTRL BIT0.
346962306a36Sopenharmony_ci	 */
347062306a36Sopenharmony_ci	if (is_qla8032(ha) || is_qla8042(ha)) {
347162306a36Sopenharmony_ci		drv_active = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DRV_ACTIVE);
347262306a36Sopenharmony_ci		if ((drv_active == (1 << ha->func_num)) && !ql4xdontresethba)
347362306a36Sopenharmony_ci			qla4_83xx_clear_idc_dontreset(ha);
347462306a36Sopenharmony_ci	}
347562306a36Sopenharmony_ci
347662306a36Sopenharmony_ci	if (is_qla8022(ha)) {
347762306a36Sopenharmony_ci		qla4_82xx_set_idc_ver(ha);
347862306a36Sopenharmony_ci	} else if (is_qla8032(ha) || is_qla8042(ha)) {
347962306a36Sopenharmony_ci		rval = qla4_83xx_set_idc_ver(ha);
348062306a36Sopenharmony_ci		if (rval == QLA_ERROR)
348162306a36Sopenharmony_ci			qla4_8xxx_clear_drv_active(ha);
348262306a36Sopenharmony_ci	}
348362306a36Sopenharmony_ci
348462306a36Sopenharmony_ci	ha->isp_ops->idc_unlock(ha);
348562306a36Sopenharmony_ci
348662306a36Sopenharmony_ciexit_update_idc_reg:
348762306a36Sopenharmony_ci	return rval;
348862306a36Sopenharmony_ci}
348962306a36Sopenharmony_ci
349062306a36Sopenharmony_ci/**
349162306a36Sopenharmony_ci * qla4_8xxx_device_state_handler - Adapter state machine
349262306a36Sopenharmony_ci * @ha: pointer to host adapter structure.
349362306a36Sopenharmony_ci *
349462306a36Sopenharmony_ci * Note: IDC lock must be UNLOCKED upon entry
349562306a36Sopenharmony_ci **/
349662306a36Sopenharmony_ciint qla4_8xxx_device_state_handler(struct scsi_qla_host *ha)
349762306a36Sopenharmony_ci{
349862306a36Sopenharmony_ci	uint32_t dev_state;
349962306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
350062306a36Sopenharmony_ci	unsigned long dev_init_timeout;
350162306a36Sopenharmony_ci
350262306a36Sopenharmony_ci	rval = qla4_8xxx_update_idc_reg(ha);
350362306a36Sopenharmony_ci	if (rval == QLA_ERROR)
350462306a36Sopenharmony_ci		goto exit_state_handler;
350562306a36Sopenharmony_ci
350662306a36Sopenharmony_ci	dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE);
350762306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "Device state is 0x%x = %s\n",
350862306a36Sopenharmony_ci			  dev_state, dev_state < MAX_STATES ?
350962306a36Sopenharmony_ci			  qdev_state[dev_state] : "Unknown"));
351062306a36Sopenharmony_ci
351162306a36Sopenharmony_ci	/* wait for 30 seconds for device to go ready */
351262306a36Sopenharmony_ci	dev_init_timeout = jiffies + (ha->nx_dev_init_timeout * HZ);
351362306a36Sopenharmony_ci
351462306a36Sopenharmony_ci	ha->isp_ops->idc_lock(ha);
351562306a36Sopenharmony_ci	while (1) {
351662306a36Sopenharmony_ci
351762306a36Sopenharmony_ci		if (time_after_eq(jiffies, dev_init_timeout)) {
351862306a36Sopenharmony_ci			ql4_printk(KERN_WARNING, ha,
351962306a36Sopenharmony_ci				   "%s: Device Init Failed 0x%x = %s\n",
352062306a36Sopenharmony_ci				   DRIVER_NAME,
352162306a36Sopenharmony_ci				   dev_state, dev_state < MAX_STATES ?
352262306a36Sopenharmony_ci				   qdev_state[dev_state] : "Unknown");
352362306a36Sopenharmony_ci			qla4_8xxx_wr_direct(ha, QLA8XXX_CRB_DEV_STATE,
352462306a36Sopenharmony_ci					    QLA8XXX_DEV_FAILED);
352562306a36Sopenharmony_ci		}
352662306a36Sopenharmony_ci
352762306a36Sopenharmony_ci		dev_state = qla4_8xxx_rd_direct(ha, QLA8XXX_CRB_DEV_STATE);
352862306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "Device state is 0x%x = %s\n",
352962306a36Sopenharmony_ci			   dev_state, dev_state < MAX_STATES ?
353062306a36Sopenharmony_ci			   qdev_state[dev_state] : "Unknown");
353162306a36Sopenharmony_ci
353262306a36Sopenharmony_ci		/* NOTE: Make sure idc unlocked upon exit of switch statement */
353362306a36Sopenharmony_ci		switch (dev_state) {
353462306a36Sopenharmony_ci		case QLA8XXX_DEV_READY:
353562306a36Sopenharmony_ci			goto exit;
353662306a36Sopenharmony_ci		case QLA8XXX_DEV_COLD:
353762306a36Sopenharmony_ci			rval = qla4_8xxx_device_bootstrap(ha);
353862306a36Sopenharmony_ci			goto exit;
353962306a36Sopenharmony_ci		case QLA8XXX_DEV_INITIALIZING:
354062306a36Sopenharmony_ci			ha->isp_ops->idc_unlock(ha);
354162306a36Sopenharmony_ci			msleep(1000);
354262306a36Sopenharmony_ci			ha->isp_ops->idc_lock(ha);
354362306a36Sopenharmony_ci			break;
354462306a36Sopenharmony_ci		case QLA8XXX_DEV_NEED_RESET:
354562306a36Sopenharmony_ci			/*
354662306a36Sopenharmony_ci			 * For ISP8324 and ISP8042, if NEED_RESET is set by any
354762306a36Sopenharmony_ci			 * driver, it should be honored, irrespective of
354862306a36Sopenharmony_ci			 * IDC_CTRL DONTRESET_BIT0
354962306a36Sopenharmony_ci			 */
355062306a36Sopenharmony_ci			if (is_qla8032(ha) || is_qla8042(ha)) {
355162306a36Sopenharmony_ci				qla4_83xx_need_reset_handler(ha);
355262306a36Sopenharmony_ci			} else if (is_qla8022(ha)) {
355362306a36Sopenharmony_ci				if (!ql4xdontresethba) {
355462306a36Sopenharmony_ci					qla4_82xx_need_reset_handler(ha);
355562306a36Sopenharmony_ci					/* Update timeout value after need
355662306a36Sopenharmony_ci					 * reset handler */
355762306a36Sopenharmony_ci					dev_init_timeout = jiffies +
355862306a36Sopenharmony_ci						(ha->nx_dev_init_timeout * HZ);
355962306a36Sopenharmony_ci				} else {
356062306a36Sopenharmony_ci					ha->isp_ops->idc_unlock(ha);
356162306a36Sopenharmony_ci					msleep(1000);
356262306a36Sopenharmony_ci					ha->isp_ops->idc_lock(ha);
356362306a36Sopenharmony_ci				}
356462306a36Sopenharmony_ci			}
356562306a36Sopenharmony_ci			break;
356662306a36Sopenharmony_ci		case QLA8XXX_DEV_NEED_QUIESCENT:
356762306a36Sopenharmony_ci			/* idc locked/unlocked in handler */
356862306a36Sopenharmony_ci			qla4_8xxx_need_qsnt_handler(ha);
356962306a36Sopenharmony_ci			break;
357062306a36Sopenharmony_ci		case QLA8XXX_DEV_QUIESCENT:
357162306a36Sopenharmony_ci			ha->isp_ops->idc_unlock(ha);
357262306a36Sopenharmony_ci			msleep(1000);
357362306a36Sopenharmony_ci			ha->isp_ops->idc_lock(ha);
357462306a36Sopenharmony_ci			break;
357562306a36Sopenharmony_ci		case QLA8XXX_DEV_FAILED:
357662306a36Sopenharmony_ci			ha->isp_ops->idc_unlock(ha);
357762306a36Sopenharmony_ci			qla4xxx_dead_adapter_cleanup(ha);
357862306a36Sopenharmony_ci			rval = QLA_ERROR;
357962306a36Sopenharmony_ci			ha->isp_ops->idc_lock(ha);
358062306a36Sopenharmony_ci			goto exit;
358162306a36Sopenharmony_ci		default:
358262306a36Sopenharmony_ci			ha->isp_ops->idc_unlock(ha);
358362306a36Sopenharmony_ci			qla4xxx_dead_adapter_cleanup(ha);
358462306a36Sopenharmony_ci			rval = QLA_ERROR;
358562306a36Sopenharmony_ci			ha->isp_ops->idc_lock(ha);
358662306a36Sopenharmony_ci			goto exit;
358762306a36Sopenharmony_ci		}
358862306a36Sopenharmony_ci	}
358962306a36Sopenharmony_ciexit:
359062306a36Sopenharmony_ci	ha->isp_ops->idc_unlock(ha);
359162306a36Sopenharmony_ciexit_state_handler:
359262306a36Sopenharmony_ci	return rval;
359362306a36Sopenharmony_ci}
359462306a36Sopenharmony_ci
359562306a36Sopenharmony_ciint qla4_8xxx_load_risc(struct scsi_qla_host *ha)
359662306a36Sopenharmony_ci{
359762306a36Sopenharmony_ci	int retval;
359862306a36Sopenharmony_ci
359962306a36Sopenharmony_ci	/* clear the interrupt */
360062306a36Sopenharmony_ci	if (is_qla8032(ha) || is_qla8042(ha)) {
360162306a36Sopenharmony_ci		writel(0, &ha->qla4_83xx_reg->risc_intr);
360262306a36Sopenharmony_ci		readl(&ha->qla4_83xx_reg->risc_intr);
360362306a36Sopenharmony_ci	} else if (is_qla8022(ha)) {
360462306a36Sopenharmony_ci		writel(0, &ha->qla4_82xx_reg->host_int);
360562306a36Sopenharmony_ci		readl(&ha->qla4_82xx_reg->host_int);
360662306a36Sopenharmony_ci	}
360762306a36Sopenharmony_ci
360862306a36Sopenharmony_ci	retval = qla4_8xxx_device_state_handler(ha);
360962306a36Sopenharmony_ci
361062306a36Sopenharmony_ci	/* Initialize request and response queues. */
361162306a36Sopenharmony_ci	if (retval == QLA_SUCCESS)
361262306a36Sopenharmony_ci		qla4xxx_init_rings(ha);
361362306a36Sopenharmony_ci
361462306a36Sopenharmony_ci	if (retval == QLA_SUCCESS && !test_bit(AF_IRQ_ATTACHED, &ha->flags))
361562306a36Sopenharmony_ci		retval = qla4xxx_request_irqs(ha);
361662306a36Sopenharmony_ci
361762306a36Sopenharmony_ci	return retval;
361862306a36Sopenharmony_ci}
361962306a36Sopenharmony_ci
362062306a36Sopenharmony_ci/*****************************************************************************/
362162306a36Sopenharmony_ci/* Flash Manipulation Routines                                               */
362262306a36Sopenharmony_ci/*****************************************************************************/
362362306a36Sopenharmony_ci
362462306a36Sopenharmony_ci#define OPTROM_BURST_SIZE       0x1000
362562306a36Sopenharmony_ci#define OPTROM_BURST_DWORDS     (OPTROM_BURST_SIZE / 4)
362662306a36Sopenharmony_ci
362762306a36Sopenharmony_ci#define FARX_DATA_FLAG	BIT_31
362862306a36Sopenharmony_ci#define FARX_ACCESS_FLASH_CONF	0x7FFD0000
362962306a36Sopenharmony_ci#define FARX_ACCESS_FLASH_DATA	0x7FF00000
363062306a36Sopenharmony_ci
363162306a36Sopenharmony_cistatic inline uint32_t
363262306a36Sopenharmony_ciflash_conf_addr(struct ql82xx_hw_data *hw, uint32_t faddr)
363362306a36Sopenharmony_ci{
363462306a36Sopenharmony_ci	return hw->flash_conf_off | faddr;
363562306a36Sopenharmony_ci}
363662306a36Sopenharmony_ci
363762306a36Sopenharmony_cistatic uint32_t *
363862306a36Sopenharmony_ciqla4_82xx_read_flash_data(struct scsi_qla_host *ha, uint32_t *dwptr,
363962306a36Sopenharmony_ci    uint32_t faddr, uint32_t length)
364062306a36Sopenharmony_ci{
364162306a36Sopenharmony_ci	uint32_t i;
364262306a36Sopenharmony_ci	uint32_t val;
364362306a36Sopenharmony_ci	int loops = 0;
364462306a36Sopenharmony_ci	while ((qla4_82xx_rom_lock(ha) != 0) && (loops < 50000)) {
364562306a36Sopenharmony_ci		udelay(100);
364662306a36Sopenharmony_ci		cond_resched();
364762306a36Sopenharmony_ci		loops++;
364862306a36Sopenharmony_ci	}
364962306a36Sopenharmony_ci	if (loops >= 50000) {
365062306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha, "ROM lock failed\n");
365162306a36Sopenharmony_ci		return dwptr;
365262306a36Sopenharmony_ci	}
365362306a36Sopenharmony_ci
365462306a36Sopenharmony_ci	/* Dword reads to flash. */
365562306a36Sopenharmony_ci	for (i = 0; i < length/4; i++, faddr += 4) {
365662306a36Sopenharmony_ci		if (qla4_82xx_do_rom_fast_read(ha, faddr, &val)) {
365762306a36Sopenharmony_ci			ql4_printk(KERN_WARNING, ha,
365862306a36Sopenharmony_ci			    "Do ROM fast read failed\n");
365962306a36Sopenharmony_ci			goto done_read;
366062306a36Sopenharmony_ci		}
366162306a36Sopenharmony_ci		dwptr[i] = cpu_to_le32(val);
366262306a36Sopenharmony_ci	}
366362306a36Sopenharmony_ci
366462306a36Sopenharmony_cidone_read:
366562306a36Sopenharmony_ci	qla4_82xx_rom_unlock(ha);
366662306a36Sopenharmony_ci	return dwptr;
366762306a36Sopenharmony_ci}
366862306a36Sopenharmony_ci
366962306a36Sopenharmony_ci/*
367062306a36Sopenharmony_ci * Address and length are byte address
367162306a36Sopenharmony_ci */
367262306a36Sopenharmony_cistatic uint8_t *
367362306a36Sopenharmony_ciqla4_82xx_read_optrom_data(struct scsi_qla_host *ha, uint8_t *buf,
367462306a36Sopenharmony_ci		uint32_t offset, uint32_t length)
367562306a36Sopenharmony_ci{
367662306a36Sopenharmony_ci	qla4_82xx_read_flash_data(ha, (uint32_t *)buf, offset, length);
367762306a36Sopenharmony_ci	return buf;
367862306a36Sopenharmony_ci}
367962306a36Sopenharmony_ci
368062306a36Sopenharmony_cistatic int
368162306a36Sopenharmony_ciqla4_8xxx_find_flt_start(struct scsi_qla_host *ha, uint32_t *start)
368262306a36Sopenharmony_ci{
368362306a36Sopenharmony_ci	const char *loc, *locations[] = { "DEF", "PCI" };
368462306a36Sopenharmony_ci
368562306a36Sopenharmony_ci	/*
368662306a36Sopenharmony_ci	 * FLT-location structure resides after the last PCI region.
368762306a36Sopenharmony_ci	 */
368862306a36Sopenharmony_ci
368962306a36Sopenharmony_ci	/* Begin with sane defaults. */
369062306a36Sopenharmony_ci	loc = locations[0];
369162306a36Sopenharmony_ci	*start = FA_FLASH_LAYOUT_ADDR_82;
369262306a36Sopenharmony_ci
369362306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "FLTL[%s] = 0x%x.\n", loc, *start));
369462306a36Sopenharmony_ci	return QLA_SUCCESS;
369562306a36Sopenharmony_ci}
369662306a36Sopenharmony_ci
369762306a36Sopenharmony_cistatic void
369862306a36Sopenharmony_ciqla4_8xxx_get_flt_info(struct scsi_qla_host *ha, uint32_t flt_addr)
369962306a36Sopenharmony_ci{
370062306a36Sopenharmony_ci	const char *loc, *locations[] = { "DEF", "FLT" };
370162306a36Sopenharmony_ci	uint16_t *wptr;
370262306a36Sopenharmony_ci	uint16_t cnt, chksum;
370362306a36Sopenharmony_ci	uint32_t start, status;
370462306a36Sopenharmony_ci	struct qla_flt_header *flt;
370562306a36Sopenharmony_ci	struct qla_flt_region *region;
370662306a36Sopenharmony_ci	struct ql82xx_hw_data *hw = &ha->hw;
370762306a36Sopenharmony_ci
370862306a36Sopenharmony_ci	hw->flt_region_flt = flt_addr;
370962306a36Sopenharmony_ci	wptr = (uint16_t *)ha->request_ring;
371062306a36Sopenharmony_ci	flt = (struct qla_flt_header *)ha->request_ring;
371162306a36Sopenharmony_ci	region = (struct qla_flt_region *)&flt[1];
371262306a36Sopenharmony_ci
371362306a36Sopenharmony_ci	if (is_qla8022(ha)) {
371462306a36Sopenharmony_ci		qla4_82xx_read_optrom_data(ha, (uint8_t *)ha->request_ring,
371562306a36Sopenharmony_ci					   flt_addr << 2, OPTROM_BURST_SIZE);
371662306a36Sopenharmony_ci	} else if (is_qla8032(ha) || is_qla8042(ha)) {
371762306a36Sopenharmony_ci		status = qla4_83xx_flash_read_u32(ha, flt_addr << 2,
371862306a36Sopenharmony_ci						  (uint8_t *)ha->request_ring,
371962306a36Sopenharmony_ci						  0x400);
372062306a36Sopenharmony_ci		if (status != QLA_SUCCESS)
372162306a36Sopenharmony_ci			goto no_flash_data;
372262306a36Sopenharmony_ci	}
372362306a36Sopenharmony_ci
372462306a36Sopenharmony_ci	if (*wptr == cpu_to_le16(0xffff))
372562306a36Sopenharmony_ci		goto no_flash_data;
372662306a36Sopenharmony_ci	if (flt->version != cpu_to_le16(1)) {
372762306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "Unsupported FLT detected: "
372862306a36Sopenharmony_ci			"version=0x%x length=0x%x checksum=0x%x.\n",
372962306a36Sopenharmony_ci			le16_to_cpu(flt->version), le16_to_cpu(flt->length),
373062306a36Sopenharmony_ci			le16_to_cpu(flt->checksum)));
373162306a36Sopenharmony_ci		goto no_flash_data;
373262306a36Sopenharmony_ci	}
373362306a36Sopenharmony_ci
373462306a36Sopenharmony_ci	cnt = (sizeof(struct qla_flt_header) + le16_to_cpu(flt->length)) >> 1;
373562306a36Sopenharmony_ci	for (chksum = 0; cnt; cnt--)
373662306a36Sopenharmony_ci		chksum += le16_to_cpu(*wptr++);
373762306a36Sopenharmony_ci	if (chksum) {
373862306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "Inconsistent FLT detected: "
373962306a36Sopenharmony_ci			"version=0x%x length=0x%x checksum=0x%x.\n",
374062306a36Sopenharmony_ci			le16_to_cpu(flt->version), le16_to_cpu(flt->length),
374162306a36Sopenharmony_ci			chksum));
374262306a36Sopenharmony_ci		goto no_flash_data;
374362306a36Sopenharmony_ci	}
374462306a36Sopenharmony_ci
374562306a36Sopenharmony_ci	loc = locations[1];
374662306a36Sopenharmony_ci	cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region);
374762306a36Sopenharmony_ci	for ( ; cnt; cnt--, region++) {
374862306a36Sopenharmony_ci		/* Store addresses as DWORD offsets. */
374962306a36Sopenharmony_ci		start = le32_to_cpu(region->start) >> 2;
375062306a36Sopenharmony_ci
375162306a36Sopenharmony_ci		DEBUG3(ql4_printk(KERN_DEBUG, ha, "FLT[%02x]: start=0x%x "
375262306a36Sopenharmony_ci		    "end=0x%x size=0x%x.\n", le32_to_cpu(region->code), start,
375362306a36Sopenharmony_ci		    le32_to_cpu(region->end) >> 2, le32_to_cpu(region->size)));
375462306a36Sopenharmony_ci
375562306a36Sopenharmony_ci		switch (le32_to_cpu(region->code) & 0xff) {
375662306a36Sopenharmony_ci		case FLT_REG_FDT:
375762306a36Sopenharmony_ci			hw->flt_region_fdt = start;
375862306a36Sopenharmony_ci			break;
375962306a36Sopenharmony_ci		case FLT_REG_BOOT_CODE_82:
376062306a36Sopenharmony_ci			hw->flt_region_boot = start;
376162306a36Sopenharmony_ci			break;
376262306a36Sopenharmony_ci		case FLT_REG_FW_82:
376362306a36Sopenharmony_ci		case FLT_REG_FW_82_1:
376462306a36Sopenharmony_ci			hw->flt_region_fw = start;
376562306a36Sopenharmony_ci			break;
376662306a36Sopenharmony_ci		case FLT_REG_BOOTLOAD_82:
376762306a36Sopenharmony_ci			hw->flt_region_bootload = start;
376862306a36Sopenharmony_ci			break;
376962306a36Sopenharmony_ci		case FLT_REG_ISCSI_PARAM:
377062306a36Sopenharmony_ci			hw->flt_iscsi_param =  start;
377162306a36Sopenharmony_ci			break;
377262306a36Sopenharmony_ci		case FLT_REG_ISCSI_CHAP:
377362306a36Sopenharmony_ci			hw->flt_region_chap =  start;
377462306a36Sopenharmony_ci			hw->flt_chap_size =  le32_to_cpu(region->size);
377562306a36Sopenharmony_ci			break;
377662306a36Sopenharmony_ci		case FLT_REG_ISCSI_DDB:
377762306a36Sopenharmony_ci			hw->flt_region_ddb =  start;
377862306a36Sopenharmony_ci			hw->flt_ddb_size =  le32_to_cpu(region->size);
377962306a36Sopenharmony_ci			break;
378062306a36Sopenharmony_ci		}
378162306a36Sopenharmony_ci	}
378262306a36Sopenharmony_ci	goto done;
378362306a36Sopenharmony_ci
378462306a36Sopenharmony_cino_flash_data:
378562306a36Sopenharmony_ci	/* Use hardcoded defaults. */
378662306a36Sopenharmony_ci	loc = locations[0];
378762306a36Sopenharmony_ci
378862306a36Sopenharmony_ci	hw->flt_region_fdt      = FA_FLASH_DESCR_ADDR_82;
378962306a36Sopenharmony_ci	hw->flt_region_boot     = FA_BOOT_CODE_ADDR_82;
379062306a36Sopenharmony_ci	hw->flt_region_bootload = FA_BOOT_LOAD_ADDR_82;
379162306a36Sopenharmony_ci	hw->flt_region_fw       = FA_RISC_CODE_ADDR_82;
379262306a36Sopenharmony_ci	hw->flt_region_chap	= FA_FLASH_ISCSI_CHAP >> 2;
379362306a36Sopenharmony_ci	hw->flt_chap_size	= FA_FLASH_CHAP_SIZE;
379462306a36Sopenharmony_ci	hw->flt_region_ddb	= FA_FLASH_ISCSI_DDB >> 2;
379562306a36Sopenharmony_ci	hw->flt_ddb_size	= FA_FLASH_DDB_SIZE;
379662306a36Sopenharmony_ci
379762306a36Sopenharmony_cidone:
379862306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha,
379962306a36Sopenharmony_ci			  "FLT[%s]: flt=0x%x fdt=0x%x boot=0x%x bootload=0x%x fw=0x%x chap=0x%x chap_size=0x%x ddb=0x%x  ddb_size=0x%x\n",
380062306a36Sopenharmony_ci			  loc, hw->flt_region_flt, hw->flt_region_fdt,
380162306a36Sopenharmony_ci			  hw->flt_region_boot, hw->flt_region_bootload,
380262306a36Sopenharmony_ci			  hw->flt_region_fw, hw->flt_region_chap,
380362306a36Sopenharmony_ci			  hw->flt_chap_size, hw->flt_region_ddb,
380462306a36Sopenharmony_ci			  hw->flt_ddb_size));
380562306a36Sopenharmony_ci}
380662306a36Sopenharmony_ci
380762306a36Sopenharmony_cistatic void
380862306a36Sopenharmony_ciqla4_82xx_get_fdt_info(struct scsi_qla_host *ha)
380962306a36Sopenharmony_ci{
381062306a36Sopenharmony_ci#define FLASH_BLK_SIZE_4K       0x1000
381162306a36Sopenharmony_ci#define FLASH_BLK_SIZE_32K      0x8000
381262306a36Sopenharmony_ci#define FLASH_BLK_SIZE_64K      0x10000
381362306a36Sopenharmony_ci	const char *loc, *locations[] = { "MID", "FDT" };
381462306a36Sopenharmony_ci	uint16_t cnt, chksum;
381562306a36Sopenharmony_ci	uint16_t *wptr;
381662306a36Sopenharmony_ci	struct qla_fdt_layout *fdt;
381762306a36Sopenharmony_ci	uint16_t mid = 0;
381862306a36Sopenharmony_ci	uint16_t fid = 0;
381962306a36Sopenharmony_ci	struct ql82xx_hw_data *hw = &ha->hw;
382062306a36Sopenharmony_ci
382162306a36Sopenharmony_ci	hw->flash_conf_off = FARX_ACCESS_FLASH_CONF;
382262306a36Sopenharmony_ci	hw->flash_data_off = FARX_ACCESS_FLASH_DATA;
382362306a36Sopenharmony_ci
382462306a36Sopenharmony_ci	wptr = (uint16_t *)ha->request_ring;
382562306a36Sopenharmony_ci	fdt = (struct qla_fdt_layout *)ha->request_ring;
382662306a36Sopenharmony_ci	qla4_82xx_read_optrom_data(ha, (uint8_t *)ha->request_ring,
382762306a36Sopenharmony_ci	    hw->flt_region_fdt << 2, OPTROM_BURST_SIZE);
382862306a36Sopenharmony_ci
382962306a36Sopenharmony_ci	if (*wptr == cpu_to_le16(0xffff))
383062306a36Sopenharmony_ci		goto no_flash_data;
383162306a36Sopenharmony_ci
383262306a36Sopenharmony_ci	if (fdt->sig[0] != 'Q' || fdt->sig[1] != 'L' || fdt->sig[2] != 'I' ||
383362306a36Sopenharmony_ci	    fdt->sig[3] != 'D')
383462306a36Sopenharmony_ci		goto no_flash_data;
383562306a36Sopenharmony_ci
383662306a36Sopenharmony_ci	for (cnt = 0, chksum = 0; cnt < sizeof(struct qla_fdt_layout) >> 1;
383762306a36Sopenharmony_ci	    cnt++)
383862306a36Sopenharmony_ci		chksum += le16_to_cpu(*wptr++);
383962306a36Sopenharmony_ci
384062306a36Sopenharmony_ci	if (chksum) {
384162306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha, "Inconsistent FDT detected: "
384262306a36Sopenharmony_ci		    "checksum=0x%x id=%c version=0x%x.\n", chksum, fdt->sig[0],
384362306a36Sopenharmony_ci		    le16_to_cpu(fdt->version)));
384462306a36Sopenharmony_ci		goto no_flash_data;
384562306a36Sopenharmony_ci	}
384662306a36Sopenharmony_ci
384762306a36Sopenharmony_ci	loc = locations[1];
384862306a36Sopenharmony_ci	mid = le16_to_cpu(fdt->man_id);
384962306a36Sopenharmony_ci	fid = le16_to_cpu(fdt->id);
385062306a36Sopenharmony_ci	hw->fdt_wrt_disable = fdt->wrt_disable_bits;
385162306a36Sopenharmony_ci	hw->fdt_erase_cmd = flash_conf_addr(hw, 0x0300 | fdt->erase_cmd);
385262306a36Sopenharmony_ci	hw->fdt_block_size = le32_to_cpu(fdt->block_size);
385362306a36Sopenharmony_ci
385462306a36Sopenharmony_ci	if (fdt->unprotect_sec_cmd) {
385562306a36Sopenharmony_ci		hw->fdt_unprotect_sec_cmd = flash_conf_addr(hw, 0x0300 |
385662306a36Sopenharmony_ci		    fdt->unprotect_sec_cmd);
385762306a36Sopenharmony_ci		hw->fdt_protect_sec_cmd = fdt->protect_sec_cmd ?
385862306a36Sopenharmony_ci		    flash_conf_addr(hw, 0x0300 | fdt->protect_sec_cmd) :
385962306a36Sopenharmony_ci		    flash_conf_addr(hw, 0x0336);
386062306a36Sopenharmony_ci	}
386162306a36Sopenharmony_ci	goto done;
386262306a36Sopenharmony_ci
386362306a36Sopenharmony_cino_flash_data:
386462306a36Sopenharmony_ci	loc = locations[0];
386562306a36Sopenharmony_ci	hw->fdt_block_size = FLASH_BLK_SIZE_64K;
386662306a36Sopenharmony_cidone:
386762306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "FDT[%s]: (0x%x/0x%x) erase=0x%x "
386862306a36Sopenharmony_ci		"pro=%x upro=%x wrtd=0x%x blk=0x%x.\n", loc, mid, fid,
386962306a36Sopenharmony_ci		hw->fdt_erase_cmd, hw->fdt_protect_sec_cmd,
387062306a36Sopenharmony_ci		hw->fdt_unprotect_sec_cmd, hw->fdt_wrt_disable,
387162306a36Sopenharmony_ci		hw->fdt_block_size));
387262306a36Sopenharmony_ci}
387362306a36Sopenharmony_ci
387462306a36Sopenharmony_cistatic void
387562306a36Sopenharmony_ciqla4_82xx_get_idc_param(struct scsi_qla_host *ha)
387662306a36Sopenharmony_ci{
387762306a36Sopenharmony_ci#define QLA82XX_IDC_PARAM_ADDR      0x003e885c
387862306a36Sopenharmony_ci	uint32_t *wptr;
387962306a36Sopenharmony_ci
388062306a36Sopenharmony_ci	if (!is_qla8022(ha))
388162306a36Sopenharmony_ci		return;
388262306a36Sopenharmony_ci	wptr = (uint32_t *)ha->request_ring;
388362306a36Sopenharmony_ci	qla4_82xx_read_optrom_data(ha, (uint8_t *)ha->request_ring,
388462306a36Sopenharmony_ci			QLA82XX_IDC_PARAM_ADDR , 8);
388562306a36Sopenharmony_ci
388662306a36Sopenharmony_ci	if (*wptr == cpu_to_le32(0xffffffff)) {
388762306a36Sopenharmony_ci		ha->nx_dev_init_timeout = ROM_DEV_INIT_TIMEOUT;
388862306a36Sopenharmony_ci		ha->nx_reset_timeout = ROM_DRV_RESET_ACK_TIMEOUT;
388962306a36Sopenharmony_ci	} else {
389062306a36Sopenharmony_ci		ha->nx_dev_init_timeout = le32_to_cpu(*wptr++);
389162306a36Sopenharmony_ci		ha->nx_reset_timeout = le32_to_cpu(*wptr);
389262306a36Sopenharmony_ci	}
389362306a36Sopenharmony_ci
389462306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_DEBUG, ha,
389562306a36Sopenharmony_ci		"ha->nx_dev_init_timeout = %d\n", ha->nx_dev_init_timeout));
389662306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_DEBUG, ha,
389762306a36Sopenharmony_ci		"ha->nx_reset_timeout = %d\n", ha->nx_reset_timeout));
389862306a36Sopenharmony_ci	return;
389962306a36Sopenharmony_ci}
390062306a36Sopenharmony_ci
390162306a36Sopenharmony_civoid qla4_82xx_queue_mbox_cmd(struct scsi_qla_host *ha, uint32_t *mbx_cmd,
390262306a36Sopenharmony_ci			      int in_count)
390362306a36Sopenharmony_ci{
390462306a36Sopenharmony_ci	int i;
390562306a36Sopenharmony_ci
390662306a36Sopenharmony_ci	/* Load all mailbox registers, except mailbox 0. */
390762306a36Sopenharmony_ci	for (i = 1; i < in_count; i++)
390862306a36Sopenharmony_ci		writel(mbx_cmd[i], &ha->qla4_82xx_reg->mailbox_in[i]);
390962306a36Sopenharmony_ci
391062306a36Sopenharmony_ci	/* Wakeup firmware  */
391162306a36Sopenharmony_ci	writel(mbx_cmd[0], &ha->qla4_82xx_reg->mailbox_in[0]);
391262306a36Sopenharmony_ci	readl(&ha->qla4_82xx_reg->mailbox_in[0]);
391362306a36Sopenharmony_ci	writel(HINT_MBX_INT_PENDING, &ha->qla4_82xx_reg->hint);
391462306a36Sopenharmony_ci	readl(&ha->qla4_82xx_reg->hint);
391562306a36Sopenharmony_ci}
391662306a36Sopenharmony_ci
391762306a36Sopenharmony_civoid qla4_82xx_process_mbox_intr(struct scsi_qla_host *ha, int out_count)
391862306a36Sopenharmony_ci{
391962306a36Sopenharmony_ci	int intr_status;
392062306a36Sopenharmony_ci
392162306a36Sopenharmony_ci	intr_status = readl(&ha->qla4_82xx_reg->host_int);
392262306a36Sopenharmony_ci	if (intr_status & ISRX_82XX_RISC_INT) {
392362306a36Sopenharmony_ci		ha->mbox_status_count = out_count;
392462306a36Sopenharmony_ci		intr_status = readl(&ha->qla4_82xx_reg->host_status);
392562306a36Sopenharmony_ci		ha->isp_ops->interrupt_service_routine(ha, intr_status);
392662306a36Sopenharmony_ci
392762306a36Sopenharmony_ci		if (test_bit(AF_INTERRUPTS_ON, &ha->flags) &&
392862306a36Sopenharmony_ci		    (!ha->pdev->msi_enabled && !ha->pdev->msix_enabled))
392962306a36Sopenharmony_ci			qla4_82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg,
393062306a36Sopenharmony_ci					0xfbff);
393162306a36Sopenharmony_ci	}
393262306a36Sopenharmony_ci}
393362306a36Sopenharmony_ci
393462306a36Sopenharmony_ciint
393562306a36Sopenharmony_ciqla4_8xxx_get_flash_info(struct scsi_qla_host *ha)
393662306a36Sopenharmony_ci{
393762306a36Sopenharmony_ci	int ret;
393862306a36Sopenharmony_ci	uint32_t flt_addr;
393962306a36Sopenharmony_ci
394062306a36Sopenharmony_ci	ret = qla4_8xxx_find_flt_start(ha, &flt_addr);
394162306a36Sopenharmony_ci	if (ret != QLA_SUCCESS)
394262306a36Sopenharmony_ci		return ret;
394362306a36Sopenharmony_ci
394462306a36Sopenharmony_ci	qla4_8xxx_get_flt_info(ha, flt_addr);
394562306a36Sopenharmony_ci	if (is_qla8022(ha)) {
394662306a36Sopenharmony_ci		qla4_82xx_get_fdt_info(ha);
394762306a36Sopenharmony_ci		qla4_82xx_get_idc_param(ha);
394862306a36Sopenharmony_ci	} else if (is_qla8032(ha) || is_qla8042(ha)) {
394962306a36Sopenharmony_ci		qla4_83xx_get_idc_param(ha);
395062306a36Sopenharmony_ci	}
395162306a36Sopenharmony_ci
395262306a36Sopenharmony_ci	return QLA_SUCCESS;
395362306a36Sopenharmony_ci}
395462306a36Sopenharmony_ci
395562306a36Sopenharmony_ci/**
395662306a36Sopenharmony_ci * qla4_8xxx_stop_firmware - stops firmware on specified adapter instance
395762306a36Sopenharmony_ci * @ha: pointer to host adapter structure.
395862306a36Sopenharmony_ci *
395962306a36Sopenharmony_ci * Remarks:
396062306a36Sopenharmony_ci * For iSCSI, throws away all I/O and AENs into bit bucket, so they will
396162306a36Sopenharmony_ci * not be available after successful return.  Driver must cleanup potential
396262306a36Sopenharmony_ci * outstanding I/O's after calling this funcion.
396362306a36Sopenharmony_ci **/
396462306a36Sopenharmony_ciint
396562306a36Sopenharmony_ciqla4_8xxx_stop_firmware(struct scsi_qla_host *ha)
396662306a36Sopenharmony_ci{
396762306a36Sopenharmony_ci	int status;
396862306a36Sopenharmony_ci	uint32_t mbox_cmd[MBOX_REG_COUNT];
396962306a36Sopenharmony_ci	uint32_t mbox_sts[MBOX_REG_COUNT];
397062306a36Sopenharmony_ci
397162306a36Sopenharmony_ci	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
397262306a36Sopenharmony_ci	memset(&mbox_sts, 0, sizeof(mbox_sts));
397362306a36Sopenharmony_ci
397462306a36Sopenharmony_ci	mbox_cmd[0] = MBOX_CMD_STOP_FW;
397562306a36Sopenharmony_ci	status = qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1,
397662306a36Sopenharmony_ci	    &mbox_cmd[0], &mbox_sts[0]);
397762306a36Sopenharmony_ci
397862306a36Sopenharmony_ci	DEBUG2(printk("scsi%ld: %s: status = %d\n", ha->host_no,
397962306a36Sopenharmony_ci	    __func__, status));
398062306a36Sopenharmony_ci	return status;
398162306a36Sopenharmony_ci}
398262306a36Sopenharmony_ci
398362306a36Sopenharmony_ci/**
398462306a36Sopenharmony_ci * qla4_82xx_isp_reset - Resets ISP and aborts all outstanding commands.
398562306a36Sopenharmony_ci * @ha: pointer to host adapter structure.
398662306a36Sopenharmony_ci **/
398762306a36Sopenharmony_ciint
398862306a36Sopenharmony_ciqla4_82xx_isp_reset(struct scsi_qla_host *ha)
398962306a36Sopenharmony_ci{
399062306a36Sopenharmony_ci	int rval;
399162306a36Sopenharmony_ci	uint32_t dev_state;
399262306a36Sopenharmony_ci
399362306a36Sopenharmony_ci	qla4_82xx_idc_lock(ha);
399462306a36Sopenharmony_ci	dev_state = qla4_82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
399562306a36Sopenharmony_ci
399662306a36Sopenharmony_ci	if (dev_state == QLA8XXX_DEV_READY) {
399762306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "HW State: NEED RESET\n");
399862306a36Sopenharmony_ci		qla4_82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
399962306a36Sopenharmony_ci		    QLA8XXX_DEV_NEED_RESET);
400062306a36Sopenharmony_ci		set_bit(AF_8XXX_RST_OWNER, &ha->flags);
400162306a36Sopenharmony_ci	} else
400262306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "HW State: DEVICE INITIALIZING\n");
400362306a36Sopenharmony_ci
400462306a36Sopenharmony_ci	qla4_82xx_idc_unlock(ha);
400562306a36Sopenharmony_ci
400662306a36Sopenharmony_ci	rval = qla4_8xxx_device_state_handler(ha);
400762306a36Sopenharmony_ci
400862306a36Sopenharmony_ci	qla4_82xx_idc_lock(ha);
400962306a36Sopenharmony_ci	qla4_8xxx_clear_rst_ready(ha);
401062306a36Sopenharmony_ci	qla4_82xx_idc_unlock(ha);
401162306a36Sopenharmony_ci
401262306a36Sopenharmony_ci	if (rval == QLA_SUCCESS) {
401362306a36Sopenharmony_ci		ql4_printk(KERN_INFO, ha, "Clearing AF_RECOVERY in qla4_82xx_isp_reset\n");
401462306a36Sopenharmony_ci		clear_bit(AF_FW_RECOVERY, &ha->flags);
401562306a36Sopenharmony_ci	}
401662306a36Sopenharmony_ci
401762306a36Sopenharmony_ci	return rval;
401862306a36Sopenharmony_ci}
401962306a36Sopenharmony_ci
402062306a36Sopenharmony_ci/**
402162306a36Sopenharmony_ci * qla4_8xxx_get_sys_info - get adapter MAC address(es) and serial number
402262306a36Sopenharmony_ci * @ha: pointer to host adapter structure.
402362306a36Sopenharmony_ci *
402462306a36Sopenharmony_ci **/
402562306a36Sopenharmony_ciint qla4_8xxx_get_sys_info(struct scsi_qla_host *ha)
402662306a36Sopenharmony_ci{
402762306a36Sopenharmony_ci	uint32_t mbox_cmd[MBOX_REG_COUNT];
402862306a36Sopenharmony_ci	uint32_t mbox_sts[MBOX_REG_COUNT];
402962306a36Sopenharmony_ci	struct mbx_sys_info *sys_info;
403062306a36Sopenharmony_ci	dma_addr_t sys_info_dma;
403162306a36Sopenharmony_ci	int status = QLA_ERROR;
403262306a36Sopenharmony_ci
403362306a36Sopenharmony_ci	sys_info = dma_alloc_coherent(&ha->pdev->dev, sizeof(*sys_info),
403462306a36Sopenharmony_ci				      &sys_info_dma, GFP_KERNEL);
403562306a36Sopenharmony_ci	if (sys_info == NULL) {
403662306a36Sopenharmony_ci		DEBUG2(printk("scsi%ld: %s: Unable to allocate dma buffer.\n",
403762306a36Sopenharmony_ci		    ha->host_no, __func__));
403862306a36Sopenharmony_ci		return status;
403962306a36Sopenharmony_ci	}
404062306a36Sopenharmony_ci
404162306a36Sopenharmony_ci	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
404262306a36Sopenharmony_ci	memset(&mbox_sts, 0, sizeof(mbox_sts));
404362306a36Sopenharmony_ci
404462306a36Sopenharmony_ci	mbox_cmd[0] = MBOX_CMD_GET_SYS_INFO;
404562306a36Sopenharmony_ci	mbox_cmd[1] = LSDW(sys_info_dma);
404662306a36Sopenharmony_ci	mbox_cmd[2] = MSDW(sys_info_dma);
404762306a36Sopenharmony_ci	mbox_cmd[4] = sizeof(*sys_info);
404862306a36Sopenharmony_ci
404962306a36Sopenharmony_ci	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 6, &mbox_cmd[0],
405062306a36Sopenharmony_ci	    &mbox_sts[0]) != QLA_SUCCESS) {
405162306a36Sopenharmony_ci		DEBUG2(printk("scsi%ld: %s: GET_SYS_INFO failed\n",
405262306a36Sopenharmony_ci		    ha->host_no, __func__));
405362306a36Sopenharmony_ci		goto exit_validate_mac82;
405462306a36Sopenharmony_ci	}
405562306a36Sopenharmony_ci
405662306a36Sopenharmony_ci	/* Make sure we receive the minimum required data to cache internally */
405762306a36Sopenharmony_ci	if (((is_qla8032(ha) || is_qla8042(ha)) ? mbox_sts[3] : mbox_sts[4]) <
405862306a36Sopenharmony_ci	    offsetof(struct mbx_sys_info, reserved)) {
405962306a36Sopenharmony_ci		DEBUG2(printk("scsi%ld: %s: GET_SYS_INFO data receive"
406062306a36Sopenharmony_ci		    " error (%x)\n", ha->host_no, __func__, mbox_sts[4]));
406162306a36Sopenharmony_ci		goto exit_validate_mac82;
406262306a36Sopenharmony_ci	}
406362306a36Sopenharmony_ci
406462306a36Sopenharmony_ci	/* Save M.A.C. address & serial_number */
406562306a36Sopenharmony_ci	ha->port_num = sys_info->port_num;
406662306a36Sopenharmony_ci	memcpy(ha->my_mac, &sys_info->mac_addr[0],
406762306a36Sopenharmony_ci	    min(sizeof(ha->my_mac), sizeof(sys_info->mac_addr)));
406862306a36Sopenharmony_ci	memcpy(ha->serial_number, &sys_info->serial_number,
406962306a36Sopenharmony_ci	    min(sizeof(ha->serial_number), sizeof(sys_info->serial_number)));
407062306a36Sopenharmony_ci	memcpy(ha->model_name, &sys_info->board_id_str,
407162306a36Sopenharmony_ci	       min(sizeof(ha->model_name), sizeof(sys_info->board_id_str)));
407262306a36Sopenharmony_ci	ha->phy_port_cnt = sys_info->phys_port_cnt;
407362306a36Sopenharmony_ci	ha->phy_port_num = sys_info->port_num;
407462306a36Sopenharmony_ci	ha->iscsi_pci_func_cnt = sys_info->iscsi_pci_func_cnt;
407562306a36Sopenharmony_ci
407662306a36Sopenharmony_ci	DEBUG2(printk("scsi%ld: %s: mac %pM serial %s\n",
407762306a36Sopenharmony_ci	    ha->host_no, __func__, ha->my_mac, ha->serial_number));
407862306a36Sopenharmony_ci
407962306a36Sopenharmony_ci	status = QLA_SUCCESS;
408062306a36Sopenharmony_ci
408162306a36Sopenharmony_ciexit_validate_mac82:
408262306a36Sopenharmony_ci	dma_free_coherent(&ha->pdev->dev, sizeof(*sys_info), sys_info,
408362306a36Sopenharmony_ci			  sys_info_dma);
408462306a36Sopenharmony_ci	return status;
408562306a36Sopenharmony_ci}
408662306a36Sopenharmony_ci
408762306a36Sopenharmony_ci/* Interrupt handling helpers. */
408862306a36Sopenharmony_ci
408962306a36Sopenharmony_ciint qla4_8xxx_intr_enable(struct scsi_qla_host *ha)
409062306a36Sopenharmony_ci{
409162306a36Sopenharmony_ci	uint32_t mbox_cmd[MBOX_REG_COUNT];
409262306a36Sopenharmony_ci	uint32_t mbox_sts[MBOX_REG_COUNT];
409362306a36Sopenharmony_ci
409462306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s\n", __func__));
409562306a36Sopenharmony_ci
409662306a36Sopenharmony_ci	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
409762306a36Sopenharmony_ci	memset(&mbox_sts, 0, sizeof(mbox_sts));
409862306a36Sopenharmony_ci	mbox_cmd[0] = MBOX_CMD_ENABLE_INTRS;
409962306a36Sopenharmony_ci	mbox_cmd[1] = INTR_ENABLE;
410062306a36Sopenharmony_ci	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
410162306a36Sopenharmony_ci		&mbox_sts[0]) != QLA_SUCCESS) {
410262306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
410362306a36Sopenharmony_ci		    "%s: MBOX_CMD_ENABLE_INTRS failed (0x%04x)\n",
410462306a36Sopenharmony_ci		    __func__, mbox_sts[0]));
410562306a36Sopenharmony_ci		return QLA_ERROR;
410662306a36Sopenharmony_ci	}
410762306a36Sopenharmony_ci	return QLA_SUCCESS;
410862306a36Sopenharmony_ci}
410962306a36Sopenharmony_ci
411062306a36Sopenharmony_ciint qla4_8xxx_intr_disable(struct scsi_qla_host *ha)
411162306a36Sopenharmony_ci{
411262306a36Sopenharmony_ci	uint32_t mbox_cmd[MBOX_REG_COUNT];
411362306a36Sopenharmony_ci	uint32_t mbox_sts[MBOX_REG_COUNT];
411462306a36Sopenharmony_ci
411562306a36Sopenharmony_ci	DEBUG2(ql4_printk(KERN_INFO, ha, "%s\n", __func__));
411662306a36Sopenharmony_ci
411762306a36Sopenharmony_ci	memset(&mbox_cmd, 0, sizeof(mbox_cmd));
411862306a36Sopenharmony_ci	memset(&mbox_sts, 0, sizeof(mbox_sts));
411962306a36Sopenharmony_ci	mbox_cmd[0] = MBOX_CMD_ENABLE_INTRS;
412062306a36Sopenharmony_ci	mbox_cmd[1] = INTR_DISABLE;
412162306a36Sopenharmony_ci	if (qla4xxx_mailbox_command(ha, MBOX_REG_COUNT, 1, &mbox_cmd[0],
412262306a36Sopenharmony_ci	    &mbox_sts[0]) != QLA_SUCCESS) {
412362306a36Sopenharmony_ci		DEBUG2(ql4_printk(KERN_INFO, ha,
412462306a36Sopenharmony_ci			"%s: MBOX_CMD_ENABLE_INTRS failed (0x%04x)\n",
412562306a36Sopenharmony_ci			__func__, mbox_sts[0]));
412662306a36Sopenharmony_ci		return QLA_ERROR;
412762306a36Sopenharmony_ci	}
412862306a36Sopenharmony_ci
412962306a36Sopenharmony_ci	return QLA_SUCCESS;
413062306a36Sopenharmony_ci}
413162306a36Sopenharmony_ci
413262306a36Sopenharmony_civoid
413362306a36Sopenharmony_ciqla4_82xx_enable_intrs(struct scsi_qla_host *ha)
413462306a36Sopenharmony_ci{
413562306a36Sopenharmony_ci	qla4_8xxx_intr_enable(ha);
413662306a36Sopenharmony_ci
413762306a36Sopenharmony_ci	spin_lock_irq(&ha->hardware_lock);
413862306a36Sopenharmony_ci	/* BIT 10 - reset */
413962306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);
414062306a36Sopenharmony_ci	spin_unlock_irq(&ha->hardware_lock);
414162306a36Sopenharmony_ci	set_bit(AF_INTERRUPTS_ON, &ha->flags);
414262306a36Sopenharmony_ci}
414362306a36Sopenharmony_ci
414462306a36Sopenharmony_civoid
414562306a36Sopenharmony_ciqla4_82xx_disable_intrs(struct scsi_qla_host *ha)
414662306a36Sopenharmony_ci{
414762306a36Sopenharmony_ci	if (test_and_clear_bit(AF_INTERRUPTS_ON, &ha->flags))
414862306a36Sopenharmony_ci		qla4_8xxx_intr_disable(ha);
414962306a36Sopenharmony_ci
415062306a36Sopenharmony_ci	spin_lock_irq(&ha->hardware_lock);
415162306a36Sopenharmony_ci	/* BIT 10 - set */
415262306a36Sopenharmony_ci	qla4_82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0x0400);
415362306a36Sopenharmony_ci	spin_unlock_irq(&ha->hardware_lock);
415462306a36Sopenharmony_ci}
415562306a36Sopenharmony_ci
415662306a36Sopenharmony_ciint
415762306a36Sopenharmony_ciqla4_8xxx_enable_msix(struct scsi_qla_host *ha)
415862306a36Sopenharmony_ci{
415962306a36Sopenharmony_ci	int ret;
416062306a36Sopenharmony_ci
416162306a36Sopenharmony_ci	ret = pci_alloc_irq_vectors(ha->pdev, QLA_MSIX_ENTRIES,
416262306a36Sopenharmony_ci			QLA_MSIX_ENTRIES, PCI_IRQ_MSIX);
416362306a36Sopenharmony_ci	if (ret < 0) {
416462306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha,
416562306a36Sopenharmony_ci		    "MSI-X: Failed to enable support -- %d/%d\n",
416662306a36Sopenharmony_ci		    QLA_MSIX_ENTRIES, ret);
416762306a36Sopenharmony_ci		return ret;
416862306a36Sopenharmony_ci	}
416962306a36Sopenharmony_ci
417062306a36Sopenharmony_ci	ret = request_irq(pci_irq_vector(ha->pdev, 0),
417162306a36Sopenharmony_ci			qla4_8xxx_default_intr_handler, 0, "qla4xxx (default)",
417262306a36Sopenharmony_ci			ha);
417362306a36Sopenharmony_ci	if (ret)
417462306a36Sopenharmony_ci		goto out_free_vectors;
417562306a36Sopenharmony_ci
417662306a36Sopenharmony_ci	ret = request_irq(pci_irq_vector(ha->pdev, 1),
417762306a36Sopenharmony_ci			qla4_8xxx_msix_rsp_q, 0, "qla4xxx (rsp_q)", ha);
417862306a36Sopenharmony_ci	if (ret)
417962306a36Sopenharmony_ci		goto out_free_default_irq;
418062306a36Sopenharmony_ci
418162306a36Sopenharmony_ci	return 0;
418262306a36Sopenharmony_ci
418362306a36Sopenharmony_ciout_free_default_irq:
418462306a36Sopenharmony_ci	free_irq(pci_irq_vector(ha->pdev, 0), ha);
418562306a36Sopenharmony_ciout_free_vectors:
418662306a36Sopenharmony_ci	pci_free_irq_vectors(ha->pdev);
418762306a36Sopenharmony_ci	return ret;
418862306a36Sopenharmony_ci}
418962306a36Sopenharmony_ci
419062306a36Sopenharmony_ciint qla4_8xxx_check_init_adapter_retry(struct scsi_qla_host *ha)
419162306a36Sopenharmony_ci{
419262306a36Sopenharmony_ci	int status = QLA_SUCCESS;
419362306a36Sopenharmony_ci
419462306a36Sopenharmony_ci	/* Dont retry adapter initialization if IRQ allocation failed */
419562306a36Sopenharmony_ci	if (!test_bit(AF_IRQ_ATTACHED, &ha->flags)) {
419662306a36Sopenharmony_ci		ql4_printk(KERN_WARNING, ha, "%s: Skipping retry of adapter initialization as IRQs are not attached\n",
419762306a36Sopenharmony_ci			   __func__);
419862306a36Sopenharmony_ci		status = QLA_ERROR;
419962306a36Sopenharmony_ci		goto exit_init_adapter_failure;
420062306a36Sopenharmony_ci	}
420162306a36Sopenharmony_ci
420262306a36Sopenharmony_ci	/* Since interrupts are registered in start_firmware for
420362306a36Sopenharmony_ci	 * 8xxx, release them here if initialize_adapter fails
420462306a36Sopenharmony_ci	 * and retry adapter initialization */
420562306a36Sopenharmony_ci	qla4xxx_free_irqs(ha);
420662306a36Sopenharmony_ci
420762306a36Sopenharmony_ciexit_init_adapter_failure:
420862306a36Sopenharmony_ci	return status;
420962306a36Sopenharmony_ci}
4210