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(®->req_q_out[0], 0); 174762306a36Sopenharmony_ci wrt_reg_dword(®->rsp_q_in[0], 0); 174862306a36Sopenharmony_ci wrt_reg_dword(®->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 = ®->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(®->host_int)) { 202662306a36Sopenharmony_ci stat = rd_reg_dword(®->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(®->mailbox_out[1]); 203962306a36Sopenharmony_ci mb[2] = rd_reg_word(®->mailbox_out[2]); 204062306a36Sopenharmony_ci mb[3] = rd_reg_word(®->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(®->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(®->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(®->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(®->mailbox_out[1]); 210862306a36Sopenharmony_ci mb[2] = rd_reg_word(®->mailbox_out[2]); 210962306a36Sopenharmony_ci mb[3] = rd_reg_word(®->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(®->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(®->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(®->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(®->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(®->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(®->mailbox_out[1]); 220162306a36Sopenharmony_ci mb[2] = rd_reg_word(®->mailbox_out[2]); 220262306a36Sopenharmony_ci mb[3] = rd_reg_word(®->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(®->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