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