162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * QLogic Fibre Channel HBA Driver
462306a36Sopenharmony_ci * Copyright (c)  2003-2014 QLogic Corporation
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#include "qla_def.h"
762306a36Sopenharmony_ci#include <linux/delay.h>
862306a36Sopenharmony_ci#include <linux/io-64-nonatomic-lo-hi.h>
962306a36Sopenharmony_ci#include <linux/pci.h>
1062306a36Sopenharmony_ci#include <linux/ratelimit.h>
1162306a36Sopenharmony_ci#include <linux/vmalloc.h>
1262306a36Sopenharmony_ci#include <scsi/scsi_tcq.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#define MASK(n)			((1ULL<<(n))-1)
1562306a36Sopenharmony_ci#define MN_WIN(addr) (((addr & 0x1fc0000) >> 1) | \
1662306a36Sopenharmony_ci	((addr >> 25) & 0x3ff))
1762306a36Sopenharmony_ci#define OCM_WIN(addr) (((addr & 0x1ff0000) >> 1) | \
1862306a36Sopenharmony_ci	((addr >> 25) & 0x3ff))
1962306a36Sopenharmony_ci#define MS_WIN(addr) (addr & 0x0ffc0000)
2062306a36Sopenharmony_ci#define QLA82XX_PCI_MN_2M   (0)
2162306a36Sopenharmony_ci#define QLA82XX_PCI_MS_2M   (0x80000)
2262306a36Sopenharmony_ci#define QLA82XX_PCI_OCM0_2M (0xc0000)
2362306a36Sopenharmony_ci#define VALID_OCM_ADDR(addr) (((addr) & 0x3f800) != 0x3f800)
2462306a36Sopenharmony_ci#define GET_MEM_OFFS_2M(addr) (addr & MASK(18))
2562306a36Sopenharmony_ci#define BLOCK_PROTECT_BITS 0x0F
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 QLA82XX_PCI_CAMQM_2M_END	(0x04800800UL)
3262306a36Sopenharmony_ci#define CRB_HI(off)	((qla82xx_crb_hub_agt[CRB_BLK(off)] << 20) | \
3362306a36Sopenharmony_ci			((off) & 0xf0000))
3462306a36Sopenharmony_ci#define QLA82XX_PCI_CAMQM_2M_BASE	(0x000ff800UL)
3562306a36Sopenharmony_ci#define CRB_INDIRECT_2M	(0x1e0000UL)
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci#define MAX_CRB_XFORM 60
3862306a36Sopenharmony_cistatic unsigned long crb_addr_xform[MAX_CRB_XFORM];
3962306a36Sopenharmony_cistatic int qla82xx_crb_table_initialized;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci#define qla82xx_crb_addr_transform(name) \
4262306a36Sopenharmony_ci	(crb_addr_xform[QLA82XX_HW_PX_MAP_CRB_##name] = \
4362306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_##name << 20)
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ciconst int MD_MIU_TEST_AGT_RDDATA[] = {
4662306a36Sopenharmony_ci	0x410000A8, 0x410000AC,
4762306a36Sopenharmony_ci	0x410000B8, 0x410000BC
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic void qla82xx_crb_addr_transform_setup(void)
5162306a36Sopenharmony_ci{
5262306a36Sopenharmony_ci	qla82xx_crb_addr_transform(XDMA);
5362306a36Sopenharmony_ci	qla82xx_crb_addr_transform(TIMR);
5462306a36Sopenharmony_ci	qla82xx_crb_addr_transform(SRE);
5562306a36Sopenharmony_ci	qla82xx_crb_addr_transform(SQN3);
5662306a36Sopenharmony_ci	qla82xx_crb_addr_transform(SQN2);
5762306a36Sopenharmony_ci	qla82xx_crb_addr_transform(SQN1);
5862306a36Sopenharmony_ci	qla82xx_crb_addr_transform(SQN0);
5962306a36Sopenharmony_ci	qla82xx_crb_addr_transform(SQS3);
6062306a36Sopenharmony_ci	qla82xx_crb_addr_transform(SQS2);
6162306a36Sopenharmony_ci	qla82xx_crb_addr_transform(SQS1);
6262306a36Sopenharmony_ci	qla82xx_crb_addr_transform(SQS0);
6362306a36Sopenharmony_ci	qla82xx_crb_addr_transform(RPMX7);
6462306a36Sopenharmony_ci	qla82xx_crb_addr_transform(RPMX6);
6562306a36Sopenharmony_ci	qla82xx_crb_addr_transform(RPMX5);
6662306a36Sopenharmony_ci	qla82xx_crb_addr_transform(RPMX4);
6762306a36Sopenharmony_ci	qla82xx_crb_addr_transform(RPMX3);
6862306a36Sopenharmony_ci	qla82xx_crb_addr_transform(RPMX2);
6962306a36Sopenharmony_ci	qla82xx_crb_addr_transform(RPMX1);
7062306a36Sopenharmony_ci	qla82xx_crb_addr_transform(RPMX0);
7162306a36Sopenharmony_ci	qla82xx_crb_addr_transform(ROMUSB);
7262306a36Sopenharmony_ci	qla82xx_crb_addr_transform(SN);
7362306a36Sopenharmony_ci	qla82xx_crb_addr_transform(QMN);
7462306a36Sopenharmony_ci	qla82xx_crb_addr_transform(QMS);
7562306a36Sopenharmony_ci	qla82xx_crb_addr_transform(PGNI);
7662306a36Sopenharmony_ci	qla82xx_crb_addr_transform(PGND);
7762306a36Sopenharmony_ci	qla82xx_crb_addr_transform(PGN3);
7862306a36Sopenharmony_ci	qla82xx_crb_addr_transform(PGN2);
7962306a36Sopenharmony_ci	qla82xx_crb_addr_transform(PGN1);
8062306a36Sopenharmony_ci	qla82xx_crb_addr_transform(PGN0);
8162306a36Sopenharmony_ci	qla82xx_crb_addr_transform(PGSI);
8262306a36Sopenharmony_ci	qla82xx_crb_addr_transform(PGSD);
8362306a36Sopenharmony_ci	qla82xx_crb_addr_transform(PGS3);
8462306a36Sopenharmony_ci	qla82xx_crb_addr_transform(PGS2);
8562306a36Sopenharmony_ci	qla82xx_crb_addr_transform(PGS1);
8662306a36Sopenharmony_ci	qla82xx_crb_addr_transform(PGS0);
8762306a36Sopenharmony_ci	qla82xx_crb_addr_transform(PS);
8862306a36Sopenharmony_ci	qla82xx_crb_addr_transform(PH);
8962306a36Sopenharmony_ci	qla82xx_crb_addr_transform(NIU);
9062306a36Sopenharmony_ci	qla82xx_crb_addr_transform(I2Q);
9162306a36Sopenharmony_ci	qla82xx_crb_addr_transform(EG);
9262306a36Sopenharmony_ci	qla82xx_crb_addr_transform(MN);
9362306a36Sopenharmony_ci	qla82xx_crb_addr_transform(MS);
9462306a36Sopenharmony_ci	qla82xx_crb_addr_transform(CAS2);
9562306a36Sopenharmony_ci	qla82xx_crb_addr_transform(CAS1);
9662306a36Sopenharmony_ci	qla82xx_crb_addr_transform(CAS0);
9762306a36Sopenharmony_ci	qla82xx_crb_addr_transform(CAM);
9862306a36Sopenharmony_ci	qla82xx_crb_addr_transform(C2C1);
9962306a36Sopenharmony_ci	qla82xx_crb_addr_transform(C2C0);
10062306a36Sopenharmony_ci	qla82xx_crb_addr_transform(SMB);
10162306a36Sopenharmony_ci	qla82xx_crb_addr_transform(OCM0);
10262306a36Sopenharmony_ci	/*
10362306a36Sopenharmony_ci	 * Used only in P3 just define it for P2 also.
10462306a36Sopenharmony_ci	 */
10562306a36Sopenharmony_ci	qla82xx_crb_addr_transform(I2C0);
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	qla82xx_crb_table_initialized = 1;
10862306a36Sopenharmony_ci}
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_cistatic struct crb_128M_2M_block_map crb_128M_2M_map[64] = {
11162306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },
11262306a36Sopenharmony_ci	{{{1, 0x0100000, 0x0102000, 0x120000},
11362306a36Sopenharmony_ci	{1, 0x0110000, 0x0120000, 0x130000},
11462306a36Sopenharmony_ci	{1, 0x0120000, 0x0122000, 0x124000},
11562306a36Sopenharmony_ci	{1, 0x0130000, 0x0132000, 0x126000},
11662306a36Sopenharmony_ci	{1, 0x0140000, 0x0142000, 0x128000},
11762306a36Sopenharmony_ci	{1, 0x0150000, 0x0152000, 0x12a000},
11862306a36Sopenharmony_ci	{1, 0x0160000, 0x0170000, 0x110000},
11962306a36Sopenharmony_ci	{1, 0x0170000, 0x0172000, 0x12e000},
12062306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
12162306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
12262306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
12362306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
12462306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
12562306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
12662306a36Sopenharmony_ci	{1, 0x01e0000, 0x01e0800, 0x122000},
12762306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000} } } ,
12862306a36Sopenharmony_ci	{{{1, 0x0200000, 0x0210000, 0x180000} } },
12962306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },
13062306a36Sopenharmony_ci	{{{1, 0x0400000, 0x0401000, 0x169000} } },
13162306a36Sopenharmony_ci	{{{1, 0x0500000, 0x0510000, 0x140000} } },
13262306a36Sopenharmony_ci	{{{1, 0x0600000, 0x0610000, 0x1c0000} } },
13362306a36Sopenharmony_ci	{{{1, 0x0700000, 0x0704000, 0x1b8000} } },
13462306a36Sopenharmony_ci	{{{1, 0x0800000, 0x0802000, 0x170000},
13562306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
13662306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
13762306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
13862306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
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	{1, 0x08f0000, 0x08f2000, 0x172000} } },
15062306a36Sopenharmony_ci	{{{1, 0x0900000, 0x0902000, 0x174000},
15162306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
15262306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
15362306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
15462306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
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	{1, 0x09f0000, 0x09f2000, 0x176000} } },
16662306a36Sopenharmony_ci	{{{0, 0x0a00000, 0x0a02000, 0x178000},
16762306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
16862306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
16962306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
17062306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
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	{1, 0x0af0000, 0x0af2000, 0x17a000} } },
18262306a36Sopenharmony_ci	{{{0, 0x0b00000, 0x0b02000, 0x17c000},
18362306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
18462306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
18562306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
18662306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
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	{1, 0x0bf0000, 0x0bf2000, 0x17e000} } },
19862306a36Sopenharmony_ci	{{{1, 0x0c00000, 0x0c04000, 0x1d4000} } },
19962306a36Sopenharmony_ci	{{{1, 0x0d00000, 0x0d04000, 0x1a4000} } },
20062306a36Sopenharmony_ci	{{{1, 0x0e00000, 0x0e04000, 0x1a0000} } },
20162306a36Sopenharmony_ci	{{{1, 0x0f00000, 0x0f01000, 0x164000} } },
20262306a36Sopenharmony_ci	{{{0, 0x1000000, 0x1004000, 0x1a8000} } },
20362306a36Sopenharmony_ci	{{{1, 0x1100000, 0x1101000, 0x160000} } },
20462306a36Sopenharmony_ci	{{{1, 0x1200000, 0x1201000, 0x161000} } },
20562306a36Sopenharmony_ci	{{{1, 0x1300000, 0x1301000, 0x162000} } },
20662306a36Sopenharmony_ci	{{{1, 0x1400000, 0x1401000, 0x163000} } },
20762306a36Sopenharmony_ci	{{{1, 0x1500000, 0x1501000, 0x165000} } },
20862306a36Sopenharmony_ci	{{{1, 0x1600000, 0x1601000, 0x166000} } },
20962306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },
21062306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },
21162306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },
21262306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },
21362306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },
21462306a36Sopenharmony_ci	{{{0, 0,         0,         0} } },
21562306a36Sopenharmony_ci	{{{1, 0x1d00000, 0x1d10000, 0x190000} } },
21662306a36Sopenharmony_ci	{{{1, 0x1e00000, 0x1e01000, 0x16a000} } },
21762306a36Sopenharmony_ci	{{{1, 0x1f00000, 0x1f10000, 0x150000} } },
21862306a36Sopenharmony_ci	{{{0} } },
21962306a36Sopenharmony_ci	{{{1, 0x2100000, 0x2102000, 0x120000},
22062306a36Sopenharmony_ci	{1, 0x2110000, 0x2120000, 0x130000},
22162306a36Sopenharmony_ci	{1, 0x2120000, 0x2122000, 0x124000},
22262306a36Sopenharmony_ci	{1, 0x2130000, 0x2132000, 0x126000},
22362306a36Sopenharmony_ci	{1, 0x2140000, 0x2142000, 0x128000},
22462306a36Sopenharmony_ci	{1, 0x2150000, 0x2152000, 0x12a000},
22562306a36Sopenharmony_ci	{1, 0x2160000, 0x2170000, 0x110000},
22662306a36Sopenharmony_ci	{1, 0x2170000, 0x2172000, 0x12e000},
22762306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
22862306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
22962306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
23062306a36Sopenharmony_ci	{0, 0x0000000, 0x0000000, 0x000000},
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	{{{1, 0x2200000, 0x2204000, 0x1b0000} } },
23662306a36Sopenharmony_ci	{{{0} } },
23762306a36Sopenharmony_ci	{{{0} } },
23862306a36Sopenharmony_ci	{{{0} } },
23962306a36Sopenharmony_ci	{{{0} } },
24062306a36Sopenharmony_ci	{{{0} } },
24162306a36Sopenharmony_ci	{{{1, 0x2800000, 0x2804000, 0x1a4000} } },
24262306a36Sopenharmony_ci	{{{1, 0x2900000, 0x2901000, 0x16b000} } },
24362306a36Sopenharmony_ci	{{{1, 0x2a00000, 0x2a00400, 0x1ac400} } },
24462306a36Sopenharmony_ci	{{{1, 0x2b00000, 0x2b00400, 0x1ac800} } },
24562306a36Sopenharmony_ci	{{{1, 0x2c00000, 0x2c00400, 0x1acc00} } },
24662306a36Sopenharmony_ci	{{{1, 0x2d00000, 0x2d00400, 0x1ad000} } },
24762306a36Sopenharmony_ci	{{{1, 0x2e00000, 0x2e00400, 0x1ad400} } },
24862306a36Sopenharmony_ci	{{{1, 0x2f00000, 0x2f00400, 0x1ad800} } },
24962306a36Sopenharmony_ci	{{{1, 0x3000000, 0x3000400, 0x1adc00} } },
25062306a36Sopenharmony_ci	{{{0, 0x3100000, 0x3104000, 0x1a8000} } },
25162306a36Sopenharmony_ci	{{{1, 0x3200000, 0x3204000, 0x1d4000} } },
25262306a36Sopenharmony_ci	{{{1, 0x3300000, 0x3304000, 0x1a0000} } },
25362306a36Sopenharmony_ci	{{{0} } },
25462306a36Sopenharmony_ci	{{{1, 0x3500000, 0x3500400, 0x1ac000} } },
25562306a36Sopenharmony_ci	{{{1, 0x3600000, 0x3600400, 0x1ae000} } },
25662306a36Sopenharmony_ci	{{{1, 0x3700000, 0x3700400, 0x1ae400} } },
25762306a36Sopenharmony_ci	{{{1, 0x3800000, 0x3804000, 0x1d0000} } },
25862306a36Sopenharmony_ci	{{{1, 0x3900000, 0x3904000, 0x1b4000} } },
25962306a36Sopenharmony_ci	{{{1, 0x3a00000, 0x3a04000, 0x1d8000} } },
26062306a36Sopenharmony_ci	{{{0} } },
26162306a36Sopenharmony_ci	{{{0} } },
26262306a36Sopenharmony_ci	{{{1, 0x3d00000, 0x3d04000, 0x1dc000} } },
26362306a36Sopenharmony_ci	{{{1, 0x3e00000, 0x3e01000, 0x167000} } },
26462306a36Sopenharmony_ci	{{{1, 0x3f00000, 0x3f01000, 0x168000} } }
26562306a36Sopenharmony_ci};
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci/*
26862306a36Sopenharmony_ci * top 12 bits of crb internal address (hub, agent)
26962306a36Sopenharmony_ci */
27062306a36Sopenharmony_cistatic unsigned qla82xx_crb_hub_agt[64] = {
27162306a36Sopenharmony_ci	0,
27262306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PS,
27362306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_MN,
27462306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_MS,
27562306a36Sopenharmony_ci	0,
27662306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_SRE,
27762306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_NIU,
27862306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_QMN,
27962306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_SQN0,
28062306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_SQN1,
28162306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_SQN2,
28262306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_SQN3,
28362306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q,
28462306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR,
28562306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB,
28662306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGN4,
28762306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA,
28862306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGN0,
28962306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGN1,
29062306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGN2,
29162306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGN3,
29262306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGND,
29362306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGNI,
29462306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGS0,
29562306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGS1,
29662306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGS2,
29762306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGS3,
29862306a36Sopenharmony_ci	0,
29962306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGSI,
30062306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_SN,
30162306a36Sopenharmony_ci	0,
30262306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_EG,
30362306a36Sopenharmony_ci	0,
30462306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PS,
30562306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_CAM,
30662306a36Sopenharmony_ci	0,
30762306a36Sopenharmony_ci	0,
30862306a36Sopenharmony_ci	0,
30962306a36Sopenharmony_ci	0,
31062306a36Sopenharmony_ci	0,
31162306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_TIMR,
31262306a36Sopenharmony_ci	0,
31362306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX1,
31462306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX2,
31562306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX3,
31662306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX4,
31762306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX5,
31862306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX6,
31962306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX7,
32062306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_XDMA,
32162306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_I2Q,
32262306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_ROMUSB,
32362306a36Sopenharmony_ci	0,
32462306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX0,
32562306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX8,
32662306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_RPMX9,
32762306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_OCM0,
32862306a36Sopenharmony_ci	0,
32962306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_SMB,
33062306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_I2C0,
33162306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_I2C1,
33262306a36Sopenharmony_ci	0,
33362306a36Sopenharmony_ci	QLA82XX_HW_CRB_HUB_AGT_ADR_PGNC,
33462306a36Sopenharmony_ci	0,
33562306a36Sopenharmony_ci};
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci/* Device states */
33862306a36Sopenharmony_cistatic const char *const q_dev_state[] = {
33962306a36Sopenharmony_ci	[QLA8XXX_DEV_UNKNOWN]		= "Unknown",
34062306a36Sopenharmony_ci	[QLA8XXX_DEV_COLD]		= "Cold/Re-init",
34162306a36Sopenharmony_ci	[QLA8XXX_DEV_INITIALIZING]	= "Initializing",
34262306a36Sopenharmony_ci	[QLA8XXX_DEV_READY]		= "Ready",
34362306a36Sopenharmony_ci	[QLA8XXX_DEV_NEED_RESET]	= "Need Reset",
34462306a36Sopenharmony_ci	[QLA8XXX_DEV_NEED_QUIESCENT]	= "Need Quiescent",
34562306a36Sopenharmony_ci	[QLA8XXX_DEV_FAILED]		= "Failed",
34662306a36Sopenharmony_ci	[QLA8XXX_DEV_QUIESCENT]		= "Quiescent",
34762306a36Sopenharmony_ci};
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ciconst char *qdev_state(uint32_t dev_state)
35062306a36Sopenharmony_ci{
35162306a36Sopenharmony_ci	return (dev_state < MAX_STATES) ? q_dev_state[dev_state] : "Unknown";
35262306a36Sopenharmony_ci}
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci/*
35562306a36Sopenharmony_ci * In: 'off_in' is offset from CRB space in 128M pci map
35662306a36Sopenharmony_ci * Out: 'off_out' is 2M pci map addr
35762306a36Sopenharmony_ci * side effect: lock crb window
35862306a36Sopenharmony_ci */
35962306a36Sopenharmony_cistatic void
36062306a36Sopenharmony_ciqla82xx_pci_set_crbwindow_2M(struct qla_hw_data *ha, ulong off_in,
36162306a36Sopenharmony_ci			     void __iomem **off_out)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	u32 win_read;
36462306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	ha->crb_win = CRB_HI(off_in);
36762306a36Sopenharmony_ci	writel(ha->crb_win, CRB_WINDOW_2M + ha->nx_pcibase);
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	/* Read back value to make sure write has gone through before trying
37062306a36Sopenharmony_ci	 * to use it.
37162306a36Sopenharmony_ci	 */
37262306a36Sopenharmony_ci	win_read = rd_reg_dword(CRB_WINDOW_2M + ha->nx_pcibase);
37362306a36Sopenharmony_ci	if (win_read != ha->crb_win) {
37462306a36Sopenharmony_ci		ql_dbg(ql_dbg_p3p, vha, 0xb000,
37562306a36Sopenharmony_ci		    "%s: Written crbwin (0x%x) "
37662306a36Sopenharmony_ci		    "!= Read crbwin (0x%x), off=0x%lx.\n",
37762306a36Sopenharmony_ci		    __func__, ha->crb_win, win_read, off_in);
37862306a36Sopenharmony_ci	}
37962306a36Sopenharmony_ci	*off_out = (off_in & MASK(16)) + CRB_INDIRECT_2M + ha->nx_pcibase;
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic int
38362306a36Sopenharmony_ciqla82xx_pci_get_crb_addr_2M(struct qla_hw_data *ha, ulong off_in,
38462306a36Sopenharmony_ci			    void __iomem **off_out)
38562306a36Sopenharmony_ci{
38662306a36Sopenharmony_ci	struct crb_128M_2M_sub_block_map *m;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	if (off_in >= QLA82XX_CRB_MAX)
38962306a36Sopenharmony_ci		return -1;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	if (off_in >= QLA82XX_PCI_CAMQM && off_in < QLA82XX_PCI_CAMQM_2M_END) {
39262306a36Sopenharmony_ci		*off_out = (off_in - QLA82XX_PCI_CAMQM) +
39362306a36Sopenharmony_ci		    QLA82XX_PCI_CAMQM_2M_BASE + ha->nx_pcibase;
39462306a36Sopenharmony_ci		return 0;
39562306a36Sopenharmony_ci	}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	if (off_in < QLA82XX_PCI_CRBSPACE)
39862306a36Sopenharmony_ci		return -1;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	off_in -= QLA82XX_PCI_CRBSPACE;
40162306a36Sopenharmony_ci
40262306a36Sopenharmony_ci	/* Try direct map */
40362306a36Sopenharmony_ci	m = &crb_128M_2M_map[CRB_BLK(off_in)].sub_block[CRB_SUBBLK(off_in)];
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	if (m->valid && (m->start_128M <= off_in) && (m->end_128M > off_in)) {
40662306a36Sopenharmony_ci		*off_out = off_in + m->start_2M - m->start_128M + ha->nx_pcibase;
40762306a36Sopenharmony_ci		return 0;
40862306a36Sopenharmony_ci	}
40962306a36Sopenharmony_ci	/* Not in direct map, use crb window */
41062306a36Sopenharmony_ci	*off_out = (void __iomem *)off_in;
41162306a36Sopenharmony_ci	return 1;
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci#define CRB_WIN_LOCK_TIMEOUT 100000000
41562306a36Sopenharmony_cistatic int qla82xx_crb_win_lock(struct qla_hw_data *ha)
41662306a36Sopenharmony_ci{
41762306a36Sopenharmony_ci	int done = 0, timeout = 0;
41862306a36Sopenharmony_ci
41962306a36Sopenharmony_ci	while (!done) {
42062306a36Sopenharmony_ci		/* acquire semaphore3 from PCI HW block */
42162306a36Sopenharmony_ci		done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_LOCK));
42262306a36Sopenharmony_ci		if (done == 1)
42362306a36Sopenharmony_ci			break;
42462306a36Sopenharmony_ci		if (timeout >= CRB_WIN_LOCK_TIMEOUT)
42562306a36Sopenharmony_ci			return -1;
42662306a36Sopenharmony_ci		timeout++;
42762306a36Sopenharmony_ci	}
42862306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_WIN_LOCK_ID, ha->portnum);
42962306a36Sopenharmony_ci	return 0;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ciint
43362306a36Sopenharmony_ciqla82xx_wr_32(struct qla_hw_data *ha, ulong off_in, u32 data)
43462306a36Sopenharmony_ci{
43562306a36Sopenharmony_ci	void __iomem *off;
43662306a36Sopenharmony_ci	unsigned long flags = 0;
43762306a36Sopenharmony_ci	int rv;
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	rv = qla82xx_pci_get_crb_addr_2M(ha, off_in, &off);
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_ci	BUG_ON(rv == -1);
44262306a36Sopenharmony_ci
44362306a36Sopenharmony_ci	if (rv == 1) {
44462306a36Sopenharmony_ci#ifndef __CHECKER__
44562306a36Sopenharmony_ci		write_lock_irqsave(&ha->hw_lock, flags);
44662306a36Sopenharmony_ci#endif
44762306a36Sopenharmony_ci		qla82xx_crb_win_lock(ha);
44862306a36Sopenharmony_ci		qla82xx_pci_set_crbwindow_2M(ha, off_in, &off);
44962306a36Sopenharmony_ci	}
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	writel(data, (void __iomem *)off);
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	if (rv == 1) {
45462306a36Sopenharmony_ci		qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK));
45562306a36Sopenharmony_ci#ifndef __CHECKER__
45662306a36Sopenharmony_ci		write_unlock_irqrestore(&ha->hw_lock, flags);
45762306a36Sopenharmony_ci#endif
45862306a36Sopenharmony_ci	}
45962306a36Sopenharmony_ci	return 0;
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ciint
46362306a36Sopenharmony_ciqla82xx_rd_32(struct qla_hw_data *ha, ulong off_in)
46462306a36Sopenharmony_ci{
46562306a36Sopenharmony_ci	void __iomem *off;
46662306a36Sopenharmony_ci	unsigned long flags = 0;
46762306a36Sopenharmony_ci	int rv;
46862306a36Sopenharmony_ci	u32 data;
46962306a36Sopenharmony_ci
47062306a36Sopenharmony_ci	rv = qla82xx_pci_get_crb_addr_2M(ha, off_in, &off);
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	BUG_ON(rv == -1);
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	if (rv == 1) {
47562306a36Sopenharmony_ci#ifndef __CHECKER__
47662306a36Sopenharmony_ci		write_lock_irqsave(&ha->hw_lock, flags);
47762306a36Sopenharmony_ci#endif
47862306a36Sopenharmony_ci		qla82xx_crb_win_lock(ha);
47962306a36Sopenharmony_ci		qla82xx_pci_set_crbwindow_2M(ha, off_in, &off);
48062306a36Sopenharmony_ci	}
48162306a36Sopenharmony_ci	data = rd_reg_dword(off);
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	if (rv == 1) {
48462306a36Sopenharmony_ci		qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM7_UNLOCK));
48562306a36Sopenharmony_ci#ifndef __CHECKER__
48662306a36Sopenharmony_ci		write_unlock_irqrestore(&ha->hw_lock, flags);
48762306a36Sopenharmony_ci#endif
48862306a36Sopenharmony_ci	}
48962306a36Sopenharmony_ci	return data;
49062306a36Sopenharmony_ci}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci/*
49362306a36Sopenharmony_ci * Context: task, might sleep
49462306a36Sopenharmony_ci */
49562306a36Sopenharmony_ciint qla82xx_idc_lock(struct qla_hw_data *ha)
49662306a36Sopenharmony_ci{
49762306a36Sopenharmony_ci	const int delay_ms = 100, timeout_ms = 2000;
49862306a36Sopenharmony_ci	int done, total = 0;
49962306a36Sopenharmony_ci
50062306a36Sopenharmony_ci	might_sleep();
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	while (true) {
50362306a36Sopenharmony_ci		/* acquire semaphore5 from PCI HW block */
50462306a36Sopenharmony_ci		done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_LOCK));
50562306a36Sopenharmony_ci		if (done == 1)
50662306a36Sopenharmony_ci			break;
50762306a36Sopenharmony_ci		if (WARN_ON_ONCE(total >= timeout_ms))
50862306a36Sopenharmony_ci			return -1;
50962306a36Sopenharmony_ci
51062306a36Sopenharmony_ci		total += delay_ms;
51162306a36Sopenharmony_ci		msleep(delay_ms);
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	return 0;
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_civoid qla82xx_idc_unlock(struct qla_hw_data *ha)
51862306a36Sopenharmony_ci{
51962306a36Sopenharmony_ci	qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM5_UNLOCK));
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci/*
52362306a36Sopenharmony_ci * check memory access boundary.
52462306a36Sopenharmony_ci * used by test agent. support ddr access only for now
52562306a36Sopenharmony_ci */
52662306a36Sopenharmony_cistatic unsigned long
52762306a36Sopenharmony_ciqla82xx_pci_mem_bound_check(struct qla_hw_data *ha,
52862306a36Sopenharmony_ci	unsigned long long addr, int size)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	if (!addr_in_range(addr, QLA82XX_ADDR_DDR_NET,
53162306a36Sopenharmony_ci		QLA82XX_ADDR_DDR_NET_MAX) ||
53262306a36Sopenharmony_ci		!addr_in_range(addr + size - 1, QLA82XX_ADDR_DDR_NET,
53362306a36Sopenharmony_ci		QLA82XX_ADDR_DDR_NET_MAX) ||
53462306a36Sopenharmony_ci		((size != 1) && (size != 2) && (size != 4) && (size != 8)))
53562306a36Sopenharmony_ci			return 0;
53662306a36Sopenharmony_ci	else
53762306a36Sopenharmony_ci		return 1;
53862306a36Sopenharmony_ci}
53962306a36Sopenharmony_ci
54062306a36Sopenharmony_cistatic int qla82xx_pci_set_window_warning_count;
54162306a36Sopenharmony_ci
54262306a36Sopenharmony_cistatic unsigned long
54362306a36Sopenharmony_ciqla82xx_pci_set_window(struct qla_hw_data *ha, unsigned long long addr)
54462306a36Sopenharmony_ci{
54562306a36Sopenharmony_ci	int window;
54662306a36Sopenharmony_ci	u32 win_read;
54762306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
54862306a36Sopenharmony_ci
54962306a36Sopenharmony_ci	if (addr_in_range(addr, QLA82XX_ADDR_DDR_NET,
55062306a36Sopenharmony_ci		QLA82XX_ADDR_DDR_NET_MAX)) {
55162306a36Sopenharmony_ci		/* DDR network side */
55262306a36Sopenharmony_ci		window = MN_WIN(addr);
55362306a36Sopenharmony_ci		ha->ddr_mn_window = window;
55462306a36Sopenharmony_ci		qla82xx_wr_32(ha,
55562306a36Sopenharmony_ci			ha->mn_win_crb | QLA82XX_PCI_CRBSPACE, window);
55662306a36Sopenharmony_ci		win_read = qla82xx_rd_32(ha,
55762306a36Sopenharmony_ci			ha->mn_win_crb | QLA82XX_PCI_CRBSPACE);
55862306a36Sopenharmony_ci		if ((win_read << 17) != window) {
55962306a36Sopenharmony_ci			ql_dbg(ql_dbg_p3p, vha, 0xb003,
56062306a36Sopenharmony_ci			    "%s: Written MNwin (0x%x) != Read MNwin (0x%x).\n",
56162306a36Sopenharmony_ci			    __func__, window, win_read);
56262306a36Sopenharmony_ci		}
56362306a36Sopenharmony_ci		addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_DDR_NET;
56462306a36Sopenharmony_ci	} else if (addr_in_range(addr, QLA82XX_ADDR_OCM0,
56562306a36Sopenharmony_ci		QLA82XX_ADDR_OCM0_MAX)) {
56662306a36Sopenharmony_ci		unsigned int temp1;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci		if ((addr & 0x00ff800) == 0xff800) {
56962306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb004,
57062306a36Sopenharmony_ci			    "%s: QM access not handled.\n", __func__);
57162306a36Sopenharmony_ci			addr = -1UL;
57262306a36Sopenharmony_ci		}
57362306a36Sopenharmony_ci		window = OCM_WIN(addr);
57462306a36Sopenharmony_ci		ha->ddr_mn_window = window;
57562306a36Sopenharmony_ci		qla82xx_wr_32(ha,
57662306a36Sopenharmony_ci			ha->mn_win_crb | QLA82XX_PCI_CRBSPACE, window);
57762306a36Sopenharmony_ci		win_read = qla82xx_rd_32(ha,
57862306a36Sopenharmony_ci			ha->mn_win_crb | QLA82XX_PCI_CRBSPACE);
57962306a36Sopenharmony_ci		temp1 = ((window & 0x1FF) << 7) |
58062306a36Sopenharmony_ci		    ((window & 0x0FFFE0000) >> 17);
58162306a36Sopenharmony_ci		if (win_read != temp1) {
58262306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb005,
58362306a36Sopenharmony_ci			    "%s: Written OCMwin (0x%x) != Read OCMwin (0x%x).\n",
58462306a36Sopenharmony_ci			    __func__, temp1, win_read);
58562306a36Sopenharmony_ci		}
58662306a36Sopenharmony_ci		addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_OCM0_2M;
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	} else if (addr_in_range(addr, QLA82XX_ADDR_QDR_NET,
58962306a36Sopenharmony_ci		QLA82XX_P3_ADDR_QDR_NET_MAX)) {
59062306a36Sopenharmony_ci		/* QDR network side */
59162306a36Sopenharmony_ci		window = MS_WIN(addr);
59262306a36Sopenharmony_ci		ha->qdr_sn_window = window;
59362306a36Sopenharmony_ci		qla82xx_wr_32(ha,
59462306a36Sopenharmony_ci			ha->ms_win_crb | QLA82XX_PCI_CRBSPACE, window);
59562306a36Sopenharmony_ci		win_read = qla82xx_rd_32(ha,
59662306a36Sopenharmony_ci			ha->ms_win_crb | QLA82XX_PCI_CRBSPACE);
59762306a36Sopenharmony_ci		if (win_read != window) {
59862306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb006,
59962306a36Sopenharmony_ci			    "%s: Written MSwin (0x%x) != Read MSwin (0x%x).\n",
60062306a36Sopenharmony_ci			    __func__, window, win_read);
60162306a36Sopenharmony_ci		}
60262306a36Sopenharmony_ci		addr = GET_MEM_OFFS_2M(addr) + QLA82XX_PCI_QDR_NET;
60362306a36Sopenharmony_ci	} else {
60462306a36Sopenharmony_ci		/*
60562306a36Sopenharmony_ci		 * peg gdb frequently accesses memory that doesn't exist,
60662306a36Sopenharmony_ci		 * this limits the chit chat so debugging isn't slowed down.
60762306a36Sopenharmony_ci		 */
60862306a36Sopenharmony_ci		if ((qla82xx_pci_set_window_warning_count++ < 8) ||
60962306a36Sopenharmony_ci		    (qla82xx_pci_set_window_warning_count%64 == 0)) {
61062306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb007,
61162306a36Sopenharmony_ci			    "%s: Warning:%s Unknown address range!.\n",
61262306a36Sopenharmony_ci			    __func__, QLA2XXX_DRIVER_NAME);
61362306a36Sopenharmony_ci		}
61462306a36Sopenharmony_ci		addr = -1UL;
61562306a36Sopenharmony_ci	}
61662306a36Sopenharmony_ci	return addr;
61762306a36Sopenharmony_ci}
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci/* check if address is in the same windows as the previous access */
62062306a36Sopenharmony_cistatic int qla82xx_pci_is_same_window(struct qla_hw_data *ha,
62162306a36Sopenharmony_ci	unsigned long long addr)
62262306a36Sopenharmony_ci{
62362306a36Sopenharmony_ci	int			window;
62462306a36Sopenharmony_ci	unsigned long long	qdr_max;
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	qdr_max = QLA82XX_P3_ADDR_QDR_NET_MAX;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	/* DDR network side */
62962306a36Sopenharmony_ci	if (addr_in_range(addr, QLA82XX_ADDR_DDR_NET,
63062306a36Sopenharmony_ci		QLA82XX_ADDR_DDR_NET_MAX))
63162306a36Sopenharmony_ci		BUG();
63262306a36Sopenharmony_ci	else if (addr_in_range(addr, QLA82XX_ADDR_OCM0,
63362306a36Sopenharmony_ci		QLA82XX_ADDR_OCM0_MAX))
63462306a36Sopenharmony_ci		return 1;
63562306a36Sopenharmony_ci	else if (addr_in_range(addr, QLA82XX_ADDR_OCM1,
63662306a36Sopenharmony_ci		QLA82XX_ADDR_OCM1_MAX))
63762306a36Sopenharmony_ci		return 1;
63862306a36Sopenharmony_ci	else if (addr_in_range(addr, QLA82XX_ADDR_QDR_NET, qdr_max)) {
63962306a36Sopenharmony_ci		/* QDR network side */
64062306a36Sopenharmony_ci		window = ((addr - QLA82XX_ADDR_QDR_NET) >> 22) & 0x3f;
64162306a36Sopenharmony_ci		if (ha->qdr_sn_window == window)
64262306a36Sopenharmony_ci			return 1;
64362306a36Sopenharmony_ci	}
64462306a36Sopenharmony_ci	return 0;
64562306a36Sopenharmony_ci}
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_cistatic int qla82xx_pci_mem_read_direct(struct qla_hw_data *ha,
64862306a36Sopenharmony_ci	u64 off, void *data, int size)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	unsigned long   flags;
65162306a36Sopenharmony_ci	void __iomem *addr = NULL;
65262306a36Sopenharmony_ci	int             ret = 0;
65362306a36Sopenharmony_ci	u64             start;
65462306a36Sopenharmony_ci	uint8_t __iomem  *mem_ptr = NULL;
65562306a36Sopenharmony_ci	unsigned long   mem_base;
65662306a36Sopenharmony_ci	unsigned long   mem_page;
65762306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_ci	write_lock_irqsave(&ha->hw_lock, flags);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	/*
66262306a36Sopenharmony_ci	 * If attempting to access unknown address or straddle hw windows,
66362306a36Sopenharmony_ci	 * do not access.
66462306a36Sopenharmony_ci	 */
66562306a36Sopenharmony_ci	start = qla82xx_pci_set_window(ha, off);
66662306a36Sopenharmony_ci	if ((start == -1UL) ||
66762306a36Sopenharmony_ci		(qla82xx_pci_is_same_window(ha, off + size - 1) == 0)) {
66862306a36Sopenharmony_ci		write_unlock_irqrestore(&ha->hw_lock, flags);
66962306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb008,
67062306a36Sopenharmony_ci		    "%s out of bound pci memory "
67162306a36Sopenharmony_ci		    "access, offset is 0x%llx.\n",
67262306a36Sopenharmony_ci		    QLA2XXX_DRIVER_NAME, off);
67362306a36Sopenharmony_ci		return -1;
67462306a36Sopenharmony_ci	}
67562306a36Sopenharmony_ci
67662306a36Sopenharmony_ci	write_unlock_irqrestore(&ha->hw_lock, flags);
67762306a36Sopenharmony_ci	mem_base = pci_resource_start(ha->pdev, 0);
67862306a36Sopenharmony_ci	mem_page = start & PAGE_MASK;
67962306a36Sopenharmony_ci	/* Map two pages whenever user tries to access addresses in two
68062306a36Sopenharmony_ci	* consecutive pages.
68162306a36Sopenharmony_ci	*/
68262306a36Sopenharmony_ci	if (mem_page != ((start + size - 1) & PAGE_MASK))
68362306a36Sopenharmony_ci		mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2);
68462306a36Sopenharmony_ci	else
68562306a36Sopenharmony_ci		mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE);
68662306a36Sopenharmony_ci	if (mem_ptr == NULL) {
68762306a36Sopenharmony_ci		*(u8  *)data = 0;
68862306a36Sopenharmony_ci		return -1;
68962306a36Sopenharmony_ci	}
69062306a36Sopenharmony_ci	addr = mem_ptr;
69162306a36Sopenharmony_ci	addr += start & (PAGE_SIZE - 1);
69262306a36Sopenharmony_ci	write_lock_irqsave(&ha->hw_lock, flags);
69362306a36Sopenharmony_ci
69462306a36Sopenharmony_ci	switch (size) {
69562306a36Sopenharmony_ci	case 1:
69662306a36Sopenharmony_ci		*(u8  *)data = readb(addr);
69762306a36Sopenharmony_ci		break;
69862306a36Sopenharmony_ci	case 2:
69962306a36Sopenharmony_ci		*(u16 *)data = readw(addr);
70062306a36Sopenharmony_ci		break;
70162306a36Sopenharmony_ci	case 4:
70262306a36Sopenharmony_ci		*(u32 *)data = readl(addr);
70362306a36Sopenharmony_ci		break;
70462306a36Sopenharmony_ci	case 8:
70562306a36Sopenharmony_ci		*(u64 *)data = readq(addr);
70662306a36Sopenharmony_ci		break;
70762306a36Sopenharmony_ci	default:
70862306a36Sopenharmony_ci		ret = -1;
70962306a36Sopenharmony_ci		break;
71062306a36Sopenharmony_ci	}
71162306a36Sopenharmony_ci	write_unlock_irqrestore(&ha->hw_lock, flags);
71262306a36Sopenharmony_ci
71362306a36Sopenharmony_ci	if (mem_ptr)
71462306a36Sopenharmony_ci		iounmap(mem_ptr);
71562306a36Sopenharmony_ci	return ret;
71662306a36Sopenharmony_ci}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_cistatic int
71962306a36Sopenharmony_ciqla82xx_pci_mem_write_direct(struct qla_hw_data *ha,
72062306a36Sopenharmony_ci	u64 off, void *data, int size)
72162306a36Sopenharmony_ci{
72262306a36Sopenharmony_ci	unsigned long   flags;
72362306a36Sopenharmony_ci	void  __iomem *addr = NULL;
72462306a36Sopenharmony_ci	int             ret = 0;
72562306a36Sopenharmony_ci	u64             start;
72662306a36Sopenharmony_ci	uint8_t __iomem *mem_ptr = NULL;
72762306a36Sopenharmony_ci	unsigned long   mem_base;
72862306a36Sopenharmony_ci	unsigned long   mem_page;
72962306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	write_lock_irqsave(&ha->hw_lock, flags);
73262306a36Sopenharmony_ci
73362306a36Sopenharmony_ci	/*
73462306a36Sopenharmony_ci	 * If attempting to access unknown address or straddle hw windows,
73562306a36Sopenharmony_ci	 * do not access.
73662306a36Sopenharmony_ci	 */
73762306a36Sopenharmony_ci	start = qla82xx_pci_set_window(ha, off);
73862306a36Sopenharmony_ci	if ((start == -1UL) ||
73962306a36Sopenharmony_ci		(qla82xx_pci_is_same_window(ha, off + size - 1) == 0)) {
74062306a36Sopenharmony_ci		write_unlock_irqrestore(&ha->hw_lock, flags);
74162306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0xb009,
74262306a36Sopenharmony_ci		    "%s out of bound memory "
74362306a36Sopenharmony_ci		    "access, offset is 0x%llx.\n",
74462306a36Sopenharmony_ci		    QLA2XXX_DRIVER_NAME, off);
74562306a36Sopenharmony_ci		return -1;
74662306a36Sopenharmony_ci	}
74762306a36Sopenharmony_ci
74862306a36Sopenharmony_ci	write_unlock_irqrestore(&ha->hw_lock, flags);
74962306a36Sopenharmony_ci	mem_base = pci_resource_start(ha->pdev, 0);
75062306a36Sopenharmony_ci	mem_page = start & PAGE_MASK;
75162306a36Sopenharmony_ci	/* Map two pages whenever user tries to access addresses in two
75262306a36Sopenharmony_ci	 * consecutive pages.
75362306a36Sopenharmony_ci	 */
75462306a36Sopenharmony_ci	if (mem_page != ((start + size - 1) & PAGE_MASK))
75562306a36Sopenharmony_ci		mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE*2);
75662306a36Sopenharmony_ci	else
75762306a36Sopenharmony_ci		mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE);
75862306a36Sopenharmony_ci	if (mem_ptr == NULL)
75962306a36Sopenharmony_ci		return -1;
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	addr = mem_ptr;
76262306a36Sopenharmony_ci	addr += start & (PAGE_SIZE - 1);
76362306a36Sopenharmony_ci	write_lock_irqsave(&ha->hw_lock, flags);
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	switch (size) {
76662306a36Sopenharmony_ci	case 1:
76762306a36Sopenharmony_ci		writeb(*(u8  *)data, addr);
76862306a36Sopenharmony_ci		break;
76962306a36Sopenharmony_ci	case 2:
77062306a36Sopenharmony_ci		writew(*(u16 *)data, addr);
77162306a36Sopenharmony_ci		break;
77262306a36Sopenharmony_ci	case 4:
77362306a36Sopenharmony_ci		writel(*(u32 *)data, addr);
77462306a36Sopenharmony_ci		break;
77562306a36Sopenharmony_ci	case 8:
77662306a36Sopenharmony_ci		writeq(*(u64 *)data, addr);
77762306a36Sopenharmony_ci		break;
77862306a36Sopenharmony_ci	default:
77962306a36Sopenharmony_ci		ret = -1;
78062306a36Sopenharmony_ci		break;
78162306a36Sopenharmony_ci	}
78262306a36Sopenharmony_ci	write_unlock_irqrestore(&ha->hw_lock, flags);
78362306a36Sopenharmony_ci	if (mem_ptr)
78462306a36Sopenharmony_ci		iounmap(mem_ptr);
78562306a36Sopenharmony_ci	return ret;
78662306a36Sopenharmony_ci}
78762306a36Sopenharmony_ci
78862306a36Sopenharmony_ci#define MTU_FUDGE_FACTOR 100
78962306a36Sopenharmony_cistatic unsigned long
79062306a36Sopenharmony_ciqla82xx_decode_crb_addr(unsigned long addr)
79162306a36Sopenharmony_ci{
79262306a36Sopenharmony_ci	int i;
79362306a36Sopenharmony_ci	unsigned long base_addr, offset, pci_base;
79462306a36Sopenharmony_ci
79562306a36Sopenharmony_ci	if (!qla82xx_crb_table_initialized)
79662306a36Sopenharmony_ci		qla82xx_crb_addr_transform_setup();
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	pci_base = ADDR_ERROR;
79962306a36Sopenharmony_ci	base_addr = addr & 0xfff00000;
80062306a36Sopenharmony_ci	offset = addr & 0x000fffff;
80162306a36Sopenharmony_ci
80262306a36Sopenharmony_ci	for (i = 0; i < MAX_CRB_XFORM; i++) {
80362306a36Sopenharmony_ci		if (crb_addr_xform[i] == base_addr) {
80462306a36Sopenharmony_ci			pci_base = i << 20;
80562306a36Sopenharmony_ci			break;
80662306a36Sopenharmony_ci		}
80762306a36Sopenharmony_ci	}
80862306a36Sopenharmony_ci	if (pci_base == ADDR_ERROR)
80962306a36Sopenharmony_ci		return pci_base;
81062306a36Sopenharmony_ci	return pci_base + offset;
81162306a36Sopenharmony_ci}
81262306a36Sopenharmony_ci
81362306a36Sopenharmony_cistatic long rom_max_timeout = 100;
81462306a36Sopenharmony_cistatic long qla82xx_rom_lock_timeout = 100;
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_cistatic int
81762306a36Sopenharmony_ciqla82xx_rom_lock(struct qla_hw_data *ha)
81862306a36Sopenharmony_ci{
81962306a36Sopenharmony_ci	int done = 0, timeout = 0;
82062306a36Sopenharmony_ci	uint32_t lock_owner = 0;
82162306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
82262306a36Sopenharmony_ci
82362306a36Sopenharmony_ci	while (!done) {
82462306a36Sopenharmony_ci		/* acquire semaphore2 from PCI HW block */
82562306a36Sopenharmony_ci		done = qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_LOCK));
82662306a36Sopenharmony_ci		if (done == 1)
82762306a36Sopenharmony_ci			break;
82862306a36Sopenharmony_ci		if (timeout >= qla82xx_rom_lock_timeout) {
82962306a36Sopenharmony_ci			lock_owner = qla82xx_rd_32(ha, QLA82XX_ROM_LOCK_ID);
83062306a36Sopenharmony_ci			ql_dbg(ql_dbg_p3p, vha, 0xb157,
83162306a36Sopenharmony_ci			    "%s: Simultaneous flash access by following ports, active port = %d: accessing port = %d",
83262306a36Sopenharmony_ci			    __func__, ha->portnum, lock_owner);
83362306a36Sopenharmony_ci			return -1;
83462306a36Sopenharmony_ci		}
83562306a36Sopenharmony_ci		timeout++;
83662306a36Sopenharmony_ci	}
83762306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_ROM_LOCK_ID, ha->portnum);
83862306a36Sopenharmony_ci	return 0;
83962306a36Sopenharmony_ci}
84062306a36Sopenharmony_ci
84162306a36Sopenharmony_cistatic void
84262306a36Sopenharmony_ciqla82xx_rom_unlock(struct qla_hw_data *ha)
84362306a36Sopenharmony_ci{
84462306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_ROM_LOCK_ID, 0xffffffff);
84562306a36Sopenharmony_ci	qla82xx_rd_32(ha, QLA82XX_PCIE_REG(PCIE_SEM2_UNLOCK));
84662306a36Sopenharmony_ci}
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_cistatic int
84962306a36Sopenharmony_ciqla82xx_wait_rom_busy(struct qla_hw_data *ha)
85062306a36Sopenharmony_ci{
85162306a36Sopenharmony_ci	long timeout = 0;
85262306a36Sopenharmony_ci	long done = 0 ;
85362306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
85462306a36Sopenharmony_ci
85562306a36Sopenharmony_ci	while (done == 0) {
85662306a36Sopenharmony_ci		done = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_STATUS);
85762306a36Sopenharmony_ci		done &= 4;
85862306a36Sopenharmony_ci		timeout++;
85962306a36Sopenharmony_ci		if (timeout >= rom_max_timeout) {
86062306a36Sopenharmony_ci			ql_dbg(ql_dbg_p3p, vha, 0xb00a,
86162306a36Sopenharmony_ci			    "%s: Timeout reached waiting for rom busy.\n",
86262306a36Sopenharmony_ci			    QLA2XXX_DRIVER_NAME);
86362306a36Sopenharmony_ci			return -1;
86462306a36Sopenharmony_ci		}
86562306a36Sopenharmony_ci	}
86662306a36Sopenharmony_ci	return 0;
86762306a36Sopenharmony_ci}
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_cistatic int
87062306a36Sopenharmony_ciqla82xx_wait_rom_done(struct qla_hw_data *ha)
87162306a36Sopenharmony_ci{
87262306a36Sopenharmony_ci	long timeout = 0;
87362306a36Sopenharmony_ci	long done = 0 ;
87462306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	while (done == 0) {
87762306a36Sopenharmony_ci		done = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_STATUS);
87862306a36Sopenharmony_ci		done &= 2;
87962306a36Sopenharmony_ci		timeout++;
88062306a36Sopenharmony_ci		if (timeout >= rom_max_timeout) {
88162306a36Sopenharmony_ci			ql_dbg(ql_dbg_p3p, vha, 0xb00b,
88262306a36Sopenharmony_ci			    "%s: Timeout reached waiting for rom done.\n",
88362306a36Sopenharmony_ci			    QLA2XXX_DRIVER_NAME);
88462306a36Sopenharmony_ci			return -1;
88562306a36Sopenharmony_ci		}
88662306a36Sopenharmony_ci	}
88762306a36Sopenharmony_ci	return 0;
88862306a36Sopenharmony_ci}
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_cistatic int
89162306a36Sopenharmony_ciqla82xx_md_rw_32(struct qla_hw_data *ha, uint32_t off, u32 data, uint8_t flag)
89262306a36Sopenharmony_ci{
89362306a36Sopenharmony_ci	uint32_t  off_value, rval = 0;
89462306a36Sopenharmony_ci
89562306a36Sopenharmony_ci	wrt_reg_dword(CRB_WINDOW_2M + ha->nx_pcibase, off & 0xFFFF0000);
89662306a36Sopenharmony_ci
89762306a36Sopenharmony_ci	/* Read back value to make sure write has gone through */
89862306a36Sopenharmony_ci	rd_reg_dword(CRB_WINDOW_2M + ha->nx_pcibase);
89962306a36Sopenharmony_ci	off_value  = (off & 0x0000FFFF);
90062306a36Sopenharmony_ci
90162306a36Sopenharmony_ci	if (flag)
90262306a36Sopenharmony_ci		wrt_reg_dword(off_value + CRB_INDIRECT_2M + ha->nx_pcibase,
90362306a36Sopenharmony_ci			      data);
90462306a36Sopenharmony_ci	else
90562306a36Sopenharmony_ci		rval = rd_reg_dword(off_value + CRB_INDIRECT_2M +
90662306a36Sopenharmony_ci				    ha->nx_pcibase);
90762306a36Sopenharmony_ci
90862306a36Sopenharmony_ci	return rval;
90962306a36Sopenharmony_ci}
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_cistatic int
91262306a36Sopenharmony_ciqla82xx_do_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp)
91362306a36Sopenharmony_ci{
91462306a36Sopenharmony_ci	/* Dword reads to flash. */
91562306a36Sopenharmony_ci	qla82xx_md_rw_32(ha, MD_DIRECT_ROM_WINDOW, (addr & 0xFFFF0000), 1);
91662306a36Sopenharmony_ci	*valp = qla82xx_md_rw_32(ha, MD_DIRECT_ROM_READ_BASE +
91762306a36Sopenharmony_ci	    (addr & 0x0000FFFF), 0, 0);
91862306a36Sopenharmony_ci
91962306a36Sopenharmony_ci	return 0;
92062306a36Sopenharmony_ci}
92162306a36Sopenharmony_ci
92262306a36Sopenharmony_cistatic int
92362306a36Sopenharmony_ciqla82xx_rom_fast_read(struct qla_hw_data *ha, int addr, int *valp)
92462306a36Sopenharmony_ci{
92562306a36Sopenharmony_ci	int ret, loops = 0;
92662306a36Sopenharmony_ci	uint32_t lock_owner = 0;
92762306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	while ((qla82xx_rom_lock(ha) != 0) && (loops < 50000)) {
93062306a36Sopenharmony_ci		udelay(100);
93162306a36Sopenharmony_ci		schedule();
93262306a36Sopenharmony_ci		loops++;
93362306a36Sopenharmony_ci	}
93462306a36Sopenharmony_ci	if (loops >= 50000) {
93562306a36Sopenharmony_ci		lock_owner = qla82xx_rd_32(ha, QLA82XX_ROM_LOCK_ID);
93662306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0x00b9,
93762306a36Sopenharmony_ci		    "Failed to acquire SEM2 lock, Lock Owner %u.\n",
93862306a36Sopenharmony_ci		    lock_owner);
93962306a36Sopenharmony_ci		return -1;
94062306a36Sopenharmony_ci	}
94162306a36Sopenharmony_ci	ret = qla82xx_do_rom_fast_read(ha, addr, valp);
94262306a36Sopenharmony_ci	qla82xx_rom_unlock(ha);
94362306a36Sopenharmony_ci	return ret;
94462306a36Sopenharmony_ci}
94562306a36Sopenharmony_ci
94662306a36Sopenharmony_cistatic int
94762306a36Sopenharmony_ciqla82xx_read_status_reg(struct qla_hw_data *ha, uint32_t *val)
94862306a36Sopenharmony_ci{
94962306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
95062306a36Sopenharmony_ci
95162306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_RDSR);
95262306a36Sopenharmony_ci	qla82xx_wait_rom_busy(ha);
95362306a36Sopenharmony_ci	if (qla82xx_wait_rom_done(ha)) {
95462306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb00c,
95562306a36Sopenharmony_ci		    "Error waiting for rom done.\n");
95662306a36Sopenharmony_ci		return -1;
95762306a36Sopenharmony_ci	}
95862306a36Sopenharmony_ci	*val = qla82xx_rd_32(ha, QLA82XX_ROMUSB_ROM_RDATA);
95962306a36Sopenharmony_ci	return 0;
96062306a36Sopenharmony_ci}
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_cistatic int
96362306a36Sopenharmony_ciqla82xx_flash_wait_write_finish(struct qla_hw_data *ha)
96462306a36Sopenharmony_ci{
96562306a36Sopenharmony_ci	uint32_t val = 0;
96662306a36Sopenharmony_ci	int i, ret;
96762306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
96862306a36Sopenharmony_ci
96962306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0);
97062306a36Sopenharmony_ci	for (i = 0; i < 50000; i++) {
97162306a36Sopenharmony_ci		ret = qla82xx_read_status_reg(ha, &val);
97262306a36Sopenharmony_ci		if (ret < 0 || (val & 1) == 0)
97362306a36Sopenharmony_ci			return ret;
97462306a36Sopenharmony_ci		udelay(10);
97562306a36Sopenharmony_ci		cond_resched();
97662306a36Sopenharmony_ci	}
97762306a36Sopenharmony_ci	ql_log(ql_log_warn, vha, 0xb00d,
97862306a36Sopenharmony_ci	       "Timeout reached waiting for write finish.\n");
97962306a36Sopenharmony_ci	return -1;
98062306a36Sopenharmony_ci}
98162306a36Sopenharmony_ci
98262306a36Sopenharmony_cistatic int
98362306a36Sopenharmony_ciqla82xx_flash_set_write_enable(struct qla_hw_data *ha)
98462306a36Sopenharmony_ci{
98562306a36Sopenharmony_ci	uint32_t val;
98662306a36Sopenharmony_ci
98762306a36Sopenharmony_ci	qla82xx_wait_rom_busy(ha);
98862306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 0);
98962306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_WREN);
99062306a36Sopenharmony_ci	qla82xx_wait_rom_busy(ha);
99162306a36Sopenharmony_ci	if (qla82xx_wait_rom_done(ha))
99262306a36Sopenharmony_ci		return -1;
99362306a36Sopenharmony_ci	if (qla82xx_read_status_reg(ha, &val) != 0)
99462306a36Sopenharmony_ci		return -1;
99562306a36Sopenharmony_ci	if ((val & 2) != 2)
99662306a36Sopenharmony_ci		return -1;
99762306a36Sopenharmony_ci	return 0;
99862306a36Sopenharmony_ci}
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_cistatic int
100162306a36Sopenharmony_ciqla82xx_write_status_reg(struct qla_hw_data *ha, uint32_t val)
100262306a36Sopenharmony_ci{
100362306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
100462306a36Sopenharmony_ci
100562306a36Sopenharmony_ci	if (qla82xx_flash_set_write_enable(ha))
100662306a36Sopenharmony_ci		return -1;
100762306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_WDATA, val);
100862306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, 0x1);
100962306a36Sopenharmony_ci	if (qla82xx_wait_rom_done(ha)) {
101062306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb00e,
101162306a36Sopenharmony_ci		    "Error waiting for rom done.\n");
101262306a36Sopenharmony_ci		return -1;
101362306a36Sopenharmony_ci	}
101462306a36Sopenharmony_ci	return qla82xx_flash_wait_write_finish(ha);
101562306a36Sopenharmony_ci}
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_cistatic int
101862306a36Sopenharmony_ciqla82xx_write_disable_flash(struct qla_hw_data *ha)
101962306a36Sopenharmony_ci{
102062306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
102162306a36Sopenharmony_ci
102262306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_WRDI);
102362306a36Sopenharmony_ci	if (qla82xx_wait_rom_done(ha)) {
102462306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb00f,
102562306a36Sopenharmony_ci		    "Error waiting for rom done.\n");
102662306a36Sopenharmony_ci		return -1;
102762306a36Sopenharmony_ci	}
102862306a36Sopenharmony_ci	return 0;
102962306a36Sopenharmony_ci}
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_cistatic int
103262306a36Sopenharmony_ciql82xx_rom_lock_d(struct qla_hw_data *ha)
103362306a36Sopenharmony_ci{
103462306a36Sopenharmony_ci	int loops = 0;
103562306a36Sopenharmony_ci	uint32_t lock_owner = 0;
103662306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	while ((qla82xx_rom_lock(ha) != 0) && (loops < 50000)) {
103962306a36Sopenharmony_ci		udelay(100);
104062306a36Sopenharmony_ci		cond_resched();
104162306a36Sopenharmony_ci		loops++;
104262306a36Sopenharmony_ci	}
104362306a36Sopenharmony_ci	if (loops >= 50000) {
104462306a36Sopenharmony_ci		lock_owner = qla82xx_rd_32(ha, QLA82XX_ROM_LOCK_ID);
104562306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb010,
104662306a36Sopenharmony_ci		    "ROM lock failed, Lock Owner %u.\n", lock_owner);
104762306a36Sopenharmony_ci		return -1;
104862306a36Sopenharmony_ci	}
104962306a36Sopenharmony_ci	return 0;
105062306a36Sopenharmony_ci}
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_cistatic int
105362306a36Sopenharmony_ciqla82xx_write_flash_dword(struct qla_hw_data *ha, uint32_t flashaddr,
105462306a36Sopenharmony_ci	uint32_t data)
105562306a36Sopenharmony_ci{
105662306a36Sopenharmony_ci	int ret = 0;
105762306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
105862306a36Sopenharmony_ci
105962306a36Sopenharmony_ci	ret = ql82xx_rom_lock_d(ha);
106062306a36Sopenharmony_ci	if (ret < 0) {
106162306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb011,
106262306a36Sopenharmony_ci		    "ROM lock failed.\n");
106362306a36Sopenharmony_ci		return ret;
106462306a36Sopenharmony_ci	}
106562306a36Sopenharmony_ci
106662306a36Sopenharmony_ci	ret = qla82xx_flash_set_write_enable(ha);
106762306a36Sopenharmony_ci	if (ret < 0)
106862306a36Sopenharmony_ci		goto done_write;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_WDATA, data);
107162306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, flashaddr);
107262306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 3);
107362306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_PP);
107462306a36Sopenharmony_ci	qla82xx_wait_rom_busy(ha);
107562306a36Sopenharmony_ci	if (qla82xx_wait_rom_done(ha)) {
107662306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb012,
107762306a36Sopenharmony_ci		    "Error waiting for rom done.\n");
107862306a36Sopenharmony_ci		ret = -1;
107962306a36Sopenharmony_ci		goto done_write;
108062306a36Sopenharmony_ci	}
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_ci	ret = qla82xx_flash_wait_write_finish(ha);
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_cidone_write:
108562306a36Sopenharmony_ci	qla82xx_rom_unlock(ha);
108662306a36Sopenharmony_ci	return ret;
108762306a36Sopenharmony_ci}
108862306a36Sopenharmony_ci
108962306a36Sopenharmony_ci/* This routine does CRB initialize sequence
109062306a36Sopenharmony_ci *  to put the ISP into operational state
109162306a36Sopenharmony_ci */
109262306a36Sopenharmony_cistatic int
109362306a36Sopenharmony_ciqla82xx_pinit_from_rom(scsi_qla_host_t *vha)
109462306a36Sopenharmony_ci{
109562306a36Sopenharmony_ci	int addr, val;
109662306a36Sopenharmony_ci	int i ;
109762306a36Sopenharmony_ci	struct crb_addr_pair *buf;
109862306a36Sopenharmony_ci	unsigned long off;
109962306a36Sopenharmony_ci	unsigned offset, n;
110062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci	struct crb_addr_pair {
110362306a36Sopenharmony_ci		long addr;
110462306a36Sopenharmony_ci		long data;
110562306a36Sopenharmony_ci	};
110662306a36Sopenharmony_ci
110762306a36Sopenharmony_ci	/* Halt all the individual PEGs and other blocks of the ISP */
110862306a36Sopenharmony_ci	qla82xx_rom_lock(ha);
110962306a36Sopenharmony_ci
111062306a36Sopenharmony_ci	/* disable all I2Q */
111162306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x10, 0x0);
111262306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x14, 0x0);
111362306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x18, 0x0);
111462306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x1c, 0x0);
111562306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x20, 0x0);
111662306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_I2Q + 0x24, 0x0);
111762306a36Sopenharmony_ci
111862306a36Sopenharmony_ci	/* disable all niu interrupts */
111962306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x40, 0xff);
112062306a36Sopenharmony_ci	/* disable xge rx/tx */
112162306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x70000, 0x00);
112262306a36Sopenharmony_ci	/* disable xg1 rx/tx */
112362306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x80000, 0x00);
112462306a36Sopenharmony_ci	/* disable sideband mac */
112562306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x90000, 0x00);
112662306a36Sopenharmony_ci	/* disable ap0 mac */
112762306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0xa0000, 0x00);
112862306a36Sopenharmony_ci	/* disable ap1 mac */
112962306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0xb0000, 0x00);
113062306a36Sopenharmony_ci
113162306a36Sopenharmony_ci	/* halt sre */
113262306a36Sopenharmony_ci	val = qla82xx_rd_32(ha, QLA82XX_CRB_SRE + 0x1000);
113362306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_SRE + 0x1000, val & (~(0x1)));
113462306a36Sopenharmony_ci
113562306a36Sopenharmony_ci	/* halt epg */
113662306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_EPG + 0x1300, 0x1);
113762306a36Sopenharmony_ci
113862306a36Sopenharmony_ci	/* halt timers */
113962306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x0, 0x0);
114062306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x8, 0x0);
114162306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x10, 0x0);
114262306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x18, 0x0);
114362306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x100, 0x0);
114462306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_TIMER + 0x200, 0x0);
114562306a36Sopenharmony_ci
114662306a36Sopenharmony_ci	/* halt pegs */
114762306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x3c, 1);
114862306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_1 + 0x3c, 1);
114962306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_2 + 0x3c, 1);
115062306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_3 + 0x3c, 1);
115162306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_4 + 0x3c, 1);
115262306a36Sopenharmony_ci	msleep(20);
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	/* big hammer */
115562306a36Sopenharmony_ci	if (test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))
115662306a36Sopenharmony_ci		/* don't reset CAM block on reset */
115762306a36Sopenharmony_ci		qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xfeffffff);
115862306a36Sopenharmony_ci	else
115962306a36Sopenharmony_ci		qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0xffffffff);
116062306a36Sopenharmony_ci	qla82xx_rom_unlock(ha);
116162306a36Sopenharmony_ci
116262306a36Sopenharmony_ci	/* Read the signature value from the flash.
116362306a36Sopenharmony_ci	 * Offset 0: Contain signature (0xcafecafe)
116462306a36Sopenharmony_ci	 * Offset 4: Offset and number of addr/value pairs
116562306a36Sopenharmony_ci	 * that present in CRB initialize sequence
116662306a36Sopenharmony_ci	 */
116762306a36Sopenharmony_ci	n = 0;
116862306a36Sopenharmony_ci	if (qla82xx_rom_fast_read(ha, 0, &n) != 0 || n != 0xcafecafeUL ||
116962306a36Sopenharmony_ci	    qla82xx_rom_fast_read(ha, 4, &n) != 0) {
117062306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0x006e,
117162306a36Sopenharmony_ci		    "Error Reading crb_init area: n: %08x.\n", n);
117262306a36Sopenharmony_ci		return -1;
117362306a36Sopenharmony_ci	}
117462306a36Sopenharmony_ci
117562306a36Sopenharmony_ci	/* Offset in flash = lower 16 bits
117662306a36Sopenharmony_ci	 * Number of entries = upper 16 bits
117762306a36Sopenharmony_ci	 */
117862306a36Sopenharmony_ci	offset = n & 0xffffU;
117962306a36Sopenharmony_ci	n = (n >> 16) & 0xffffU;
118062306a36Sopenharmony_ci
118162306a36Sopenharmony_ci	/* number of addr/value pair should not exceed 1024 entries */
118262306a36Sopenharmony_ci	if (n  >= 1024) {
118362306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0x0071,
118462306a36Sopenharmony_ci		    "Card flash not initialized:n=0x%x.\n", n);
118562306a36Sopenharmony_ci		return -1;
118662306a36Sopenharmony_ci	}
118762306a36Sopenharmony_ci
118862306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x0072,
118962306a36Sopenharmony_ci	    "%d CRB init values found in ROM.\n", n);
119062306a36Sopenharmony_ci
119162306a36Sopenharmony_ci	buf = kmalloc_array(n, sizeof(struct crb_addr_pair), GFP_KERNEL);
119262306a36Sopenharmony_ci	if (buf == NULL) {
119362306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0x010c,
119462306a36Sopenharmony_ci		    "Unable to allocate memory.\n");
119562306a36Sopenharmony_ci		return -ENOMEM;
119662306a36Sopenharmony_ci	}
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	for (i = 0; i < n; i++) {
119962306a36Sopenharmony_ci		if (qla82xx_rom_fast_read(ha, 8*i + 4*offset, &val) != 0 ||
120062306a36Sopenharmony_ci		    qla82xx_rom_fast_read(ha, 8*i + 4*offset + 4, &addr) != 0) {
120162306a36Sopenharmony_ci			kfree(buf);
120262306a36Sopenharmony_ci			return -1;
120362306a36Sopenharmony_ci		}
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci		buf[i].addr = addr;
120662306a36Sopenharmony_ci		buf[i].data = val;
120762306a36Sopenharmony_ci	}
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	for (i = 0; i < n; i++) {
121062306a36Sopenharmony_ci		/* Translate internal CRB initialization
121162306a36Sopenharmony_ci		 * address to PCI bus address
121262306a36Sopenharmony_ci		 */
121362306a36Sopenharmony_ci		off = qla82xx_decode_crb_addr((unsigned long)buf[i].addr) +
121462306a36Sopenharmony_ci		    QLA82XX_PCI_CRBSPACE;
121562306a36Sopenharmony_ci		/* Not all CRB  addr/value pair to be written,
121662306a36Sopenharmony_ci		 * some of them are skipped
121762306a36Sopenharmony_ci		 */
121862306a36Sopenharmony_ci
121962306a36Sopenharmony_ci		/* skipping cold reboot MAGIC */
122062306a36Sopenharmony_ci		if (off == QLA82XX_CAM_RAM(0x1fc))
122162306a36Sopenharmony_ci			continue;
122262306a36Sopenharmony_ci
122362306a36Sopenharmony_ci		/* do not reset PCI */
122462306a36Sopenharmony_ci		if (off == (ROMUSB_GLB + 0xbc))
122562306a36Sopenharmony_ci			continue;
122662306a36Sopenharmony_ci
122762306a36Sopenharmony_ci		/* skip core clock, so that firmware can increase the clock */
122862306a36Sopenharmony_ci		if (off == (ROMUSB_GLB + 0xc8))
122962306a36Sopenharmony_ci			continue;
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci		/* skip the function enable register */
123262306a36Sopenharmony_ci		if (off == QLA82XX_PCIE_REG(PCIE_SETUP_FUNCTION))
123362306a36Sopenharmony_ci			continue;
123462306a36Sopenharmony_ci
123562306a36Sopenharmony_ci		if (off == QLA82XX_PCIE_REG(PCIE_SETUP_FUNCTION2))
123662306a36Sopenharmony_ci			continue;
123762306a36Sopenharmony_ci
123862306a36Sopenharmony_ci		if ((off & 0x0ff00000) == QLA82XX_CRB_SMB)
123962306a36Sopenharmony_ci			continue;
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci		if ((off & 0x0ff00000) == QLA82XX_CRB_DDR_NET)
124262306a36Sopenharmony_ci			continue;
124362306a36Sopenharmony_ci
124462306a36Sopenharmony_ci		if (off == ADDR_ERROR) {
124562306a36Sopenharmony_ci			ql_log(ql_log_fatal, vha, 0x0116,
124662306a36Sopenharmony_ci			    "Unknown addr: 0x%08lx.\n", buf[i].addr);
124762306a36Sopenharmony_ci			continue;
124862306a36Sopenharmony_ci		}
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci		qla82xx_wr_32(ha, off, buf[i].data);
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci		/* ISP requires much bigger delay to settle down,
125362306a36Sopenharmony_ci		 * else crb_window returns 0xffffffff
125462306a36Sopenharmony_ci		 */
125562306a36Sopenharmony_ci		if (off == QLA82XX_ROMUSB_GLB_SW_RESET)
125662306a36Sopenharmony_ci			msleep(1000);
125762306a36Sopenharmony_ci
125862306a36Sopenharmony_ci		/* ISP requires millisec delay between
125962306a36Sopenharmony_ci		 * successive CRB register updation
126062306a36Sopenharmony_ci		 */
126162306a36Sopenharmony_ci		msleep(1);
126262306a36Sopenharmony_ci	}
126362306a36Sopenharmony_ci
126462306a36Sopenharmony_ci	kfree(buf);
126562306a36Sopenharmony_ci
126662306a36Sopenharmony_ci	/* Resetting the data and instruction cache */
126762306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_D+0xec, 0x1e);
126862306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_D+0x4c, 8);
126962306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_I+0x4c, 8);
127062306a36Sopenharmony_ci
127162306a36Sopenharmony_ci	/* Clear all protocol processing engines */
127262306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0+0x8, 0);
127362306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0+0xc, 0);
127462306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_1+0x8, 0);
127562306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_1+0xc, 0);
127662306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_2+0x8, 0);
127762306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_2+0xc, 0);
127862306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_3+0x8, 0);
127962306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_3+0xc, 0);
128062306a36Sopenharmony_ci	return 0;
128162306a36Sopenharmony_ci}
128262306a36Sopenharmony_ci
128362306a36Sopenharmony_cistatic int
128462306a36Sopenharmony_ciqla82xx_pci_mem_write_2M(struct qla_hw_data *ha,
128562306a36Sopenharmony_ci		u64 off, void *data, int size)
128662306a36Sopenharmony_ci{
128762306a36Sopenharmony_ci	int i, j, ret = 0, loop, sz[2], off0;
128862306a36Sopenharmony_ci	int scale, shift_amount, startword;
128962306a36Sopenharmony_ci	uint32_t temp;
129062306a36Sopenharmony_ci	uint64_t off8, mem_crb, tmpw, word[2] = {0, 0};
129162306a36Sopenharmony_ci
129262306a36Sopenharmony_ci	/*
129362306a36Sopenharmony_ci	 * If not MN, go check for MS or invalid.
129462306a36Sopenharmony_ci	 */
129562306a36Sopenharmony_ci	if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX)
129662306a36Sopenharmony_ci		mem_crb = QLA82XX_CRB_QDR_NET;
129762306a36Sopenharmony_ci	else {
129862306a36Sopenharmony_ci		mem_crb = QLA82XX_CRB_DDR_NET;
129962306a36Sopenharmony_ci		if (qla82xx_pci_mem_bound_check(ha, off, size) == 0)
130062306a36Sopenharmony_ci			return qla82xx_pci_mem_write_direct(ha,
130162306a36Sopenharmony_ci			    off, data, size);
130262306a36Sopenharmony_ci	}
130362306a36Sopenharmony_ci
130462306a36Sopenharmony_ci	off0 = off & 0x7;
130562306a36Sopenharmony_ci	sz[0] = (size < (8 - off0)) ? size : (8 - off0);
130662306a36Sopenharmony_ci	sz[1] = size - sz[0];
130762306a36Sopenharmony_ci
130862306a36Sopenharmony_ci	off8 = off & 0xfffffff0;
130962306a36Sopenharmony_ci	loop = (((off & 0xf) + size - 1) >> 4) + 1;
131062306a36Sopenharmony_ci	shift_amount = 4;
131162306a36Sopenharmony_ci	scale = 2;
131262306a36Sopenharmony_ci	startword = (off & 0xf)/8;
131362306a36Sopenharmony_ci
131462306a36Sopenharmony_ci	for (i = 0; i < loop; i++) {
131562306a36Sopenharmony_ci		if (qla82xx_pci_mem_read_2M(ha, off8 +
131662306a36Sopenharmony_ci		    (i << shift_amount), &word[i * scale], 8))
131762306a36Sopenharmony_ci			return -1;
131862306a36Sopenharmony_ci	}
131962306a36Sopenharmony_ci
132062306a36Sopenharmony_ci	switch (size) {
132162306a36Sopenharmony_ci	case 1:
132262306a36Sopenharmony_ci		tmpw = *((uint8_t *)data);
132362306a36Sopenharmony_ci		break;
132462306a36Sopenharmony_ci	case 2:
132562306a36Sopenharmony_ci		tmpw = *((uint16_t *)data);
132662306a36Sopenharmony_ci		break;
132762306a36Sopenharmony_ci	case 4:
132862306a36Sopenharmony_ci		tmpw = *((uint32_t *)data);
132962306a36Sopenharmony_ci		break;
133062306a36Sopenharmony_ci	case 8:
133162306a36Sopenharmony_ci	default:
133262306a36Sopenharmony_ci		tmpw = *((uint64_t *)data);
133362306a36Sopenharmony_ci		break;
133462306a36Sopenharmony_ci	}
133562306a36Sopenharmony_ci
133662306a36Sopenharmony_ci	if (sz[0] == 8) {
133762306a36Sopenharmony_ci		word[startword] = tmpw;
133862306a36Sopenharmony_ci	} else {
133962306a36Sopenharmony_ci		word[startword] &=
134062306a36Sopenharmony_ci			~((~(~0ULL << (sz[0] * 8))) << (off0 * 8));
134162306a36Sopenharmony_ci		word[startword] |= tmpw << (off0 * 8);
134262306a36Sopenharmony_ci	}
134362306a36Sopenharmony_ci	if (sz[1] != 0) {
134462306a36Sopenharmony_ci		word[startword+1] &= ~(~0ULL << (sz[1] * 8));
134562306a36Sopenharmony_ci		word[startword+1] |= tmpw >> (sz[0] * 8);
134662306a36Sopenharmony_ci	}
134762306a36Sopenharmony_ci
134862306a36Sopenharmony_ci	for (i = 0; i < loop; i++) {
134962306a36Sopenharmony_ci		temp = off8 + (i << shift_amount);
135062306a36Sopenharmony_ci		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_LO, temp);
135162306a36Sopenharmony_ci		temp = 0;
135262306a36Sopenharmony_ci		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_ADDR_HI, temp);
135362306a36Sopenharmony_ci		temp = word[i * scale] & 0xffffffff;
135462306a36Sopenharmony_ci		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_LO, temp);
135562306a36Sopenharmony_ci		temp = (word[i * scale] >> 32) & 0xffffffff;
135662306a36Sopenharmony_ci		qla82xx_wr_32(ha, mem_crb+MIU_TEST_AGT_WRDATA_HI, temp);
135762306a36Sopenharmony_ci		temp = word[i*scale + 1] & 0xffffffff;
135862306a36Sopenharmony_ci		qla82xx_wr_32(ha, mem_crb +
135962306a36Sopenharmony_ci		    MIU_TEST_AGT_WRDATA_UPPER_LO, temp);
136062306a36Sopenharmony_ci		temp = (word[i*scale + 1] >> 32) & 0xffffffff;
136162306a36Sopenharmony_ci		qla82xx_wr_32(ha, mem_crb +
136262306a36Sopenharmony_ci		    MIU_TEST_AGT_WRDATA_UPPER_HI, temp);
136362306a36Sopenharmony_ci
136462306a36Sopenharmony_ci		temp = MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
136562306a36Sopenharmony_ci		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
136662306a36Sopenharmony_ci		temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE | MIU_TA_CTL_WRITE;
136762306a36Sopenharmony_ci		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_ci		for (j = 0; j < MAX_CTL_CHECK; j++) {
137062306a36Sopenharmony_ci			temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL);
137162306a36Sopenharmony_ci			if ((temp & MIU_TA_CTL_BUSY) == 0)
137262306a36Sopenharmony_ci				break;
137362306a36Sopenharmony_ci		}
137462306a36Sopenharmony_ci
137562306a36Sopenharmony_ci		if (j >= MAX_CTL_CHECK) {
137662306a36Sopenharmony_ci			if (printk_ratelimit())
137762306a36Sopenharmony_ci				dev_err(&ha->pdev->dev,
137862306a36Sopenharmony_ci				    "failed to write through agent.\n");
137962306a36Sopenharmony_ci			ret = -1;
138062306a36Sopenharmony_ci			break;
138162306a36Sopenharmony_ci		}
138262306a36Sopenharmony_ci	}
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	return ret;
138562306a36Sopenharmony_ci}
138662306a36Sopenharmony_ci
138762306a36Sopenharmony_cistatic int
138862306a36Sopenharmony_ciqla82xx_fw_load_from_flash(struct qla_hw_data *ha)
138962306a36Sopenharmony_ci{
139062306a36Sopenharmony_ci	int  i;
139162306a36Sopenharmony_ci	long size = 0;
139262306a36Sopenharmony_ci	long flashaddr = ha->flt_region_bootload << 2;
139362306a36Sopenharmony_ci	long memaddr = BOOTLD_START;
139462306a36Sopenharmony_ci	u64 data;
139562306a36Sopenharmony_ci	u32 high, low;
139662306a36Sopenharmony_ci
139762306a36Sopenharmony_ci	size = (IMAGE_START - BOOTLD_START) / 8;
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	for (i = 0; i < size; i++) {
140062306a36Sopenharmony_ci		if ((qla82xx_rom_fast_read(ha, flashaddr, (int *)&low)) ||
140162306a36Sopenharmony_ci		    (qla82xx_rom_fast_read(ha, flashaddr + 4, (int *)&high))) {
140262306a36Sopenharmony_ci			return -1;
140362306a36Sopenharmony_ci		}
140462306a36Sopenharmony_ci		data = ((u64)high << 32) | low ;
140562306a36Sopenharmony_ci		qla82xx_pci_mem_write_2M(ha, memaddr, &data, 8);
140662306a36Sopenharmony_ci		flashaddr += 8;
140762306a36Sopenharmony_ci		memaddr += 8;
140862306a36Sopenharmony_ci
140962306a36Sopenharmony_ci		if (i % 0x1000 == 0)
141062306a36Sopenharmony_ci			msleep(1);
141162306a36Sopenharmony_ci	}
141262306a36Sopenharmony_ci	udelay(100);
141362306a36Sopenharmony_ci	read_lock(&ha->hw_lock);
141462306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020);
141562306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
141662306a36Sopenharmony_ci	read_unlock(&ha->hw_lock);
141762306a36Sopenharmony_ci	return 0;
141862306a36Sopenharmony_ci}
141962306a36Sopenharmony_ci
142062306a36Sopenharmony_ciint
142162306a36Sopenharmony_ciqla82xx_pci_mem_read_2M(struct qla_hw_data *ha,
142262306a36Sopenharmony_ci		u64 off, void *data, int size)
142362306a36Sopenharmony_ci{
142462306a36Sopenharmony_ci	int i, j = 0, k, start, end, loop, sz[2], off0[2];
142562306a36Sopenharmony_ci	int	      shift_amount;
142662306a36Sopenharmony_ci	uint32_t      temp;
142762306a36Sopenharmony_ci	uint64_t      off8, val, mem_crb, word[2] = {0, 0};
142862306a36Sopenharmony_ci
142962306a36Sopenharmony_ci	/*
143062306a36Sopenharmony_ci	 * If not MN, go check for MS or invalid.
143162306a36Sopenharmony_ci	 */
143262306a36Sopenharmony_ci
143362306a36Sopenharmony_ci	if (off >= QLA82XX_ADDR_QDR_NET && off <= QLA82XX_P3_ADDR_QDR_NET_MAX)
143462306a36Sopenharmony_ci		mem_crb = QLA82XX_CRB_QDR_NET;
143562306a36Sopenharmony_ci	else {
143662306a36Sopenharmony_ci		mem_crb = QLA82XX_CRB_DDR_NET;
143762306a36Sopenharmony_ci		if (qla82xx_pci_mem_bound_check(ha, off, size) == 0)
143862306a36Sopenharmony_ci			return qla82xx_pci_mem_read_direct(ha,
143962306a36Sopenharmony_ci			    off, data, size);
144062306a36Sopenharmony_ci	}
144162306a36Sopenharmony_ci
144262306a36Sopenharmony_ci	off8 = off & 0xfffffff0;
144362306a36Sopenharmony_ci	off0[0] = off & 0xf;
144462306a36Sopenharmony_ci	sz[0] = (size < (16 - off0[0])) ? size : (16 - off0[0]);
144562306a36Sopenharmony_ci	shift_amount = 4;
144662306a36Sopenharmony_ci	loop = ((off0[0] + size - 1) >> shift_amount) + 1;
144762306a36Sopenharmony_ci	off0[1] = 0;
144862306a36Sopenharmony_ci	sz[1] = size - sz[0];
144962306a36Sopenharmony_ci
145062306a36Sopenharmony_ci	for (i = 0; i < loop; i++) {
145162306a36Sopenharmony_ci		temp = off8 + (i << shift_amount);
145262306a36Sopenharmony_ci		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_LO, temp);
145362306a36Sopenharmony_ci		temp = 0;
145462306a36Sopenharmony_ci		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_ADDR_HI, temp);
145562306a36Sopenharmony_ci		temp = MIU_TA_CTL_ENABLE;
145662306a36Sopenharmony_ci		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
145762306a36Sopenharmony_ci		temp = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE;
145862306a36Sopenharmony_ci		qla82xx_wr_32(ha, mem_crb + MIU_TEST_AGT_CTRL, temp);
145962306a36Sopenharmony_ci
146062306a36Sopenharmony_ci		for (j = 0; j < MAX_CTL_CHECK; j++) {
146162306a36Sopenharmony_ci			temp = qla82xx_rd_32(ha, mem_crb + MIU_TEST_AGT_CTRL);
146262306a36Sopenharmony_ci			if ((temp & MIU_TA_CTL_BUSY) == 0)
146362306a36Sopenharmony_ci				break;
146462306a36Sopenharmony_ci		}
146562306a36Sopenharmony_ci
146662306a36Sopenharmony_ci		if (j >= MAX_CTL_CHECK) {
146762306a36Sopenharmony_ci			if (printk_ratelimit())
146862306a36Sopenharmony_ci				dev_err(&ha->pdev->dev,
146962306a36Sopenharmony_ci				    "failed to read through agent.\n");
147062306a36Sopenharmony_ci			break;
147162306a36Sopenharmony_ci		}
147262306a36Sopenharmony_ci
147362306a36Sopenharmony_ci		start = off0[i] >> 2;
147462306a36Sopenharmony_ci		end   = (off0[i] + sz[i] - 1) >> 2;
147562306a36Sopenharmony_ci		for (k = start; k <= end; k++) {
147662306a36Sopenharmony_ci			temp = qla82xx_rd_32(ha,
147762306a36Sopenharmony_ci					mem_crb + MIU_TEST_AGT_RDDATA(k));
147862306a36Sopenharmony_ci			word[i] |= ((uint64_t)temp << (32 * (k & 1)));
147962306a36Sopenharmony_ci		}
148062306a36Sopenharmony_ci	}
148162306a36Sopenharmony_ci
148262306a36Sopenharmony_ci	if (j >= MAX_CTL_CHECK)
148362306a36Sopenharmony_ci		return -1;
148462306a36Sopenharmony_ci
148562306a36Sopenharmony_ci	if ((off0[0] & 7) == 0) {
148662306a36Sopenharmony_ci		val = word[0];
148762306a36Sopenharmony_ci	} else {
148862306a36Sopenharmony_ci		val = ((word[0] >> (off0[0] * 8)) & (~(~0ULL << (sz[0] * 8)))) |
148962306a36Sopenharmony_ci			((word[1] & (~(~0ULL << (sz[1] * 8)))) << (sz[0] * 8));
149062306a36Sopenharmony_ci	}
149162306a36Sopenharmony_ci
149262306a36Sopenharmony_ci	switch (size) {
149362306a36Sopenharmony_ci	case 1:
149462306a36Sopenharmony_ci		*(uint8_t  *)data = val;
149562306a36Sopenharmony_ci		break;
149662306a36Sopenharmony_ci	case 2:
149762306a36Sopenharmony_ci		*(uint16_t *)data = val;
149862306a36Sopenharmony_ci		break;
149962306a36Sopenharmony_ci	case 4:
150062306a36Sopenharmony_ci		*(uint32_t *)data = val;
150162306a36Sopenharmony_ci		break;
150262306a36Sopenharmony_ci	case 8:
150362306a36Sopenharmony_ci		*(uint64_t *)data = val;
150462306a36Sopenharmony_ci		break;
150562306a36Sopenharmony_ci	}
150662306a36Sopenharmony_ci	return 0;
150762306a36Sopenharmony_ci}
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci
151062306a36Sopenharmony_cistatic struct qla82xx_uri_table_desc *
151162306a36Sopenharmony_ciqla82xx_get_table_desc(const u8 *unirom, int section)
151262306a36Sopenharmony_ci{
151362306a36Sopenharmony_ci	uint32_t i;
151462306a36Sopenharmony_ci	struct qla82xx_uri_table_desc *directory =
151562306a36Sopenharmony_ci		(struct qla82xx_uri_table_desc *)&unirom[0];
151662306a36Sopenharmony_ci	uint32_t offset;
151762306a36Sopenharmony_ci	uint32_t tab_type;
151862306a36Sopenharmony_ci	uint32_t entries = le32_to_cpu(directory->num_entries);
151962306a36Sopenharmony_ci
152062306a36Sopenharmony_ci	for (i = 0; i < entries; i++) {
152162306a36Sopenharmony_ci		offset = le32_to_cpu(directory->findex) +
152262306a36Sopenharmony_ci		    (i * le32_to_cpu(directory->entry_size));
152362306a36Sopenharmony_ci		tab_type = get_unaligned_le32((u32 *)&unirom[offset] + 8);
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci		if (tab_type == section)
152662306a36Sopenharmony_ci			return (struct qla82xx_uri_table_desc *)&unirom[offset];
152762306a36Sopenharmony_ci	}
152862306a36Sopenharmony_ci
152962306a36Sopenharmony_ci	return NULL;
153062306a36Sopenharmony_ci}
153162306a36Sopenharmony_ci
153262306a36Sopenharmony_cistatic struct qla82xx_uri_data_desc *
153362306a36Sopenharmony_ciqla82xx_get_data_desc(struct qla_hw_data *ha,
153462306a36Sopenharmony_ci	u32 section, u32 idx_offset)
153562306a36Sopenharmony_ci{
153662306a36Sopenharmony_ci	const u8 *unirom = ha->hablob->fw->data;
153762306a36Sopenharmony_ci	int idx = get_unaligned_le32((u32 *)&unirom[ha->file_prd_off] +
153862306a36Sopenharmony_ci				     idx_offset);
153962306a36Sopenharmony_ci	struct qla82xx_uri_table_desc *tab_desc = NULL;
154062306a36Sopenharmony_ci	uint32_t offset;
154162306a36Sopenharmony_ci
154262306a36Sopenharmony_ci	tab_desc = qla82xx_get_table_desc(unirom, section);
154362306a36Sopenharmony_ci	if (!tab_desc)
154462306a36Sopenharmony_ci		return NULL;
154562306a36Sopenharmony_ci
154662306a36Sopenharmony_ci	offset = le32_to_cpu(tab_desc->findex) +
154762306a36Sopenharmony_ci	    (le32_to_cpu(tab_desc->entry_size) * idx);
154862306a36Sopenharmony_ci
154962306a36Sopenharmony_ci	return (struct qla82xx_uri_data_desc *)&unirom[offset];
155062306a36Sopenharmony_ci}
155162306a36Sopenharmony_ci
155262306a36Sopenharmony_cistatic u8 *
155362306a36Sopenharmony_ciqla82xx_get_bootld_offset(struct qla_hw_data *ha)
155462306a36Sopenharmony_ci{
155562306a36Sopenharmony_ci	u32 offset = BOOTLD_START;
155662306a36Sopenharmony_ci	struct qla82xx_uri_data_desc *uri_desc = NULL;
155762306a36Sopenharmony_ci
155862306a36Sopenharmony_ci	if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
155962306a36Sopenharmony_ci		uri_desc = qla82xx_get_data_desc(ha,
156062306a36Sopenharmony_ci		    QLA82XX_URI_DIR_SECT_BOOTLD, QLA82XX_URI_BOOTLD_IDX_OFF);
156162306a36Sopenharmony_ci		if (uri_desc)
156262306a36Sopenharmony_ci			offset = le32_to_cpu(uri_desc->findex);
156362306a36Sopenharmony_ci	}
156462306a36Sopenharmony_ci
156562306a36Sopenharmony_ci	return (u8 *)&ha->hablob->fw->data[offset];
156662306a36Sopenharmony_ci}
156762306a36Sopenharmony_ci
156862306a36Sopenharmony_cistatic u32 qla82xx_get_fw_size(struct qla_hw_data *ha)
156962306a36Sopenharmony_ci{
157062306a36Sopenharmony_ci	struct qla82xx_uri_data_desc *uri_desc = NULL;
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_ci	if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
157362306a36Sopenharmony_ci		uri_desc =  qla82xx_get_data_desc(ha, QLA82XX_URI_DIR_SECT_FW,
157462306a36Sopenharmony_ci		    QLA82XX_URI_FIRMWARE_IDX_OFF);
157562306a36Sopenharmony_ci		if (uri_desc)
157662306a36Sopenharmony_ci			return le32_to_cpu(uri_desc->size);
157762306a36Sopenharmony_ci	}
157862306a36Sopenharmony_ci
157962306a36Sopenharmony_ci	return get_unaligned_le32(&ha->hablob->fw->data[FW_SIZE_OFFSET]);
158062306a36Sopenharmony_ci}
158162306a36Sopenharmony_ci
158262306a36Sopenharmony_cistatic u8 *
158362306a36Sopenharmony_ciqla82xx_get_fw_offs(struct qla_hw_data *ha)
158462306a36Sopenharmony_ci{
158562306a36Sopenharmony_ci	u32 offset = IMAGE_START;
158662306a36Sopenharmony_ci	struct qla82xx_uri_data_desc *uri_desc = NULL;
158762306a36Sopenharmony_ci
158862306a36Sopenharmony_ci	if (ha->fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
158962306a36Sopenharmony_ci		uri_desc = qla82xx_get_data_desc(ha, QLA82XX_URI_DIR_SECT_FW,
159062306a36Sopenharmony_ci			QLA82XX_URI_FIRMWARE_IDX_OFF);
159162306a36Sopenharmony_ci		if (uri_desc)
159262306a36Sopenharmony_ci			offset = le32_to_cpu(uri_desc->findex);
159362306a36Sopenharmony_ci	}
159462306a36Sopenharmony_ci
159562306a36Sopenharmony_ci	return (u8 *)&ha->hablob->fw->data[offset];
159662306a36Sopenharmony_ci}
159762306a36Sopenharmony_ci
159862306a36Sopenharmony_ci/* PCI related functions */
159962306a36Sopenharmony_ciint qla82xx_pci_region_offset(struct pci_dev *pdev, int region)
160062306a36Sopenharmony_ci{
160162306a36Sopenharmony_ci	unsigned long val = 0;
160262306a36Sopenharmony_ci	u32 control;
160362306a36Sopenharmony_ci
160462306a36Sopenharmony_ci	switch (region) {
160562306a36Sopenharmony_ci	case 0:
160662306a36Sopenharmony_ci		val = 0;
160762306a36Sopenharmony_ci		break;
160862306a36Sopenharmony_ci	case 1:
160962306a36Sopenharmony_ci		pci_read_config_dword(pdev, QLA82XX_PCI_REG_MSIX_TBL, &control);
161062306a36Sopenharmony_ci		val = control + QLA82XX_MSIX_TBL_SPACE;
161162306a36Sopenharmony_ci		break;
161262306a36Sopenharmony_ci	}
161362306a36Sopenharmony_ci	return val;
161462306a36Sopenharmony_ci}
161562306a36Sopenharmony_ci
161662306a36Sopenharmony_ci
161762306a36Sopenharmony_ciint
161862306a36Sopenharmony_ciqla82xx_iospace_config(struct qla_hw_data *ha)
161962306a36Sopenharmony_ci{
162062306a36Sopenharmony_ci	uint32_t len = 0;
162162306a36Sopenharmony_ci
162262306a36Sopenharmony_ci	if (pci_request_regions(ha->pdev, QLA2XXX_DRIVER_NAME)) {
162362306a36Sopenharmony_ci		ql_log_pci(ql_log_fatal, ha->pdev, 0x000c,
162462306a36Sopenharmony_ci		    "Failed to reserver selected regions.\n");
162562306a36Sopenharmony_ci		goto iospace_error_exit;
162662306a36Sopenharmony_ci	}
162762306a36Sopenharmony_ci
162862306a36Sopenharmony_ci	/* Use MMIO operations for all accesses. */
162962306a36Sopenharmony_ci	if (!(pci_resource_flags(ha->pdev, 0) & IORESOURCE_MEM)) {
163062306a36Sopenharmony_ci		ql_log_pci(ql_log_fatal, ha->pdev, 0x000d,
163162306a36Sopenharmony_ci		    "Region #0 not an MMIO resource, aborting.\n");
163262306a36Sopenharmony_ci		goto iospace_error_exit;
163362306a36Sopenharmony_ci	}
163462306a36Sopenharmony_ci
163562306a36Sopenharmony_ci	len = pci_resource_len(ha->pdev, 0);
163662306a36Sopenharmony_ci	ha->nx_pcibase = ioremap(pci_resource_start(ha->pdev, 0), len);
163762306a36Sopenharmony_ci	if (!ha->nx_pcibase) {
163862306a36Sopenharmony_ci		ql_log_pci(ql_log_fatal, ha->pdev, 0x000e,
163962306a36Sopenharmony_ci		    "Cannot remap pcibase MMIO, aborting.\n");
164062306a36Sopenharmony_ci		goto iospace_error_exit;
164162306a36Sopenharmony_ci	}
164262306a36Sopenharmony_ci
164362306a36Sopenharmony_ci	/* Mapping of IO base pointer */
164462306a36Sopenharmony_ci	if (IS_QLA8044(ha)) {
164562306a36Sopenharmony_ci		ha->iobase = ha->nx_pcibase;
164662306a36Sopenharmony_ci	} else if (IS_QLA82XX(ha)) {
164762306a36Sopenharmony_ci		ha->iobase = ha->nx_pcibase + 0xbc000 + (ha->pdev->devfn << 11);
164862306a36Sopenharmony_ci	}
164962306a36Sopenharmony_ci
165062306a36Sopenharmony_ci	if (!ql2xdbwr) {
165162306a36Sopenharmony_ci		ha->nxdb_wr_ptr = ioremap((pci_resource_start(ha->pdev, 4) +
165262306a36Sopenharmony_ci		    (ha->pdev->devfn << 12)), 4);
165362306a36Sopenharmony_ci		if (!ha->nxdb_wr_ptr) {
165462306a36Sopenharmony_ci			ql_log_pci(ql_log_fatal, ha->pdev, 0x000f,
165562306a36Sopenharmony_ci			    "Cannot remap MMIO, aborting.\n");
165662306a36Sopenharmony_ci			goto iospace_error_exit;
165762306a36Sopenharmony_ci		}
165862306a36Sopenharmony_ci
165962306a36Sopenharmony_ci		/* Mapping of IO base pointer,
166062306a36Sopenharmony_ci		 * door bell read and write pointer
166162306a36Sopenharmony_ci		 */
166262306a36Sopenharmony_ci		ha->nxdb_rd_ptr = ha->nx_pcibase + (512 * 1024) +
166362306a36Sopenharmony_ci		    (ha->pdev->devfn * 8);
166462306a36Sopenharmony_ci	} else {
166562306a36Sopenharmony_ci		ha->nxdb_wr_ptr = (void __iomem *)(ha->pdev->devfn == 6 ?
166662306a36Sopenharmony_ci			QLA82XX_CAMRAM_DB1 :
166762306a36Sopenharmony_ci			QLA82XX_CAMRAM_DB2);
166862306a36Sopenharmony_ci	}
166962306a36Sopenharmony_ci
167062306a36Sopenharmony_ci	ha->max_req_queues = ha->max_rsp_queues = 1;
167162306a36Sopenharmony_ci	ha->msix_count = ha->max_rsp_queues + 1;
167262306a36Sopenharmony_ci	ql_dbg_pci(ql_dbg_multiq, ha->pdev, 0xc006,
167362306a36Sopenharmony_ci	    "nx_pci_base=%p iobase=%p "
167462306a36Sopenharmony_ci	    "max_req_queues=%d msix_count=%d.\n",
167562306a36Sopenharmony_ci	    ha->nx_pcibase, ha->iobase,
167662306a36Sopenharmony_ci	    ha->max_req_queues, ha->msix_count);
167762306a36Sopenharmony_ci	ql_dbg_pci(ql_dbg_init, ha->pdev, 0x0010,
167862306a36Sopenharmony_ci	    "nx_pci_base=%p iobase=%p "
167962306a36Sopenharmony_ci	    "max_req_queues=%d msix_count=%d.\n",
168062306a36Sopenharmony_ci	    ha->nx_pcibase, ha->iobase,
168162306a36Sopenharmony_ci	    ha->max_req_queues, ha->msix_count);
168262306a36Sopenharmony_ci	return 0;
168362306a36Sopenharmony_ci
168462306a36Sopenharmony_ciiospace_error_exit:
168562306a36Sopenharmony_ci	return -ENOMEM;
168662306a36Sopenharmony_ci}
168762306a36Sopenharmony_ci
168862306a36Sopenharmony_ci/* GS related functions */
168962306a36Sopenharmony_ci
169062306a36Sopenharmony_ci/* Initialization related functions */
169162306a36Sopenharmony_ci
169262306a36Sopenharmony_ci/**
169362306a36Sopenharmony_ci * qla82xx_pci_config() - Setup ISP82xx PCI configuration registers.
169462306a36Sopenharmony_ci * @vha: HA context
169562306a36Sopenharmony_ci *
169662306a36Sopenharmony_ci * Returns 0 on success.
169762306a36Sopenharmony_ci*/
169862306a36Sopenharmony_ciint
169962306a36Sopenharmony_ciqla82xx_pci_config(scsi_qla_host_t *vha)
170062306a36Sopenharmony_ci{
170162306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
170262306a36Sopenharmony_ci	int ret;
170362306a36Sopenharmony_ci
170462306a36Sopenharmony_ci	pci_set_master(ha->pdev);
170562306a36Sopenharmony_ci	ret = pci_set_mwi(ha->pdev);
170662306a36Sopenharmony_ci	ha->chip_revision = ha->pdev->revision;
170762306a36Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x0043,
170862306a36Sopenharmony_ci	    "Chip revision:%d; pci_set_mwi() returned %d.\n",
170962306a36Sopenharmony_ci	    ha->chip_revision, ret);
171062306a36Sopenharmony_ci	return 0;
171162306a36Sopenharmony_ci}
171262306a36Sopenharmony_ci
171362306a36Sopenharmony_ci/**
171462306a36Sopenharmony_ci * qla82xx_reset_chip() - Setup ISP82xx PCI configuration registers.
171562306a36Sopenharmony_ci * @vha: HA context
171662306a36Sopenharmony_ci *
171762306a36Sopenharmony_ci * Returns 0 on success.
171862306a36Sopenharmony_ci */
171962306a36Sopenharmony_ciint
172062306a36Sopenharmony_ciqla82xx_reset_chip(scsi_qla_host_t *vha)
172162306a36Sopenharmony_ci{
172262306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
172362306a36Sopenharmony_ci
172462306a36Sopenharmony_ci	ha->isp_ops->disable_intrs(ha);
172562306a36Sopenharmony_ci
172662306a36Sopenharmony_ci	return QLA_SUCCESS;
172762306a36Sopenharmony_ci}
172862306a36Sopenharmony_ci
172962306a36Sopenharmony_civoid qla82xx_config_rings(struct scsi_qla_host *vha)
173062306a36Sopenharmony_ci{
173162306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
173262306a36Sopenharmony_ci	struct device_reg_82xx __iomem *reg = &ha->iobase->isp82;
173362306a36Sopenharmony_ci	struct init_cb_81xx *icb;
173462306a36Sopenharmony_ci	struct req_que *req = ha->req_q_map[0];
173562306a36Sopenharmony_ci	struct rsp_que *rsp = ha->rsp_q_map[0];
173662306a36Sopenharmony_ci
173762306a36Sopenharmony_ci	/* Setup ring parameters in initialization control block. */
173862306a36Sopenharmony_ci	icb = (struct init_cb_81xx *)ha->init_cb;
173962306a36Sopenharmony_ci	icb->request_q_outpointer = cpu_to_le16(0);
174062306a36Sopenharmony_ci	icb->response_q_inpointer = cpu_to_le16(0);
174162306a36Sopenharmony_ci	icb->request_q_length = cpu_to_le16(req->length);
174262306a36Sopenharmony_ci	icb->response_q_length = cpu_to_le16(rsp->length);
174362306a36Sopenharmony_ci	put_unaligned_le64(req->dma, &icb->request_q_address);
174462306a36Sopenharmony_ci	put_unaligned_le64(rsp->dma, &icb->response_q_address);
174562306a36Sopenharmony_ci
174662306a36Sopenharmony_ci	wrt_reg_dword(&reg->req_q_out[0], 0);
174762306a36Sopenharmony_ci	wrt_reg_dword(&reg->rsp_q_in[0], 0);
174862306a36Sopenharmony_ci	wrt_reg_dword(&reg->rsp_q_out[0], 0);
174962306a36Sopenharmony_ci}
175062306a36Sopenharmony_ci
175162306a36Sopenharmony_cistatic int
175262306a36Sopenharmony_ciqla82xx_fw_load_from_blob(struct qla_hw_data *ha)
175362306a36Sopenharmony_ci{
175462306a36Sopenharmony_ci	u64 *ptr64;
175562306a36Sopenharmony_ci	u32 i, flashaddr, size;
175662306a36Sopenharmony_ci	__le64 data;
175762306a36Sopenharmony_ci
175862306a36Sopenharmony_ci	size = (IMAGE_START - BOOTLD_START) / 8;
175962306a36Sopenharmony_ci
176062306a36Sopenharmony_ci	ptr64 = (u64 *)qla82xx_get_bootld_offset(ha);
176162306a36Sopenharmony_ci	flashaddr = BOOTLD_START;
176262306a36Sopenharmony_ci
176362306a36Sopenharmony_ci	for (i = 0; i < size; i++) {
176462306a36Sopenharmony_ci		data = cpu_to_le64(ptr64[i]);
176562306a36Sopenharmony_ci		if (qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8))
176662306a36Sopenharmony_ci			return -EIO;
176762306a36Sopenharmony_ci		flashaddr += 8;
176862306a36Sopenharmony_ci	}
176962306a36Sopenharmony_ci
177062306a36Sopenharmony_ci	flashaddr = FLASH_ADDR_START;
177162306a36Sopenharmony_ci	size = qla82xx_get_fw_size(ha) / 8;
177262306a36Sopenharmony_ci	ptr64 = (u64 *)qla82xx_get_fw_offs(ha);
177362306a36Sopenharmony_ci
177462306a36Sopenharmony_ci	for (i = 0; i < size; i++) {
177562306a36Sopenharmony_ci		data = cpu_to_le64(ptr64[i]);
177662306a36Sopenharmony_ci
177762306a36Sopenharmony_ci		if (qla82xx_pci_mem_write_2M(ha, flashaddr, &data, 8))
177862306a36Sopenharmony_ci			return -EIO;
177962306a36Sopenharmony_ci		flashaddr += 8;
178062306a36Sopenharmony_ci	}
178162306a36Sopenharmony_ci	udelay(100);
178262306a36Sopenharmony_ci
178362306a36Sopenharmony_ci	/* Write a magic value to CAMRAM register
178462306a36Sopenharmony_ci	 * at a specified offset to indicate
178562306a36Sopenharmony_ci	 * that all data is written and
178662306a36Sopenharmony_ci	 * ready for firmware to initialize.
178762306a36Sopenharmony_ci	 */
178862306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CAM_RAM(0x1fc), QLA82XX_BDINFO_MAGIC);
178962306a36Sopenharmony_ci
179062306a36Sopenharmony_ci	read_lock(&ha->hw_lock);
179162306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_PEG_NET_0 + 0x18, 0x1020);
179262306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, 0x80001e);
179362306a36Sopenharmony_ci	read_unlock(&ha->hw_lock);
179462306a36Sopenharmony_ci	return 0;
179562306a36Sopenharmony_ci}
179662306a36Sopenharmony_ci
179762306a36Sopenharmony_cistatic int
179862306a36Sopenharmony_ciqla82xx_set_product_offset(struct qla_hw_data *ha)
179962306a36Sopenharmony_ci{
180062306a36Sopenharmony_ci	struct qla82xx_uri_table_desc *ptab_desc = NULL;
180162306a36Sopenharmony_ci	const uint8_t *unirom = ha->hablob->fw->data;
180262306a36Sopenharmony_ci	uint32_t i;
180362306a36Sopenharmony_ci	uint32_t entries;
180462306a36Sopenharmony_ci	uint32_t flags, file_chiprev, offset;
180562306a36Sopenharmony_ci	uint8_t chiprev = ha->chip_revision;
180662306a36Sopenharmony_ci	/* Hardcoding mn_present flag for P3P */
180762306a36Sopenharmony_ci	int mn_present = 0;
180862306a36Sopenharmony_ci	uint32_t flagbit;
180962306a36Sopenharmony_ci
181062306a36Sopenharmony_ci	ptab_desc = qla82xx_get_table_desc(unirom,
181162306a36Sopenharmony_ci		 QLA82XX_URI_DIR_SECT_PRODUCT_TBL);
181262306a36Sopenharmony_ci	if (!ptab_desc)
181362306a36Sopenharmony_ci		return -1;
181462306a36Sopenharmony_ci
181562306a36Sopenharmony_ci	entries = le32_to_cpu(ptab_desc->num_entries);
181662306a36Sopenharmony_ci
181762306a36Sopenharmony_ci	for (i = 0; i < entries; i++) {
181862306a36Sopenharmony_ci		offset = le32_to_cpu(ptab_desc->findex) +
181962306a36Sopenharmony_ci			(i * le32_to_cpu(ptab_desc->entry_size));
182062306a36Sopenharmony_ci		flags = le32_to_cpu(*((__le32 *)&unirom[offset] +
182162306a36Sopenharmony_ci			QLA82XX_URI_FLAGS_OFF));
182262306a36Sopenharmony_ci		file_chiprev = le32_to_cpu(*((__le32 *)&unirom[offset] +
182362306a36Sopenharmony_ci			QLA82XX_URI_CHIP_REV_OFF));
182462306a36Sopenharmony_ci
182562306a36Sopenharmony_ci		flagbit = mn_present ? 1 : 2;
182662306a36Sopenharmony_ci
182762306a36Sopenharmony_ci		if ((chiprev == file_chiprev) && ((1ULL << flagbit) & flags)) {
182862306a36Sopenharmony_ci			ha->file_prd_off = offset;
182962306a36Sopenharmony_ci			return 0;
183062306a36Sopenharmony_ci		}
183162306a36Sopenharmony_ci	}
183262306a36Sopenharmony_ci	return -1;
183362306a36Sopenharmony_ci}
183462306a36Sopenharmony_ci
183562306a36Sopenharmony_cistatic int
183662306a36Sopenharmony_ciqla82xx_validate_firmware_blob(scsi_qla_host_t *vha, uint8_t fw_type)
183762306a36Sopenharmony_ci{
183862306a36Sopenharmony_ci	uint32_t val;
183962306a36Sopenharmony_ci	uint32_t min_size;
184062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
184162306a36Sopenharmony_ci	const struct firmware *fw = ha->hablob->fw;
184262306a36Sopenharmony_ci
184362306a36Sopenharmony_ci	ha->fw_type = fw_type;
184462306a36Sopenharmony_ci
184562306a36Sopenharmony_ci	if (fw_type == QLA82XX_UNIFIED_ROMIMAGE) {
184662306a36Sopenharmony_ci		if (qla82xx_set_product_offset(ha))
184762306a36Sopenharmony_ci			return -EINVAL;
184862306a36Sopenharmony_ci
184962306a36Sopenharmony_ci		min_size = QLA82XX_URI_FW_MIN_SIZE;
185062306a36Sopenharmony_ci	} else {
185162306a36Sopenharmony_ci		val = get_unaligned_le32(&fw->data[QLA82XX_FW_MAGIC_OFFSET]);
185262306a36Sopenharmony_ci		if (val != QLA82XX_BDINFO_MAGIC)
185362306a36Sopenharmony_ci			return -EINVAL;
185462306a36Sopenharmony_ci
185562306a36Sopenharmony_ci		min_size = QLA82XX_FW_MIN_SIZE;
185662306a36Sopenharmony_ci	}
185762306a36Sopenharmony_ci
185862306a36Sopenharmony_ci	if (fw->size < min_size)
185962306a36Sopenharmony_ci		return -EINVAL;
186062306a36Sopenharmony_ci	return 0;
186162306a36Sopenharmony_ci}
186262306a36Sopenharmony_ci
186362306a36Sopenharmony_cistatic int
186462306a36Sopenharmony_ciqla82xx_check_cmdpeg_state(struct qla_hw_data *ha)
186562306a36Sopenharmony_ci{
186662306a36Sopenharmony_ci	u32 val = 0;
186762306a36Sopenharmony_ci	int retries = 60;
186862306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
186962306a36Sopenharmony_ci
187062306a36Sopenharmony_ci	do {
187162306a36Sopenharmony_ci		read_lock(&ha->hw_lock);
187262306a36Sopenharmony_ci		val = qla82xx_rd_32(ha, CRB_CMDPEG_STATE);
187362306a36Sopenharmony_ci		read_unlock(&ha->hw_lock);
187462306a36Sopenharmony_ci
187562306a36Sopenharmony_ci		switch (val) {
187662306a36Sopenharmony_ci		case PHAN_INITIALIZE_COMPLETE:
187762306a36Sopenharmony_ci		case PHAN_INITIALIZE_ACK:
187862306a36Sopenharmony_ci			return QLA_SUCCESS;
187962306a36Sopenharmony_ci		case PHAN_INITIALIZE_FAILED:
188062306a36Sopenharmony_ci			break;
188162306a36Sopenharmony_ci		default:
188262306a36Sopenharmony_ci			break;
188362306a36Sopenharmony_ci		}
188462306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x00a8,
188562306a36Sopenharmony_ci		    "CRB_CMDPEG_STATE: 0x%x and retries:0x%x.\n",
188662306a36Sopenharmony_ci		    val, retries);
188762306a36Sopenharmony_ci
188862306a36Sopenharmony_ci		msleep(500);
188962306a36Sopenharmony_ci
189062306a36Sopenharmony_ci	} while (--retries);
189162306a36Sopenharmony_ci
189262306a36Sopenharmony_ci	ql_log(ql_log_fatal, vha, 0x00a9,
189362306a36Sopenharmony_ci	    "Cmd Peg initialization failed: 0x%x.\n", val);
189462306a36Sopenharmony_ci
189562306a36Sopenharmony_ci	val = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_PEGTUNE_DONE);
189662306a36Sopenharmony_ci	read_lock(&ha->hw_lock);
189762306a36Sopenharmony_ci	qla82xx_wr_32(ha, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED);
189862306a36Sopenharmony_ci	read_unlock(&ha->hw_lock);
189962306a36Sopenharmony_ci	return QLA_FUNCTION_FAILED;
190062306a36Sopenharmony_ci}
190162306a36Sopenharmony_ci
190262306a36Sopenharmony_cistatic int
190362306a36Sopenharmony_ciqla82xx_check_rcvpeg_state(struct qla_hw_data *ha)
190462306a36Sopenharmony_ci{
190562306a36Sopenharmony_ci	u32 val = 0;
190662306a36Sopenharmony_ci	int retries = 60;
190762306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
190862306a36Sopenharmony_ci
190962306a36Sopenharmony_ci	do {
191062306a36Sopenharmony_ci		read_lock(&ha->hw_lock);
191162306a36Sopenharmony_ci		val = qla82xx_rd_32(ha, CRB_RCVPEG_STATE);
191262306a36Sopenharmony_ci		read_unlock(&ha->hw_lock);
191362306a36Sopenharmony_ci
191462306a36Sopenharmony_ci		switch (val) {
191562306a36Sopenharmony_ci		case PHAN_INITIALIZE_COMPLETE:
191662306a36Sopenharmony_ci		case PHAN_INITIALIZE_ACK:
191762306a36Sopenharmony_ci			return QLA_SUCCESS;
191862306a36Sopenharmony_ci		case PHAN_INITIALIZE_FAILED:
191962306a36Sopenharmony_ci			break;
192062306a36Sopenharmony_ci		default:
192162306a36Sopenharmony_ci			break;
192262306a36Sopenharmony_ci		}
192362306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x00ab,
192462306a36Sopenharmony_ci		    "CRB_RCVPEG_STATE: 0x%x and retries: 0x%x.\n",
192562306a36Sopenharmony_ci		    val, retries);
192662306a36Sopenharmony_ci
192762306a36Sopenharmony_ci		msleep(500);
192862306a36Sopenharmony_ci
192962306a36Sopenharmony_ci	} while (--retries);
193062306a36Sopenharmony_ci
193162306a36Sopenharmony_ci	ql_log(ql_log_fatal, vha, 0x00ac,
193262306a36Sopenharmony_ci	    "Rcv Peg initialization failed: 0x%x.\n", val);
193362306a36Sopenharmony_ci	read_lock(&ha->hw_lock);
193462306a36Sopenharmony_ci	qla82xx_wr_32(ha, CRB_RCVPEG_STATE, PHAN_INITIALIZE_FAILED);
193562306a36Sopenharmony_ci	read_unlock(&ha->hw_lock);
193662306a36Sopenharmony_ci	return QLA_FUNCTION_FAILED;
193762306a36Sopenharmony_ci}
193862306a36Sopenharmony_ci
193962306a36Sopenharmony_ci/* ISR related functions */
194062306a36Sopenharmony_cistatic struct qla82xx_legacy_intr_set legacy_intr[] =
194162306a36Sopenharmony_ci	QLA82XX_LEGACY_INTR_CONFIG;
194262306a36Sopenharmony_ci
194362306a36Sopenharmony_ci/*
194462306a36Sopenharmony_ci * qla82xx_mbx_completion() - Process mailbox command completions.
194562306a36Sopenharmony_ci * @ha: SCSI driver HA context
194662306a36Sopenharmony_ci * @mb0: Mailbox0 register
194762306a36Sopenharmony_ci */
194862306a36Sopenharmony_civoid
194962306a36Sopenharmony_ciqla82xx_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
195062306a36Sopenharmony_ci{
195162306a36Sopenharmony_ci	uint16_t	cnt;
195262306a36Sopenharmony_ci	__le16 __iomem *wptr;
195362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
195462306a36Sopenharmony_ci	struct device_reg_82xx __iomem *reg = &ha->iobase->isp82;
195562306a36Sopenharmony_ci
195662306a36Sopenharmony_ci	wptr = &reg->mailbox_out[1];
195762306a36Sopenharmony_ci
195862306a36Sopenharmony_ci	/* Load return mailbox registers. */
195962306a36Sopenharmony_ci	ha->flags.mbox_int = 1;
196062306a36Sopenharmony_ci	ha->mailbox_out[0] = mb0;
196162306a36Sopenharmony_ci
196262306a36Sopenharmony_ci	for (cnt = 1; cnt < ha->mbx_count; cnt++) {
196362306a36Sopenharmony_ci		ha->mailbox_out[cnt] = rd_reg_word(wptr);
196462306a36Sopenharmony_ci		wptr++;
196562306a36Sopenharmony_ci	}
196662306a36Sopenharmony_ci
196762306a36Sopenharmony_ci	if (!ha->mcp)
196862306a36Sopenharmony_ci		ql_dbg(ql_dbg_async, vha, 0x5053,
196962306a36Sopenharmony_ci		    "MBX pointer ERROR.\n");
197062306a36Sopenharmony_ci}
197162306a36Sopenharmony_ci
197262306a36Sopenharmony_ci/**
197362306a36Sopenharmony_ci * qla82xx_intr_handler() - Process interrupts for the ISP23xx and ISP63xx.
197462306a36Sopenharmony_ci * @irq: interrupt number
197562306a36Sopenharmony_ci * @dev_id: SCSI driver HA context
197662306a36Sopenharmony_ci *
197762306a36Sopenharmony_ci * Called by system whenever the host adapter generates an interrupt.
197862306a36Sopenharmony_ci *
197962306a36Sopenharmony_ci * Returns handled flag.
198062306a36Sopenharmony_ci */
198162306a36Sopenharmony_ciirqreturn_t
198262306a36Sopenharmony_ciqla82xx_intr_handler(int irq, void *dev_id)
198362306a36Sopenharmony_ci{
198462306a36Sopenharmony_ci	scsi_qla_host_t	*vha;
198562306a36Sopenharmony_ci	struct qla_hw_data *ha;
198662306a36Sopenharmony_ci	struct rsp_que *rsp;
198762306a36Sopenharmony_ci	struct device_reg_82xx __iomem *reg;
198862306a36Sopenharmony_ci	int status = 0, status1 = 0;
198962306a36Sopenharmony_ci	unsigned long	flags;
199062306a36Sopenharmony_ci	unsigned long	iter;
199162306a36Sopenharmony_ci	uint32_t	stat = 0;
199262306a36Sopenharmony_ci	uint16_t	mb[8];
199362306a36Sopenharmony_ci
199462306a36Sopenharmony_ci	rsp = (struct rsp_que *) dev_id;
199562306a36Sopenharmony_ci	if (!rsp) {
199662306a36Sopenharmony_ci		ql_log(ql_log_info, NULL, 0xb053,
199762306a36Sopenharmony_ci		    "%s: NULL response queue pointer.\n", __func__);
199862306a36Sopenharmony_ci		return IRQ_NONE;
199962306a36Sopenharmony_ci	}
200062306a36Sopenharmony_ci	ha = rsp->hw;
200162306a36Sopenharmony_ci
200262306a36Sopenharmony_ci	if (!ha->flags.msi_enabled) {
200362306a36Sopenharmony_ci		status = qla82xx_rd_32(ha, ISR_INT_VECTOR);
200462306a36Sopenharmony_ci		if (!(status & ha->nx_legacy_intr.int_vec_bit))
200562306a36Sopenharmony_ci			return IRQ_NONE;
200662306a36Sopenharmony_ci
200762306a36Sopenharmony_ci		status1 = qla82xx_rd_32(ha, ISR_INT_STATE_REG);
200862306a36Sopenharmony_ci		if (!ISR_IS_LEGACY_INTR_TRIGGERED(status1))
200962306a36Sopenharmony_ci			return IRQ_NONE;
201062306a36Sopenharmony_ci	}
201162306a36Sopenharmony_ci
201262306a36Sopenharmony_ci	/* clear the interrupt */
201362306a36Sopenharmony_ci	qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_status_reg, 0xffffffff);
201462306a36Sopenharmony_ci
201562306a36Sopenharmony_ci	/* read twice to ensure write is flushed */
201662306a36Sopenharmony_ci	qla82xx_rd_32(ha, ISR_INT_VECTOR);
201762306a36Sopenharmony_ci	qla82xx_rd_32(ha, ISR_INT_VECTOR);
201862306a36Sopenharmony_ci
201962306a36Sopenharmony_ci	reg = &ha->iobase->isp82;
202062306a36Sopenharmony_ci
202162306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
202262306a36Sopenharmony_ci	vha = pci_get_drvdata(ha->pdev);
202362306a36Sopenharmony_ci	for (iter = 1; iter--; ) {
202462306a36Sopenharmony_ci
202562306a36Sopenharmony_ci		if (rd_reg_dword(&reg->host_int)) {
202662306a36Sopenharmony_ci			stat = rd_reg_dword(&reg->host_status);
202762306a36Sopenharmony_ci
202862306a36Sopenharmony_ci			switch (stat & 0xff) {
202962306a36Sopenharmony_ci			case 0x1:
203062306a36Sopenharmony_ci			case 0x2:
203162306a36Sopenharmony_ci			case 0x10:
203262306a36Sopenharmony_ci			case 0x11:
203362306a36Sopenharmony_ci				qla82xx_mbx_completion(vha, MSW(stat));
203462306a36Sopenharmony_ci				status |= MBX_INTERRUPT;
203562306a36Sopenharmony_ci				break;
203662306a36Sopenharmony_ci			case 0x12:
203762306a36Sopenharmony_ci				mb[0] = MSW(stat);
203862306a36Sopenharmony_ci				mb[1] = rd_reg_word(&reg->mailbox_out[1]);
203962306a36Sopenharmony_ci				mb[2] = rd_reg_word(&reg->mailbox_out[2]);
204062306a36Sopenharmony_ci				mb[3] = rd_reg_word(&reg->mailbox_out[3]);
204162306a36Sopenharmony_ci				qla2x00_async_event(vha, rsp, mb);
204262306a36Sopenharmony_ci				break;
204362306a36Sopenharmony_ci			case 0x13:
204462306a36Sopenharmony_ci				qla24xx_process_response_queue(vha, rsp);
204562306a36Sopenharmony_ci				break;
204662306a36Sopenharmony_ci			default:
204762306a36Sopenharmony_ci				ql_dbg(ql_dbg_async, vha, 0x5054,
204862306a36Sopenharmony_ci				    "Unrecognized interrupt type (%d).\n",
204962306a36Sopenharmony_ci				    stat & 0xff);
205062306a36Sopenharmony_ci				break;
205162306a36Sopenharmony_ci			}
205262306a36Sopenharmony_ci		}
205362306a36Sopenharmony_ci		wrt_reg_dword(&reg->host_int, 0);
205462306a36Sopenharmony_ci	}
205562306a36Sopenharmony_ci
205662306a36Sopenharmony_ci	qla2x00_handle_mbx_completion(ha, status);
205762306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
205862306a36Sopenharmony_ci
205962306a36Sopenharmony_ci	if (!ha->flags.msi_enabled)
206062306a36Sopenharmony_ci		qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);
206162306a36Sopenharmony_ci
206262306a36Sopenharmony_ci	return IRQ_HANDLED;
206362306a36Sopenharmony_ci}
206462306a36Sopenharmony_ci
206562306a36Sopenharmony_ciirqreturn_t
206662306a36Sopenharmony_ciqla82xx_msix_default(int irq, void *dev_id)
206762306a36Sopenharmony_ci{
206862306a36Sopenharmony_ci	scsi_qla_host_t	*vha;
206962306a36Sopenharmony_ci	struct qla_hw_data *ha;
207062306a36Sopenharmony_ci	struct rsp_que *rsp;
207162306a36Sopenharmony_ci	struct device_reg_82xx __iomem *reg;
207262306a36Sopenharmony_ci	int status = 0;
207362306a36Sopenharmony_ci	unsigned long flags;
207462306a36Sopenharmony_ci	uint32_t stat = 0;
207562306a36Sopenharmony_ci	uint32_t host_int = 0;
207662306a36Sopenharmony_ci	uint16_t mb[8];
207762306a36Sopenharmony_ci
207862306a36Sopenharmony_ci	rsp = (struct rsp_que *) dev_id;
207962306a36Sopenharmony_ci	if (!rsp) {
208062306a36Sopenharmony_ci		printk(KERN_INFO
208162306a36Sopenharmony_ci			"%s(): NULL response queue pointer.\n", __func__);
208262306a36Sopenharmony_ci		return IRQ_NONE;
208362306a36Sopenharmony_ci	}
208462306a36Sopenharmony_ci	ha = rsp->hw;
208562306a36Sopenharmony_ci
208662306a36Sopenharmony_ci	reg = &ha->iobase->isp82;
208762306a36Sopenharmony_ci
208862306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
208962306a36Sopenharmony_ci	vha = pci_get_drvdata(ha->pdev);
209062306a36Sopenharmony_ci	do {
209162306a36Sopenharmony_ci		host_int = rd_reg_dword(&reg->host_int);
209262306a36Sopenharmony_ci		if (qla2x00_check_reg32_for_disconnect(vha, host_int))
209362306a36Sopenharmony_ci			break;
209462306a36Sopenharmony_ci		if (host_int) {
209562306a36Sopenharmony_ci			stat = rd_reg_dword(&reg->host_status);
209662306a36Sopenharmony_ci
209762306a36Sopenharmony_ci			switch (stat & 0xff) {
209862306a36Sopenharmony_ci			case 0x1:
209962306a36Sopenharmony_ci			case 0x2:
210062306a36Sopenharmony_ci			case 0x10:
210162306a36Sopenharmony_ci			case 0x11:
210262306a36Sopenharmony_ci				qla82xx_mbx_completion(vha, MSW(stat));
210362306a36Sopenharmony_ci				status |= MBX_INTERRUPT;
210462306a36Sopenharmony_ci				break;
210562306a36Sopenharmony_ci			case 0x12:
210662306a36Sopenharmony_ci				mb[0] = MSW(stat);
210762306a36Sopenharmony_ci				mb[1] = rd_reg_word(&reg->mailbox_out[1]);
210862306a36Sopenharmony_ci				mb[2] = rd_reg_word(&reg->mailbox_out[2]);
210962306a36Sopenharmony_ci				mb[3] = rd_reg_word(&reg->mailbox_out[3]);
211062306a36Sopenharmony_ci				qla2x00_async_event(vha, rsp, mb);
211162306a36Sopenharmony_ci				break;
211262306a36Sopenharmony_ci			case 0x13:
211362306a36Sopenharmony_ci				qla24xx_process_response_queue(vha, rsp);
211462306a36Sopenharmony_ci				break;
211562306a36Sopenharmony_ci			default:
211662306a36Sopenharmony_ci				ql_dbg(ql_dbg_async, vha, 0x5041,
211762306a36Sopenharmony_ci				    "Unrecognized interrupt type (%d).\n",
211862306a36Sopenharmony_ci				    stat & 0xff);
211962306a36Sopenharmony_ci				break;
212062306a36Sopenharmony_ci			}
212162306a36Sopenharmony_ci		}
212262306a36Sopenharmony_ci		wrt_reg_dword(&reg->host_int, 0);
212362306a36Sopenharmony_ci	} while (0);
212462306a36Sopenharmony_ci
212562306a36Sopenharmony_ci	qla2x00_handle_mbx_completion(ha, status);
212662306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
212762306a36Sopenharmony_ci
212862306a36Sopenharmony_ci	return IRQ_HANDLED;
212962306a36Sopenharmony_ci}
213062306a36Sopenharmony_ci
213162306a36Sopenharmony_ciirqreturn_t
213262306a36Sopenharmony_ciqla82xx_msix_rsp_q(int irq, void *dev_id)
213362306a36Sopenharmony_ci{
213462306a36Sopenharmony_ci	scsi_qla_host_t	*vha;
213562306a36Sopenharmony_ci	struct qla_hw_data *ha;
213662306a36Sopenharmony_ci	struct rsp_que *rsp;
213762306a36Sopenharmony_ci	struct device_reg_82xx __iomem *reg;
213862306a36Sopenharmony_ci	unsigned long flags;
213962306a36Sopenharmony_ci	uint32_t host_int = 0;
214062306a36Sopenharmony_ci
214162306a36Sopenharmony_ci	rsp = (struct rsp_que *) dev_id;
214262306a36Sopenharmony_ci	if (!rsp) {
214362306a36Sopenharmony_ci		printk(KERN_INFO
214462306a36Sopenharmony_ci			"%s(): NULL response queue pointer.\n", __func__);
214562306a36Sopenharmony_ci		return IRQ_NONE;
214662306a36Sopenharmony_ci	}
214762306a36Sopenharmony_ci
214862306a36Sopenharmony_ci	ha = rsp->hw;
214962306a36Sopenharmony_ci	reg = &ha->iobase->isp82;
215062306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
215162306a36Sopenharmony_ci	vha = pci_get_drvdata(ha->pdev);
215262306a36Sopenharmony_ci	host_int = rd_reg_dword(&reg->host_int);
215362306a36Sopenharmony_ci	if (qla2x00_check_reg32_for_disconnect(vha, host_int))
215462306a36Sopenharmony_ci		goto out;
215562306a36Sopenharmony_ci	qla24xx_process_response_queue(vha, rsp);
215662306a36Sopenharmony_ci	wrt_reg_dword(&reg->host_int, 0);
215762306a36Sopenharmony_ciout:
215862306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
215962306a36Sopenharmony_ci	return IRQ_HANDLED;
216062306a36Sopenharmony_ci}
216162306a36Sopenharmony_ci
216262306a36Sopenharmony_civoid
216362306a36Sopenharmony_ciqla82xx_poll(int irq, void *dev_id)
216462306a36Sopenharmony_ci{
216562306a36Sopenharmony_ci	scsi_qla_host_t	*vha;
216662306a36Sopenharmony_ci	struct qla_hw_data *ha;
216762306a36Sopenharmony_ci	struct rsp_que *rsp;
216862306a36Sopenharmony_ci	struct device_reg_82xx __iomem *reg;
216962306a36Sopenharmony_ci	uint32_t stat;
217062306a36Sopenharmony_ci	uint32_t host_int = 0;
217162306a36Sopenharmony_ci	uint16_t mb[8];
217262306a36Sopenharmony_ci	unsigned long flags;
217362306a36Sopenharmony_ci
217462306a36Sopenharmony_ci	rsp = (struct rsp_que *) dev_id;
217562306a36Sopenharmony_ci	if (!rsp) {
217662306a36Sopenharmony_ci		printk(KERN_INFO
217762306a36Sopenharmony_ci			"%s(): NULL response queue pointer.\n", __func__);
217862306a36Sopenharmony_ci		return;
217962306a36Sopenharmony_ci	}
218062306a36Sopenharmony_ci	ha = rsp->hw;
218162306a36Sopenharmony_ci
218262306a36Sopenharmony_ci	reg = &ha->iobase->isp82;
218362306a36Sopenharmony_ci	spin_lock_irqsave(&ha->hardware_lock, flags);
218462306a36Sopenharmony_ci	vha = pci_get_drvdata(ha->pdev);
218562306a36Sopenharmony_ci
218662306a36Sopenharmony_ci	host_int = rd_reg_dword(&reg->host_int);
218762306a36Sopenharmony_ci	if (qla2x00_check_reg32_for_disconnect(vha, host_int))
218862306a36Sopenharmony_ci		goto out;
218962306a36Sopenharmony_ci	if (host_int) {
219062306a36Sopenharmony_ci		stat = rd_reg_dword(&reg->host_status);
219162306a36Sopenharmony_ci		switch (stat & 0xff) {
219262306a36Sopenharmony_ci		case 0x1:
219362306a36Sopenharmony_ci		case 0x2:
219462306a36Sopenharmony_ci		case 0x10:
219562306a36Sopenharmony_ci		case 0x11:
219662306a36Sopenharmony_ci			qla82xx_mbx_completion(vha, MSW(stat));
219762306a36Sopenharmony_ci			break;
219862306a36Sopenharmony_ci		case 0x12:
219962306a36Sopenharmony_ci			mb[0] = MSW(stat);
220062306a36Sopenharmony_ci			mb[1] = rd_reg_word(&reg->mailbox_out[1]);
220162306a36Sopenharmony_ci			mb[2] = rd_reg_word(&reg->mailbox_out[2]);
220262306a36Sopenharmony_ci			mb[3] = rd_reg_word(&reg->mailbox_out[3]);
220362306a36Sopenharmony_ci			qla2x00_async_event(vha, rsp, mb);
220462306a36Sopenharmony_ci			break;
220562306a36Sopenharmony_ci		case 0x13:
220662306a36Sopenharmony_ci			qla24xx_process_response_queue(vha, rsp);
220762306a36Sopenharmony_ci			break;
220862306a36Sopenharmony_ci		default:
220962306a36Sopenharmony_ci			ql_dbg(ql_dbg_p3p, vha, 0xb013,
221062306a36Sopenharmony_ci			    "Unrecognized interrupt type (%d).\n",
221162306a36Sopenharmony_ci			    stat * 0xff);
221262306a36Sopenharmony_ci			break;
221362306a36Sopenharmony_ci		}
221462306a36Sopenharmony_ci		wrt_reg_dword(&reg->host_int, 0);
221562306a36Sopenharmony_ci	}
221662306a36Sopenharmony_ciout:
221762306a36Sopenharmony_ci	spin_unlock_irqrestore(&ha->hardware_lock, flags);
221862306a36Sopenharmony_ci}
221962306a36Sopenharmony_ci
222062306a36Sopenharmony_civoid
222162306a36Sopenharmony_ciqla82xx_enable_intrs(struct qla_hw_data *ha)
222262306a36Sopenharmony_ci{
222362306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
222462306a36Sopenharmony_ci
222562306a36Sopenharmony_ci	qla82xx_mbx_intr_enable(vha);
222662306a36Sopenharmony_ci	spin_lock_irq(&ha->hardware_lock);
222762306a36Sopenharmony_ci	if (IS_QLA8044(ha))
222862306a36Sopenharmony_ci		qla8044_wr_reg(ha, LEG_INTR_MASK_OFFSET, 0);
222962306a36Sopenharmony_ci	else
223062306a36Sopenharmony_ci		qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0xfbff);
223162306a36Sopenharmony_ci	spin_unlock_irq(&ha->hardware_lock);
223262306a36Sopenharmony_ci	ha->interrupts_on = 1;
223362306a36Sopenharmony_ci}
223462306a36Sopenharmony_ci
223562306a36Sopenharmony_civoid
223662306a36Sopenharmony_ciqla82xx_disable_intrs(struct qla_hw_data *ha)
223762306a36Sopenharmony_ci{
223862306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
223962306a36Sopenharmony_ci
224062306a36Sopenharmony_ci	if (ha->interrupts_on)
224162306a36Sopenharmony_ci		qla82xx_mbx_intr_disable(vha);
224262306a36Sopenharmony_ci
224362306a36Sopenharmony_ci	spin_lock_irq(&ha->hardware_lock);
224462306a36Sopenharmony_ci	if (IS_QLA8044(ha))
224562306a36Sopenharmony_ci		qla8044_wr_reg(ha, LEG_INTR_MASK_OFFSET, 1);
224662306a36Sopenharmony_ci	else
224762306a36Sopenharmony_ci		qla82xx_wr_32(ha, ha->nx_legacy_intr.tgt_mask_reg, 0x0400);
224862306a36Sopenharmony_ci	spin_unlock_irq(&ha->hardware_lock);
224962306a36Sopenharmony_ci	ha->interrupts_on = 0;
225062306a36Sopenharmony_ci}
225162306a36Sopenharmony_ci
225262306a36Sopenharmony_civoid qla82xx_init_flags(struct qla_hw_data *ha)
225362306a36Sopenharmony_ci{
225462306a36Sopenharmony_ci	struct qla82xx_legacy_intr_set *nx_legacy_intr;
225562306a36Sopenharmony_ci
225662306a36Sopenharmony_ci	/* ISP 8021 initializations */
225762306a36Sopenharmony_ci	rwlock_init(&ha->hw_lock);
225862306a36Sopenharmony_ci	ha->qdr_sn_window = -1;
225962306a36Sopenharmony_ci	ha->ddr_mn_window = -1;
226062306a36Sopenharmony_ci	ha->curr_window = 255;
226162306a36Sopenharmony_ci	ha->portnum = PCI_FUNC(ha->pdev->devfn);
226262306a36Sopenharmony_ci	nx_legacy_intr = &legacy_intr[ha->portnum];
226362306a36Sopenharmony_ci	ha->nx_legacy_intr.int_vec_bit = nx_legacy_intr->int_vec_bit;
226462306a36Sopenharmony_ci	ha->nx_legacy_intr.tgt_status_reg = nx_legacy_intr->tgt_status_reg;
226562306a36Sopenharmony_ci	ha->nx_legacy_intr.tgt_mask_reg = nx_legacy_intr->tgt_mask_reg;
226662306a36Sopenharmony_ci	ha->nx_legacy_intr.pci_int_reg = nx_legacy_intr->pci_int_reg;
226762306a36Sopenharmony_ci}
226862306a36Sopenharmony_ci
226962306a36Sopenharmony_cistatic inline void
227062306a36Sopenharmony_ciqla82xx_set_idc_version(scsi_qla_host_t *vha)
227162306a36Sopenharmony_ci{
227262306a36Sopenharmony_ci	int idc_ver;
227362306a36Sopenharmony_ci	uint32_t drv_active;
227462306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
227562306a36Sopenharmony_ci
227662306a36Sopenharmony_ci	drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
227762306a36Sopenharmony_ci	if (drv_active == (QLA82XX_DRV_ACTIVE << (ha->portnum * 4))) {
227862306a36Sopenharmony_ci		qla82xx_wr_32(ha, QLA82XX_CRB_DRV_IDC_VERSION,
227962306a36Sopenharmony_ci		    QLA82XX_IDC_VERSION);
228062306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0xb082,
228162306a36Sopenharmony_ci		    "IDC version updated to %d\n", QLA82XX_IDC_VERSION);
228262306a36Sopenharmony_ci	} else {
228362306a36Sopenharmony_ci		idc_ver = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_IDC_VERSION);
228462306a36Sopenharmony_ci		if (idc_ver != QLA82XX_IDC_VERSION)
228562306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0xb083,
228662306a36Sopenharmony_ci			    "qla2xxx driver IDC version %d is not compatible "
228762306a36Sopenharmony_ci			    "with IDC version %d of the other drivers\n",
228862306a36Sopenharmony_ci			    QLA82XX_IDC_VERSION, idc_ver);
228962306a36Sopenharmony_ci	}
229062306a36Sopenharmony_ci}
229162306a36Sopenharmony_ci
229262306a36Sopenharmony_ciinline void
229362306a36Sopenharmony_ciqla82xx_set_drv_active(scsi_qla_host_t *vha)
229462306a36Sopenharmony_ci{
229562306a36Sopenharmony_ci	uint32_t drv_active;
229662306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
229762306a36Sopenharmony_ci
229862306a36Sopenharmony_ci	drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
229962306a36Sopenharmony_ci
230062306a36Sopenharmony_ci	/* If reset value is all FF's, initialize DRV_ACTIVE */
230162306a36Sopenharmony_ci	if (drv_active == 0xffffffff) {
230262306a36Sopenharmony_ci		qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE,
230362306a36Sopenharmony_ci			QLA82XX_DRV_NOT_ACTIVE);
230462306a36Sopenharmony_ci		drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
230562306a36Sopenharmony_ci	}
230662306a36Sopenharmony_ci	drv_active |= (QLA82XX_DRV_ACTIVE << (ha->portnum * 4));
230762306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active);
230862306a36Sopenharmony_ci}
230962306a36Sopenharmony_ci
231062306a36Sopenharmony_ciinline void
231162306a36Sopenharmony_ciqla82xx_clear_drv_active(struct qla_hw_data *ha)
231262306a36Sopenharmony_ci{
231362306a36Sopenharmony_ci	uint32_t drv_active;
231462306a36Sopenharmony_ci
231562306a36Sopenharmony_ci	drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
231662306a36Sopenharmony_ci	drv_active &= ~(QLA82XX_DRV_ACTIVE << (ha->portnum * 4));
231762306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_DRV_ACTIVE, drv_active);
231862306a36Sopenharmony_ci}
231962306a36Sopenharmony_ci
232062306a36Sopenharmony_cistatic inline int
232162306a36Sopenharmony_ciqla82xx_need_reset(struct qla_hw_data *ha)
232262306a36Sopenharmony_ci{
232362306a36Sopenharmony_ci	uint32_t drv_state;
232462306a36Sopenharmony_ci	int rval;
232562306a36Sopenharmony_ci
232662306a36Sopenharmony_ci	if (ha->flags.nic_core_reset_owner)
232762306a36Sopenharmony_ci		return 1;
232862306a36Sopenharmony_ci	else {
232962306a36Sopenharmony_ci		drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
233062306a36Sopenharmony_ci		rval = drv_state & (QLA82XX_DRVST_RST_RDY << (ha->portnum * 4));
233162306a36Sopenharmony_ci		return rval;
233262306a36Sopenharmony_ci	}
233362306a36Sopenharmony_ci}
233462306a36Sopenharmony_ci
233562306a36Sopenharmony_cistatic inline void
233662306a36Sopenharmony_ciqla82xx_set_rst_ready(struct qla_hw_data *ha)
233762306a36Sopenharmony_ci{
233862306a36Sopenharmony_ci	uint32_t drv_state;
233962306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
234062306a36Sopenharmony_ci
234162306a36Sopenharmony_ci	drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
234262306a36Sopenharmony_ci
234362306a36Sopenharmony_ci	/* If reset value is all FF's, initialize DRV_STATE */
234462306a36Sopenharmony_ci	if (drv_state == 0xffffffff) {
234562306a36Sopenharmony_ci		qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, QLA82XX_DRVST_NOT_RDY);
234662306a36Sopenharmony_ci		drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
234762306a36Sopenharmony_ci	}
234862306a36Sopenharmony_ci	drv_state |= (QLA82XX_DRVST_RST_RDY << (ha->portnum * 4));
234962306a36Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x00bb,
235062306a36Sopenharmony_ci	    "drv_state = 0x%08x.\n", drv_state);
235162306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state);
235262306a36Sopenharmony_ci}
235362306a36Sopenharmony_ci
235462306a36Sopenharmony_cistatic inline void
235562306a36Sopenharmony_ciqla82xx_clear_rst_ready(struct qla_hw_data *ha)
235662306a36Sopenharmony_ci{
235762306a36Sopenharmony_ci	uint32_t drv_state;
235862306a36Sopenharmony_ci
235962306a36Sopenharmony_ci	drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
236062306a36Sopenharmony_ci	drv_state &= ~(QLA82XX_DRVST_RST_RDY << (ha->portnum * 4));
236162306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, drv_state);
236262306a36Sopenharmony_ci}
236362306a36Sopenharmony_ci
236462306a36Sopenharmony_cistatic inline void
236562306a36Sopenharmony_ciqla82xx_set_qsnt_ready(struct qla_hw_data *ha)
236662306a36Sopenharmony_ci{
236762306a36Sopenharmony_ci	uint32_t qsnt_state;
236862306a36Sopenharmony_ci
236962306a36Sopenharmony_ci	qsnt_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
237062306a36Sopenharmony_ci	qsnt_state |= (QLA82XX_DRVST_QSNT_RDY << (ha->portnum * 4));
237162306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state);
237262306a36Sopenharmony_ci}
237362306a36Sopenharmony_ci
237462306a36Sopenharmony_civoid
237562306a36Sopenharmony_ciqla82xx_clear_qsnt_ready(scsi_qla_host_t *vha)
237662306a36Sopenharmony_ci{
237762306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
237862306a36Sopenharmony_ci	uint32_t qsnt_state;
237962306a36Sopenharmony_ci
238062306a36Sopenharmony_ci	qsnt_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
238162306a36Sopenharmony_ci	qsnt_state &= ~(QLA82XX_DRVST_QSNT_RDY << (ha->portnum * 4));
238262306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_DRV_STATE, qsnt_state);
238362306a36Sopenharmony_ci}
238462306a36Sopenharmony_ci
238562306a36Sopenharmony_cistatic int
238662306a36Sopenharmony_ciqla82xx_load_fw(scsi_qla_host_t *vha)
238762306a36Sopenharmony_ci{
238862306a36Sopenharmony_ci	int rst;
238962306a36Sopenharmony_ci	struct fw_blob *blob;
239062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
239162306a36Sopenharmony_ci
239262306a36Sopenharmony_ci	if (qla82xx_pinit_from_rom(vha) != QLA_SUCCESS) {
239362306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0x009f,
239462306a36Sopenharmony_ci		    "Error during CRB initialization.\n");
239562306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
239662306a36Sopenharmony_ci	}
239762306a36Sopenharmony_ci	udelay(500);
239862306a36Sopenharmony_ci
239962306a36Sopenharmony_ci	/* Bring QM and CAMRAM out of reset */
240062306a36Sopenharmony_ci	rst = qla82xx_rd_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET);
240162306a36Sopenharmony_ci	rst &= ~((1 << 28) | (1 << 24));
240262306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_ROMUSB_GLB_SW_RESET, rst);
240362306a36Sopenharmony_ci
240462306a36Sopenharmony_ci	/*
240562306a36Sopenharmony_ci	 * FW Load priority:
240662306a36Sopenharmony_ci	 * 1) Operational firmware residing in flash.
240762306a36Sopenharmony_ci	 * 2) Firmware via request-firmware interface (.bin file).
240862306a36Sopenharmony_ci	 */
240962306a36Sopenharmony_ci	if (ql2xfwloadbin == 2)
241062306a36Sopenharmony_ci		goto try_blob_fw;
241162306a36Sopenharmony_ci
241262306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x00a0,
241362306a36Sopenharmony_ci	    "Attempting to load firmware from flash.\n");
241462306a36Sopenharmony_ci
241562306a36Sopenharmony_ci	if (qla82xx_fw_load_from_flash(ha) == QLA_SUCCESS) {
241662306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x00a1,
241762306a36Sopenharmony_ci		    "Firmware loaded successfully from flash.\n");
241862306a36Sopenharmony_ci		return QLA_SUCCESS;
241962306a36Sopenharmony_ci	} else {
242062306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x0108,
242162306a36Sopenharmony_ci		    "Firmware load from flash failed.\n");
242262306a36Sopenharmony_ci	}
242362306a36Sopenharmony_ci
242462306a36Sopenharmony_citry_blob_fw:
242562306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x00a2,
242662306a36Sopenharmony_ci	    "Attempting to load firmware from blob.\n");
242762306a36Sopenharmony_ci
242862306a36Sopenharmony_ci	/* Load firmware blob. */
242962306a36Sopenharmony_ci	blob = ha->hablob = qla2x00_request_firmware(vha);
243062306a36Sopenharmony_ci	if (!blob) {
243162306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0x00a3,
243262306a36Sopenharmony_ci		    "Firmware image not present.\n");
243362306a36Sopenharmony_ci		goto fw_load_failed;
243462306a36Sopenharmony_ci	}
243562306a36Sopenharmony_ci
243662306a36Sopenharmony_ci	/* Validating firmware blob */
243762306a36Sopenharmony_ci	if (qla82xx_validate_firmware_blob(vha,
243862306a36Sopenharmony_ci		QLA82XX_FLASH_ROMIMAGE)) {
243962306a36Sopenharmony_ci		/* Fallback to URI format */
244062306a36Sopenharmony_ci		if (qla82xx_validate_firmware_blob(vha,
244162306a36Sopenharmony_ci			QLA82XX_UNIFIED_ROMIMAGE)) {
244262306a36Sopenharmony_ci			ql_log(ql_log_fatal, vha, 0x00a4,
244362306a36Sopenharmony_ci			    "No valid firmware image found.\n");
244462306a36Sopenharmony_ci			return QLA_FUNCTION_FAILED;
244562306a36Sopenharmony_ci		}
244662306a36Sopenharmony_ci	}
244762306a36Sopenharmony_ci
244862306a36Sopenharmony_ci	if (qla82xx_fw_load_from_blob(ha) == QLA_SUCCESS) {
244962306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x00a5,
245062306a36Sopenharmony_ci		    "Firmware loaded successfully from binary blob.\n");
245162306a36Sopenharmony_ci		return QLA_SUCCESS;
245262306a36Sopenharmony_ci	}
245362306a36Sopenharmony_ci
245462306a36Sopenharmony_ci	ql_log(ql_log_fatal, vha, 0x00a6,
245562306a36Sopenharmony_ci	       "Firmware load failed for binary blob.\n");
245662306a36Sopenharmony_ci	blob->fw = NULL;
245762306a36Sopenharmony_ci	blob = NULL;
245862306a36Sopenharmony_ci
245962306a36Sopenharmony_cifw_load_failed:
246062306a36Sopenharmony_ci	return QLA_FUNCTION_FAILED;
246162306a36Sopenharmony_ci}
246262306a36Sopenharmony_ci
246362306a36Sopenharmony_ciint
246462306a36Sopenharmony_ciqla82xx_start_firmware(scsi_qla_host_t *vha)
246562306a36Sopenharmony_ci{
246662306a36Sopenharmony_ci	uint16_t      lnk;
246762306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
246862306a36Sopenharmony_ci
246962306a36Sopenharmony_ci	/* scrub dma mask expansion register */
247062306a36Sopenharmony_ci	qla82xx_wr_32(ha, CRB_DMA_SHIFT, QLA82XX_DMA_SHIFT_VALUE);
247162306a36Sopenharmony_ci
247262306a36Sopenharmony_ci	/* Put both the PEG CMD and RCV PEG to default state
247362306a36Sopenharmony_ci	 * of 0 before resetting the hardware
247462306a36Sopenharmony_ci	 */
247562306a36Sopenharmony_ci	qla82xx_wr_32(ha, CRB_CMDPEG_STATE, 0);
247662306a36Sopenharmony_ci	qla82xx_wr_32(ha, CRB_RCVPEG_STATE, 0);
247762306a36Sopenharmony_ci
247862306a36Sopenharmony_ci	/* Overwrite stale initialization register values */
247962306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS1, 0);
248062306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_PEG_HALT_STATUS2, 0);
248162306a36Sopenharmony_ci
248262306a36Sopenharmony_ci	if (qla82xx_load_fw(vha) != QLA_SUCCESS) {
248362306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0x00a7,
248462306a36Sopenharmony_ci		    "Error trying to start fw.\n");
248562306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
248662306a36Sopenharmony_ci	}
248762306a36Sopenharmony_ci
248862306a36Sopenharmony_ci	/* Handshake with the card before we register the devices. */
248962306a36Sopenharmony_ci	if (qla82xx_check_cmdpeg_state(ha) != QLA_SUCCESS) {
249062306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0x00aa,
249162306a36Sopenharmony_ci		    "Error during card handshake.\n");
249262306a36Sopenharmony_ci		return QLA_FUNCTION_FAILED;
249362306a36Sopenharmony_ci	}
249462306a36Sopenharmony_ci
249562306a36Sopenharmony_ci	/* Negotiated Link width */
249662306a36Sopenharmony_ci	pcie_capability_read_word(ha->pdev, PCI_EXP_LNKSTA, &lnk);
249762306a36Sopenharmony_ci	ha->link_width = (lnk >> 4) & 0x3f;
249862306a36Sopenharmony_ci
249962306a36Sopenharmony_ci	/* Synchronize with Receive peg */
250062306a36Sopenharmony_ci	return qla82xx_check_rcvpeg_state(ha);
250162306a36Sopenharmony_ci}
250262306a36Sopenharmony_ci
250362306a36Sopenharmony_cistatic __le32 *
250462306a36Sopenharmony_ciqla82xx_read_flash_data(scsi_qla_host_t *vha, __le32 *dwptr, uint32_t faddr,
250562306a36Sopenharmony_ci	uint32_t length)
250662306a36Sopenharmony_ci{
250762306a36Sopenharmony_ci	uint32_t i;
250862306a36Sopenharmony_ci	uint32_t val;
250962306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
251062306a36Sopenharmony_ci
251162306a36Sopenharmony_ci	/* Dword reads to flash. */
251262306a36Sopenharmony_ci	for (i = 0; i < length/4; i++, faddr += 4) {
251362306a36Sopenharmony_ci		if (qla82xx_rom_fast_read(ha, faddr, &val)) {
251462306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x0106,
251562306a36Sopenharmony_ci			    "Do ROM fast read failed.\n");
251662306a36Sopenharmony_ci			goto done_read;
251762306a36Sopenharmony_ci		}
251862306a36Sopenharmony_ci		dwptr[i] = cpu_to_le32(val);
251962306a36Sopenharmony_ci	}
252062306a36Sopenharmony_cidone_read:
252162306a36Sopenharmony_ci	return dwptr;
252262306a36Sopenharmony_ci}
252362306a36Sopenharmony_ci
252462306a36Sopenharmony_cistatic int
252562306a36Sopenharmony_ciqla82xx_unprotect_flash(struct qla_hw_data *ha)
252662306a36Sopenharmony_ci{
252762306a36Sopenharmony_ci	int ret;
252862306a36Sopenharmony_ci	uint32_t val;
252962306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
253062306a36Sopenharmony_ci
253162306a36Sopenharmony_ci	ret = ql82xx_rom_lock_d(ha);
253262306a36Sopenharmony_ci	if (ret < 0) {
253362306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb014,
253462306a36Sopenharmony_ci		    "ROM Lock failed.\n");
253562306a36Sopenharmony_ci		return ret;
253662306a36Sopenharmony_ci	}
253762306a36Sopenharmony_ci
253862306a36Sopenharmony_ci	ret = qla82xx_read_status_reg(ha, &val);
253962306a36Sopenharmony_ci	if (ret < 0)
254062306a36Sopenharmony_ci		goto done_unprotect;
254162306a36Sopenharmony_ci
254262306a36Sopenharmony_ci	val &= ~(BLOCK_PROTECT_BITS << 2);
254362306a36Sopenharmony_ci	ret = qla82xx_write_status_reg(ha, val);
254462306a36Sopenharmony_ci	if (ret < 0) {
254562306a36Sopenharmony_ci		val |= (BLOCK_PROTECT_BITS << 2);
254662306a36Sopenharmony_ci		qla82xx_write_status_reg(ha, val);
254762306a36Sopenharmony_ci	}
254862306a36Sopenharmony_ci
254962306a36Sopenharmony_ci	if (qla82xx_write_disable_flash(ha) != 0)
255062306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb015,
255162306a36Sopenharmony_ci		    "Write disable failed.\n");
255262306a36Sopenharmony_ci
255362306a36Sopenharmony_cidone_unprotect:
255462306a36Sopenharmony_ci	qla82xx_rom_unlock(ha);
255562306a36Sopenharmony_ci	return ret;
255662306a36Sopenharmony_ci}
255762306a36Sopenharmony_ci
255862306a36Sopenharmony_cistatic int
255962306a36Sopenharmony_ciqla82xx_protect_flash(struct qla_hw_data *ha)
256062306a36Sopenharmony_ci{
256162306a36Sopenharmony_ci	int ret;
256262306a36Sopenharmony_ci	uint32_t val;
256362306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
256462306a36Sopenharmony_ci
256562306a36Sopenharmony_ci	ret = ql82xx_rom_lock_d(ha);
256662306a36Sopenharmony_ci	if (ret < 0) {
256762306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb016,
256862306a36Sopenharmony_ci		    "ROM Lock failed.\n");
256962306a36Sopenharmony_ci		return ret;
257062306a36Sopenharmony_ci	}
257162306a36Sopenharmony_ci
257262306a36Sopenharmony_ci	ret = qla82xx_read_status_reg(ha, &val);
257362306a36Sopenharmony_ci	if (ret < 0)
257462306a36Sopenharmony_ci		goto done_protect;
257562306a36Sopenharmony_ci
257662306a36Sopenharmony_ci	val |= (BLOCK_PROTECT_BITS << 2);
257762306a36Sopenharmony_ci	/* LOCK all sectors */
257862306a36Sopenharmony_ci	ret = qla82xx_write_status_reg(ha, val);
257962306a36Sopenharmony_ci	if (ret < 0)
258062306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb017,
258162306a36Sopenharmony_ci		    "Write status register failed.\n");
258262306a36Sopenharmony_ci
258362306a36Sopenharmony_ci	if (qla82xx_write_disable_flash(ha) != 0)
258462306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb018,
258562306a36Sopenharmony_ci		    "Write disable failed.\n");
258662306a36Sopenharmony_cidone_protect:
258762306a36Sopenharmony_ci	qla82xx_rom_unlock(ha);
258862306a36Sopenharmony_ci	return ret;
258962306a36Sopenharmony_ci}
259062306a36Sopenharmony_ci
259162306a36Sopenharmony_cistatic int
259262306a36Sopenharmony_ciqla82xx_erase_sector(struct qla_hw_data *ha, int addr)
259362306a36Sopenharmony_ci{
259462306a36Sopenharmony_ci	int ret = 0;
259562306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
259662306a36Sopenharmony_ci
259762306a36Sopenharmony_ci	ret = ql82xx_rom_lock_d(ha);
259862306a36Sopenharmony_ci	if (ret < 0) {
259962306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb019,
260062306a36Sopenharmony_ci		    "ROM Lock failed.\n");
260162306a36Sopenharmony_ci		return ret;
260262306a36Sopenharmony_ci	}
260362306a36Sopenharmony_ci
260462306a36Sopenharmony_ci	qla82xx_flash_set_write_enable(ha);
260562306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ADDRESS, addr);
260662306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_ABYTE_CNT, 3);
260762306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_ROMUSB_ROM_INSTR_OPCODE, M25P_INSTR_SE);
260862306a36Sopenharmony_ci
260962306a36Sopenharmony_ci	if (qla82xx_wait_rom_done(ha)) {
261062306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb01a,
261162306a36Sopenharmony_ci		    "Error waiting for rom done.\n");
261262306a36Sopenharmony_ci		ret = -1;
261362306a36Sopenharmony_ci		goto done;
261462306a36Sopenharmony_ci	}
261562306a36Sopenharmony_ci	ret = qla82xx_flash_wait_write_finish(ha);
261662306a36Sopenharmony_cidone:
261762306a36Sopenharmony_ci	qla82xx_rom_unlock(ha);
261862306a36Sopenharmony_ci	return ret;
261962306a36Sopenharmony_ci}
262062306a36Sopenharmony_ci
262162306a36Sopenharmony_ci/*
262262306a36Sopenharmony_ci * Address and length are byte address
262362306a36Sopenharmony_ci */
262462306a36Sopenharmony_civoid *
262562306a36Sopenharmony_ciqla82xx_read_optrom_data(struct scsi_qla_host *vha, void *buf,
262662306a36Sopenharmony_ci	uint32_t offset, uint32_t length)
262762306a36Sopenharmony_ci{
262862306a36Sopenharmony_ci	scsi_block_requests(vha->host);
262962306a36Sopenharmony_ci	qla82xx_read_flash_data(vha, buf, offset, length);
263062306a36Sopenharmony_ci	scsi_unblock_requests(vha->host);
263162306a36Sopenharmony_ci	return buf;
263262306a36Sopenharmony_ci}
263362306a36Sopenharmony_ci
263462306a36Sopenharmony_cistatic int
263562306a36Sopenharmony_ciqla82xx_write_flash_data(struct scsi_qla_host *vha, __le32 *dwptr,
263662306a36Sopenharmony_ci	uint32_t faddr, uint32_t dwords)
263762306a36Sopenharmony_ci{
263862306a36Sopenharmony_ci	int ret;
263962306a36Sopenharmony_ci	uint32_t liter;
264062306a36Sopenharmony_ci	uint32_t rest_addr;
264162306a36Sopenharmony_ci	dma_addr_t optrom_dma;
264262306a36Sopenharmony_ci	void *optrom = NULL;
264362306a36Sopenharmony_ci	int page_mode = 0;
264462306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
264562306a36Sopenharmony_ci
264662306a36Sopenharmony_ci	ret = -1;
264762306a36Sopenharmony_ci
264862306a36Sopenharmony_ci	/* Prepare burst-capable write on supported ISPs. */
264962306a36Sopenharmony_ci	if (page_mode && !(faddr & 0xfff) &&
265062306a36Sopenharmony_ci	    dwords > OPTROM_BURST_DWORDS) {
265162306a36Sopenharmony_ci		optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
265262306a36Sopenharmony_ci		    &optrom_dma, GFP_KERNEL);
265362306a36Sopenharmony_ci		if (!optrom) {
265462306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb01b,
265562306a36Sopenharmony_ci			    "Unable to allocate memory "
265662306a36Sopenharmony_ci			    "for optrom burst write (%x KB).\n",
265762306a36Sopenharmony_ci			    OPTROM_BURST_SIZE / 1024);
265862306a36Sopenharmony_ci		}
265962306a36Sopenharmony_ci	}
266062306a36Sopenharmony_ci
266162306a36Sopenharmony_ci	rest_addr = ha->fdt_block_size - 1;
266262306a36Sopenharmony_ci
266362306a36Sopenharmony_ci	ret = qla82xx_unprotect_flash(ha);
266462306a36Sopenharmony_ci	if (ret) {
266562306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb01c,
266662306a36Sopenharmony_ci		    "Unable to unprotect flash for update.\n");
266762306a36Sopenharmony_ci		goto write_done;
266862306a36Sopenharmony_ci	}
266962306a36Sopenharmony_ci
267062306a36Sopenharmony_ci	for (liter = 0; liter < dwords; liter++, faddr += 4, dwptr++) {
267162306a36Sopenharmony_ci		/* Are we at the beginning of a sector? */
267262306a36Sopenharmony_ci		if ((faddr & rest_addr) == 0) {
267362306a36Sopenharmony_ci
267462306a36Sopenharmony_ci			ret = qla82xx_erase_sector(ha, faddr);
267562306a36Sopenharmony_ci			if (ret) {
267662306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0xb01d,
267762306a36Sopenharmony_ci				    "Unable to erase sector: address=%x.\n",
267862306a36Sopenharmony_ci				    faddr);
267962306a36Sopenharmony_ci				break;
268062306a36Sopenharmony_ci			}
268162306a36Sopenharmony_ci		}
268262306a36Sopenharmony_ci
268362306a36Sopenharmony_ci		/* Go with burst-write. */
268462306a36Sopenharmony_ci		if (optrom && (liter + OPTROM_BURST_DWORDS) <= dwords) {
268562306a36Sopenharmony_ci			/* Copy data to DMA'ble buffer. */
268662306a36Sopenharmony_ci			memcpy(optrom, dwptr, OPTROM_BURST_SIZE);
268762306a36Sopenharmony_ci
268862306a36Sopenharmony_ci			ret = qla2x00_load_ram(vha, optrom_dma,
268962306a36Sopenharmony_ci			    (ha->flash_data_off | faddr),
269062306a36Sopenharmony_ci			    OPTROM_BURST_DWORDS);
269162306a36Sopenharmony_ci			if (ret != QLA_SUCCESS) {
269262306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0xb01e,
269362306a36Sopenharmony_ci				    "Unable to burst-write optrom segment "
269462306a36Sopenharmony_ci				    "(%x/%x/%llx).\n", ret,
269562306a36Sopenharmony_ci				    (ha->flash_data_off | faddr),
269662306a36Sopenharmony_ci				    (unsigned long long)optrom_dma);
269762306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0xb01f,
269862306a36Sopenharmony_ci				    "Reverting to slow-write.\n");
269962306a36Sopenharmony_ci
270062306a36Sopenharmony_ci				dma_free_coherent(&ha->pdev->dev,
270162306a36Sopenharmony_ci				    OPTROM_BURST_SIZE, optrom, optrom_dma);
270262306a36Sopenharmony_ci				optrom = NULL;
270362306a36Sopenharmony_ci			} else {
270462306a36Sopenharmony_ci				liter += OPTROM_BURST_DWORDS - 1;
270562306a36Sopenharmony_ci				faddr += OPTROM_BURST_DWORDS - 1;
270662306a36Sopenharmony_ci				dwptr += OPTROM_BURST_DWORDS - 1;
270762306a36Sopenharmony_ci				continue;
270862306a36Sopenharmony_ci			}
270962306a36Sopenharmony_ci		}
271062306a36Sopenharmony_ci
271162306a36Sopenharmony_ci		ret = qla82xx_write_flash_dword(ha, faddr,
271262306a36Sopenharmony_ci						le32_to_cpu(*dwptr));
271362306a36Sopenharmony_ci		if (ret) {
271462306a36Sopenharmony_ci			ql_dbg(ql_dbg_p3p, vha, 0xb020,
271562306a36Sopenharmony_ci			    "Unable to program flash address=%x data=%x.\n",
271662306a36Sopenharmony_ci			    faddr, *dwptr);
271762306a36Sopenharmony_ci			break;
271862306a36Sopenharmony_ci		}
271962306a36Sopenharmony_ci	}
272062306a36Sopenharmony_ci
272162306a36Sopenharmony_ci	ret = qla82xx_protect_flash(ha);
272262306a36Sopenharmony_ci	if (ret)
272362306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb021,
272462306a36Sopenharmony_ci		    "Unable to protect flash after update.\n");
272562306a36Sopenharmony_ciwrite_done:
272662306a36Sopenharmony_ci	if (optrom)
272762306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev,
272862306a36Sopenharmony_ci		    OPTROM_BURST_SIZE, optrom, optrom_dma);
272962306a36Sopenharmony_ci	return ret;
273062306a36Sopenharmony_ci}
273162306a36Sopenharmony_ci
273262306a36Sopenharmony_ciint
273362306a36Sopenharmony_ciqla82xx_write_optrom_data(struct scsi_qla_host *vha, void *buf,
273462306a36Sopenharmony_ci	uint32_t offset, uint32_t length)
273562306a36Sopenharmony_ci{
273662306a36Sopenharmony_ci	int rval;
273762306a36Sopenharmony_ci
273862306a36Sopenharmony_ci	/* Suspend HBA. */
273962306a36Sopenharmony_ci	scsi_block_requests(vha->host);
274062306a36Sopenharmony_ci	rval = qla82xx_write_flash_data(vha, buf, offset, length >> 2);
274162306a36Sopenharmony_ci	scsi_unblock_requests(vha->host);
274262306a36Sopenharmony_ci
274362306a36Sopenharmony_ci	/* Convert return ISP82xx to generic */
274462306a36Sopenharmony_ci	if (rval)
274562306a36Sopenharmony_ci		rval = QLA_FUNCTION_FAILED;
274662306a36Sopenharmony_ci	else
274762306a36Sopenharmony_ci		rval = QLA_SUCCESS;
274862306a36Sopenharmony_ci	return rval;
274962306a36Sopenharmony_ci}
275062306a36Sopenharmony_ci
275162306a36Sopenharmony_civoid
275262306a36Sopenharmony_ciqla82xx_start_iocbs(scsi_qla_host_t *vha)
275362306a36Sopenharmony_ci{
275462306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
275562306a36Sopenharmony_ci	struct req_que *req = ha->req_q_map[0];
275662306a36Sopenharmony_ci	uint32_t dbval;
275762306a36Sopenharmony_ci
275862306a36Sopenharmony_ci	/* Adjust ring index. */
275962306a36Sopenharmony_ci	req->ring_index++;
276062306a36Sopenharmony_ci	if (req->ring_index == req->length) {
276162306a36Sopenharmony_ci		req->ring_index = 0;
276262306a36Sopenharmony_ci		req->ring_ptr = req->ring;
276362306a36Sopenharmony_ci	} else
276462306a36Sopenharmony_ci		req->ring_ptr++;
276562306a36Sopenharmony_ci
276662306a36Sopenharmony_ci	dbval = 0x04 | (ha->portnum << 5);
276762306a36Sopenharmony_ci
276862306a36Sopenharmony_ci	dbval = dbval | (req->id << 8) | (req->ring_index << 16);
276962306a36Sopenharmony_ci	if (ql2xdbwr)
277062306a36Sopenharmony_ci		qla82xx_wr_32(ha, (unsigned long)ha->nxdb_wr_ptr, dbval);
277162306a36Sopenharmony_ci	else {
277262306a36Sopenharmony_ci		wrt_reg_dword(ha->nxdb_wr_ptr, dbval);
277362306a36Sopenharmony_ci		wmb();
277462306a36Sopenharmony_ci		while (rd_reg_dword(ha->nxdb_rd_ptr) != dbval) {
277562306a36Sopenharmony_ci			wrt_reg_dword(ha->nxdb_wr_ptr, dbval);
277662306a36Sopenharmony_ci			wmb();
277762306a36Sopenharmony_ci		}
277862306a36Sopenharmony_ci	}
277962306a36Sopenharmony_ci}
278062306a36Sopenharmony_ci
278162306a36Sopenharmony_cistatic void
278262306a36Sopenharmony_ciqla82xx_rom_lock_recovery(struct qla_hw_data *ha)
278362306a36Sopenharmony_ci{
278462306a36Sopenharmony_ci	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
278562306a36Sopenharmony_ci	uint32_t lock_owner = 0;
278662306a36Sopenharmony_ci
278762306a36Sopenharmony_ci	if (qla82xx_rom_lock(ha)) {
278862306a36Sopenharmony_ci		lock_owner = qla82xx_rd_32(ha, QLA82XX_ROM_LOCK_ID);
278962306a36Sopenharmony_ci		/* Someone else is holding the lock. */
279062306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0xb022,
279162306a36Sopenharmony_ci		    "Resetting rom_lock, Lock Owner %u.\n", lock_owner);
279262306a36Sopenharmony_ci	}
279362306a36Sopenharmony_ci	/*
279462306a36Sopenharmony_ci	 * Either we got the lock, or someone
279562306a36Sopenharmony_ci	 * else died while holding it.
279662306a36Sopenharmony_ci	 * In either case, unlock.
279762306a36Sopenharmony_ci	 */
279862306a36Sopenharmony_ci	qla82xx_rom_unlock(ha);
279962306a36Sopenharmony_ci}
280062306a36Sopenharmony_ci
280162306a36Sopenharmony_ci/*
280262306a36Sopenharmony_ci * qla82xx_device_bootstrap
280362306a36Sopenharmony_ci *    Initialize device, set DEV_READY, start fw
280462306a36Sopenharmony_ci *
280562306a36Sopenharmony_ci * Note:
280662306a36Sopenharmony_ci *      IDC lock must be held upon entry
280762306a36Sopenharmony_ci *
280862306a36Sopenharmony_ci * Return:
280962306a36Sopenharmony_ci *    Success : 0
281062306a36Sopenharmony_ci *    Failed  : 1
281162306a36Sopenharmony_ci */
281262306a36Sopenharmony_cistatic int
281362306a36Sopenharmony_ciqla82xx_device_bootstrap(scsi_qla_host_t *vha)
281462306a36Sopenharmony_ci{
281562306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
281662306a36Sopenharmony_ci	int i;
281762306a36Sopenharmony_ci	uint32_t old_count, count;
281862306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
281962306a36Sopenharmony_ci	int need_reset = 0;
282062306a36Sopenharmony_ci
282162306a36Sopenharmony_ci	need_reset = qla82xx_need_reset(ha);
282262306a36Sopenharmony_ci
282362306a36Sopenharmony_ci	if (need_reset) {
282462306a36Sopenharmony_ci		/* We are trying to perform a recovery here. */
282562306a36Sopenharmony_ci		if (ha->flags.isp82xx_fw_hung)
282662306a36Sopenharmony_ci			qla82xx_rom_lock_recovery(ha);
282762306a36Sopenharmony_ci	} else  {
282862306a36Sopenharmony_ci		old_count = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
282962306a36Sopenharmony_ci		for (i = 0; i < 10; i++) {
283062306a36Sopenharmony_ci			msleep(200);
283162306a36Sopenharmony_ci			count = qla82xx_rd_32(ha, QLA82XX_PEG_ALIVE_COUNTER);
283262306a36Sopenharmony_ci			if (count != old_count) {
283362306a36Sopenharmony_ci				rval = QLA_SUCCESS;
283462306a36Sopenharmony_ci				goto dev_ready;
283562306a36Sopenharmony_ci			}
283662306a36Sopenharmony_ci		}
283762306a36Sopenharmony_ci		qla82xx_rom_lock_recovery(ha);
283862306a36Sopenharmony_ci	}
283962306a36Sopenharmony_ci
284062306a36Sopenharmony_ci	/* set to DEV_INITIALIZING */
284162306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x009e,
284262306a36Sopenharmony_ci	    "HW State: INITIALIZING.\n");
284362306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA8XXX_DEV_INITIALIZING);
284462306a36Sopenharmony_ci
284562306a36Sopenharmony_ci	qla82xx_idc_unlock(ha);
284662306a36Sopenharmony_ci	rval = qla82xx_start_firmware(vha);
284762306a36Sopenharmony_ci	qla82xx_idc_lock(ha);
284862306a36Sopenharmony_ci
284962306a36Sopenharmony_ci	if (rval != QLA_SUCCESS) {
285062306a36Sopenharmony_ci		ql_log(ql_log_fatal, vha, 0x00ad,
285162306a36Sopenharmony_ci		    "HW State: FAILED.\n");
285262306a36Sopenharmony_ci		qla82xx_clear_drv_active(ha);
285362306a36Sopenharmony_ci		qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA8XXX_DEV_FAILED);
285462306a36Sopenharmony_ci		return rval;
285562306a36Sopenharmony_ci	}
285662306a36Sopenharmony_ci
285762306a36Sopenharmony_cidev_ready:
285862306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x00ae,
285962306a36Sopenharmony_ci	    "HW State: READY.\n");
286062306a36Sopenharmony_ci	qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA8XXX_DEV_READY);
286162306a36Sopenharmony_ci
286262306a36Sopenharmony_ci	return QLA_SUCCESS;
286362306a36Sopenharmony_ci}
286462306a36Sopenharmony_ci
286562306a36Sopenharmony_ci/*
286662306a36Sopenharmony_ci* qla82xx_need_qsnt_handler
286762306a36Sopenharmony_ci*    Code to start quiescence sequence
286862306a36Sopenharmony_ci*
286962306a36Sopenharmony_ci* Note:
287062306a36Sopenharmony_ci*      IDC lock must be held upon entry
287162306a36Sopenharmony_ci*
287262306a36Sopenharmony_ci* Return: void
287362306a36Sopenharmony_ci*/
287462306a36Sopenharmony_ci
287562306a36Sopenharmony_cistatic void
287662306a36Sopenharmony_ciqla82xx_need_qsnt_handler(scsi_qla_host_t *vha)
287762306a36Sopenharmony_ci{
287862306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
287962306a36Sopenharmony_ci	uint32_t dev_state, drv_state, drv_active;
288062306a36Sopenharmony_ci	unsigned long reset_timeout;
288162306a36Sopenharmony_ci
288262306a36Sopenharmony_ci	if (vha->flags.online) {
288362306a36Sopenharmony_ci		/*Block any further I/O and wait for pending cmnds to complete*/
288462306a36Sopenharmony_ci		qla2x00_quiesce_io(vha);
288562306a36Sopenharmony_ci	}
288662306a36Sopenharmony_ci
288762306a36Sopenharmony_ci	/* Set the quiescence ready bit */
288862306a36Sopenharmony_ci	qla82xx_set_qsnt_ready(ha);
288962306a36Sopenharmony_ci
289062306a36Sopenharmony_ci	/*wait for 30 secs for other functions to ack */
289162306a36Sopenharmony_ci	reset_timeout = jiffies + (30 * HZ);
289262306a36Sopenharmony_ci
289362306a36Sopenharmony_ci	drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
289462306a36Sopenharmony_ci	drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
289562306a36Sopenharmony_ci	/* Its 2 that is written when qsnt is acked, moving one bit */
289662306a36Sopenharmony_ci	drv_active = drv_active << 0x01;
289762306a36Sopenharmony_ci
289862306a36Sopenharmony_ci	while (drv_state != drv_active) {
289962306a36Sopenharmony_ci
290062306a36Sopenharmony_ci		if (time_after_eq(jiffies, reset_timeout)) {
290162306a36Sopenharmony_ci			/* quiescence timeout, other functions didn't ack
290262306a36Sopenharmony_ci			 * changing the state to DEV_READY
290362306a36Sopenharmony_ci			 */
290462306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0xb023,
290562306a36Sopenharmony_ci			    "%s : QUIESCENT TIMEOUT DRV_ACTIVE:%d "
290662306a36Sopenharmony_ci			    "DRV_STATE:%d.\n", QLA2XXX_DRIVER_NAME,
290762306a36Sopenharmony_ci			    drv_active, drv_state);
290862306a36Sopenharmony_ci			qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
290962306a36Sopenharmony_ci			    QLA8XXX_DEV_READY);
291062306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0xb025,
291162306a36Sopenharmony_ci			    "HW State: DEV_READY.\n");
291262306a36Sopenharmony_ci			qla82xx_idc_unlock(ha);
291362306a36Sopenharmony_ci			qla2x00_perform_loop_resync(vha);
291462306a36Sopenharmony_ci			qla82xx_idc_lock(ha);
291562306a36Sopenharmony_ci
291662306a36Sopenharmony_ci			qla82xx_clear_qsnt_ready(vha);
291762306a36Sopenharmony_ci			return;
291862306a36Sopenharmony_ci		}
291962306a36Sopenharmony_ci
292062306a36Sopenharmony_ci		qla82xx_idc_unlock(ha);
292162306a36Sopenharmony_ci		msleep(1000);
292262306a36Sopenharmony_ci		qla82xx_idc_lock(ha);
292362306a36Sopenharmony_ci
292462306a36Sopenharmony_ci		drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
292562306a36Sopenharmony_ci		drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
292662306a36Sopenharmony_ci		drv_active = drv_active << 0x01;
292762306a36Sopenharmony_ci	}
292862306a36Sopenharmony_ci	dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
292962306a36Sopenharmony_ci	/* everyone acked so set the state to DEV_QUIESCENCE */
293062306a36Sopenharmony_ci	if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT) {
293162306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0xb026,
293262306a36Sopenharmony_ci		    "HW State: DEV_QUIESCENT.\n");
293362306a36Sopenharmony_ci		qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA8XXX_DEV_QUIESCENT);
293462306a36Sopenharmony_ci	}
293562306a36Sopenharmony_ci}
293662306a36Sopenharmony_ci
293762306a36Sopenharmony_ci/*
293862306a36Sopenharmony_ci* qla82xx_wait_for_state_change
293962306a36Sopenharmony_ci*    Wait for device state to change from given current state
294062306a36Sopenharmony_ci*
294162306a36Sopenharmony_ci* Note:
294262306a36Sopenharmony_ci*     IDC lock must not be held upon entry
294362306a36Sopenharmony_ci*
294462306a36Sopenharmony_ci* Return:
294562306a36Sopenharmony_ci*    Changed device state.
294662306a36Sopenharmony_ci*/
294762306a36Sopenharmony_ciuint32_t
294862306a36Sopenharmony_ciqla82xx_wait_for_state_change(scsi_qla_host_t *vha, uint32_t curr_state)
294962306a36Sopenharmony_ci{
295062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
295162306a36Sopenharmony_ci	uint32_t dev_state;
295262306a36Sopenharmony_ci
295362306a36Sopenharmony_ci	do {
295462306a36Sopenharmony_ci		msleep(1000);
295562306a36Sopenharmony_ci		qla82xx_idc_lock(ha);
295662306a36Sopenharmony_ci		dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
295762306a36Sopenharmony_ci		qla82xx_idc_unlock(ha);
295862306a36Sopenharmony_ci	} while (dev_state == curr_state);
295962306a36Sopenharmony_ci
296062306a36Sopenharmony_ci	return dev_state;
296162306a36Sopenharmony_ci}
296262306a36Sopenharmony_ci
296362306a36Sopenharmony_civoid
296462306a36Sopenharmony_ciqla8xxx_dev_failed_handler(scsi_qla_host_t *vha)
296562306a36Sopenharmony_ci{
296662306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
296762306a36Sopenharmony_ci
296862306a36Sopenharmony_ci	/* Disable the board */
296962306a36Sopenharmony_ci	ql_log(ql_log_fatal, vha, 0x00b8,
297062306a36Sopenharmony_ci	    "Disabling the board.\n");
297162306a36Sopenharmony_ci
297262306a36Sopenharmony_ci	if (IS_QLA82XX(ha)) {
297362306a36Sopenharmony_ci		qla82xx_clear_drv_active(ha);
297462306a36Sopenharmony_ci		qla82xx_idc_unlock(ha);
297562306a36Sopenharmony_ci	} else if (IS_QLA8044(ha)) {
297662306a36Sopenharmony_ci		qla8044_clear_drv_active(ha);
297762306a36Sopenharmony_ci		qla8044_idc_unlock(ha);
297862306a36Sopenharmony_ci	}
297962306a36Sopenharmony_ci
298062306a36Sopenharmony_ci	/* Set DEV_FAILED flag to disable timer */
298162306a36Sopenharmony_ci	vha->device_flags |= DFLG_DEV_FAILED;
298262306a36Sopenharmony_ci	qla2x00_abort_all_cmds(vha, DID_NO_CONNECT << 16);
298362306a36Sopenharmony_ci	qla2x00_mark_all_devices_lost(vha);
298462306a36Sopenharmony_ci	vha->flags.online = 0;
298562306a36Sopenharmony_ci	vha->flags.init_done = 0;
298662306a36Sopenharmony_ci}
298762306a36Sopenharmony_ci
298862306a36Sopenharmony_ci/*
298962306a36Sopenharmony_ci * qla82xx_need_reset_handler
299062306a36Sopenharmony_ci *    Code to start reset sequence
299162306a36Sopenharmony_ci *
299262306a36Sopenharmony_ci * Note:
299362306a36Sopenharmony_ci *      IDC lock must be held upon entry
299462306a36Sopenharmony_ci *
299562306a36Sopenharmony_ci * Return:
299662306a36Sopenharmony_ci *    Success : 0
299762306a36Sopenharmony_ci *    Failed  : 1
299862306a36Sopenharmony_ci */
299962306a36Sopenharmony_cistatic void
300062306a36Sopenharmony_ciqla82xx_need_reset_handler(scsi_qla_host_t *vha)
300162306a36Sopenharmony_ci{
300262306a36Sopenharmony_ci	uint32_t dev_state, drv_state, drv_active;
300362306a36Sopenharmony_ci	uint32_t active_mask = 0;
300462306a36Sopenharmony_ci	unsigned long reset_timeout;
300562306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
300662306a36Sopenharmony_ci	struct req_que *req = ha->req_q_map[0];
300762306a36Sopenharmony_ci
300862306a36Sopenharmony_ci	if (vha->flags.online) {
300962306a36Sopenharmony_ci		qla82xx_idc_unlock(ha);
301062306a36Sopenharmony_ci		qla2x00_abort_isp_cleanup(vha);
301162306a36Sopenharmony_ci		ha->isp_ops->get_flash_version(vha, req->ring);
301262306a36Sopenharmony_ci		ha->isp_ops->nvram_config(vha);
301362306a36Sopenharmony_ci		qla82xx_idc_lock(ha);
301462306a36Sopenharmony_ci	}
301562306a36Sopenharmony_ci
301662306a36Sopenharmony_ci	drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
301762306a36Sopenharmony_ci	if (!ha->flags.nic_core_reset_owner) {
301862306a36Sopenharmony_ci		ql_dbg(ql_dbg_p3p, vha, 0xb028,
301962306a36Sopenharmony_ci		    "reset_acknowledged by 0x%x\n", ha->portnum);
302062306a36Sopenharmony_ci		qla82xx_set_rst_ready(ha);
302162306a36Sopenharmony_ci	} else {
302262306a36Sopenharmony_ci		active_mask = ~(QLA82XX_DRV_ACTIVE << (ha->portnum * 4));
302362306a36Sopenharmony_ci		drv_active &= active_mask;
302462306a36Sopenharmony_ci		ql_dbg(ql_dbg_p3p, vha, 0xb029,
302562306a36Sopenharmony_ci		    "active_mask: 0x%08x\n", active_mask);
302662306a36Sopenharmony_ci	}
302762306a36Sopenharmony_ci
302862306a36Sopenharmony_ci	/* wait for 10 seconds for reset ack from all functions */
302962306a36Sopenharmony_ci	reset_timeout = jiffies + (ha->fcoe_reset_timeout * HZ);
303062306a36Sopenharmony_ci
303162306a36Sopenharmony_ci	drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
303262306a36Sopenharmony_ci	drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
303362306a36Sopenharmony_ci	dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
303462306a36Sopenharmony_ci
303562306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb02a,
303662306a36Sopenharmony_ci	    "drv_state: 0x%08x, drv_active: 0x%08x, "
303762306a36Sopenharmony_ci	    "dev_state: 0x%08x, active_mask: 0x%08x\n",
303862306a36Sopenharmony_ci	    drv_state, drv_active, dev_state, active_mask);
303962306a36Sopenharmony_ci
304062306a36Sopenharmony_ci	while (drv_state != drv_active &&
304162306a36Sopenharmony_ci	    dev_state != QLA8XXX_DEV_INITIALIZING) {
304262306a36Sopenharmony_ci		if (time_after_eq(jiffies, reset_timeout)) {
304362306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x00b5,
304462306a36Sopenharmony_ci			    "Reset timeout.\n");
304562306a36Sopenharmony_ci			break;
304662306a36Sopenharmony_ci		}
304762306a36Sopenharmony_ci		qla82xx_idc_unlock(ha);
304862306a36Sopenharmony_ci		msleep(1000);
304962306a36Sopenharmony_ci		qla82xx_idc_lock(ha);
305062306a36Sopenharmony_ci		drv_state = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_STATE);
305162306a36Sopenharmony_ci		drv_active = qla82xx_rd_32(ha, QLA82XX_CRB_DRV_ACTIVE);
305262306a36Sopenharmony_ci		if (ha->flags.nic_core_reset_owner)
305362306a36Sopenharmony_ci			drv_active &= active_mask;
305462306a36Sopenharmony_ci		dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
305562306a36Sopenharmony_ci	}
305662306a36Sopenharmony_ci
305762306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb02b,
305862306a36Sopenharmony_ci	    "drv_state: 0x%08x, drv_active: 0x%08x, "
305962306a36Sopenharmony_ci	    "dev_state: 0x%08x, active_mask: 0x%08x\n",
306062306a36Sopenharmony_ci	    drv_state, drv_active, dev_state, active_mask);
306162306a36Sopenharmony_ci
306262306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x00b6,
306362306a36Sopenharmony_ci	    "Device state is 0x%x = %s.\n",
306462306a36Sopenharmony_ci	    dev_state, qdev_state(dev_state));
306562306a36Sopenharmony_ci
306662306a36Sopenharmony_ci	/* Force to DEV_COLD unless someone else is starting a reset */
306762306a36Sopenharmony_ci	if (dev_state != QLA8XXX_DEV_INITIALIZING &&
306862306a36Sopenharmony_ci	    dev_state != QLA8XXX_DEV_COLD) {
306962306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0x00b7,
307062306a36Sopenharmony_ci		    "HW State: COLD/RE-INIT.\n");
307162306a36Sopenharmony_ci		qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE, QLA8XXX_DEV_COLD);
307262306a36Sopenharmony_ci		qla82xx_set_rst_ready(ha);
307362306a36Sopenharmony_ci		if (ql2xmdenable) {
307462306a36Sopenharmony_ci			if (qla82xx_md_collect(vha))
307562306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0xb02c,
307662306a36Sopenharmony_ci				    "Minidump not collected.\n");
307762306a36Sopenharmony_ci		} else
307862306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb04f,
307962306a36Sopenharmony_ci			    "Minidump disabled.\n");
308062306a36Sopenharmony_ci	}
308162306a36Sopenharmony_ci}
308262306a36Sopenharmony_ci
308362306a36Sopenharmony_ciint
308462306a36Sopenharmony_ciqla82xx_check_md_needed(scsi_qla_host_t *vha)
308562306a36Sopenharmony_ci{
308662306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
308762306a36Sopenharmony_ci	uint16_t fw_major_version, fw_minor_version, fw_subminor_version;
308862306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
308962306a36Sopenharmony_ci
309062306a36Sopenharmony_ci	fw_major_version = ha->fw_major_version;
309162306a36Sopenharmony_ci	fw_minor_version = ha->fw_minor_version;
309262306a36Sopenharmony_ci	fw_subminor_version = ha->fw_subminor_version;
309362306a36Sopenharmony_ci
309462306a36Sopenharmony_ci	rval = qla2x00_get_fw_version(vha);
309562306a36Sopenharmony_ci	if (rval != QLA_SUCCESS)
309662306a36Sopenharmony_ci		return rval;
309762306a36Sopenharmony_ci
309862306a36Sopenharmony_ci	if (ql2xmdenable) {
309962306a36Sopenharmony_ci		if (!ha->fw_dumped) {
310062306a36Sopenharmony_ci			if ((fw_major_version != ha->fw_major_version ||
310162306a36Sopenharmony_ci			    fw_minor_version != ha->fw_minor_version ||
310262306a36Sopenharmony_ci			    fw_subminor_version != ha->fw_subminor_version) ||
310362306a36Sopenharmony_ci			    (ha->prev_minidump_failed)) {
310462306a36Sopenharmony_ci				ql_dbg(ql_dbg_p3p, vha, 0xb02d,
310562306a36Sopenharmony_ci				    "Firmware version differs Previous version: %d:%d:%d - New version: %d:%d:%d, prev_minidump_failed: %d.\n",
310662306a36Sopenharmony_ci				    fw_major_version, fw_minor_version,
310762306a36Sopenharmony_ci				    fw_subminor_version,
310862306a36Sopenharmony_ci				    ha->fw_major_version,
310962306a36Sopenharmony_ci				    ha->fw_minor_version,
311062306a36Sopenharmony_ci				    ha->fw_subminor_version,
311162306a36Sopenharmony_ci				    ha->prev_minidump_failed);
311262306a36Sopenharmony_ci				/* Release MiniDump resources */
311362306a36Sopenharmony_ci				qla82xx_md_free(vha);
311462306a36Sopenharmony_ci				/* ALlocate MiniDump resources */
311562306a36Sopenharmony_ci				qla82xx_md_prep(vha);
311662306a36Sopenharmony_ci			}
311762306a36Sopenharmony_ci		} else
311862306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0xb02e,
311962306a36Sopenharmony_ci			    "Firmware dump available to retrieve\n");
312062306a36Sopenharmony_ci	}
312162306a36Sopenharmony_ci	return rval;
312262306a36Sopenharmony_ci}
312362306a36Sopenharmony_ci
312462306a36Sopenharmony_ci
312562306a36Sopenharmony_cistatic int
312662306a36Sopenharmony_ciqla82xx_check_fw_alive(scsi_qla_host_t *vha)
312762306a36Sopenharmony_ci{
312862306a36Sopenharmony_ci	uint32_t fw_heartbeat_counter;
312962306a36Sopenharmony_ci	int status = 0;
313062306a36Sopenharmony_ci
313162306a36Sopenharmony_ci	fw_heartbeat_counter = qla82xx_rd_32(vha->hw,
313262306a36Sopenharmony_ci		QLA82XX_PEG_ALIVE_COUNTER);
313362306a36Sopenharmony_ci	/* all 0xff, assume AER/EEH in progress, ignore */
313462306a36Sopenharmony_ci	if (fw_heartbeat_counter == 0xffffffff) {
313562306a36Sopenharmony_ci		ql_dbg(ql_dbg_timer, vha, 0x6003,
313662306a36Sopenharmony_ci		    "FW heartbeat counter is 0xffffffff, "
313762306a36Sopenharmony_ci		    "returning status=%d.\n", status);
313862306a36Sopenharmony_ci		return status;
313962306a36Sopenharmony_ci	}
314062306a36Sopenharmony_ci	if (vha->fw_heartbeat_counter == fw_heartbeat_counter) {
314162306a36Sopenharmony_ci		vha->seconds_since_last_heartbeat++;
314262306a36Sopenharmony_ci		/* FW not alive after 2 seconds */
314362306a36Sopenharmony_ci		if (vha->seconds_since_last_heartbeat == 2) {
314462306a36Sopenharmony_ci			vha->seconds_since_last_heartbeat = 0;
314562306a36Sopenharmony_ci			status = 1;
314662306a36Sopenharmony_ci		}
314762306a36Sopenharmony_ci	} else
314862306a36Sopenharmony_ci		vha->seconds_since_last_heartbeat = 0;
314962306a36Sopenharmony_ci	vha->fw_heartbeat_counter = fw_heartbeat_counter;
315062306a36Sopenharmony_ci	if (status)
315162306a36Sopenharmony_ci		ql_dbg(ql_dbg_timer, vha, 0x6004,
315262306a36Sopenharmony_ci		    "Returning status=%d.\n", status);
315362306a36Sopenharmony_ci	return status;
315462306a36Sopenharmony_ci}
315562306a36Sopenharmony_ci
315662306a36Sopenharmony_ci/*
315762306a36Sopenharmony_ci * qla82xx_device_state_handler
315862306a36Sopenharmony_ci *	Main state handler
315962306a36Sopenharmony_ci *
316062306a36Sopenharmony_ci * Note:
316162306a36Sopenharmony_ci *      IDC lock must be held upon entry
316262306a36Sopenharmony_ci *
316362306a36Sopenharmony_ci * Return:
316462306a36Sopenharmony_ci *    Success : 0
316562306a36Sopenharmony_ci *    Failed  : 1
316662306a36Sopenharmony_ci */
316762306a36Sopenharmony_ciint
316862306a36Sopenharmony_ciqla82xx_device_state_handler(scsi_qla_host_t *vha)
316962306a36Sopenharmony_ci{
317062306a36Sopenharmony_ci	uint32_t dev_state;
317162306a36Sopenharmony_ci	uint32_t old_dev_state;
317262306a36Sopenharmony_ci	int rval = QLA_SUCCESS;
317362306a36Sopenharmony_ci	unsigned long dev_init_timeout;
317462306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
317562306a36Sopenharmony_ci	int loopcount = 0;
317662306a36Sopenharmony_ci
317762306a36Sopenharmony_ci	qla82xx_idc_lock(ha);
317862306a36Sopenharmony_ci	if (!vha->flags.init_done) {
317962306a36Sopenharmony_ci		qla82xx_set_drv_active(vha);
318062306a36Sopenharmony_ci		qla82xx_set_idc_version(vha);
318162306a36Sopenharmony_ci	}
318262306a36Sopenharmony_ci
318362306a36Sopenharmony_ci	dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
318462306a36Sopenharmony_ci	old_dev_state = dev_state;
318562306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0x009b,
318662306a36Sopenharmony_ci	    "Device state is 0x%x = %s.\n",
318762306a36Sopenharmony_ci	    dev_state, qdev_state(dev_state));
318862306a36Sopenharmony_ci
318962306a36Sopenharmony_ci	/* wait for 30 seconds for device to go ready */
319062306a36Sopenharmony_ci	dev_init_timeout = jiffies + (ha->fcoe_dev_init_timeout * HZ);
319162306a36Sopenharmony_ci
319262306a36Sopenharmony_ci	while (1) {
319362306a36Sopenharmony_ci
319462306a36Sopenharmony_ci		if (time_after_eq(jiffies, dev_init_timeout)) {
319562306a36Sopenharmony_ci			ql_log(ql_log_fatal, vha, 0x009c,
319662306a36Sopenharmony_ci			    "Device init failed.\n");
319762306a36Sopenharmony_ci			rval = QLA_FUNCTION_FAILED;
319862306a36Sopenharmony_ci			break;
319962306a36Sopenharmony_ci		}
320062306a36Sopenharmony_ci		dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
320162306a36Sopenharmony_ci		if (old_dev_state != dev_state) {
320262306a36Sopenharmony_ci			loopcount = 0;
320362306a36Sopenharmony_ci			old_dev_state = dev_state;
320462306a36Sopenharmony_ci		}
320562306a36Sopenharmony_ci		if (loopcount < 5) {
320662306a36Sopenharmony_ci			ql_log(ql_log_info, vha, 0x009d,
320762306a36Sopenharmony_ci			    "Device state is 0x%x = %s.\n",
320862306a36Sopenharmony_ci			    dev_state, qdev_state(dev_state));
320962306a36Sopenharmony_ci		}
321062306a36Sopenharmony_ci
321162306a36Sopenharmony_ci		switch (dev_state) {
321262306a36Sopenharmony_ci		case QLA8XXX_DEV_READY:
321362306a36Sopenharmony_ci			ha->flags.nic_core_reset_owner = 0;
321462306a36Sopenharmony_ci			goto rel_lock;
321562306a36Sopenharmony_ci		case QLA8XXX_DEV_COLD:
321662306a36Sopenharmony_ci			rval = qla82xx_device_bootstrap(vha);
321762306a36Sopenharmony_ci			break;
321862306a36Sopenharmony_ci		case QLA8XXX_DEV_INITIALIZING:
321962306a36Sopenharmony_ci			qla82xx_idc_unlock(ha);
322062306a36Sopenharmony_ci			msleep(1000);
322162306a36Sopenharmony_ci			qla82xx_idc_lock(ha);
322262306a36Sopenharmony_ci			break;
322362306a36Sopenharmony_ci		case QLA8XXX_DEV_NEED_RESET:
322462306a36Sopenharmony_ci			if (!ql2xdontresethba)
322562306a36Sopenharmony_ci				qla82xx_need_reset_handler(vha);
322662306a36Sopenharmony_ci			else {
322762306a36Sopenharmony_ci				qla82xx_idc_unlock(ha);
322862306a36Sopenharmony_ci				msleep(1000);
322962306a36Sopenharmony_ci				qla82xx_idc_lock(ha);
323062306a36Sopenharmony_ci			}
323162306a36Sopenharmony_ci			dev_init_timeout = jiffies +
323262306a36Sopenharmony_ci			    (ha->fcoe_dev_init_timeout * HZ);
323362306a36Sopenharmony_ci			break;
323462306a36Sopenharmony_ci		case QLA8XXX_DEV_NEED_QUIESCENT:
323562306a36Sopenharmony_ci			qla82xx_need_qsnt_handler(vha);
323662306a36Sopenharmony_ci			/* Reset timeout value after quiescence handler */
323762306a36Sopenharmony_ci			dev_init_timeout = jiffies + (ha->fcoe_dev_init_timeout
323862306a36Sopenharmony_ci							 * HZ);
323962306a36Sopenharmony_ci			break;
324062306a36Sopenharmony_ci		case QLA8XXX_DEV_QUIESCENT:
324162306a36Sopenharmony_ci			/* Owner will exit and other will wait for the state
324262306a36Sopenharmony_ci			 * to get changed
324362306a36Sopenharmony_ci			 */
324462306a36Sopenharmony_ci			if (ha->flags.quiesce_owner)
324562306a36Sopenharmony_ci				goto rel_lock;
324662306a36Sopenharmony_ci
324762306a36Sopenharmony_ci			qla82xx_idc_unlock(ha);
324862306a36Sopenharmony_ci			msleep(1000);
324962306a36Sopenharmony_ci			qla82xx_idc_lock(ha);
325062306a36Sopenharmony_ci
325162306a36Sopenharmony_ci			/* Reset timeout value after quiescence handler */
325262306a36Sopenharmony_ci			dev_init_timeout = jiffies + (ha->fcoe_dev_init_timeout
325362306a36Sopenharmony_ci							 * HZ);
325462306a36Sopenharmony_ci			break;
325562306a36Sopenharmony_ci		case QLA8XXX_DEV_FAILED:
325662306a36Sopenharmony_ci			qla8xxx_dev_failed_handler(vha);
325762306a36Sopenharmony_ci			rval = QLA_FUNCTION_FAILED;
325862306a36Sopenharmony_ci			goto exit;
325962306a36Sopenharmony_ci		default:
326062306a36Sopenharmony_ci			qla82xx_idc_unlock(ha);
326162306a36Sopenharmony_ci			msleep(1000);
326262306a36Sopenharmony_ci			qla82xx_idc_lock(ha);
326362306a36Sopenharmony_ci		}
326462306a36Sopenharmony_ci		loopcount++;
326562306a36Sopenharmony_ci	}
326662306a36Sopenharmony_cirel_lock:
326762306a36Sopenharmony_ci	qla82xx_idc_unlock(ha);
326862306a36Sopenharmony_ciexit:
326962306a36Sopenharmony_ci	return rval;
327062306a36Sopenharmony_ci}
327162306a36Sopenharmony_ci
327262306a36Sopenharmony_cistatic int qla82xx_check_temp(scsi_qla_host_t *vha)
327362306a36Sopenharmony_ci{
327462306a36Sopenharmony_ci	uint32_t temp, temp_state, temp_val;
327562306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
327662306a36Sopenharmony_ci
327762306a36Sopenharmony_ci	temp = qla82xx_rd_32(ha, CRB_TEMP_STATE);
327862306a36Sopenharmony_ci	temp_state = qla82xx_get_temp_state(temp);
327962306a36Sopenharmony_ci	temp_val = qla82xx_get_temp_val(temp);
328062306a36Sopenharmony_ci
328162306a36Sopenharmony_ci	if (temp_state == QLA82XX_TEMP_PANIC) {
328262306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x600e,
328362306a36Sopenharmony_ci		    "Device temperature %d degrees C exceeds "
328462306a36Sopenharmony_ci		    " maximum allowed. Hardware has been shut down.\n",
328562306a36Sopenharmony_ci		    temp_val);
328662306a36Sopenharmony_ci		return 1;
328762306a36Sopenharmony_ci	} else if (temp_state == QLA82XX_TEMP_WARN) {
328862306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x600f,
328962306a36Sopenharmony_ci		    "Device temperature %d degrees C exceeds "
329062306a36Sopenharmony_ci		    "operating range. Immediate action needed.\n",
329162306a36Sopenharmony_ci		    temp_val);
329262306a36Sopenharmony_ci	}
329362306a36Sopenharmony_ci	return 0;
329462306a36Sopenharmony_ci}
329562306a36Sopenharmony_ci
329662306a36Sopenharmony_ciint qla82xx_read_temperature(scsi_qla_host_t *vha)
329762306a36Sopenharmony_ci{
329862306a36Sopenharmony_ci	uint32_t temp;
329962306a36Sopenharmony_ci
330062306a36Sopenharmony_ci	temp = qla82xx_rd_32(vha->hw, CRB_TEMP_STATE);
330162306a36Sopenharmony_ci	return qla82xx_get_temp_val(temp);
330262306a36Sopenharmony_ci}
330362306a36Sopenharmony_ci
330462306a36Sopenharmony_civoid qla82xx_clear_pending_mbx(scsi_qla_host_t *vha)
330562306a36Sopenharmony_ci{
330662306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
330762306a36Sopenharmony_ci
330862306a36Sopenharmony_ci	if (ha->flags.mbox_busy) {
330962306a36Sopenharmony_ci		ha->flags.mbox_int = 1;
331062306a36Sopenharmony_ci		ha->flags.mbox_busy = 0;
331162306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x6010,
331262306a36Sopenharmony_ci		    "Doing premature completion of mbx command.\n");
331362306a36Sopenharmony_ci		if (test_and_clear_bit(MBX_INTR_WAIT, &ha->mbx_cmd_flags))
331462306a36Sopenharmony_ci			complete(&ha->mbx_intr_comp);
331562306a36Sopenharmony_ci	}
331662306a36Sopenharmony_ci}
331762306a36Sopenharmony_ci
331862306a36Sopenharmony_civoid qla82xx_watchdog(scsi_qla_host_t *vha)
331962306a36Sopenharmony_ci{
332062306a36Sopenharmony_ci	uint32_t dev_state, halt_status;
332162306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
332262306a36Sopenharmony_ci
332362306a36Sopenharmony_ci	/* don't poll if reset is going on */
332462306a36Sopenharmony_ci	if (!ha->flags.nic_core_reset_hdlr_active) {
332562306a36Sopenharmony_ci		dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
332662306a36Sopenharmony_ci		if (qla82xx_check_temp(vha)) {
332762306a36Sopenharmony_ci			set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags);
332862306a36Sopenharmony_ci			ha->flags.isp82xx_fw_hung = 1;
332962306a36Sopenharmony_ci			qla82xx_clear_pending_mbx(vha);
333062306a36Sopenharmony_ci		} else if (dev_state == QLA8XXX_DEV_NEED_RESET &&
333162306a36Sopenharmony_ci		    !test_bit(ISP_ABORT_NEEDED, &vha->dpc_flags)) {
333262306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x6001,
333362306a36Sopenharmony_ci			    "Adapter reset needed.\n");
333462306a36Sopenharmony_ci			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
333562306a36Sopenharmony_ci		} else if (dev_state == QLA8XXX_DEV_NEED_QUIESCENT &&
333662306a36Sopenharmony_ci			!test_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags)) {
333762306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0x6002,
333862306a36Sopenharmony_ci			    "Quiescent needed.\n");
333962306a36Sopenharmony_ci			set_bit(ISP_QUIESCE_NEEDED, &vha->dpc_flags);
334062306a36Sopenharmony_ci		} else if (dev_state == QLA8XXX_DEV_FAILED &&
334162306a36Sopenharmony_ci			!test_bit(ISP_UNRECOVERABLE, &vha->dpc_flags) &&
334262306a36Sopenharmony_ci			vha->flags.online == 1) {
334362306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb055,
334462306a36Sopenharmony_ci			    "Adapter state is failed. Offlining.\n");
334562306a36Sopenharmony_ci			set_bit(ISP_UNRECOVERABLE, &vha->dpc_flags);
334662306a36Sopenharmony_ci			ha->flags.isp82xx_fw_hung = 1;
334762306a36Sopenharmony_ci			qla82xx_clear_pending_mbx(vha);
334862306a36Sopenharmony_ci		} else {
334962306a36Sopenharmony_ci			if (qla82xx_check_fw_alive(vha)) {
335062306a36Sopenharmony_ci				ql_dbg(ql_dbg_timer, vha, 0x6011,
335162306a36Sopenharmony_ci				    "disabling pause transmit on port 0 & 1.\n");
335262306a36Sopenharmony_ci				qla82xx_wr_32(ha, QLA82XX_CRB_NIU + 0x98,
335362306a36Sopenharmony_ci				    CRB_NIU_XG_PAUSE_CTL_P0|CRB_NIU_XG_PAUSE_CTL_P1);
335462306a36Sopenharmony_ci				halt_status = qla82xx_rd_32(ha,
335562306a36Sopenharmony_ci				    QLA82XX_PEG_HALT_STATUS1);
335662306a36Sopenharmony_ci				ql_log(ql_log_info, vha, 0x6005,
335762306a36Sopenharmony_ci				    "dumping hw/fw registers:.\n "
335862306a36Sopenharmony_ci				    " PEG_HALT_STATUS1: 0x%x, PEG_HALT_STATUS2: 0x%x,.\n "
335962306a36Sopenharmony_ci				    " PEG_NET_0_PC: 0x%x, PEG_NET_1_PC: 0x%x,.\n "
336062306a36Sopenharmony_ci				    " PEG_NET_2_PC: 0x%x, PEG_NET_3_PC: 0x%x,.\n "
336162306a36Sopenharmony_ci				    " PEG_NET_4_PC: 0x%x.\n", halt_status,
336262306a36Sopenharmony_ci				    qla82xx_rd_32(ha, QLA82XX_PEG_HALT_STATUS2),
336362306a36Sopenharmony_ci				    qla82xx_rd_32(ha,
336462306a36Sopenharmony_ci					    QLA82XX_CRB_PEG_NET_0 + 0x3c),
336562306a36Sopenharmony_ci				    qla82xx_rd_32(ha,
336662306a36Sopenharmony_ci					    QLA82XX_CRB_PEG_NET_1 + 0x3c),
336762306a36Sopenharmony_ci				    qla82xx_rd_32(ha,
336862306a36Sopenharmony_ci					    QLA82XX_CRB_PEG_NET_2 + 0x3c),
336962306a36Sopenharmony_ci				    qla82xx_rd_32(ha,
337062306a36Sopenharmony_ci					    QLA82XX_CRB_PEG_NET_3 + 0x3c),
337162306a36Sopenharmony_ci				    qla82xx_rd_32(ha,
337262306a36Sopenharmony_ci					    QLA82XX_CRB_PEG_NET_4 + 0x3c));
337362306a36Sopenharmony_ci				if (((halt_status & 0x1fffff00) >> 8) == 0x67)
337462306a36Sopenharmony_ci					ql_log(ql_log_warn, vha, 0xb052,
337562306a36Sopenharmony_ci					    "Firmware aborted with "
337662306a36Sopenharmony_ci					    "error code 0x00006700. Device is "
337762306a36Sopenharmony_ci					    "being reset.\n");
337862306a36Sopenharmony_ci				if (halt_status & HALT_STATUS_UNRECOVERABLE) {
337962306a36Sopenharmony_ci					set_bit(ISP_UNRECOVERABLE,
338062306a36Sopenharmony_ci					    &vha->dpc_flags);
338162306a36Sopenharmony_ci				} else {
338262306a36Sopenharmony_ci					ql_log(ql_log_info, vha, 0x6006,
338362306a36Sopenharmony_ci					    "Detect abort  needed.\n");
338462306a36Sopenharmony_ci					set_bit(ISP_ABORT_NEEDED,
338562306a36Sopenharmony_ci					    &vha->dpc_flags);
338662306a36Sopenharmony_ci				}
338762306a36Sopenharmony_ci				ha->flags.isp82xx_fw_hung = 1;
338862306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x6007, "Firmware hung.\n");
338962306a36Sopenharmony_ci				qla82xx_clear_pending_mbx(vha);
339062306a36Sopenharmony_ci			}
339162306a36Sopenharmony_ci		}
339262306a36Sopenharmony_ci	}
339362306a36Sopenharmony_ci}
339462306a36Sopenharmony_ci
339562306a36Sopenharmony_ciint qla82xx_load_risc(scsi_qla_host_t *vha, uint32_t *srisc_addr)
339662306a36Sopenharmony_ci{
339762306a36Sopenharmony_ci	int rval = -1;
339862306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
339962306a36Sopenharmony_ci
340062306a36Sopenharmony_ci	if (IS_QLA82XX(ha))
340162306a36Sopenharmony_ci		rval = qla82xx_device_state_handler(vha);
340262306a36Sopenharmony_ci	else if (IS_QLA8044(ha)) {
340362306a36Sopenharmony_ci		qla8044_idc_lock(ha);
340462306a36Sopenharmony_ci		/* Decide the reset ownership */
340562306a36Sopenharmony_ci		qla83xx_reset_ownership(vha);
340662306a36Sopenharmony_ci		qla8044_idc_unlock(ha);
340762306a36Sopenharmony_ci		rval = qla8044_device_state_handler(vha);
340862306a36Sopenharmony_ci	}
340962306a36Sopenharmony_ci	return rval;
341062306a36Sopenharmony_ci}
341162306a36Sopenharmony_ci
341262306a36Sopenharmony_civoid
341362306a36Sopenharmony_ciqla82xx_set_reset_owner(scsi_qla_host_t *vha)
341462306a36Sopenharmony_ci{
341562306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
341662306a36Sopenharmony_ci	uint32_t dev_state = 0;
341762306a36Sopenharmony_ci
341862306a36Sopenharmony_ci	if (IS_QLA82XX(ha))
341962306a36Sopenharmony_ci		dev_state = qla82xx_rd_32(ha, QLA82XX_CRB_DEV_STATE);
342062306a36Sopenharmony_ci	else if (IS_QLA8044(ha))
342162306a36Sopenharmony_ci		dev_state = qla8044_rd_direct(vha, QLA8044_CRB_DEV_STATE_INDEX);
342262306a36Sopenharmony_ci
342362306a36Sopenharmony_ci	if (dev_state == QLA8XXX_DEV_READY) {
342462306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0xb02f,
342562306a36Sopenharmony_ci		    "HW State: NEED RESET\n");
342662306a36Sopenharmony_ci		if (IS_QLA82XX(ha)) {
342762306a36Sopenharmony_ci			qla82xx_wr_32(ha, QLA82XX_CRB_DEV_STATE,
342862306a36Sopenharmony_ci			    QLA8XXX_DEV_NEED_RESET);
342962306a36Sopenharmony_ci			ha->flags.nic_core_reset_owner = 1;
343062306a36Sopenharmony_ci			ql_dbg(ql_dbg_p3p, vha, 0xb030,
343162306a36Sopenharmony_ci			    "reset_owner is 0x%x\n", ha->portnum);
343262306a36Sopenharmony_ci		} else if (IS_QLA8044(ha))
343362306a36Sopenharmony_ci			qla8044_wr_direct(vha, QLA8044_CRB_DEV_STATE_INDEX,
343462306a36Sopenharmony_ci			    QLA8XXX_DEV_NEED_RESET);
343562306a36Sopenharmony_ci	} else
343662306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0xb031,
343762306a36Sopenharmony_ci		    "Device state is 0x%x = %s.\n",
343862306a36Sopenharmony_ci		    dev_state, qdev_state(dev_state));
343962306a36Sopenharmony_ci}
344062306a36Sopenharmony_ci
344162306a36Sopenharmony_ci/*
344262306a36Sopenharmony_ci *  qla82xx_abort_isp
344362306a36Sopenharmony_ci *      Resets ISP and aborts all outstanding commands.
344462306a36Sopenharmony_ci *
344562306a36Sopenharmony_ci * Input:
344662306a36Sopenharmony_ci *      ha           = adapter block pointer.
344762306a36Sopenharmony_ci *
344862306a36Sopenharmony_ci * Returns:
344962306a36Sopenharmony_ci *      0 = success
345062306a36Sopenharmony_ci */
345162306a36Sopenharmony_ciint
345262306a36Sopenharmony_ciqla82xx_abort_isp(scsi_qla_host_t *vha)
345362306a36Sopenharmony_ci{
345462306a36Sopenharmony_ci	int rval = -1;
345562306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
345662306a36Sopenharmony_ci
345762306a36Sopenharmony_ci	if (vha->device_flags & DFLG_DEV_FAILED) {
345862306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0x8024,
345962306a36Sopenharmony_ci		    "Device in failed state, exiting.\n");
346062306a36Sopenharmony_ci		return QLA_SUCCESS;
346162306a36Sopenharmony_ci	}
346262306a36Sopenharmony_ci	ha->flags.nic_core_reset_hdlr_active = 1;
346362306a36Sopenharmony_ci
346462306a36Sopenharmony_ci	qla82xx_idc_lock(ha);
346562306a36Sopenharmony_ci	qla82xx_set_reset_owner(vha);
346662306a36Sopenharmony_ci	qla82xx_idc_unlock(ha);
346762306a36Sopenharmony_ci
346862306a36Sopenharmony_ci	if (IS_QLA82XX(ha))
346962306a36Sopenharmony_ci		rval = qla82xx_device_state_handler(vha);
347062306a36Sopenharmony_ci	else if (IS_QLA8044(ha)) {
347162306a36Sopenharmony_ci		qla8044_idc_lock(ha);
347262306a36Sopenharmony_ci		/* Decide the reset ownership */
347362306a36Sopenharmony_ci		qla83xx_reset_ownership(vha);
347462306a36Sopenharmony_ci		qla8044_idc_unlock(ha);
347562306a36Sopenharmony_ci		rval = qla8044_device_state_handler(vha);
347662306a36Sopenharmony_ci	}
347762306a36Sopenharmony_ci
347862306a36Sopenharmony_ci	qla82xx_idc_lock(ha);
347962306a36Sopenharmony_ci	qla82xx_clear_rst_ready(ha);
348062306a36Sopenharmony_ci	qla82xx_idc_unlock(ha);
348162306a36Sopenharmony_ci
348262306a36Sopenharmony_ci	if (rval == QLA_SUCCESS) {
348362306a36Sopenharmony_ci		ha->flags.isp82xx_fw_hung = 0;
348462306a36Sopenharmony_ci		ha->flags.nic_core_reset_hdlr_active = 0;
348562306a36Sopenharmony_ci		qla82xx_restart_isp(vha);
348662306a36Sopenharmony_ci	}
348762306a36Sopenharmony_ci
348862306a36Sopenharmony_ci	if (rval) {
348962306a36Sopenharmony_ci		vha->flags.online = 1;
349062306a36Sopenharmony_ci		if (test_bit(ISP_ABORT_RETRY, &vha->dpc_flags)) {
349162306a36Sopenharmony_ci			if (ha->isp_abort_cnt == 0) {
349262306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x8027,
349362306a36Sopenharmony_ci				    "ISP error recover failed - board "
349462306a36Sopenharmony_ci				    "disabled.\n");
349562306a36Sopenharmony_ci				/*
349662306a36Sopenharmony_ci				 * The next call disables the board
349762306a36Sopenharmony_ci				 * completely.
349862306a36Sopenharmony_ci				 */
349962306a36Sopenharmony_ci				ha->isp_ops->reset_adapter(vha);
350062306a36Sopenharmony_ci				vha->flags.online = 0;
350162306a36Sopenharmony_ci				clear_bit(ISP_ABORT_RETRY,
350262306a36Sopenharmony_ci				    &vha->dpc_flags);
350362306a36Sopenharmony_ci				rval = QLA_SUCCESS;
350462306a36Sopenharmony_ci			} else { /* schedule another ISP abort */
350562306a36Sopenharmony_ci				ha->isp_abort_cnt--;
350662306a36Sopenharmony_ci				ql_log(ql_log_warn, vha, 0x8036,
350762306a36Sopenharmony_ci				    "ISP abort - retry remaining %d.\n",
350862306a36Sopenharmony_ci				    ha->isp_abort_cnt);
350962306a36Sopenharmony_ci				rval = QLA_FUNCTION_FAILED;
351062306a36Sopenharmony_ci			}
351162306a36Sopenharmony_ci		} else {
351262306a36Sopenharmony_ci			ha->isp_abort_cnt = MAX_RETRIES_OF_ISP_ABORT;
351362306a36Sopenharmony_ci			ql_dbg(ql_dbg_taskm, vha, 0x8029,
351462306a36Sopenharmony_ci			    "ISP error recovery - retrying (%d) more times.\n",
351562306a36Sopenharmony_ci			    ha->isp_abort_cnt);
351662306a36Sopenharmony_ci			set_bit(ISP_ABORT_RETRY, &vha->dpc_flags);
351762306a36Sopenharmony_ci			rval = QLA_FUNCTION_FAILED;
351862306a36Sopenharmony_ci		}
351962306a36Sopenharmony_ci	}
352062306a36Sopenharmony_ci	return rval;
352162306a36Sopenharmony_ci}
352262306a36Sopenharmony_ci
352362306a36Sopenharmony_ci/*
352462306a36Sopenharmony_ci *  qla82xx_fcoe_ctx_reset
352562306a36Sopenharmony_ci *      Perform a quick reset and aborts all outstanding commands.
352662306a36Sopenharmony_ci *      This will only perform an FCoE context reset and avoids a full blown
352762306a36Sopenharmony_ci *      chip reset.
352862306a36Sopenharmony_ci *
352962306a36Sopenharmony_ci * Input:
353062306a36Sopenharmony_ci *      ha = adapter block pointer.
353162306a36Sopenharmony_ci *      is_reset_path = flag for identifying the reset path.
353262306a36Sopenharmony_ci *
353362306a36Sopenharmony_ci * Returns:
353462306a36Sopenharmony_ci *      0 = success
353562306a36Sopenharmony_ci */
353662306a36Sopenharmony_ciint qla82xx_fcoe_ctx_reset(scsi_qla_host_t *vha)
353762306a36Sopenharmony_ci{
353862306a36Sopenharmony_ci	int rval = QLA_FUNCTION_FAILED;
353962306a36Sopenharmony_ci
354062306a36Sopenharmony_ci	if (vha->flags.online) {
354162306a36Sopenharmony_ci		/* Abort all outstanding commands, so as to be requeued later */
354262306a36Sopenharmony_ci		qla2x00_abort_isp_cleanup(vha);
354362306a36Sopenharmony_ci	}
354462306a36Sopenharmony_ci
354562306a36Sopenharmony_ci	/* Stop currently executing firmware.
354662306a36Sopenharmony_ci	 * This will destroy existing FCoE context at the F/W end.
354762306a36Sopenharmony_ci	 */
354862306a36Sopenharmony_ci	qla2x00_try_to_stop_firmware(vha);
354962306a36Sopenharmony_ci
355062306a36Sopenharmony_ci	/* Restart. Creates a new FCoE context on INIT_FIRMWARE. */
355162306a36Sopenharmony_ci	rval = qla82xx_restart_isp(vha);
355262306a36Sopenharmony_ci
355362306a36Sopenharmony_ci	return rval;
355462306a36Sopenharmony_ci}
355562306a36Sopenharmony_ci
355662306a36Sopenharmony_ci/*
355762306a36Sopenharmony_ci * qla2x00_wait_for_fcoe_ctx_reset
355862306a36Sopenharmony_ci *    Wait till the FCoE context is reset.
355962306a36Sopenharmony_ci *
356062306a36Sopenharmony_ci * Note:
356162306a36Sopenharmony_ci *    Does context switching here.
356262306a36Sopenharmony_ci *    Release SPIN_LOCK (if any) before calling this routine.
356362306a36Sopenharmony_ci *
356462306a36Sopenharmony_ci * Return:
356562306a36Sopenharmony_ci *    Success (fcoe_ctx reset is done) : 0
356662306a36Sopenharmony_ci *    Failed  (fcoe_ctx reset not completed within max loop timout ) : 1
356762306a36Sopenharmony_ci */
356862306a36Sopenharmony_ciint qla2x00_wait_for_fcoe_ctx_reset(scsi_qla_host_t *vha)
356962306a36Sopenharmony_ci{
357062306a36Sopenharmony_ci	int status = QLA_FUNCTION_FAILED;
357162306a36Sopenharmony_ci	unsigned long wait_reset;
357262306a36Sopenharmony_ci
357362306a36Sopenharmony_ci	wait_reset = jiffies + (MAX_LOOP_TIMEOUT * HZ);
357462306a36Sopenharmony_ci	while ((test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags) ||
357562306a36Sopenharmony_ci	    test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags))
357662306a36Sopenharmony_ci	    && time_before(jiffies, wait_reset)) {
357762306a36Sopenharmony_ci
357862306a36Sopenharmony_ci		set_current_state(TASK_UNINTERRUPTIBLE);
357962306a36Sopenharmony_ci		schedule_timeout(HZ);
358062306a36Sopenharmony_ci
358162306a36Sopenharmony_ci		if (!test_bit(FCOE_CTX_RESET_NEEDED, &vha->dpc_flags) &&
358262306a36Sopenharmony_ci		    !test_bit(ABORT_ISP_ACTIVE, &vha->dpc_flags)) {
358362306a36Sopenharmony_ci			status = QLA_SUCCESS;
358462306a36Sopenharmony_ci			break;
358562306a36Sopenharmony_ci		}
358662306a36Sopenharmony_ci	}
358762306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb027,
358862306a36Sopenharmony_ci	       "%s: status=%d.\n", __func__, status);
358962306a36Sopenharmony_ci
359062306a36Sopenharmony_ci	return status;
359162306a36Sopenharmony_ci}
359262306a36Sopenharmony_ci
359362306a36Sopenharmony_civoid
359462306a36Sopenharmony_ciqla82xx_chip_reset_cleanup(scsi_qla_host_t *vha)
359562306a36Sopenharmony_ci{
359662306a36Sopenharmony_ci	int i, fw_state = 0;
359762306a36Sopenharmony_ci	unsigned long flags;
359862306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
359962306a36Sopenharmony_ci
360062306a36Sopenharmony_ci	/* Check if 82XX firmware is alive or not
360162306a36Sopenharmony_ci	 * We may have arrived here from NEED_RESET
360262306a36Sopenharmony_ci	 * detection only
360362306a36Sopenharmony_ci	 */
360462306a36Sopenharmony_ci	if (!ha->flags.isp82xx_fw_hung) {
360562306a36Sopenharmony_ci		for (i = 0; i < 2; i++) {
360662306a36Sopenharmony_ci			msleep(1000);
360762306a36Sopenharmony_ci			if (IS_QLA82XX(ha))
360862306a36Sopenharmony_ci				fw_state = qla82xx_check_fw_alive(vha);
360962306a36Sopenharmony_ci			else if (IS_QLA8044(ha))
361062306a36Sopenharmony_ci				fw_state = qla8044_check_fw_alive(vha);
361162306a36Sopenharmony_ci			if (fw_state) {
361262306a36Sopenharmony_ci				ha->flags.isp82xx_fw_hung = 1;
361362306a36Sopenharmony_ci				qla82xx_clear_pending_mbx(vha);
361462306a36Sopenharmony_ci				break;
361562306a36Sopenharmony_ci			}
361662306a36Sopenharmony_ci		}
361762306a36Sopenharmony_ci	}
361862306a36Sopenharmony_ci	ql_dbg(ql_dbg_init, vha, 0x00b0,
361962306a36Sopenharmony_ci	    "Entered %s fw_hung=%d.\n",
362062306a36Sopenharmony_ci	    __func__, ha->flags.isp82xx_fw_hung);
362162306a36Sopenharmony_ci
362262306a36Sopenharmony_ci	/* Abort all commands gracefully if fw NOT hung */
362362306a36Sopenharmony_ci	if (!ha->flags.isp82xx_fw_hung) {
362462306a36Sopenharmony_ci		int cnt, que;
362562306a36Sopenharmony_ci		srb_t *sp;
362662306a36Sopenharmony_ci		struct req_que *req;
362762306a36Sopenharmony_ci
362862306a36Sopenharmony_ci		spin_lock_irqsave(&ha->hardware_lock, flags);
362962306a36Sopenharmony_ci		for (que = 0; que < ha->max_req_queues; que++) {
363062306a36Sopenharmony_ci			req = ha->req_q_map[que];
363162306a36Sopenharmony_ci			if (!req)
363262306a36Sopenharmony_ci				continue;
363362306a36Sopenharmony_ci			for (cnt = 1; cnt < req->num_outstanding_cmds; cnt++) {
363462306a36Sopenharmony_ci				sp = req->outstanding_cmds[cnt];
363562306a36Sopenharmony_ci				if (sp) {
363662306a36Sopenharmony_ci					if ((!sp->u.scmd.crc_ctx ||
363762306a36Sopenharmony_ci					    (sp->flags &
363862306a36Sopenharmony_ci						SRB_FCP_CMND_DMA_VALID)) &&
363962306a36Sopenharmony_ci						!ha->flags.isp82xx_fw_hung) {
364062306a36Sopenharmony_ci						spin_unlock_irqrestore(
364162306a36Sopenharmony_ci						    &ha->hardware_lock, flags);
364262306a36Sopenharmony_ci						if (ha->isp_ops->abort_command(sp)) {
364362306a36Sopenharmony_ci							ql_log(ql_log_info, vha,
364462306a36Sopenharmony_ci							    0x00b1,
364562306a36Sopenharmony_ci							    "mbx abort failed.\n");
364662306a36Sopenharmony_ci						} else {
364762306a36Sopenharmony_ci							ql_log(ql_log_info, vha,
364862306a36Sopenharmony_ci							    0x00b2,
364962306a36Sopenharmony_ci							    "mbx abort success.\n");
365062306a36Sopenharmony_ci						}
365162306a36Sopenharmony_ci						spin_lock_irqsave(&ha->hardware_lock, flags);
365262306a36Sopenharmony_ci					}
365362306a36Sopenharmony_ci				}
365462306a36Sopenharmony_ci			}
365562306a36Sopenharmony_ci		}
365662306a36Sopenharmony_ci		spin_unlock_irqrestore(&ha->hardware_lock, flags);
365762306a36Sopenharmony_ci
365862306a36Sopenharmony_ci		/* Wait for pending cmds (physical and virtual) to complete */
365962306a36Sopenharmony_ci		if (qla2x00_eh_wait_for_pending_commands(vha, 0, 0,
366062306a36Sopenharmony_ci		    WAIT_HOST) == QLA_SUCCESS) {
366162306a36Sopenharmony_ci			ql_dbg(ql_dbg_init, vha, 0x00b3,
366262306a36Sopenharmony_ci			    "Done wait for "
366362306a36Sopenharmony_ci			    "pending commands.\n");
366462306a36Sopenharmony_ci		} else {
366562306a36Sopenharmony_ci			WARN_ON_ONCE(true);
366662306a36Sopenharmony_ci		}
366762306a36Sopenharmony_ci	}
366862306a36Sopenharmony_ci}
366962306a36Sopenharmony_ci
367062306a36Sopenharmony_ci/* Minidump related functions */
367162306a36Sopenharmony_cistatic int
367262306a36Sopenharmony_ciqla82xx_minidump_process_control(scsi_qla_host_t *vha,
367362306a36Sopenharmony_ci	qla82xx_md_entry_hdr_t *entry_hdr, __le32 **d_ptr)
367462306a36Sopenharmony_ci{
367562306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
367662306a36Sopenharmony_ci	struct qla82xx_md_entry_crb *crb_entry;
367762306a36Sopenharmony_ci	uint32_t read_value, opcode, poll_time;
367862306a36Sopenharmony_ci	uint32_t addr, index, crb_addr;
367962306a36Sopenharmony_ci	unsigned long wtime;
368062306a36Sopenharmony_ci	struct qla82xx_md_template_hdr *tmplt_hdr;
368162306a36Sopenharmony_ci	uint32_t rval = QLA_SUCCESS;
368262306a36Sopenharmony_ci	int i;
368362306a36Sopenharmony_ci
368462306a36Sopenharmony_ci	tmplt_hdr = (struct qla82xx_md_template_hdr *)ha->md_tmplt_hdr;
368562306a36Sopenharmony_ci	crb_entry = (struct qla82xx_md_entry_crb *)entry_hdr;
368662306a36Sopenharmony_ci	crb_addr = crb_entry->addr;
368762306a36Sopenharmony_ci
368862306a36Sopenharmony_ci	for (i = 0; i < crb_entry->op_count; i++) {
368962306a36Sopenharmony_ci		opcode = crb_entry->crb_ctrl.opcode;
369062306a36Sopenharmony_ci		if (opcode & QLA82XX_DBG_OPCODE_WR) {
369162306a36Sopenharmony_ci			qla82xx_md_rw_32(ha, crb_addr,
369262306a36Sopenharmony_ci			    crb_entry->value_1, 1);
369362306a36Sopenharmony_ci			opcode &= ~QLA82XX_DBG_OPCODE_WR;
369462306a36Sopenharmony_ci		}
369562306a36Sopenharmony_ci
369662306a36Sopenharmony_ci		if (opcode & QLA82XX_DBG_OPCODE_RW) {
369762306a36Sopenharmony_ci			read_value = qla82xx_md_rw_32(ha, crb_addr, 0, 0);
369862306a36Sopenharmony_ci			qla82xx_md_rw_32(ha, crb_addr, read_value, 1);
369962306a36Sopenharmony_ci			opcode &= ~QLA82XX_DBG_OPCODE_RW;
370062306a36Sopenharmony_ci		}
370162306a36Sopenharmony_ci
370262306a36Sopenharmony_ci		if (opcode & QLA82XX_DBG_OPCODE_AND) {
370362306a36Sopenharmony_ci			read_value = qla82xx_md_rw_32(ha, crb_addr, 0, 0);
370462306a36Sopenharmony_ci			read_value &= crb_entry->value_2;
370562306a36Sopenharmony_ci			opcode &= ~QLA82XX_DBG_OPCODE_AND;
370662306a36Sopenharmony_ci			if (opcode & QLA82XX_DBG_OPCODE_OR) {
370762306a36Sopenharmony_ci				read_value |= crb_entry->value_3;
370862306a36Sopenharmony_ci				opcode &= ~QLA82XX_DBG_OPCODE_OR;
370962306a36Sopenharmony_ci			}
371062306a36Sopenharmony_ci			qla82xx_md_rw_32(ha, crb_addr, read_value, 1);
371162306a36Sopenharmony_ci		}
371262306a36Sopenharmony_ci
371362306a36Sopenharmony_ci		if (opcode & QLA82XX_DBG_OPCODE_OR) {
371462306a36Sopenharmony_ci			read_value = qla82xx_md_rw_32(ha, crb_addr, 0, 0);
371562306a36Sopenharmony_ci			read_value |= crb_entry->value_3;
371662306a36Sopenharmony_ci			qla82xx_md_rw_32(ha, crb_addr, read_value, 1);
371762306a36Sopenharmony_ci			opcode &= ~QLA82XX_DBG_OPCODE_OR;
371862306a36Sopenharmony_ci		}
371962306a36Sopenharmony_ci
372062306a36Sopenharmony_ci		if (opcode & QLA82XX_DBG_OPCODE_POLL) {
372162306a36Sopenharmony_ci			poll_time = crb_entry->crb_strd.poll_timeout;
372262306a36Sopenharmony_ci			wtime = jiffies + poll_time;
372362306a36Sopenharmony_ci			read_value = qla82xx_md_rw_32(ha, crb_addr, 0, 0);
372462306a36Sopenharmony_ci
372562306a36Sopenharmony_ci			do {
372662306a36Sopenharmony_ci				if ((read_value & crb_entry->value_2)
372762306a36Sopenharmony_ci				    == crb_entry->value_1)
372862306a36Sopenharmony_ci					break;
372962306a36Sopenharmony_ci				else if (time_after_eq(jiffies, wtime)) {
373062306a36Sopenharmony_ci					/* capturing dump failed */
373162306a36Sopenharmony_ci					rval = QLA_FUNCTION_FAILED;
373262306a36Sopenharmony_ci					break;
373362306a36Sopenharmony_ci				} else
373462306a36Sopenharmony_ci					read_value = qla82xx_md_rw_32(ha,
373562306a36Sopenharmony_ci					    crb_addr, 0, 0);
373662306a36Sopenharmony_ci			} while (1);
373762306a36Sopenharmony_ci			opcode &= ~QLA82XX_DBG_OPCODE_POLL;
373862306a36Sopenharmony_ci		}
373962306a36Sopenharmony_ci
374062306a36Sopenharmony_ci		if (opcode & QLA82XX_DBG_OPCODE_RDSTATE) {
374162306a36Sopenharmony_ci			if (crb_entry->crb_strd.state_index_a) {
374262306a36Sopenharmony_ci				index = crb_entry->crb_strd.state_index_a;
374362306a36Sopenharmony_ci				addr = tmplt_hdr->saved_state_array[index];
374462306a36Sopenharmony_ci			} else
374562306a36Sopenharmony_ci				addr = crb_addr;
374662306a36Sopenharmony_ci
374762306a36Sopenharmony_ci			read_value = qla82xx_md_rw_32(ha, addr, 0, 0);
374862306a36Sopenharmony_ci			index = crb_entry->crb_ctrl.state_index_v;
374962306a36Sopenharmony_ci			tmplt_hdr->saved_state_array[index] = read_value;
375062306a36Sopenharmony_ci			opcode &= ~QLA82XX_DBG_OPCODE_RDSTATE;
375162306a36Sopenharmony_ci		}
375262306a36Sopenharmony_ci
375362306a36Sopenharmony_ci		if (opcode & QLA82XX_DBG_OPCODE_WRSTATE) {
375462306a36Sopenharmony_ci			if (crb_entry->crb_strd.state_index_a) {
375562306a36Sopenharmony_ci				index = crb_entry->crb_strd.state_index_a;
375662306a36Sopenharmony_ci				addr = tmplt_hdr->saved_state_array[index];
375762306a36Sopenharmony_ci			} else
375862306a36Sopenharmony_ci				addr = crb_addr;
375962306a36Sopenharmony_ci
376062306a36Sopenharmony_ci			if (crb_entry->crb_ctrl.state_index_v) {
376162306a36Sopenharmony_ci				index = crb_entry->crb_ctrl.state_index_v;
376262306a36Sopenharmony_ci				read_value =
376362306a36Sopenharmony_ci				    tmplt_hdr->saved_state_array[index];
376462306a36Sopenharmony_ci			} else
376562306a36Sopenharmony_ci				read_value = crb_entry->value_1;
376662306a36Sopenharmony_ci
376762306a36Sopenharmony_ci			qla82xx_md_rw_32(ha, addr, read_value, 1);
376862306a36Sopenharmony_ci			opcode &= ~QLA82XX_DBG_OPCODE_WRSTATE;
376962306a36Sopenharmony_ci		}
377062306a36Sopenharmony_ci
377162306a36Sopenharmony_ci		if (opcode & QLA82XX_DBG_OPCODE_MDSTATE) {
377262306a36Sopenharmony_ci			index = crb_entry->crb_ctrl.state_index_v;
377362306a36Sopenharmony_ci			read_value = tmplt_hdr->saved_state_array[index];
377462306a36Sopenharmony_ci			read_value <<= crb_entry->crb_ctrl.shl;
377562306a36Sopenharmony_ci			read_value >>= crb_entry->crb_ctrl.shr;
377662306a36Sopenharmony_ci			if (crb_entry->value_2)
377762306a36Sopenharmony_ci				read_value &= crb_entry->value_2;
377862306a36Sopenharmony_ci			read_value |= crb_entry->value_3;
377962306a36Sopenharmony_ci			read_value += crb_entry->value_1;
378062306a36Sopenharmony_ci			tmplt_hdr->saved_state_array[index] = read_value;
378162306a36Sopenharmony_ci			opcode &= ~QLA82XX_DBG_OPCODE_MDSTATE;
378262306a36Sopenharmony_ci		}
378362306a36Sopenharmony_ci		crb_addr += crb_entry->crb_strd.addr_stride;
378462306a36Sopenharmony_ci	}
378562306a36Sopenharmony_ci	return rval;
378662306a36Sopenharmony_ci}
378762306a36Sopenharmony_ci
378862306a36Sopenharmony_cistatic void
378962306a36Sopenharmony_ciqla82xx_minidump_process_rdocm(scsi_qla_host_t *vha,
379062306a36Sopenharmony_ci	qla82xx_md_entry_hdr_t *entry_hdr, __le32 **d_ptr)
379162306a36Sopenharmony_ci{
379262306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
379362306a36Sopenharmony_ci	uint32_t r_addr, r_stride, loop_cnt, i, r_value;
379462306a36Sopenharmony_ci	struct qla82xx_md_entry_rdocm *ocm_hdr;
379562306a36Sopenharmony_ci	__le32 *data_ptr = *d_ptr;
379662306a36Sopenharmony_ci
379762306a36Sopenharmony_ci	ocm_hdr = (struct qla82xx_md_entry_rdocm *)entry_hdr;
379862306a36Sopenharmony_ci	r_addr = ocm_hdr->read_addr;
379962306a36Sopenharmony_ci	r_stride = ocm_hdr->read_addr_stride;
380062306a36Sopenharmony_ci	loop_cnt = ocm_hdr->op_count;
380162306a36Sopenharmony_ci
380262306a36Sopenharmony_ci	for (i = 0; i < loop_cnt; i++) {
380362306a36Sopenharmony_ci		r_value = rd_reg_dword(r_addr + ha->nx_pcibase);
380462306a36Sopenharmony_ci		*data_ptr++ = cpu_to_le32(r_value);
380562306a36Sopenharmony_ci		r_addr += r_stride;
380662306a36Sopenharmony_ci	}
380762306a36Sopenharmony_ci	*d_ptr = data_ptr;
380862306a36Sopenharmony_ci}
380962306a36Sopenharmony_ci
381062306a36Sopenharmony_cistatic void
381162306a36Sopenharmony_ciqla82xx_minidump_process_rdmux(scsi_qla_host_t *vha,
381262306a36Sopenharmony_ci	qla82xx_md_entry_hdr_t *entry_hdr, __le32 **d_ptr)
381362306a36Sopenharmony_ci{
381462306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
381562306a36Sopenharmony_ci	uint32_t r_addr, s_stride, s_addr, s_value, loop_cnt, i, r_value;
381662306a36Sopenharmony_ci	struct qla82xx_md_entry_mux *mux_hdr;
381762306a36Sopenharmony_ci	__le32 *data_ptr = *d_ptr;
381862306a36Sopenharmony_ci
381962306a36Sopenharmony_ci	mux_hdr = (struct qla82xx_md_entry_mux *)entry_hdr;
382062306a36Sopenharmony_ci	r_addr = mux_hdr->read_addr;
382162306a36Sopenharmony_ci	s_addr = mux_hdr->select_addr;
382262306a36Sopenharmony_ci	s_stride = mux_hdr->select_value_stride;
382362306a36Sopenharmony_ci	s_value = mux_hdr->select_value;
382462306a36Sopenharmony_ci	loop_cnt = mux_hdr->op_count;
382562306a36Sopenharmony_ci
382662306a36Sopenharmony_ci	for (i = 0; i < loop_cnt; i++) {
382762306a36Sopenharmony_ci		qla82xx_md_rw_32(ha, s_addr, s_value, 1);
382862306a36Sopenharmony_ci		r_value = qla82xx_md_rw_32(ha, r_addr, 0, 0);
382962306a36Sopenharmony_ci		*data_ptr++ = cpu_to_le32(s_value);
383062306a36Sopenharmony_ci		*data_ptr++ = cpu_to_le32(r_value);
383162306a36Sopenharmony_ci		s_value += s_stride;
383262306a36Sopenharmony_ci	}
383362306a36Sopenharmony_ci	*d_ptr = data_ptr;
383462306a36Sopenharmony_ci}
383562306a36Sopenharmony_ci
383662306a36Sopenharmony_cistatic void
383762306a36Sopenharmony_ciqla82xx_minidump_process_rdcrb(scsi_qla_host_t *vha,
383862306a36Sopenharmony_ci	qla82xx_md_entry_hdr_t *entry_hdr, __le32 **d_ptr)
383962306a36Sopenharmony_ci{
384062306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
384162306a36Sopenharmony_ci	uint32_t r_addr, r_stride, loop_cnt, i, r_value;
384262306a36Sopenharmony_ci	struct qla82xx_md_entry_crb *crb_hdr;
384362306a36Sopenharmony_ci	__le32 *data_ptr = *d_ptr;
384462306a36Sopenharmony_ci
384562306a36Sopenharmony_ci	crb_hdr = (struct qla82xx_md_entry_crb *)entry_hdr;
384662306a36Sopenharmony_ci	r_addr = crb_hdr->addr;
384762306a36Sopenharmony_ci	r_stride = crb_hdr->crb_strd.addr_stride;
384862306a36Sopenharmony_ci	loop_cnt = crb_hdr->op_count;
384962306a36Sopenharmony_ci
385062306a36Sopenharmony_ci	for (i = 0; i < loop_cnt; i++) {
385162306a36Sopenharmony_ci		r_value = qla82xx_md_rw_32(ha, r_addr, 0, 0);
385262306a36Sopenharmony_ci		*data_ptr++ = cpu_to_le32(r_addr);
385362306a36Sopenharmony_ci		*data_ptr++ = cpu_to_le32(r_value);
385462306a36Sopenharmony_ci		r_addr += r_stride;
385562306a36Sopenharmony_ci	}
385662306a36Sopenharmony_ci	*d_ptr = data_ptr;
385762306a36Sopenharmony_ci}
385862306a36Sopenharmony_ci
385962306a36Sopenharmony_cistatic int
386062306a36Sopenharmony_ciqla82xx_minidump_process_l2tag(scsi_qla_host_t *vha,
386162306a36Sopenharmony_ci	qla82xx_md_entry_hdr_t *entry_hdr, __le32 **d_ptr)
386262306a36Sopenharmony_ci{
386362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
386462306a36Sopenharmony_ci	uint32_t addr, r_addr, c_addr, t_r_addr;
386562306a36Sopenharmony_ci	uint32_t i, k, loop_count, t_value, r_cnt, r_value;
386662306a36Sopenharmony_ci	unsigned long p_wait, w_time, p_mask;
386762306a36Sopenharmony_ci	uint32_t c_value_w, c_value_r;
386862306a36Sopenharmony_ci	struct qla82xx_md_entry_cache *cache_hdr;
386962306a36Sopenharmony_ci	int rval = QLA_FUNCTION_FAILED;
387062306a36Sopenharmony_ci	__le32 *data_ptr = *d_ptr;
387162306a36Sopenharmony_ci
387262306a36Sopenharmony_ci	cache_hdr = (struct qla82xx_md_entry_cache *)entry_hdr;
387362306a36Sopenharmony_ci	loop_count = cache_hdr->op_count;
387462306a36Sopenharmony_ci	r_addr = cache_hdr->read_addr;
387562306a36Sopenharmony_ci	c_addr = cache_hdr->control_addr;
387662306a36Sopenharmony_ci	c_value_w = cache_hdr->cache_ctrl.write_value;
387762306a36Sopenharmony_ci
387862306a36Sopenharmony_ci	t_r_addr = cache_hdr->tag_reg_addr;
387962306a36Sopenharmony_ci	t_value = cache_hdr->addr_ctrl.init_tag_value;
388062306a36Sopenharmony_ci	r_cnt = cache_hdr->read_ctrl.read_addr_cnt;
388162306a36Sopenharmony_ci	p_wait = cache_hdr->cache_ctrl.poll_wait;
388262306a36Sopenharmony_ci	p_mask = cache_hdr->cache_ctrl.poll_mask;
388362306a36Sopenharmony_ci
388462306a36Sopenharmony_ci	for (i = 0; i < loop_count; i++) {
388562306a36Sopenharmony_ci		qla82xx_md_rw_32(ha, t_r_addr, t_value, 1);
388662306a36Sopenharmony_ci		if (c_value_w)
388762306a36Sopenharmony_ci			qla82xx_md_rw_32(ha, c_addr, c_value_w, 1);
388862306a36Sopenharmony_ci
388962306a36Sopenharmony_ci		if (p_mask) {
389062306a36Sopenharmony_ci			w_time = jiffies + p_wait;
389162306a36Sopenharmony_ci			do {
389262306a36Sopenharmony_ci				c_value_r = qla82xx_md_rw_32(ha, c_addr, 0, 0);
389362306a36Sopenharmony_ci				if ((c_value_r & p_mask) == 0)
389462306a36Sopenharmony_ci					break;
389562306a36Sopenharmony_ci				else if (time_after_eq(jiffies, w_time)) {
389662306a36Sopenharmony_ci					/* capturing dump failed */
389762306a36Sopenharmony_ci					ql_dbg(ql_dbg_p3p, vha, 0xb032,
389862306a36Sopenharmony_ci					    "c_value_r: 0x%x, poll_mask: 0x%lx, "
389962306a36Sopenharmony_ci					    "w_time: 0x%lx\n",
390062306a36Sopenharmony_ci					    c_value_r, p_mask, w_time);
390162306a36Sopenharmony_ci					return rval;
390262306a36Sopenharmony_ci				}
390362306a36Sopenharmony_ci			} while (1);
390462306a36Sopenharmony_ci		}
390562306a36Sopenharmony_ci
390662306a36Sopenharmony_ci		addr = r_addr;
390762306a36Sopenharmony_ci		for (k = 0; k < r_cnt; k++) {
390862306a36Sopenharmony_ci			r_value = qla82xx_md_rw_32(ha, addr, 0, 0);
390962306a36Sopenharmony_ci			*data_ptr++ = cpu_to_le32(r_value);
391062306a36Sopenharmony_ci			addr += cache_hdr->read_ctrl.read_addr_stride;
391162306a36Sopenharmony_ci		}
391262306a36Sopenharmony_ci		t_value += cache_hdr->addr_ctrl.tag_value_stride;
391362306a36Sopenharmony_ci	}
391462306a36Sopenharmony_ci	*d_ptr = data_ptr;
391562306a36Sopenharmony_ci	return QLA_SUCCESS;
391662306a36Sopenharmony_ci}
391762306a36Sopenharmony_ci
391862306a36Sopenharmony_cistatic void
391962306a36Sopenharmony_ciqla82xx_minidump_process_l1cache(scsi_qla_host_t *vha,
392062306a36Sopenharmony_ci	qla82xx_md_entry_hdr_t *entry_hdr, __le32 **d_ptr)
392162306a36Sopenharmony_ci{
392262306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
392362306a36Sopenharmony_ci	uint32_t addr, r_addr, c_addr, t_r_addr;
392462306a36Sopenharmony_ci	uint32_t i, k, loop_count, t_value, r_cnt, r_value;
392562306a36Sopenharmony_ci	uint32_t c_value_w;
392662306a36Sopenharmony_ci	struct qla82xx_md_entry_cache *cache_hdr;
392762306a36Sopenharmony_ci	__le32 *data_ptr = *d_ptr;
392862306a36Sopenharmony_ci
392962306a36Sopenharmony_ci	cache_hdr = (struct qla82xx_md_entry_cache *)entry_hdr;
393062306a36Sopenharmony_ci	loop_count = cache_hdr->op_count;
393162306a36Sopenharmony_ci	r_addr = cache_hdr->read_addr;
393262306a36Sopenharmony_ci	c_addr = cache_hdr->control_addr;
393362306a36Sopenharmony_ci	c_value_w = cache_hdr->cache_ctrl.write_value;
393462306a36Sopenharmony_ci
393562306a36Sopenharmony_ci	t_r_addr = cache_hdr->tag_reg_addr;
393662306a36Sopenharmony_ci	t_value = cache_hdr->addr_ctrl.init_tag_value;
393762306a36Sopenharmony_ci	r_cnt = cache_hdr->read_ctrl.read_addr_cnt;
393862306a36Sopenharmony_ci
393962306a36Sopenharmony_ci	for (i = 0; i < loop_count; i++) {
394062306a36Sopenharmony_ci		qla82xx_md_rw_32(ha, t_r_addr, t_value, 1);
394162306a36Sopenharmony_ci		qla82xx_md_rw_32(ha, c_addr, c_value_w, 1);
394262306a36Sopenharmony_ci		addr = r_addr;
394362306a36Sopenharmony_ci		for (k = 0; k < r_cnt; k++) {
394462306a36Sopenharmony_ci			r_value = qla82xx_md_rw_32(ha, addr, 0, 0);
394562306a36Sopenharmony_ci			*data_ptr++ = cpu_to_le32(r_value);
394662306a36Sopenharmony_ci			addr += cache_hdr->read_ctrl.read_addr_stride;
394762306a36Sopenharmony_ci		}
394862306a36Sopenharmony_ci		t_value += cache_hdr->addr_ctrl.tag_value_stride;
394962306a36Sopenharmony_ci	}
395062306a36Sopenharmony_ci	*d_ptr = data_ptr;
395162306a36Sopenharmony_ci}
395262306a36Sopenharmony_ci
395362306a36Sopenharmony_cistatic void
395462306a36Sopenharmony_ciqla82xx_minidump_process_queue(scsi_qla_host_t *vha,
395562306a36Sopenharmony_ci	qla82xx_md_entry_hdr_t *entry_hdr, __le32 **d_ptr)
395662306a36Sopenharmony_ci{
395762306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
395862306a36Sopenharmony_ci	uint32_t s_addr, r_addr;
395962306a36Sopenharmony_ci	uint32_t r_stride, r_value, r_cnt, qid = 0;
396062306a36Sopenharmony_ci	uint32_t i, k, loop_cnt;
396162306a36Sopenharmony_ci	struct qla82xx_md_entry_queue *q_hdr;
396262306a36Sopenharmony_ci	__le32 *data_ptr = *d_ptr;
396362306a36Sopenharmony_ci
396462306a36Sopenharmony_ci	q_hdr = (struct qla82xx_md_entry_queue *)entry_hdr;
396562306a36Sopenharmony_ci	s_addr = q_hdr->select_addr;
396662306a36Sopenharmony_ci	r_cnt = q_hdr->rd_strd.read_addr_cnt;
396762306a36Sopenharmony_ci	r_stride = q_hdr->rd_strd.read_addr_stride;
396862306a36Sopenharmony_ci	loop_cnt = q_hdr->op_count;
396962306a36Sopenharmony_ci
397062306a36Sopenharmony_ci	for (i = 0; i < loop_cnt; i++) {
397162306a36Sopenharmony_ci		qla82xx_md_rw_32(ha, s_addr, qid, 1);
397262306a36Sopenharmony_ci		r_addr = q_hdr->read_addr;
397362306a36Sopenharmony_ci		for (k = 0; k < r_cnt; k++) {
397462306a36Sopenharmony_ci			r_value = qla82xx_md_rw_32(ha, r_addr, 0, 0);
397562306a36Sopenharmony_ci			*data_ptr++ = cpu_to_le32(r_value);
397662306a36Sopenharmony_ci			r_addr += r_stride;
397762306a36Sopenharmony_ci		}
397862306a36Sopenharmony_ci		qid += q_hdr->q_strd.queue_id_stride;
397962306a36Sopenharmony_ci	}
398062306a36Sopenharmony_ci	*d_ptr = data_ptr;
398162306a36Sopenharmony_ci}
398262306a36Sopenharmony_ci
398362306a36Sopenharmony_cistatic void
398462306a36Sopenharmony_ciqla82xx_minidump_process_rdrom(scsi_qla_host_t *vha,
398562306a36Sopenharmony_ci	qla82xx_md_entry_hdr_t *entry_hdr, __le32 **d_ptr)
398662306a36Sopenharmony_ci{
398762306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
398862306a36Sopenharmony_ci	uint32_t r_addr, r_value;
398962306a36Sopenharmony_ci	uint32_t i, loop_cnt;
399062306a36Sopenharmony_ci	struct qla82xx_md_entry_rdrom *rom_hdr;
399162306a36Sopenharmony_ci	__le32 *data_ptr = *d_ptr;
399262306a36Sopenharmony_ci
399362306a36Sopenharmony_ci	rom_hdr = (struct qla82xx_md_entry_rdrom *)entry_hdr;
399462306a36Sopenharmony_ci	r_addr = rom_hdr->read_addr;
399562306a36Sopenharmony_ci	loop_cnt = rom_hdr->read_data_size/sizeof(uint32_t);
399662306a36Sopenharmony_ci
399762306a36Sopenharmony_ci	for (i = 0; i < loop_cnt; i++) {
399862306a36Sopenharmony_ci		qla82xx_md_rw_32(ha, MD_DIRECT_ROM_WINDOW,
399962306a36Sopenharmony_ci		    (r_addr & 0xFFFF0000), 1);
400062306a36Sopenharmony_ci		r_value = qla82xx_md_rw_32(ha,
400162306a36Sopenharmony_ci		    MD_DIRECT_ROM_READ_BASE +
400262306a36Sopenharmony_ci		    (r_addr & 0x0000FFFF), 0, 0);
400362306a36Sopenharmony_ci		*data_ptr++ = cpu_to_le32(r_value);
400462306a36Sopenharmony_ci		r_addr += sizeof(uint32_t);
400562306a36Sopenharmony_ci	}
400662306a36Sopenharmony_ci	*d_ptr = data_ptr;
400762306a36Sopenharmony_ci}
400862306a36Sopenharmony_ci
400962306a36Sopenharmony_cistatic int
401062306a36Sopenharmony_ciqla82xx_minidump_process_rdmem(scsi_qla_host_t *vha,
401162306a36Sopenharmony_ci	qla82xx_md_entry_hdr_t *entry_hdr, __le32 **d_ptr)
401262306a36Sopenharmony_ci{
401362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
401462306a36Sopenharmony_ci	uint32_t r_addr, r_value, r_data;
401562306a36Sopenharmony_ci	uint32_t i, j, loop_cnt;
401662306a36Sopenharmony_ci	struct qla82xx_md_entry_rdmem *m_hdr;
401762306a36Sopenharmony_ci	unsigned long flags;
401862306a36Sopenharmony_ci	int rval = QLA_FUNCTION_FAILED;
401962306a36Sopenharmony_ci	__le32 *data_ptr = *d_ptr;
402062306a36Sopenharmony_ci
402162306a36Sopenharmony_ci	m_hdr = (struct qla82xx_md_entry_rdmem *)entry_hdr;
402262306a36Sopenharmony_ci	r_addr = m_hdr->read_addr;
402362306a36Sopenharmony_ci	loop_cnt = m_hdr->read_data_size/16;
402462306a36Sopenharmony_ci
402562306a36Sopenharmony_ci	if (r_addr & 0xf) {
402662306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb033,
402762306a36Sopenharmony_ci		    "Read addr 0x%x not 16 bytes aligned\n", r_addr);
402862306a36Sopenharmony_ci		return rval;
402962306a36Sopenharmony_ci	}
403062306a36Sopenharmony_ci
403162306a36Sopenharmony_ci	if (m_hdr->read_data_size % 16) {
403262306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb034,
403362306a36Sopenharmony_ci		    "Read data[0x%x] not multiple of 16 bytes\n",
403462306a36Sopenharmony_ci		    m_hdr->read_data_size);
403562306a36Sopenharmony_ci		return rval;
403662306a36Sopenharmony_ci	}
403762306a36Sopenharmony_ci
403862306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb035,
403962306a36Sopenharmony_ci	    "[%s]: rdmem_addr: 0x%x, read_data_size: 0x%x, loop_cnt: 0x%x\n",
404062306a36Sopenharmony_ci	    __func__, r_addr, m_hdr->read_data_size, loop_cnt);
404162306a36Sopenharmony_ci
404262306a36Sopenharmony_ci	write_lock_irqsave(&ha->hw_lock, flags);
404362306a36Sopenharmony_ci	for (i = 0; i < loop_cnt; i++) {
404462306a36Sopenharmony_ci		qla82xx_md_rw_32(ha, MD_MIU_TEST_AGT_ADDR_LO, r_addr, 1);
404562306a36Sopenharmony_ci		r_value = 0;
404662306a36Sopenharmony_ci		qla82xx_md_rw_32(ha, MD_MIU_TEST_AGT_ADDR_HI, r_value, 1);
404762306a36Sopenharmony_ci		r_value = MIU_TA_CTL_ENABLE;
404862306a36Sopenharmony_ci		qla82xx_md_rw_32(ha, MD_MIU_TEST_AGT_CTRL, r_value, 1);
404962306a36Sopenharmony_ci		r_value = MIU_TA_CTL_START | MIU_TA_CTL_ENABLE;
405062306a36Sopenharmony_ci		qla82xx_md_rw_32(ha, MD_MIU_TEST_AGT_CTRL, r_value, 1);
405162306a36Sopenharmony_ci
405262306a36Sopenharmony_ci		for (j = 0; j < MAX_CTL_CHECK; j++) {
405362306a36Sopenharmony_ci			r_value = qla82xx_md_rw_32(ha,
405462306a36Sopenharmony_ci			    MD_MIU_TEST_AGT_CTRL, 0, 0);
405562306a36Sopenharmony_ci			if ((r_value & MIU_TA_CTL_BUSY) == 0)
405662306a36Sopenharmony_ci				break;
405762306a36Sopenharmony_ci		}
405862306a36Sopenharmony_ci
405962306a36Sopenharmony_ci		if (j >= MAX_CTL_CHECK) {
406062306a36Sopenharmony_ci			printk_ratelimited(KERN_ERR
406162306a36Sopenharmony_ci			    "failed to read through agent\n");
406262306a36Sopenharmony_ci			write_unlock_irqrestore(&ha->hw_lock, flags);
406362306a36Sopenharmony_ci			return rval;
406462306a36Sopenharmony_ci		}
406562306a36Sopenharmony_ci
406662306a36Sopenharmony_ci		for (j = 0; j < 4; j++) {
406762306a36Sopenharmony_ci			r_data = qla82xx_md_rw_32(ha,
406862306a36Sopenharmony_ci			    MD_MIU_TEST_AGT_RDDATA[j], 0, 0);
406962306a36Sopenharmony_ci			*data_ptr++ = cpu_to_le32(r_data);
407062306a36Sopenharmony_ci		}
407162306a36Sopenharmony_ci		r_addr += 16;
407262306a36Sopenharmony_ci	}
407362306a36Sopenharmony_ci	write_unlock_irqrestore(&ha->hw_lock, flags);
407462306a36Sopenharmony_ci	*d_ptr = data_ptr;
407562306a36Sopenharmony_ci	return QLA_SUCCESS;
407662306a36Sopenharmony_ci}
407762306a36Sopenharmony_ci
407862306a36Sopenharmony_ciint
407962306a36Sopenharmony_ciqla82xx_validate_template_chksum(scsi_qla_host_t *vha)
408062306a36Sopenharmony_ci{
408162306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
408262306a36Sopenharmony_ci	uint64_t chksum = 0;
408362306a36Sopenharmony_ci	uint32_t *d_ptr = (uint32_t *)ha->md_tmplt_hdr;
408462306a36Sopenharmony_ci	int count = ha->md_template_size/sizeof(uint32_t);
408562306a36Sopenharmony_ci
408662306a36Sopenharmony_ci	while (count-- > 0)
408762306a36Sopenharmony_ci		chksum += *d_ptr++;
408862306a36Sopenharmony_ci	while (chksum >> 32)
408962306a36Sopenharmony_ci		chksum = (chksum & 0xFFFFFFFF) + (chksum >> 32);
409062306a36Sopenharmony_ci	return ~chksum;
409162306a36Sopenharmony_ci}
409262306a36Sopenharmony_ci
409362306a36Sopenharmony_cistatic void
409462306a36Sopenharmony_ciqla82xx_mark_entry_skipped(scsi_qla_host_t *vha,
409562306a36Sopenharmony_ci	qla82xx_md_entry_hdr_t *entry_hdr, int index)
409662306a36Sopenharmony_ci{
409762306a36Sopenharmony_ci	entry_hdr->d_ctrl.driver_flags |= QLA82XX_DBG_SKIPPED_FLAG;
409862306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb036,
409962306a36Sopenharmony_ci	    "Skipping entry[%d]: "
410062306a36Sopenharmony_ci	    "ETYPE[0x%x]-ELEVEL[0x%x]\n",
410162306a36Sopenharmony_ci	    index, entry_hdr->entry_type,
410262306a36Sopenharmony_ci	    entry_hdr->d_ctrl.entry_capture_mask);
410362306a36Sopenharmony_ci}
410462306a36Sopenharmony_ci
410562306a36Sopenharmony_ciint
410662306a36Sopenharmony_ciqla82xx_md_collect(scsi_qla_host_t *vha)
410762306a36Sopenharmony_ci{
410862306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
410962306a36Sopenharmony_ci	int no_entry_hdr = 0;
411062306a36Sopenharmony_ci	qla82xx_md_entry_hdr_t *entry_hdr;
411162306a36Sopenharmony_ci	struct qla82xx_md_template_hdr *tmplt_hdr;
411262306a36Sopenharmony_ci	__le32 *data_ptr;
411362306a36Sopenharmony_ci	uint32_t total_data_size = 0, f_capture_mask, data_collected = 0;
411462306a36Sopenharmony_ci	int i = 0, rval = QLA_FUNCTION_FAILED;
411562306a36Sopenharmony_ci
411662306a36Sopenharmony_ci	tmplt_hdr = (struct qla82xx_md_template_hdr *)ha->md_tmplt_hdr;
411762306a36Sopenharmony_ci	data_ptr = ha->md_dump;
411862306a36Sopenharmony_ci
411962306a36Sopenharmony_ci	if (ha->fw_dumped) {
412062306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb037,
412162306a36Sopenharmony_ci		    "Firmware has been previously dumped (%p) "
412262306a36Sopenharmony_ci		    "-- ignoring request.\n", ha->fw_dump);
412362306a36Sopenharmony_ci		goto md_failed;
412462306a36Sopenharmony_ci	}
412562306a36Sopenharmony_ci
412662306a36Sopenharmony_ci	ha->fw_dumped = false;
412762306a36Sopenharmony_ci
412862306a36Sopenharmony_ci	if (!ha->md_tmplt_hdr || !ha->md_dump) {
412962306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb038,
413062306a36Sopenharmony_ci		    "Memory not allocated for minidump capture\n");
413162306a36Sopenharmony_ci		goto md_failed;
413262306a36Sopenharmony_ci	}
413362306a36Sopenharmony_ci
413462306a36Sopenharmony_ci	if (ha->flags.isp82xx_no_md_cap) {
413562306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb054,
413662306a36Sopenharmony_ci		    "Forced reset from application, "
413762306a36Sopenharmony_ci		    "ignore minidump capture\n");
413862306a36Sopenharmony_ci		ha->flags.isp82xx_no_md_cap = 0;
413962306a36Sopenharmony_ci		goto md_failed;
414062306a36Sopenharmony_ci	}
414162306a36Sopenharmony_ci
414262306a36Sopenharmony_ci	if (qla82xx_validate_template_chksum(vha)) {
414362306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0xb039,
414462306a36Sopenharmony_ci		    "Template checksum validation error\n");
414562306a36Sopenharmony_ci		goto md_failed;
414662306a36Sopenharmony_ci	}
414762306a36Sopenharmony_ci
414862306a36Sopenharmony_ci	no_entry_hdr = tmplt_hdr->num_of_entries;
414962306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb03a,
415062306a36Sopenharmony_ci	    "No of entry headers in Template: 0x%x\n", no_entry_hdr);
415162306a36Sopenharmony_ci
415262306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb03b,
415362306a36Sopenharmony_ci	    "Capture Mask obtained: 0x%x\n", tmplt_hdr->capture_debug_level);
415462306a36Sopenharmony_ci
415562306a36Sopenharmony_ci	f_capture_mask = tmplt_hdr->capture_debug_level & 0xFF;
415662306a36Sopenharmony_ci
415762306a36Sopenharmony_ci	/* Validate whether required debug level is set */
415862306a36Sopenharmony_ci	if ((f_capture_mask & 0x3) != 0x3) {
415962306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb03c,
416062306a36Sopenharmony_ci		    "Minimum required capture mask[0x%x] level not set\n",
416162306a36Sopenharmony_ci		    f_capture_mask);
416262306a36Sopenharmony_ci		goto md_failed;
416362306a36Sopenharmony_ci	}
416462306a36Sopenharmony_ci	tmplt_hdr->driver_capture_mask = ql2xmdcapmask;
416562306a36Sopenharmony_ci
416662306a36Sopenharmony_ci	tmplt_hdr->driver_info[0] = vha->host_no;
416762306a36Sopenharmony_ci	tmplt_hdr->driver_info[1] = (QLA_DRIVER_MAJOR_VER << 24) |
416862306a36Sopenharmony_ci	    (QLA_DRIVER_MINOR_VER << 16) | (QLA_DRIVER_PATCH_VER << 8) |
416962306a36Sopenharmony_ci	    QLA_DRIVER_BETA_VER;
417062306a36Sopenharmony_ci
417162306a36Sopenharmony_ci	total_data_size = ha->md_dump_size;
417262306a36Sopenharmony_ci
417362306a36Sopenharmony_ci	ql_dbg(ql_dbg_p3p, vha, 0xb03d,
417462306a36Sopenharmony_ci	    "Total minidump data_size 0x%x to be captured\n", total_data_size);
417562306a36Sopenharmony_ci
417662306a36Sopenharmony_ci	/* Check whether template obtained is valid */
417762306a36Sopenharmony_ci	if (tmplt_hdr->entry_type != QLA82XX_TLHDR) {
417862306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb04e,
417962306a36Sopenharmony_ci		    "Bad template header entry type: 0x%x obtained\n",
418062306a36Sopenharmony_ci		    tmplt_hdr->entry_type);
418162306a36Sopenharmony_ci		goto md_failed;
418262306a36Sopenharmony_ci	}
418362306a36Sopenharmony_ci
418462306a36Sopenharmony_ci	entry_hdr = (qla82xx_md_entry_hdr_t *)
418562306a36Sopenharmony_ci	    (((uint8_t *)ha->md_tmplt_hdr) + tmplt_hdr->first_entry_offset);
418662306a36Sopenharmony_ci
418762306a36Sopenharmony_ci	/* Walk through the entry headers */
418862306a36Sopenharmony_ci	for (i = 0; i < no_entry_hdr; i++) {
418962306a36Sopenharmony_ci
419062306a36Sopenharmony_ci		if (data_collected > total_data_size) {
419162306a36Sopenharmony_ci			ql_log(ql_log_warn, vha, 0xb03e,
419262306a36Sopenharmony_ci			    "More MiniDump data collected: [0x%x]\n",
419362306a36Sopenharmony_ci			    data_collected);
419462306a36Sopenharmony_ci			goto md_failed;
419562306a36Sopenharmony_ci		}
419662306a36Sopenharmony_ci
419762306a36Sopenharmony_ci		if (!(entry_hdr->d_ctrl.entry_capture_mask &
419862306a36Sopenharmony_ci		    ql2xmdcapmask)) {
419962306a36Sopenharmony_ci			entry_hdr->d_ctrl.driver_flags |=
420062306a36Sopenharmony_ci			    QLA82XX_DBG_SKIPPED_FLAG;
420162306a36Sopenharmony_ci			ql_dbg(ql_dbg_p3p, vha, 0xb03f,
420262306a36Sopenharmony_ci			    "Skipping entry[%d]: "
420362306a36Sopenharmony_ci			    "ETYPE[0x%x]-ELEVEL[0x%x]\n",
420462306a36Sopenharmony_ci			    i, entry_hdr->entry_type,
420562306a36Sopenharmony_ci			    entry_hdr->d_ctrl.entry_capture_mask);
420662306a36Sopenharmony_ci			goto skip_nxt_entry;
420762306a36Sopenharmony_ci		}
420862306a36Sopenharmony_ci
420962306a36Sopenharmony_ci		ql_dbg(ql_dbg_p3p, vha, 0xb040,
421062306a36Sopenharmony_ci		    "[%s]: data ptr[%d]: %p, entry_hdr: %p\n"
421162306a36Sopenharmony_ci		    "entry_type: 0x%x, capture_mask: 0x%x\n",
421262306a36Sopenharmony_ci		    __func__, i, data_ptr, entry_hdr,
421362306a36Sopenharmony_ci		    entry_hdr->entry_type,
421462306a36Sopenharmony_ci		    entry_hdr->d_ctrl.entry_capture_mask);
421562306a36Sopenharmony_ci
421662306a36Sopenharmony_ci		ql_dbg(ql_dbg_p3p, vha, 0xb041,
421762306a36Sopenharmony_ci		    "Data collected: [0x%x], Dump size left:[0x%x]\n",
421862306a36Sopenharmony_ci		    data_collected, (ha->md_dump_size - data_collected));
421962306a36Sopenharmony_ci
422062306a36Sopenharmony_ci		/* Decode the entry type and take
422162306a36Sopenharmony_ci		 * required action to capture debug data */
422262306a36Sopenharmony_ci		switch (entry_hdr->entry_type) {
422362306a36Sopenharmony_ci		case QLA82XX_RDEND:
422462306a36Sopenharmony_ci			qla82xx_mark_entry_skipped(vha, entry_hdr, i);
422562306a36Sopenharmony_ci			break;
422662306a36Sopenharmony_ci		case QLA82XX_CNTRL:
422762306a36Sopenharmony_ci			rval = qla82xx_minidump_process_control(vha,
422862306a36Sopenharmony_ci			    entry_hdr, &data_ptr);
422962306a36Sopenharmony_ci			if (rval != QLA_SUCCESS) {
423062306a36Sopenharmony_ci				qla82xx_mark_entry_skipped(vha, entry_hdr, i);
423162306a36Sopenharmony_ci				goto md_failed;
423262306a36Sopenharmony_ci			}
423362306a36Sopenharmony_ci			break;
423462306a36Sopenharmony_ci		case QLA82XX_RDCRB:
423562306a36Sopenharmony_ci			qla82xx_minidump_process_rdcrb(vha,
423662306a36Sopenharmony_ci			    entry_hdr, &data_ptr);
423762306a36Sopenharmony_ci			break;
423862306a36Sopenharmony_ci		case QLA82XX_RDMEM:
423962306a36Sopenharmony_ci			rval = qla82xx_minidump_process_rdmem(vha,
424062306a36Sopenharmony_ci			    entry_hdr, &data_ptr);
424162306a36Sopenharmony_ci			if (rval != QLA_SUCCESS) {
424262306a36Sopenharmony_ci				qla82xx_mark_entry_skipped(vha, entry_hdr, i);
424362306a36Sopenharmony_ci				goto md_failed;
424462306a36Sopenharmony_ci			}
424562306a36Sopenharmony_ci			break;
424662306a36Sopenharmony_ci		case QLA82XX_BOARD:
424762306a36Sopenharmony_ci		case QLA82XX_RDROM:
424862306a36Sopenharmony_ci			qla82xx_minidump_process_rdrom(vha,
424962306a36Sopenharmony_ci			    entry_hdr, &data_ptr);
425062306a36Sopenharmony_ci			break;
425162306a36Sopenharmony_ci		case QLA82XX_L2DTG:
425262306a36Sopenharmony_ci		case QLA82XX_L2ITG:
425362306a36Sopenharmony_ci		case QLA82XX_L2DAT:
425462306a36Sopenharmony_ci		case QLA82XX_L2INS:
425562306a36Sopenharmony_ci			rval = qla82xx_minidump_process_l2tag(vha,
425662306a36Sopenharmony_ci			    entry_hdr, &data_ptr);
425762306a36Sopenharmony_ci			if (rval != QLA_SUCCESS) {
425862306a36Sopenharmony_ci				qla82xx_mark_entry_skipped(vha, entry_hdr, i);
425962306a36Sopenharmony_ci				goto md_failed;
426062306a36Sopenharmony_ci			}
426162306a36Sopenharmony_ci			break;
426262306a36Sopenharmony_ci		case QLA82XX_L1DAT:
426362306a36Sopenharmony_ci		case QLA82XX_L1INS:
426462306a36Sopenharmony_ci			qla82xx_minidump_process_l1cache(vha,
426562306a36Sopenharmony_ci			    entry_hdr, &data_ptr);
426662306a36Sopenharmony_ci			break;
426762306a36Sopenharmony_ci		case QLA82XX_RDOCM:
426862306a36Sopenharmony_ci			qla82xx_minidump_process_rdocm(vha,
426962306a36Sopenharmony_ci			    entry_hdr, &data_ptr);
427062306a36Sopenharmony_ci			break;
427162306a36Sopenharmony_ci		case QLA82XX_RDMUX:
427262306a36Sopenharmony_ci			qla82xx_minidump_process_rdmux(vha,
427362306a36Sopenharmony_ci			    entry_hdr, &data_ptr);
427462306a36Sopenharmony_ci			break;
427562306a36Sopenharmony_ci		case QLA82XX_QUEUE:
427662306a36Sopenharmony_ci			qla82xx_minidump_process_queue(vha,
427762306a36Sopenharmony_ci			    entry_hdr, &data_ptr);
427862306a36Sopenharmony_ci			break;
427962306a36Sopenharmony_ci		case QLA82XX_RDNOP:
428062306a36Sopenharmony_ci		default:
428162306a36Sopenharmony_ci			qla82xx_mark_entry_skipped(vha, entry_hdr, i);
428262306a36Sopenharmony_ci			break;
428362306a36Sopenharmony_ci		}
428462306a36Sopenharmony_ci
428562306a36Sopenharmony_ci		ql_dbg(ql_dbg_p3p, vha, 0xb042,
428662306a36Sopenharmony_ci		    "[%s]: data ptr[%d]: %p\n", __func__, i, data_ptr);
428762306a36Sopenharmony_ci
428862306a36Sopenharmony_ci		data_collected = (uint8_t *)data_ptr -
428962306a36Sopenharmony_ci		    (uint8_t *)ha->md_dump;
429062306a36Sopenharmony_ciskip_nxt_entry:
429162306a36Sopenharmony_ci		entry_hdr = (qla82xx_md_entry_hdr_t *)
429262306a36Sopenharmony_ci		    (((uint8_t *)entry_hdr) + entry_hdr->entry_size);
429362306a36Sopenharmony_ci	}
429462306a36Sopenharmony_ci
429562306a36Sopenharmony_ci	if (data_collected != total_data_size) {
429662306a36Sopenharmony_ci		ql_dbg(ql_dbg_p3p, vha, 0xb043,
429762306a36Sopenharmony_ci		    "MiniDump data mismatch: Data collected: [0x%x],"
429862306a36Sopenharmony_ci		    "total_data_size:[0x%x]\n",
429962306a36Sopenharmony_ci		    data_collected, total_data_size);
430062306a36Sopenharmony_ci		goto md_failed;
430162306a36Sopenharmony_ci	}
430262306a36Sopenharmony_ci
430362306a36Sopenharmony_ci	ql_log(ql_log_info, vha, 0xb044,
430462306a36Sopenharmony_ci	    "Firmware dump saved to temp buffer (%ld/%p %ld/%p).\n",
430562306a36Sopenharmony_ci	    vha->host_no, ha->md_tmplt_hdr, vha->host_no, ha->md_dump);
430662306a36Sopenharmony_ci	ha->fw_dumped = true;
430762306a36Sopenharmony_ci	qla2x00_post_uevent_work(vha, QLA_UEVENT_CODE_FW_DUMP);
430862306a36Sopenharmony_ci
430962306a36Sopenharmony_cimd_failed:
431062306a36Sopenharmony_ci	return rval;
431162306a36Sopenharmony_ci}
431262306a36Sopenharmony_ci
431362306a36Sopenharmony_ciint
431462306a36Sopenharmony_ciqla82xx_md_alloc(scsi_qla_host_t *vha)
431562306a36Sopenharmony_ci{
431662306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
431762306a36Sopenharmony_ci	int i, k;
431862306a36Sopenharmony_ci	struct qla82xx_md_template_hdr *tmplt_hdr;
431962306a36Sopenharmony_ci
432062306a36Sopenharmony_ci	tmplt_hdr = (struct qla82xx_md_template_hdr *)ha->md_tmplt_hdr;
432162306a36Sopenharmony_ci
432262306a36Sopenharmony_ci	if (ql2xmdcapmask < 0x3 || ql2xmdcapmask > 0x7F) {
432362306a36Sopenharmony_ci		ql2xmdcapmask = tmplt_hdr->capture_debug_level & 0xFF;
432462306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0xb045,
432562306a36Sopenharmony_ci		    "Forcing driver capture mask to firmware default capture mask: 0x%x.\n",
432662306a36Sopenharmony_ci		    ql2xmdcapmask);
432762306a36Sopenharmony_ci	}
432862306a36Sopenharmony_ci
432962306a36Sopenharmony_ci	for (i = 0x2, k = 1; (i & QLA82XX_DEFAULT_CAP_MASK); i <<= 1, k++) {
433062306a36Sopenharmony_ci		if (i & ql2xmdcapmask)
433162306a36Sopenharmony_ci			ha->md_dump_size += tmplt_hdr->capture_size_array[k];
433262306a36Sopenharmony_ci	}
433362306a36Sopenharmony_ci
433462306a36Sopenharmony_ci	if (ha->md_dump) {
433562306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb046,
433662306a36Sopenharmony_ci		    "Firmware dump previously allocated.\n");
433762306a36Sopenharmony_ci		return 1;
433862306a36Sopenharmony_ci	}
433962306a36Sopenharmony_ci
434062306a36Sopenharmony_ci	ha->md_dump = vmalloc(ha->md_dump_size);
434162306a36Sopenharmony_ci	if (ha->md_dump == NULL) {
434262306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb047,
434362306a36Sopenharmony_ci		    "Unable to allocate memory for Minidump size "
434462306a36Sopenharmony_ci		    "(0x%x).\n", ha->md_dump_size);
434562306a36Sopenharmony_ci		return 1;
434662306a36Sopenharmony_ci	}
434762306a36Sopenharmony_ci	return 0;
434862306a36Sopenharmony_ci}
434962306a36Sopenharmony_ci
435062306a36Sopenharmony_civoid
435162306a36Sopenharmony_ciqla82xx_md_free(scsi_qla_host_t *vha)
435262306a36Sopenharmony_ci{
435362306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
435462306a36Sopenharmony_ci
435562306a36Sopenharmony_ci	/* Release the template header allocated */
435662306a36Sopenharmony_ci	if (ha->md_tmplt_hdr) {
435762306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0xb048,
435862306a36Sopenharmony_ci		    "Free MiniDump template: %p, size (%d KB)\n",
435962306a36Sopenharmony_ci		    ha->md_tmplt_hdr, ha->md_template_size / 1024);
436062306a36Sopenharmony_ci		dma_free_coherent(&ha->pdev->dev, ha->md_template_size,
436162306a36Sopenharmony_ci		    ha->md_tmplt_hdr, ha->md_tmplt_hdr_dma);
436262306a36Sopenharmony_ci		ha->md_tmplt_hdr = NULL;
436362306a36Sopenharmony_ci	}
436462306a36Sopenharmony_ci
436562306a36Sopenharmony_ci	/* Release the template data buffer allocated */
436662306a36Sopenharmony_ci	if (ha->md_dump) {
436762306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0xb049,
436862306a36Sopenharmony_ci		    "Free MiniDump memory: %p, size (%d KB)\n",
436962306a36Sopenharmony_ci		    ha->md_dump, ha->md_dump_size / 1024);
437062306a36Sopenharmony_ci		vfree(ha->md_dump);
437162306a36Sopenharmony_ci		ha->md_dump_size = 0;
437262306a36Sopenharmony_ci		ha->md_dump = NULL;
437362306a36Sopenharmony_ci	}
437462306a36Sopenharmony_ci}
437562306a36Sopenharmony_ci
437662306a36Sopenharmony_civoid
437762306a36Sopenharmony_ciqla82xx_md_prep(scsi_qla_host_t *vha)
437862306a36Sopenharmony_ci{
437962306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
438062306a36Sopenharmony_ci	int rval;
438162306a36Sopenharmony_ci
438262306a36Sopenharmony_ci	/* Get Minidump template size */
438362306a36Sopenharmony_ci	rval = qla82xx_md_get_template_size(vha);
438462306a36Sopenharmony_ci	if (rval == QLA_SUCCESS) {
438562306a36Sopenharmony_ci		ql_log(ql_log_info, vha, 0xb04a,
438662306a36Sopenharmony_ci		    "MiniDump Template size obtained (%d KB)\n",
438762306a36Sopenharmony_ci		    ha->md_template_size / 1024);
438862306a36Sopenharmony_ci
438962306a36Sopenharmony_ci		/* Get Minidump template */
439062306a36Sopenharmony_ci		if (IS_QLA8044(ha))
439162306a36Sopenharmony_ci			rval = qla8044_md_get_template(vha);
439262306a36Sopenharmony_ci		else
439362306a36Sopenharmony_ci			rval = qla82xx_md_get_template(vha);
439462306a36Sopenharmony_ci
439562306a36Sopenharmony_ci		if (rval == QLA_SUCCESS) {
439662306a36Sopenharmony_ci			ql_dbg(ql_dbg_p3p, vha, 0xb04b,
439762306a36Sopenharmony_ci			    "MiniDump Template obtained\n");
439862306a36Sopenharmony_ci
439962306a36Sopenharmony_ci			/* Allocate memory for minidump */
440062306a36Sopenharmony_ci			rval = qla82xx_md_alloc(vha);
440162306a36Sopenharmony_ci			if (rval == QLA_SUCCESS)
440262306a36Sopenharmony_ci				ql_log(ql_log_info, vha, 0xb04c,
440362306a36Sopenharmony_ci				    "MiniDump memory allocated (%d KB)\n",
440462306a36Sopenharmony_ci				    ha->md_dump_size / 1024);
440562306a36Sopenharmony_ci			else {
440662306a36Sopenharmony_ci				ql_log(ql_log_info, vha, 0xb04d,
440762306a36Sopenharmony_ci				    "Free MiniDump template: %p, size: (%d KB)\n",
440862306a36Sopenharmony_ci				    ha->md_tmplt_hdr,
440962306a36Sopenharmony_ci				    ha->md_template_size / 1024);
441062306a36Sopenharmony_ci				dma_free_coherent(&ha->pdev->dev,
441162306a36Sopenharmony_ci				    ha->md_template_size,
441262306a36Sopenharmony_ci				    ha->md_tmplt_hdr, ha->md_tmplt_hdr_dma);
441362306a36Sopenharmony_ci				ha->md_tmplt_hdr = NULL;
441462306a36Sopenharmony_ci			}
441562306a36Sopenharmony_ci
441662306a36Sopenharmony_ci		}
441762306a36Sopenharmony_ci	}
441862306a36Sopenharmony_ci}
441962306a36Sopenharmony_ci
442062306a36Sopenharmony_ciint
442162306a36Sopenharmony_ciqla82xx_beacon_on(struct scsi_qla_host *vha)
442262306a36Sopenharmony_ci{
442362306a36Sopenharmony_ci
442462306a36Sopenharmony_ci	int rval;
442562306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
442662306a36Sopenharmony_ci
442762306a36Sopenharmony_ci	qla82xx_idc_lock(ha);
442862306a36Sopenharmony_ci	rval = qla82xx_mbx_beacon_ctl(vha, 1);
442962306a36Sopenharmony_ci
443062306a36Sopenharmony_ci	if (rval) {
443162306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb050,
443262306a36Sopenharmony_ci		    "mbx set led config failed in %s\n", __func__);
443362306a36Sopenharmony_ci		goto exit;
443462306a36Sopenharmony_ci	}
443562306a36Sopenharmony_ci	ha->beacon_blink_led = 1;
443662306a36Sopenharmony_ciexit:
443762306a36Sopenharmony_ci	qla82xx_idc_unlock(ha);
443862306a36Sopenharmony_ci	return rval;
443962306a36Sopenharmony_ci}
444062306a36Sopenharmony_ci
444162306a36Sopenharmony_ciint
444262306a36Sopenharmony_ciqla82xx_beacon_off(struct scsi_qla_host *vha)
444362306a36Sopenharmony_ci{
444462306a36Sopenharmony_ci
444562306a36Sopenharmony_ci	int rval;
444662306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
444762306a36Sopenharmony_ci
444862306a36Sopenharmony_ci	qla82xx_idc_lock(ha);
444962306a36Sopenharmony_ci	rval = qla82xx_mbx_beacon_ctl(vha, 0);
445062306a36Sopenharmony_ci
445162306a36Sopenharmony_ci	if (rval) {
445262306a36Sopenharmony_ci		ql_log(ql_log_warn, vha, 0xb051,
445362306a36Sopenharmony_ci		    "mbx set led config failed in %s\n", __func__);
445462306a36Sopenharmony_ci		goto exit;
445562306a36Sopenharmony_ci	}
445662306a36Sopenharmony_ci	ha->beacon_blink_led = 0;
445762306a36Sopenharmony_ciexit:
445862306a36Sopenharmony_ci	qla82xx_idc_unlock(ha);
445962306a36Sopenharmony_ci	return rval;
446062306a36Sopenharmony_ci}
446162306a36Sopenharmony_ci
446262306a36Sopenharmony_civoid
446362306a36Sopenharmony_ciqla82xx_fw_dump(scsi_qla_host_t *vha)
446462306a36Sopenharmony_ci{
446562306a36Sopenharmony_ci	struct qla_hw_data *ha = vha->hw;
446662306a36Sopenharmony_ci
446762306a36Sopenharmony_ci	if (!ha->allow_cna_fw_dump)
446862306a36Sopenharmony_ci		return;
446962306a36Sopenharmony_ci
447062306a36Sopenharmony_ci	scsi_block_requests(vha->host);
447162306a36Sopenharmony_ci	ha->flags.isp82xx_no_md_cap = 1;
447262306a36Sopenharmony_ci	qla82xx_idc_lock(ha);
447362306a36Sopenharmony_ci	qla82xx_set_reset_owner(vha);
447462306a36Sopenharmony_ci	qla82xx_idc_unlock(ha);
447562306a36Sopenharmony_ci	qla2x00_wait_for_chip_reset(vha);
447662306a36Sopenharmony_ci	scsi_unblock_requests(vha->host);
447762306a36Sopenharmony_ci}
4478