xref: /openbmc/linux/drivers/scsi/qla2xxx/qla_sup.c (revision 7e24a55b2122746c2eef192296fc84624354f895)
177adf3f0SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2fa90c54fSAndrew Vasquez /*
3fa90c54fSAndrew Vasquez  * QLogic Fibre Channel HBA Driver
4bd21eaf9SArmen Baloyan  * Copyright (c)  2003-2014 QLogic Corporation
5fa90c54fSAndrew Vasquez  */
61da177e4SLinus Torvalds #include "qla_def.h"
71da177e4SLinus Torvalds 
81da177e4SLinus Torvalds #include <linux/delay.h>
95a0e3ad6STejun Heo #include <linux/slab.h>
102c96d8d0SAndrew Vasquez #include <linux/vmalloc.h>
117c0f6ba6SLinus Torvalds #include <linux/uaccess.h>
121da177e4SLinus Torvalds 
131da177e4SLinus Torvalds /*
141da177e4SLinus Torvalds  * NVRAM support routines
151da177e4SLinus Torvalds  */
161da177e4SLinus Torvalds 
171da177e4SLinus Torvalds /**
181da177e4SLinus Torvalds  * qla2x00_lock_nvram_access() -
191da177e4SLinus Torvalds  * @ha: HA context
201da177e4SLinus Torvalds  */
21a824ebb3SAdrian Bunk static void
qla2x00_lock_nvram_access(struct qla_hw_data * ha)227b867cf7SAnirban Chakraborty qla2x00_lock_nvram_access(struct qla_hw_data *ha)
231da177e4SLinus Torvalds {
241da177e4SLinus Torvalds 	uint16_t data;
253d71644cSAndrew Vasquez 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds 	if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha)) {
2804474d3aSBart Van Assche 		data = rd_reg_word(&reg->nvram);
291da177e4SLinus Torvalds 		while (data & NVR_BUSY) {
301da177e4SLinus Torvalds 			udelay(100);
3104474d3aSBart Van Assche 			data = rd_reg_word(&reg->nvram);
321da177e4SLinus Torvalds 		}
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds 		/* Lock resource */
3504474d3aSBart Van Assche 		wrt_reg_word(&reg->u.isp2300.host_semaphore, 0x1);
3604474d3aSBart Van Assche 		rd_reg_word(&reg->u.isp2300.host_semaphore);
371da177e4SLinus Torvalds 		udelay(5);
3804474d3aSBart Van Assche 		data = rd_reg_word(&reg->u.isp2300.host_semaphore);
391da177e4SLinus Torvalds 		while ((data & BIT_0) == 0) {
401da177e4SLinus Torvalds 			/* Lock failed */
411da177e4SLinus Torvalds 			udelay(100);
4204474d3aSBart Van Assche 			wrt_reg_word(&reg->u.isp2300.host_semaphore, 0x1);
4304474d3aSBart Van Assche 			rd_reg_word(&reg->u.isp2300.host_semaphore);
441da177e4SLinus Torvalds 			udelay(5);
4504474d3aSBart Van Assche 			data = rd_reg_word(&reg->u.isp2300.host_semaphore);
461da177e4SLinus Torvalds 		}
471da177e4SLinus Torvalds 	}
481da177e4SLinus Torvalds }
491da177e4SLinus Torvalds 
501da177e4SLinus Torvalds /**
511da177e4SLinus Torvalds  * qla2x00_unlock_nvram_access() -
521da177e4SLinus Torvalds  * @ha: HA context
531da177e4SLinus Torvalds  */
54a824ebb3SAdrian Bunk static void
qla2x00_unlock_nvram_access(struct qla_hw_data * ha)557b867cf7SAnirban Chakraborty qla2x00_unlock_nvram_access(struct qla_hw_data *ha)
561da177e4SLinus Torvalds {
573d71644cSAndrew Vasquez 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
581da177e4SLinus Torvalds 
591da177e4SLinus Torvalds 	if (!IS_QLA2100(ha) && !IS_QLA2200(ha) && !IS_QLA2300(ha)) {
6004474d3aSBart Van Assche 		wrt_reg_word(&reg->u.isp2300.host_semaphore, 0);
6104474d3aSBart Van Assche 		rd_reg_word(&reg->u.isp2300.host_semaphore);
621da177e4SLinus Torvalds 	}
631da177e4SLinus Torvalds }
641da177e4SLinus Torvalds 
651da177e4SLinus Torvalds /**
667b867cf7SAnirban Chakraborty  * qla2x00_nv_write() - Prepare for NVRAM read/write operation.
677b867cf7SAnirban Chakraborty  * @ha: HA context
687b867cf7SAnirban Chakraborty  * @data: Serial interface selector
697b867cf7SAnirban Chakraborty  */
707b867cf7SAnirban Chakraborty static void
qla2x00_nv_write(struct qla_hw_data * ha,uint16_t data)717b867cf7SAnirban Chakraborty qla2x00_nv_write(struct qla_hw_data *ha, uint16_t data)
727b867cf7SAnirban Chakraborty {
737b867cf7SAnirban Chakraborty 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
747b867cf7SAnirban Chakraborty 
7504474d3aSBart Van Assche 	wrt_reg_word(&reg->nvram, data | NVR_SELECT | NVR_WRT_ENABLE);
7604474d3aSBart Van Assche 	rd_reg_word(&reg->nvram);		/* PCI Posting. */
777b867cf7SAnirban Chakraborty 	NVRAM_DELAY();
7804474d3aSBart Van Assche 	wrt_reg_word(&reg->nvram, data | NVR_SELECT | NVR_CLOCK |
797b867cf7SAnirban Chakraborty 	    NVR_WRT_ENABLE);
8004474d3aSBart Van Assche 	rd_reg_word(&reg->nvram);		/* PCI Posting. */
817b867cf7SAnirban Chakraborty 	NVRAM_DELAY();
8204474d3aSBart Van Assche 	wrt_reg_word(&reg->nvram, data | NVR_SELECT | NVR_WRT_ENABLE);
8304474d3aSBart Van Assche 	rd_reg_word(&reg->nvram);		/* PCI Posting. */
847b867cf7SAnirban Chakraborty 	NVRAM_DELAY();
857b867cf7SAnirban Chakraborty }
867b867cf7SAnirban Chakraborty 
877b867cf7SAnirban Chakraborty /**
887b867cf7SAnirban Chakraborty  * qla2x00_nvram_request() - Sends read command to NVRAM and gets data from
897b867cf7SAnirban Chakraborty  *	NVRAM.
907b867cf7SAnirban Chakraborty  * @ha: HA context
917b867cf7SAnirban Chakraborty  * @nv_cmd: NVRAM command
927b867cf7SAnirban Chakraborty  *
937b867cf7SAnirban Chakraborty  * Bit definitions for NVRAM command:
947b867cf7SAnirban Chakraborty  *
957b867cf7SAnirban Chakraborty  *	Bit 26     = start bit
967b867cf7SAnirban Chakraborty  *	Bit 25, 24 = opcode
977b867cf7SAnirban Chakraborty  *	Bit 23-16  = address
987b867cf7SAnirban Chakraborty  *	Bit 15-0   = write data
997b867cf7SAnirban Chakraborty  *
1007b867cf7SAnirban Chakraborty  * Returns the word read from nvram @addr.
1017b867cf7SAnirban Chakraborty  */
1027b867cf7SAnirban Chakraborty static uint16_t
qla2x00_nvram_request(struct qla_hw_data * ha,uint32_t nv_cmd)1037b867cf7SAnirban Chakraborty qla2x00_nvram_request(struct qla_hw_data *ha, uint32_t nv_cmd)
1047b867cf7SAnirban Chakraborty {
1057b867cf7SAnirban Chakraborty 	uint8_t		cnt;
1067b867cf7SAnirban Chakraborty 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
1077b867cf7SAnirban Chakraborty 	uint16_t	data = 0;
1087b867cf7SAnirban Chakraborty 	uint16_t	reg_data;
1097b867cf7SAnirban Chakraborty 
1107b867cf7SAnirban Chakraborty 	/* Send command to NVRAM. */
1117b867cf7SAnirban Chakraborty 	nv_cmd <<= 5;
1127b867cf7SAnirban Chakraborty 	for (cnt = 0; cnt < 11; cnt++) {
1137b867cf7SAnirban Chakraborty 		if (nv_cmd & BIT_31)
1147b867cf7SAnirban Chakraborty 			qla2x00_nv_write(ha, NVR_DATA_OUT);
1157b867cf7SAnirban Chakraborty 		else
1167b867cf7SAnirban Chakraborty 			qla2x00_nv_write(ha, 0);
1177b867cf7SAnirban Chakraborty 		nv_cmd <<= 1;
1187b867cf7SAnirban Chakraborty 	}
1197b867cf7SAnirban Chakraborty 
1207b867cf7SAnirban Chakraborty 	/* Read data from NVRAM. */
1217b867cf7SAnirban Chakraborty 	for (cnt = 0; cnt < 16; cnt++) {
12204474d3aSBart Van Assche 		wrt_reg_word(&reg->nvram, NVR_SELECT | NVR_CLOCK);
12304474d3aSBart Van Assche 		rd_reg_word(&reg->nvram);	/* PCI Posting. */
1247b867cf7SAnirban Chakraborty 		NVRAM_DELAY();
1257b867cf7SAnirban Chakraborty 		data <<= 1;
12604474d3aSBart Van Assche 		reg_data = rd_reg_word(&reg->nvram);
1277b867cf7SAnirban Chakraborty 		if (reg_data & NVR_DATA_IN)
1287b867cf7SAnirban Chakraborty 			data |= BIT_0;
12904474d3aSBart Van Assche 		wrt_reg_word(&reg->nvram, NVR_SELECT);
13004474d3aSBart Van Assche 		rd_reg_word(&reg->nvram);	/* PCI Posting. */
1317b867cf7SAnirban Chakraborty 		NVRAM_DELAY();
1327b867cf7SAnirban Chakraborty 	}
1337b867cf7SAnirban Chakraborty 
1347b867cf7SAnirban Chakraborty 	/* Deselect chip. */
13504474d3aSBart Van Assche 	wrt_reg_word(&reg->nvram, NVR_DESELECT);
13604474d3aSBart Van Assche 	rd_reg_word(&reg->nvram);		/* PCI Posting. */
1377b867cf7SAnirban Chakraborty 	NVRAM_DELAY();
1387b867cf7SAnirban Chakraborty 
1397b867cf7SAnirban Chakraborty 	return data;
1407b867cf7SAnirban Chakraborty }
1417b867cf7SAnirban Chakraborty 
1427b867cf7SAnirban Chakraborty 
1437b867cf7SAnirban Chakraborty /**
1441da177e4SLinus Torvalds  * qla2x00_get_nvram_word() - Calculates word position in NVRAM and calls the
1451da177e4SLinus Torvalds  *	request routine to get the word from NVRAM.
1461da177e4SLinus Torvalds  * @ha: HA context
1471da177e4SLinus Torvalds  * @addr: Address in NVRAM to read
1481da177e4SLinus Torvalds  *
1491da177e4SLinus Torvalds  * Returns the word read from nvram @addr.
1501da177e4SLinus Torvalds  */
151a824ebb3SAdrian Bunk static uint16_t
qla2x00_get_nvram_word(struct qla_hw_data * ha,uint32_t addr)1527b867cf7SAnirban Chakraborty qla2x00_get_nvram_word(struct qla_hw_data *ha, uint32_t addr)
1531da177e4SLinus Torvalds {
1541da177e4SLinus Torvalds 	uint16_t	data;
1551da177e4SLinus Torvalds 	uint32_t	nv_cmd;
1561da177e4SLinus Torvalds 
1571da177e4SLinus Torvalds 	nv_cmd = addr << 16;
1581da177e4SLinus Torvalds 	nv_cmd |= NV_READ_OP;
1591da177e4SLinus Torvalds 	data = qla2x00_nvram_request(ha, nv_cmd);
1601da177e4SLinus Torvalds 
1611da177e4SLinus Torvalds 	return (data);
1621da177e4SLinus Torvalds }
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds /**
1657b867cf7SAnirban Chakraborty  * qla2x00_nv_deselect() - Deselect NVRAM operations.
1667b867cf7SAnirban Chakraborty  * @ha: HA context
1677b867cf7SAnirban Chakraborty  */
1687b867cf7SAnirban Chakraborty static void
qla2x00_nv_deselect(struct qla_hw_data * ha)1697b867cf7SAnirban Chakraborty qla2x00_nv_deselect(struct qla_hw_data *ha)
1707b867cf7SAnirban Chakraborty {
1717b867cf7SAnirban Chakraborty 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
1727b867cf7SAnirban Chakraborty 
17304474d3aSBart Van Assche 	wrt_reg_word(&reg->nvram, NVR_DESELECT);
17404474d3aSBart Van Assche 	rd_reg_word(&reg->nvram);		/* PCI Posting. */
1757b867cf7SAnirban Chakraborty 	NVRAM_DELAY();
1767b867cf7SAnirban Chakraborty }
1777b867cf7SAnirban Chakraborty 
1787b867cf7SAnirban Chakraborty /**
1791da177e4SLinus Torvalds  * qla2x00_write_nvram_word() - Write NVRAM data.
1801da177e4SLinus Torvalds  * @ha: HA context
1811da177e4SLinus Torvalds  * @addr: Address in NVRAM to write
1821da177e4SLinus Torvalds  * @data: word to program
1831da177e4SLinus Torvalds  */
184a824ebb3SAdrian Bunk static void
qla2x00_write_nvram_word(struct qla_hw_data * ha,uint32_t addr,__le16 data)1857ffa5b93SBart Van Assche qla2x00_write_nvram_word(struct qla_hw_data *ha, uint32_t addr, __le16 data)
1861da177e4SLinus Torvalds {
1871da177e4SLinus Torvalds 	int count;
1881da177e4SLinus Torvalds 	uint16_t word;
18945aeaf1eSRavi Anand 	uint32_t nv_cmd, wait_cnt;
1903d71644cSAndrew Vasquez 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
1917c3df132SSaurav Kashyap 	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
1921da177e4SLinus Torvalds 
1931da177e4SLinus Torvalds 	qla2x00_nv_write(ha, NVR_DATA_OUT);
1941da177e4SLinus Torvalds 	qla2x00_nv_write(ha, 0);
1951da177e4SLinus Torvalds 	qla2x00_nv_write(ha, 0);
1961da177e4SLinus Torvalds 
1971da177e4SLinus Torvalds 	for (word = 0; word < 8; word++)
1981da177e4SLinus Torvalds 		qla2x00_nv_write(ha, NVR_DATA_OUT);
1991da177e4SLinus Torvalds 
2001da177e4SLinus Torvalds 	qla2x00_nv_deselect(ha);
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds 	/* Write data */
2031da177e4SLinus Torvalds 	nv_cmd = (addr << 16) | NV_WRITE_OP;
2047ffa5b93SBart Van Assche 	nv_cmd |= (__force u16)data;
2051da177e4SLinus Torvalds 	nv_cmd <<= 5;
2061da177e4SLinus Torvalds 	for (count = 0; count < 27; count++) {
2071da177e4SLinus Torvalds 		if (nv_cmd & BIT_31)
2081da177e4SLinus Torvalds 			qla2x00_nv_write(ha, NVR_DATA_OUT);
2091da177e4SLinus Torvalds 		else
2101da177e4SLinus Torvalds 			qla2x00_nv_write(ha, 0);
2111da177e4SLinus Torvalds 
2121da177e4SLinus Torvalds 		nv_cmd <<= 1;
2131da177e4SLinus Torvalds 	}
2141da177e4SLinus Torvalds 
2151da177e4SLinus Torvalds 	qla2x00_nv_deselect(ha);
2161da177e4SLinus Torvalds 
2171da177e4SLinus Torvalds 	/* Wait for NVRAM to become ready */
21804474d3aSBart Van Assche 	wrt_reg_word(&reg->nvram, NVR_SELECT);
21904474d3aSBart Van Assche 	rd_reg_word(&reg->nvram);		/* PCI Posting. */
22045aeaf1eSRavi Anand 	wait_cnt = NVR_WAIT_CNT;
2211da177e4SLinus Torvalds 	do {
22245aeaf1eSRavi Anand 		if (!--wait_cnt) {
2237c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_user, vha, 0x708d,
2247c3df132SSaurav Kashyap 			    "NVRAM didn't go ready...\n");
22545aeaf1eSRavi Anand 			break;
22645aeaf1eSRavi Anand 		}
2271da177e4SLinus Torvalds 		NVRAM_DELAY();
22804474d3aSBart Van Assche 		word = rd_reg_word(&reg->nvram);
2291da177e4SLinus Torvalds 	} while ((word & NVR_DATA_IN) == 0);
2301da177e4SLinus Torvalds 
2311da177e4SLinus Torvalds 	qla2x00_nv_deselect(ha);
2321da177e4SLinus Torvalds 
2331da177e4SLinus Torvalds 	/* Disable writes */
2341da177e4SLinus Torvalds 	qla2x00_nv_write(ha, NVR_DATA_OUT);
2351da177e4SLinus Torvalds 	for (count = 0; count < 10; count++)
2361da177e4SLinus Torvalds 		qla2x00_nv_write(ha, 0);
2371da177e4SLinus Torvalds 
2381da177e4SLinus Torvalds 	qla2x00_nv_deselect(ha);
2391da177e4SLinus Torvalds }
2401da177e4SLinus Torvalds 
241459c5378SAndrew Vasquez static int
qla2x00_write_nvram_word_tmo(struct qla_hw_data * ha,uint32_t addr,__le16 data,uint32_t tmo)2427b867cf7SAnirban Chakraborty qla2x00_write_nvram_word_tmo(struct qla_hw_data *ha, uint32_t addr,
2437ffa5b93SBart Van Assche 			     __le16 data, uint32_t tmo)
244459c5378SAndrew Vasquez {
245459c5378SAndrew Vasquez 	int ret, count;
246459c5378SAndrew Vasquez 	uint16_t word;
247459c5378SAndrew Vasquez 	uint32_t nv_cmd;
248459c5378SAndrew Vasquez 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
249459c5378SAndrew Vasquez 
250459c5378SAndrew Vasquez 	ret = QLA_SUCCESS;
251459c5378SAndrew Vasquez 
252459c5378SAndrew Vasquez 	qla2x00_nv_write(ha, NVR_DATA_OUT);
253459c5378SAndrew Vasquez 	qla2x00_nv_write(ha, 0);
254459c5378SAndrew Vasquez 	qla2x00_nv_write(ha, 0);
255459c5378SAndrew Vasquez 
256459c5378SAndrew Vasquez 	for (word = 0; word < 8; word++)
257459c5378SAndrew Vasquez 		qla2x00_nv_write(ha, NVR_DATA_OUT);
258459c5378SAndrew Vasquez 
259459c5378SAndrew Vasquez 	qla2x00_nv_deselect(ha);
260459c5378SAndrew Vasquez 
261459c5378SAndrew Vasquez 	/* Write data */
262459c5378SAndrew Vasquez 	nv_cmd = (addr << 16) | NV_WRITE_OP;
2637ffa5b93SBart Van Assche 	nv_cmd |= (__force u16)data;
264459c5378SAndrew Vasquez 	nv_cmd <<= 5;
265459c5378SAndrew Vasquez 	for (count = 0; count < 27; count++) {
266459c5378SAndrew Vasquez 		if (nv_cmd & BIT_31)
267459c5378SAndrew Vasquez 			qla2x00_nv_write(ha, NVR_DATA_OUT);
268459c5378SAndrew Vasquez 		else
269459c5378SAndrew Vasquez 			qla2x00_nv_write(ha, 0);
270459c5378SAndrew Vasquez 
271459c5378SAndrew Vasquez 		nv_cmd <<= 1;
272459c5378SAndrew Vasquez 	}
273459c5378SAndrew Vasquez 
274459c5378SAndrew Vasquez 	qla2x00_nv_deselect(ha);
275459c5378SAndrew Vasquez 
276459c5378SAndrew Vasquez 	/* Wait for NVRAM to become ready */
27704474d3aSBart Van Assche 	wrt_reg_word(&reg->nvram, NVR_SELECT);
27804474d3aSBart Van Assche 	rd_reg_word(&reg->nvram);		/* PCI Posting. */
279459c5378SAndrew Vasquez 	do {
280459c5378SAndrew Vasquez 		NVRAM_DELAY();
28104474d3aSBart Van Assche 		word = rd_reg_word(&reg->nvram);
282459c5378SAndrew Vasquez 		if (!--tmo) {
283459c5378SAndrew Vasquez 			ret = QLA_FUNCTION_FAILED;
284459c5378SAndrew Vasquez 			break;
285459c5378SAndrew Vasquez 		}
286459c5378SAndrew Vasquez 	} while ((word & NVR_DATA_IN) == 0);
287459c5378SAndrew Vasquez 
288459c5378SAndrew Vasquez 	qla2x00_nv_deselect(ha);
289459c5378SAndrew Vasquez 
290459c5378SAndrew Vasquez 	/* Disable writes */
291459c5378SAndrew Vasquez 	qla2x00_nv_write(ha, NVR_DATA_OUT);
292459c5378SAndrew Vasquez 	for (count = 0; count < 10; count++)
293459c5378SAndrew Vasquez 		qla2x00_nv_write(ha, 0);
294459c5378SAndrew Vasquez 
295459c5378SAndrew Vasquez 	qla2x00_nv_deselect(ha);
296459c5378SAndrew Vasquez 
297459c5378SAndrew Vasquez 	return ret;
298459c5378SAndrew Vasquez }
299459c5378SAndrew Vasquez 
3001da177e4SLinus Torvalds /**
301459c5378SAndrew Vasquez  * qla2x00_clear_nvram_protection() -
302459c5378SAndrew Vasquez  * @ha: HA context
303459c5378SAndrew Vasquez  */
304459c5378SAndrew Vasquez static int
qla2x00_clear_nvram_protection(struct qla_hw_data * ha)3057b867cf7SAnirban Chakraborty qla2x00_clear_nvram_protection(struct qla_hw_data *ha)
306459c5378SAndrew Vasquez {
307459c5378SAndrew Vasquez 	int ret, stat;
308459c5378SAndrew Vasquez 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
30945aeaf1eSRavi Anand 	uint32_t word, wait_cnt;
3107ffa5b93SBart Van Assche 	__le16 wprot, wprot_old;
3117c3df132SSaurav Kashyap 	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
312459c5378SAndrew Vasquez 
313459c5378SAndrew Vasquez 	/* Clear NVRAM write protection. */
314459c5378SAndrew Vasquez 	ret = QLA_FUNCTION_FAILED;
31545aeaf1eSRavi Anand 
31645aeaf1eSRavi Anand 	wprot_old = cpu_to_le16(qla2x00_get_nvram_word(ha, ha->nvram_base));
31745aeaf1eSRavi Anand 	stat = qla2x00_write_nvram_word_tmo(ha, ha->nvram_base,
318ad950360SBart Van Assche 					    cpu_to_le16(0x1234), 100000);
31945aeaf1eSRavi Anand 	wprot = cpu_to_le16(qla2x00_get_nvram_word(ha, ha->nvram_base));
3207ffa5b93SBart Van Assche 	if (stat != QLA_SUCCESS || wprot != cpu_to_le16(0x1234)) {
321459c5378SAndrew Vasquez 		/* Write enable. */
322459c5378SAndrew Vasquez 		qla2x00_nv_write(ha, NVR_DATA_OUT);
323459c5378SAndrew Vasquez 		qla2x00_nv_write(ha, 0);
324459c5378SAndrew Vasquez 		qla2x00_nv_write(ha, 0);
325459c5378SAndrew Vasquez 		for (word = 0; word < 8; word++)
326459c5378SAndrew Vasquez 			qla2x00_nv_write(ha, NVR_DATA_OUT);
327459c5378SAndrew Vasquez 
328459c5378SAndrew Vasquez 		qla2x00_nv_deselect(ha);
329459c5378SAndrew Vasquez 
330459c5378SAndrew Vasquez 		/* Enable protection register. */
331459c5378SAndrew Vasquez 		qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
332459c5378SAndrew Vasquez 		qla2x00_nv_write(ha, NVR_PR_ENABLE);
333459c5378SAndrew Vasquez 		qla2x00_nv_write(ha, NVR_PR_ENABLE);
334459c5378SAndrew Vasquez 		for (word = 0; word < 8; word++)
335459c5378SAndrew Vasquez 			qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE);
336459c5378SAndrew Vasquez 
337459c5378SAndrew Vasquez 		qla2x00_nv_deselect(ha);
338459c5378SAndrew Vasquez 
339459c5378SAndrew Vasquez 		/* Clear protection register (ffff is cleared). */
340459c5378SAndrew Vasquez 		qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
341459c5378SAndrew Vasquez 		qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
342459c5378SAndrew Vasquez 		qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
343459c5378SAndrew Vasquez 		for (word = 0; word < 8; word++)
344459c5378SAndrew Vasquez 			qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE);
345459c5378SAndrew Vasquez 
346459c5378SAndrew Vasquez 		qla2x00_nv_deselect(ha);
347459c5378SAndrew Vasquez 
348459c5378SAndrew Vasquez 		/* Wait for NVRAM to become ready. */
34904474d3aSBart Van Assche 		wrt_reg_word(&reg->nvram, NVR_SELECT);
35004474d3aSBart Van Assche 		rd_reg_word(&reg->nvram);	/* PCI Posting. */
35145aeaf1eSRavi Anand 		wait_cnt = NVR_WAIT_CNT;
352459c5378SAndrew Vasquez 		do {
35345aeaf1eSRavi Anand 			if (!--wait_cnt) {
3547c3df132SSaurav Kashyap 				ql_dbg(ql_dbg_user, vha, 0x708e,
3557c3df132SSaurav Kashyap 				    "NVRAM didn't go ready...\n");
35645aeaf1eSRavi Anand 				break;
35745aeaf1eSRavi Anand 			}
358459c5378SAndrew Vasquez 			NVRAM_DELAY();
35904474d3aSBart Van Assche 			word = rd_reg_word(&reg->nvram);
360459c5378SAndrew Vasquez 		} while ((word & NVR_DATA_IN) == 0);
361459c5378SAndrew Vasquez 
36245aeaf1eSRavi Anand 		if (wait_cnt)
363459c5378SAndrew Vasquez 			ret = QLA_SUCCESS;
364459c5378SAndrew Vasquez 	} else
36545aeaf1eSRavi Anand 		qla2x00_write_nvram_word(ha, ha->nvram_base, wprot_old);
366459c5378SAndrew Vasquez 
367459c5378SAndrew Vasquez 	return ret;
368459c5378SAndrew Vasquez }
369459c5378SAndrew Vasquez 
370459c5378SAndrew Vasquez static void
qla2x00_set_nvram_protection(struct qla_hw_data * ha,int stat)3717b867cf7SAnirban Chakraborty qla2x00_set_nvram_protection(struct qla_hw_data *ha, int stat)
372459c5378SAndrew Vasquez {
373459c5378SAndrew Vasquez 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
37445aeaf1eSRavi Anand 	uint32_t word, wait_cnt;
3757c3df132SSaurav Kashyap 	scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
376459c5378SAndrew Vasquez 
377459c5378SAndrew Vasquez 	if (stat != QLA_SUCCESS)
378459c5378SAndrew Vasquez 		return;
379459c5378SAndrew Vasquez 
380459c5378SAndrew Vasquez 	/* Set NVRAM write protection. */
381459c5378SAndrew Vasquez 	/* Write enable. */
382459c5378SAndrew Vasquez 	qla2x00_nv_write(ha, NVR_DATA_OUT);
383459c5378SAndrew Vasquez 	qla2x00_nv_write(ha, 0);
384459c5378SAndrew Vasquez 	qla2x00_nv_write(ha, 0);
385459c5378SAndrew Vasquez 	for (word = 0; word < 8; word++)
386459c5378SAndrew Vasquez 		qla2x00_nv_write(ha, NVR_DATA_OUT);
387459c5378SAndrew Vasquez 
388459c5378SAndrew Vasquez 	qla2x00_nv_deselect(ha);
389459c5378SAndrew Vasquez 
390459c5378SAndrew Vasquez 	/* Enable protection register. */
391459c5378SAndrew Vasquez 	qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
392459c5378SAndrew Vasquez 	qla2x00_nv_write(ha, NVR_PR_ENABLE);
393459c5378SAndrew Vasquez 	qla2x00_nv_write(ha, NVR_PR_ENABLE);
394459c5378SAndrew Vasquez 	for (word = 0; word < 8; word++)
395459c5378SAndrew Vasquez 		qla2x00_nv_write(ha, NVR_DATA_OUT | NVR_PR_ENABLE);
396459c5378SAndrew Vasquez 
397459c5378SAndrew Vasquez 	qla2x00_nv_deselect(ha);
398459c5378SAndrew Vasquez 
399459c5378SAndrew Vasquez 	/* Enable protection register. */
400459c5378SAndrew Vasquez 	qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
401459c5378SAndrew Vasquez 	qla2x00_nv_write(ha, NVR_PR_ENABLE);
402459c5378SAndrew Vasquez 	qla2x00_nv_write(ha, NVR_PR_ENABLE | NVR_DATA_OUT);
403459c5378SAndrew Vasquez 	for (word = 0; word < 8; word++)
404459c5378SAndrew Vasquez 		qla2x00_nv_write(ha, NVR_PR_ENABLE);
405459c5378SAndrew Vasquez 
406459c5378SAndrew Vasquez 	qla2x00_nv_deselect(ha);
407459c5378SAndrew Vasquez 
408459c5378SAndrew Vasquez 	/* Wait for NVRAM to become ready. */
40904474d3aSBart Van Assche 	wrt_reg_word(&reg->nvram, NVR_SELECT);
41004474d3aSBart Van Assche 	rd_reg_word(&reg->nvram);		/* PCI Posting. */
41145aeaf1eSRavi Anand 	wait_cnt = NVR_WAIT_CNT;
412459c5378SAndrew Vasquez 	do {
41345aeaf1eSRavi Anand 		if (!--wait_cnt) {
4147c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_user, vha, 0x708f,
4157c3df132SSaurav Kashyap 			    "NVRAM didn't go ready...\n");
41645aeaf1eSRavi Anand 			break;
41745aeaf1eSRavi Anand 		}
418459c5378SAndrew Vasquez 		NVRAM_DELAY();
41904474d3aSBart Van Assche 		word = rd_reg_word(&reg->nvram);
420459c5378SAndrew Vasquez 	} while ((word & NVR_DATA_IN) == 0);
421459c5378SAndrew Vasquez }
422459c5378SAndrew Vasquez 
423459c5378SAndrew Vasquez 
424459c5378SAndrew Vasquez /*****************************************************************************/
425459c5378SAndrew Vasquez /* Flash Manipulation Routines                                               */
426459c5378SAndrew Vasquez /*****************************************************************************/
427459c5378SAndrew Vasquez 
428459c5378SAndrew Vasquez static inline uint32_t
flash_conf_addr(struct qla_hw_data * ha,uint32_t faddr)4293a03eb79SAndrew Vasquez flash_conf_addr(struct qla_hw_data *ha, uint32_t faddr)
430459c5378SAndrew Vasquez {
4313695310eSJoe Carnuccio 	return ha->flash_conf_off + faddr;
432459c5378SAndrew Vasquez }
433459c5378SAndrew Vasquez 
434459c5378SAndrew Vasquez static inline uint32_t
flash_data_addr(struct qla_hw_data * ha,uint32_t faddr)4353a03eb79SAndrew Vasquez flash_data_addr(struct qla_hw_data *ha, uint32_t faddr)
436459c5378SAndrew Vasquez {
4373695310eSJoe Carnuccio 	return ha->flash_data_off + faddr;
438459c5378SAndrew Vasquez }
439459c5378SAndrew Vasquez 
440459c5378SAndrew Vasquez static inline uint32_t
nvram_conf_addr(struct qla_hw_data * ha,uint32_t naddr)4413a03eb79SAndrew Vasquez nvram_conf_addr(struct qla_hw_data *ha, uint32_t naddr)
442459c5378SAndrew Vasquez {
4433695310eSJoe Carnuccio 	return ha->nvram_conf_off + naddr;
444459c5378SAndrew Vasquez }
445459c5378SAndrew Vasquez 
446459c5378SAndrew Vasquez static inline uint32_t
nvram_data_addr(struct qla_hw_data * ha,uint32_t naddr)4473a03eb79SAndrew Vasquez nvram_data_addr(struct qla_hw_data *ha, uint32_t naddr)
448459c5378SAndrew Vasquez {
4493695310eSJoe Carnuccio 	return ha->nvram_data_off + naddr;
450459c5378SAndrew Vasquez }
451459c5378SAndrew Vasquez 
4523695310eSJoe Carnuccio static int
qla24xx_read_flash_dword(struct qla_hw_data * ha,uint32_t addr,uint32_t * data)4533695310eSJoe Carnuccio qla24xx_read_flash_dword(struct qla_hw_data *ha, uint32_t addr, uint32_t *data)
454459c5378SAndrew Vasquez {
455459c5378SAndrew Vasquez 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
4563695310eSJoe Carnuccio 	ulong cnt = 30000;
457459c5378SAndrew Vasquez 
45804474d3aSBart Van Assche 	wrt_reg_dword(&reg->flash_addr, addr & ~FARX_DATA_FLAG);
4593695310eSJoe Carnuccio 
4603695310eSJoe Carnuccio 	while (cnt--) {
46104474d3aSBart Van Assche 		if (rd_reg_dword(&reg->flash_addr) & FARX_DATA_FLAG) {
46204474d3aSBart Van Assche 			*data = rd_reg_dword(&reg->flash_data);
4633695310eSJoe Carnuccio 			return QLA_SUCCESS;
4643695310eSJoe Carnuccio 		}
465459c5378SAndrew Vasquez 		udelay(10);
46640a2e34aSAndrew Vasquez 		cond_resched();
467459c5378SAndrew Vasquez 	}
468459c5378SAndrew Vasquez 
4693695310eSJoe Carnuccio 	ql_log(ql_log_warn, pci_get_drvdata(ha->pdev), 0x7090,
4703695310eSJoe Carnuccio 	    "Flash read dword at %x timeout.\n", addr);
4713695310eSJoe Carnuccio 	*data = 0xDEADDEAD;
4723695310eSJoe Carnuccio 	return QLA_FUNCTION_TIMEOUT;
473459c5378SAndrew Vasquez }
474459c5378SAndrew Vasquez 
475c43e7832SBart Van Assche int
qla24xx_read_flash_data(scsi_qla_host_t * vha,uint32_t * dwptr,uint32_t faddr,uint32_t dwords)4767b867cf7SAnirban Chakraborty qla24xx_read_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
477459c5378SAndrew Vasquez     uint32_t dwords)
478459c5378SAndrew Vasquez {
4793695310eSJoe Carnuccio 	ulong i;
480c43e7832SBart Van Assche 	int ret = QLA_SUCCESS;
4813a03eb79SAndrew Vasquez 	struct qla_hw_data *ha = vha->hw;
4823a03eb79SAndrew Vasquez 
483459c5378SAndrew Vasquez 	/* Dword reads to flash. */
4843695310eSJoe Carnuccio 	faddr =  flash_data_addr(ha, faddr);
4853695310eSJoe Carnuccio 	for (i = 0; i < dwords; i++, faddr++, dwptr++) {
486c43e7832SBart Van Assche 		ret = qla24xx_read_flash_dword(ha, faddr, dwptr);
487c43e7832SBart Van Assche 		if (ret != QLA_SUCCESS)
4883695310eSJoe Carnuccio 			break;
4893695310eSJoe Carnuccio 		cpu_to_le32s(dwptr);
4903695310eSJoe Carnuccio 	}
491459c5378SAndrew Vasquez 
492c43e7832SBart Van Assche 	return ret;
493459c5378SAndrew Vasquez }
494459c5378SAndrew Vasquez 
495e5f82ab8SAdrian Bunk static int
qla24xx_write_flash_dword(struct qla_hw_data * ha,uint32_t addr,uint32_t data)4967b867cf7SAnirban Chakraborty qla24xx_write_flash_dword(struct qla_hw_data *ha, uint32_t addr, uint32_t data)
497459c5378SAndrew Vasquez {
498459c5378SAndrew Vasquez 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
4993695310eSJoe Carnuccio 	ulong cnt = 500000;
500459c5378SAndrew Vasquez 
50104474d3aSBart Van Assche 	wrt_reg_dword(&reg->flash_data, data);
50204474d3aSBart Van Assche 	wrt_reg_dword(&reg->flash_addr, addr | FARX_DATA_FLAG);
5033695310eSJoe Carnuccio 
5043695310eSJoe Carnuccio 	while (cnt--) {
50504474d3aSBart Van Assche 		if (!(rd_reg_dword(&reg->flash_addr) & FARX_DATA_FLAG))
5063695310eSJoe Carnuccio 			return QLA_SUCCESS;
507459c5378SAndrew Vasquez 		udelay(10);
50840a2e34aSAndrew Vasquez 		cond_resched();
509459c5378SAndrew Vasquez 	}
5103695310eSJoe Carnuccio 
5113695310eSJoe Carnuccio 	ql_log(ql_log_warn, pci_get_drvdata(ha->pdev), 0x7090,
5123695310eSJoe Carnuccio 	    "Flash write dword at %x timeout.\n", addr);
5133695310eSJoe Carnuccio 	return QLA_FUNCTION_TIMEOUT;
514459c5378SAndrew Vasquez }
515459c5378SAndrew Vasquez 
516e5f82ab8SAdrian Bunk static void
qla24xx_get_flash_manufacturer(struct qla_hw_data * ha,uint8_t * man_id,uint8_t * flash_id)5177b867cf7SAnirban Chakraborty qla24xx_get_flash_manufacturer(struct qla_hw_data *ha, uint8_t *man_id,
518459c5378SAndrew Vasquez     uint8_t *flash_id)
519459c5378SAndrew Vasquez {
5203695310eSJoe Carnuccio 	uint32_t faddr, ids = 0;
521459c5378SAndrew Vasquez 
5223695310eSJoe Carnuccio 	*man_id = *flash_id = 0;
5233695310eSJoe Carnuccio 
5243695310eSJoe Carnuccio 	faddr = flash_conf_addr(ha, 0x03ab);
5253695310eSJoe Carnuccio 	if (!qla24xx_read_flash_dword(ha, faddr, &ids)) {
526459c5378SAndrew Vasquez 		*man_id = LSB(ids);
527459c5378SAndrew Vasquez 		*flash_id = MSB(ids);
5283695310eSJoe Carnuccio 	}
52945aeaf1eSRavi Anand 
53045aeaf1eSRavi Anand 	/* Check if man_id and flash_id are valid. */
53145aeaf1eSRavi Anand 	if (ids != 0xDEADDEAD && (*man_id == 0 || *flash_id == 0)) {
53245aeaf1eSRavi Anand 		/* Read information using 0x9f opcode
53345aeaf1eSRavi Anand 		 * Device ID, Mfg ID would be read in the format:
53445aeaf1eSRavi Anand 		 *   <Ext Dev Info><Device ID Part2><Device ID Part 1><Mfg ID>
53545aeaf1eSRavi Anand 		 * Example: ATMEL 0x00 01 45 1F
53645aeaf1eSRavi Anand 		 * Extract MFG and Dev ID from last two bytes.
53745aeaf1eSRavi Anand 		 */
5383695310eSJoe Carnuccio 		faddr = flash_conf_addr(ha, 0x009f);
5393695310eSJoe Carnuccio 		if (!qla24xx_read_flash_dword(ha, faddr, &ids)) {
54045aeaf1eSRavi Anand 			*man_id = LSB(ids);
54145aeaf1eSRavi Anand 			*flash_id = MSB(ids);
54245aeaf1eSRavi Anand 		}
543459c5378SAndrew Vasquez 	}
5443695310eSJoe Carnuccio }
545459c5378SAndrew Vasquez 
546c00d8994SAndrew Vasquez static int
qla2xxx_find_flt_start(scsi_qla_host_t * vha,uint32_t * start)5477b867cf7SAnirban Chakraborty qla2xxx_find_flt_start(scsi_qla_host_t *vha, uint32_t *start)
548c00d8994SAndrew Vasquez {
549c00d8994SAndrew Vasquez 	const char *loc, *locations[] = { "DEF", "PCI" };
550c00d8994SAndrew Vasquez 	uint32_t pcihdr, pcids;
5517ffa5b93SBart Van Assche 	uint16_t cnt, chksum;
5527ffa5b93SBart Van Assche 	__le16 *wptr;
5537b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
55473208dfdSAnirban Chakraborty 	struct req_que *req = ha->req_q_map[0];
5553695310eSJoe Carnuccio 	struct qla_flt_location *fltl = (void *)req->ring;
556ab053c09SBart Van Assche 	uint32_t *dcode = (uint32_t *)req->ring;
5573695310eSJoe Carnuccio 	uint8_t *buf = (void *)req->ring, *bcode,  last_image;
558*bf192b8bSQuinn Tran 	int rc;
559c00d8994SAndrew Vasquez 
560c00d8994SAndrew Vasquez 	/*
561c00d8994SAndrew Vasquez 	 * FLT-location structure resides after the last PCI region.
562c00d8994SAndrew Vasquez 	 */
563c00d8994SAndrew Vasquez 
564c00d8994SAndrew Vasquez 	/* Begin with sane defaults. */
565c00d8994SAndrew Vasquez 	loc = locations[0];
5663a03eb79SAndrew Vasquez 	*start = 0;
5673a03eb79SAndrew Vasquez 	if (IS_QLA24XX_TYPE(ha))
5683a03eb79SAndrew Vasquez 		*start = FA_FLASH_LAYOUT_ADDR_24;
5693a03eb79SAndrew Vasquez 	else if (IS_QLA25XX(ha))
5703a03eb79SAndrew Vasquez 		*start = FA_FLASH_LAYOUT_ADDR;
5713a03eb79SAndrew Vasquez 	else if (IS_QLA81XX(ha))
5723a03eb79SAndrew Vasquez 		*start = FA_FLASH_LAYOUT_ADDR_81;
5737ec0effdSAtul Deshmukh 	else if (IS_P3P_TYPE(ha)) {
574a9083016SGiridhar Malavali 		*start = FA_FLASH_LAYOUT_ADDR_82;
575a9083016SGiridhar Malavali 		goto end;
576f73cb695SChad Dupuis 	} else if (IS_QLA83XX(ha) || IS_QLA27XX(ha)) {
5776246b8a1SGiridhar Malavali 		*start = FA_FLASH_LAYOUT_ADDR_83;
5786246b8a1SGiridhar Malavali 		goto end;
579ecc89f25SJoe Carnuccio 	} else if (IS_QLA28XX(ha)) {
580ecc89f25SJoe Carnuccio 		*start = FA_FLASH_LAYOUT_ADDR_28;
581ecc89f25SJoe Carnuccio 		goto end;
582a9083016SGiridhar Malavali 	}
5833695310eSJoe Carnuccio 
584c00d8994SAndrew Vasquez 	/* Begin with first PCI expansion ROM header. */
585c00d8994SAndrew Vasquez 	pcihdr = 0;
586c00d8994SAndrew Vasquez 	do {
587c00d8994SAndrew Vasquez 		/* Verify PCI expansion ROM header. */
588*bf192b8bSQuinn Tran 		rc = qla24xx_read_flash_data(vha, dcode, pcihdr >> 2, 0x20);
589*bf192b8bSQuinn Tran 		if (rc) {
590*bf192b8bSQuinn Tran 			ql_log(ql_log_info, vha, 0x016d,
591*bf192b8bSQuinn Tran 			    "Unable to read PCI Expansion Rom Header (%x).\n", rc);
592*bf192b8bSQuinn Tran 			return QLA_FUNCTION_FAILED;
593*bf192b8bSQuinn Tran 		}
594c00d8994SAndrew Vasquez 		bcode = buf + (pcihdr % 4);
595c00d8994SAndrew Vasquez 		if (bcode[0x0] != 0x55 || bcode[0x1] != 0xaa)
596c00d8994SAndrew Vasquez 			goto end;
597c00d8994SAndrew Vasquez 
598c00d8994SAndrew Vasquez 		/* Locate PCI data structure. */
599c00d8994SAndrew Vasquez 		pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]);
600*bf192b8bSQuinn Tran 		rc = qla24xx_read_flash_data(vha, dcode, pcids >> 2, 0x20);
601*bf192b8bSQuinn Tran 		if (rc) {
602*bf192b8bSQuinn Tran 			ql_log(ql_log_info, vha, 0x0179,
603*bf192b8bSQuinn Tran 			    "Unable to read PCI Data Structure (%x).\n", rc);
604*bf192b8bSQuinn Tran 			return QLA_FUNCTION_FAILED;
605*bf192b8bSQuinn Tran 		}
606c00d8994SAndrew Vasquez 		bcode = buf + (pcihdr % 4);
607c00d8994SAndrew Vasquez 
608c00d8994SAndrew Vasquez 		/* Validate signature of PCI data structure. */
609c00d8994SAndrew Vasquez 		if (bcode[0x0] != 'P' || bcode[0x1] != 'C' ||
610c00d8994SAndrew Vasquez 		    bcode[0x2] != 'I' || bcode[0x3] != 'R')
611c00d8994SAndrew Vasquez 			goto end;
612c00d8994SAndrew Vasquez 
613c00d8994SAndrew Vasquez 		last_image = bcode[0x15] & BIT_7;
614c00d8994SAndrew Vasquez 
615c00d8994SAndrew Vasquez 		/* Locate next PCI expansion ROM. */
616c00d8994SAndrew Vasquez 		pcihdr += ((bcode[0x11] << 8) | bcode[0x10]) * 512;
617c00d8994SAndrew Vasquez 	} while (!last_image);
618c00d8994SAndrew Vasquez 
619c00d8994SAndrew Vasquez 	/* Now verify FLT-location structure. */
620*bf192b8bSQuinn Tran 	rc = qla24xx_read_flash_data(vha, dcode, pcihdr >> 2, sizeof(*fltl) >> 2);
621*bf192b8bSQuinn Tran 	if (rc) {
622*bf192b8bSQuinn Tran 		ql_log(ql_log_info, vha, 0x017a,
623*bf192b8bSQuinn Tran 		    "Unable to read FLT (%x).\n", rc);
624*bf192b8bSQuinn Tran 		return QLA_FUNCTION_FAILED;
625*bf192b8bSQuinn Tran 	}
6263695310eSJoe Carnuccio 	if (memcmp(fltl->sig, "QFLT", 4))
627c00d8994SAndrew Vasquez 		goto end;
628c00d8994SAndrew Vasquez 
6297ffa5b93SBart Van Assche 	wptr = (__force __le16 *)req->ring;
6303695310eSJoe Carnuccio 	cnt = sizeof(*fltl) / sizeof(*wptr);
631da08ef5cSJoe Carnuccio 	for (chksum = 0; cnt--; wptr++)
632da08ef5cSJoe Carnuccio 		chksum += le16_to_cpu(*wptr);
633c00d8994SAndrew Vasquez 	if (chksum) {
6347c3df132SSaurav Kashyap 		ql_log(ql_log_fatal, vha, 0x0045,
635c00d8994SAndrew Vasquez 		    "Inconsistent FLTL detected: checksum=0x%x.\n", chksum);
6367c3df132SSaurav Kashyap 		ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x010e,
637f8f97b0cSJoe Carnuccio 		    fltl, sizeof(*fltl));
638c00d8994SAndrew Vasquez 		return QLA_FUNCTION_FAILED;
639c00d8994SAndrew Vasquez 	}
640c00d8994SAndrew Vasquez 
641c00d8994SAndrew Vasquez 	/* Good data.  Use specified location. */
642c00d8994SAndrew Vasquez 	loc = locations[1];
64379c13a74SHarish Zunjarrao 	*start = (le16_to_cpu(fltl->start_hi) << 16 |
64479c13a74SHarish Zunjarrao 	    le16_to_cpu(fltl->start_lo)) >> 2;
645c00d8994SAndrew Vasquez end:
6467c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_init, vha, 0x0046,
6477c3df132SSaurav Kashyap 	    "FLTL[%s] = 0x%x.\n",
6487c3df132SSaurav Kashyap 	    loc, *start);
649c00d8994SAndrew Vasquez 	return QLA_SUCCESS;
650c00d8994SAndrew Vasquez }
651c00d8994SAndrew Vasquez 
652c00d8994SAndrew Vasquez static void
qla2xxx_get_flt_info(scsi_qla_host_t * vha,uint32_t flt_addr)6537b867cf7SAnirban Chakraborty qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
654c00d8994SAndrew Vasquez {
6553f006ac3SMichael Hernandez 	const char *locations[] = { "DEF", "FLT" }, *loc = locations[1];
6563a03eb79SAndrew Vasquez 	const uint32_t def_fw[] =
6573a03eb79SAndrew Vasquez 		{ FA_RISC_CODE_ADDR, FA_RISC_CODE_ADDR, FA_RISC_CODE_ADDR_81 };
6583a03eb79SAndrew Vasquez 	const uint32_t def_boot[] =
6593a03eb79SAndrew Vasquez 		{ FA_BOOT_CODE_ADDR, FA_BOOT_CODE_ADDR, FA_BOOT_CODE_ADDR_81 };
6603a03eb79SAndrew Vasquez 	const uint32_t def_vpd_nvram[] =
6613a03eb79SAndrew Vasquez 		{ FA_VPD_NVRAM_ADDR, FA_VPD_NVRAM_ADDR, FA_VPD_NVRAM_ADDR_81 };
6623d79038fSAndrew Vasquez 	const uint32_t def_vpd0[] =
6633d79038fSAndrew Vasquez 		{ 0, 0, FA_VPD0_ADDR_81 };
6643d79038fSAndrew Vasquez 	const uint32_t def_vpd1[] =
6653d79038fSAndrew Vasquez 		{ 0, 0, FA_VPD1_ADDR_81 };
6663d79038fSAndrew Vasquez 	const uint32_t def_nvram0[] =
6673d79038fSAndrew Vasquez 		{ 0, 0, FA_NVRAM0_ADDR_81 };
6683d79038fSAndrew Vasquez 	const uint32_t def_nvram1[] =
6693d79038fSAndrew Vasquez 		{ 0, 0, FA_NVRAM1_ADDR_81 };
6703a03eb79SAndrew Vasquez 	const uint32_t def_fdt[] =
6713a03eb79SAndrew Vasquez 		{ FA_FLASH_DESCR_ADDR_24, FA_FLASH_DESCR_ADDR,
6723a03eb79SAndrew Vasquez 			FA_FLASH_DESCR_ADDR_81 };
6733a03eb79SAndrew Vasquez 	const uint32_t def_npiv_conf0[] =
6743a03eb79SAndrew Vasquez 		{ FA_NPIV_CONF0_ADDR_24, FA_NPIV_CONF0_ADDR,
6753a03eb79SAndrew Vasquez 			FA_NPIV_CONF0_ADDR_81 };
6763a03eb79SAndrew Vasquez 	const uint32_t def_npiv_conf1[] =
6773a03eb79SAndrew Vasquez 		{ FA_NPIV_CONF1_ADDR_24, FA_NPIV_CONF1_ADDR,
6783a03eb79SAndrew Vasquez 			FA_NPIV_CONF1_ADDR_81 };
67909ff701aSSarang Radke 	const uint32_t fcp_prio_cfg0[] =
68009ff701aSSarang Radke 		{ FA_FCP_PRIO0_ADDR, FA_FCP_PRIO0_ADDR_25,
68109ff701aSSarang Radke 			0 };
68209ff701aSSarang Radke 	const uint32_t fcp_prio_cfg1[] =
68309ff701aSSarang Radke 		{ FA_FCP_PRIO1_ADDR, FA_FCP_PRIO1_ADDR_25,
68409ff701aSSarang Radke 			0 };
685c00d8994SAndrew Vasquez 
6863f006ac3SMichael Hernandez 	struct qla_hw_data *ha = vha->hw;
6873f006ac3SMichael Hernandez 	uint32_t def = IS_QLA81XX(ha) ? 2 : IS_QLA25XX(ha) ? 1 : 0;
688a27747a2SBart Van Assche 	struct qla_flt_header *flt = ha->flt;
689a27747a2SBart Van Assche 	struct qla_flt_region *region = &flt->region[0];
6907ffa5b93SBart Van Assche 	__le16 *wptr;
6917ffa5b93SBart Van Assche 	uint16_t cnt, chksum;
6923f006ac3SMichael Hernandez 	uint32_t start;
693ff8073ffSAndrew Vasquez 
694ff8073ffSAndrew Vasquez 	/* Assign FCP prio region since older adapters may not have FLT, or
695ff8073ffSAndrew Vasquez 	   FCP prio region in it's FLT.
696ff8073ffSAndrew Vasquez 	 */
697f73cb695SChad Dupuis 	ha->flt_region_fcp_prio = (ha->port_no == 0) ?
698ff8073ffSAndrew Vasquez 	    fcp_prio_cfg0[def] : fcp_prio_cfg1[def];
699ff8073ffSAndrew Vasquez 
700c00d8994SAndrew Vasquez 	ha->flt_region_flt = flt_addr;
7017ffa5b93SBart Van Assche 	wptr = (__force __le16 *)ha->flt;
702ab053c09SBart Van Assche 	ha->isp_ops->read_optrom(vha, flt, flt_addr << 2,
703cb92cb16SQuinn Tran 	    (sizeof(struct qla_flt_header) + FLT_REGIONS_SIZE));
7043f006ac3SMichael Hernandez 
7053f006ac3SMichael Hernandez 	if (le16_to_cpu(*wptr) == 0xffff)
706c00d8994SAndrew Vasquez 		goto no_flash_data;
707ad950360SBart Van Assche 	if (flt->version != cpu_to_le16(1)) {
7087c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x0047,
7097c3df132SSaurav Kashyap 		    "Unsupported FLT detected: version=0x%x length=0x%x checksum=0x%x.\n",
710c00d8994SAndrew Vasquez 		    le16_to_cpu(flt->version), le16_to_cpu(flt->length),
7117c3df132SSaurav Kashyap 		    le16_to_cpu(flt->checksum));
712c00d8994SAndrew Vasquez 		goto no_flash_data;
713c00d8994SAndrew Vasquez 	}
714c00d8994SAndrew Vasquez 
7153f006ac3SMichael Hernandez 	cnt = (sizeof(*flt) + le16_to_cpu(flt->length)) / sizeof(*wptr);
716da08ef5cSJoe Carnuccio 	for (chksum = 0; cnt--; wptr++)
717da08ef5cSJoe Carnuccio 		chksum += le16_to_cpu(*wptr);
718c00d8994SAndrew Vasquez 	if (chksum) {
7197c3df132SSaurav Kashyap 		ql_log(ql_log_fatal, vha, 0x0048,
7207c3df132SSaurav Kashyap 		    "Inconsistent FLT detected: version=0x%x length=0x%x checksum=0x%x.\n",
721c00d8994SAndrew Vasquez 		    le16_to_cpu(flt->version), le16_to_cpu(flt->length),
7227c3df132SSaurav Kashyap 		    le16_to_cpu(flt->checksum));
723c00d8994SAndrew Vasquez 		goto no_flash_data;
724c00d8994SAndrew Vasquez 	}
725c00d8994SAndrew Vasquez 
7263f006ac3SMichael Hernandez 	cnt = le16_to_cpu(flt->length) / sizeof(*region);
727c00d8994SAndrew Vasquez 	for ( ; cnt; cnt--, region++) {
728c00d8994SAndrew Vasquez 		/* Store addresses as DWORD offsets. */
729c00d8994SAndrew Vasquez 		start = le32_to_cpu(region->start) >> 2;
7307c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_init, vha, 0x0049,
731f8f97b0cSJoe Carnuccio 		    "FLT[%#x]: start=%#x end=%#x size=%#x.\n",
7323f006ac3SMichael Hernandez 		    le16_to_cpu(region->code), start,
7333f006ac3SMichael Hernandez 		    le32_to_cpu(region->end) >> 2,
7343f006ac3SMichael Hernandez 		    le32_to_cpu(region->size) >> 2);
7353f006ac3SMichael Hernandez 		if (region->attribute)
7363f006ac3SMichael Hernandez 			ql_log(ql_dbg_init, vha, 0xffff,
7373f006ac3SMichael Hernandez 			    "Region %x is secure\n", region->code);
738c00d8994SAndrew Vasquez 
739f8f97b0cSJoe Carnuccio 		switch (le16_to_cpu(region->code)) {
7406246b8a1SGiridhar Malavali 		case FLT_REG_FCOE_FW:
7416246b8a1SGiridhar Malavali 			if (!IS_QLA8031(ha))
7426246b8a1SGiridhar Malavali 				break;
7436246b8a1SGiridhar Malavali 			ha->flt_region_fw = start;
7446246b8a1SGiridhar Malavali 			break;
745c00d8994SAndrew Vasquez 		case FLT_REG_FW:
7466246b8a1SGiridhar Malavali 			if (IS_QLA8031(ha))
7476246b8a1SGiridhar Malavali 				break;
748c00d8994SAndrew Vasquez 			ha->flt_region_fw = start;
749c00d8994SAndrew Vasquez 			break;
750c00d8994SAndrew Vasquez 		case FLT_REG_BOOT_CODE:
751c00d8994SAndrew Vasquez 			ha->flt_region_boot = start;
752c00d8994SAndrew Vasquez 			break;
753c00d8994SAndrew Vasquez 		case FLT_REG_VPD_0:
7546246b8a1SGiridhar Malavali 			if (IS_QLA8031(ha))
7556246b8a1SGiridhar Malavali 				break;
756c00d8994SAndrew Vasquez 			ha->flt_region_vpd_nvram = start;
7577ec0effdSAtul Deshmukh 			if (IS_P3P_TYPE(ha))
758a9083016SGiridhar Malavali 				break;
759f73cb695SChad Dupuis 			if (ha->port_no == 0)
7603d79038fSAndrew Vasquez 				ha->flt_region_vpd = start;
7613d79038fSAndrew Vasquez 			break;
7623d79038fSAndrew Vasquez 		case FLT_REG_VPD_1:
7637ec0effdSAtul Deshmukh 			if (IS_P3P_TYPE(ha) || IS_QLA8031(ha))
764a9083016SGiridhar Malavali 				break;
765f73cb695SChad Dupuis 			if (ha->port_no == 1)
766f73cb695SChad Dupuis 				ha->flt_region_vpd = start;
767f73cb695SChad Dupuis 			break;
768f73cb695SChad Dupuis 		case FLT_REG_VPD_2:
769ecc89f25SJoe Carnuccio 			if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
770f73cb695SChad Dupuis 				break;
771f73cb695SChad Dupuis 			if (ha->port_no == 2)
772f73cb695SChad Dupuis 				ha->flt_region_vpd = start;
773f73cb695SChad Dupuis 			break;
774f73cb695SChad Dupuis 		case FLT_REG_VPD_3:
775ecc89f25SJoe Carnuccio 			if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
776f73cb695SChad Dupuis 				break;
777f73cb695SChad Dupuis 			if (ha->port_no == 3)
7783d79038fSAndrew Vasquez 				ha->flt_region_vpd = start;
7793d79038fSAndrew Vasquez 			break;
7803d79038fSAndrew Vasquez 		case FLT_REG_NVRAM_0:
7816246b8a1SGiridhar Malavali 			if (IS_QLA8031(ha))
7826246b8a1SGiridhar Malavali 				break;
783f73cb695SChad Dupuis 			if (ha->port_no == 0)
7843d79038fSAndrew Vasquez 				ha->flt_region_nvram = start;
7853d79038fSAndrew Vasquez 			break;
7863d79038fSAndrew Vasquez 		case FLT_REG_NVRAM_1:
7876246b8a1SGiridhar Malavali 			if (IS_QLA8031(ha))
7886246b8a1SGiridhar Malavali 				break;
789f73cb695SChad Dupuis 			if (ha->port_no == 1)
790f73cb695SChad Dupuis 				ha->flt_region_nvram = start;
791f73cb695SChad Dupuis 			break;
792f73cb695SChad Dupuis 		case FLT_REG_NVRAM_2:
793ecc89f25SJoe Carnuccio 			if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
794f73cb695SChad Dupuis 				break;
795f73cb695SChad Dupuis 			if (ha->port_no == 2)
796f73cb695SChad Dupuis 				ha->flt_region_nvram = start;
797f73cb695SChad Dupuis 			break;
798f73cb695SChad Dupuis 		case FLT_REG_NVRAM_3:
799ecc89f25SJoe Carnuccio 			if (!IS_QLA27XX(ha) && !IS_QLA28XX(ha))
800f73cb695SChad Dupuis 				break;
801f73cb695SChad Dupuis 			if (ha->port_no == 3)
8023d79038fSAndrew Vasquez 				ha->flt_region_nvram = start;
803c00d8994SAndrew Vasquez 			break;
804c00d8994SAndrew Vasquez 		case FLT_REG_FDT:
805c00d8994SAndrew Vasquez 			ha->flt_region_fdt = start;
806c00d8994SAndrew Vasquez 			break;
807272976caSAndrew Vasquez 		case FLT_REG_NPIV_CONF_0:
808f73cb695SChad Dupuis 			if (ha->port_no == 0)
809272976caSAndrew Vasquez 				ha->flt_region_npiv_conf = start;
810272976caSAndrew Vasquez 			break;
811272976caSAndrew Vasquez 		case FLT_REG_NPIV_CONF_1:
812f73cb695SChad Dupuis 			if (ha->port_no == 1)
813272976caSAndrew Vasquez 				ha->flt_region_npiv_conf = start;
814272976caSAndrew Vasquez 			break;
815cbc8eb67SAndrew Vasquez 		case FLT_REG_GOLD_FW:
816cbc8eb67SAndrew Vasquez 			ha->flt_region_gold_fw = start;
817cbc8eb67SAndrew Vasquez 			break;
81809ff701aSSarang Radke 		case FLT_REG_FCP_PRIO_0:
819f73cb695SChad Dupuis 			if (ha->port_no == 0)
82009ff701aSSarang Radke 				ha->flt_region_fcp_prio = start;
82109ff701aSSarang Radke 			break;
82209ff701aSSarang Radke 		case FLT_REG_FCP_PRIO_1:
823f73cb695SChad Dupuis 			if (ha->port_no == 1)
82409ff701aSSarang Radke 				ha->flt_region_fcp_prio = start;
82509ff701aSSarang Radke 			break;
826a9083016SGiridhar Malavali 		case FLT_REG_BOOT_CODE_82XX:
827a9083016SGiridhar Malavali 			ha->flt_region_boot = start;
828a9083016SGiridhar Malavali 			break;
8297ec0effdSAtul Deshmukh 		case FLT_REG_BOOT_CODE_8044:
8307ec0effdSAtul Deshmukh 			if (IS_QLA8044(ha))
8317ec0effdSAtul Deshmukh 				ha->flt_region_boot = start;
8327ec0effdSAtul Deshmukh 			break;
833a9083016SGiridhar Malavali 		case FLT_REG_FW_82XX:
834a9083016SGiridhar Malavali 			ha->flt_region_fw = start;
835a9083016SGiridhar Malavali 			break;
8367ec0effdSAtul Deshmukh 		case FLT_REG_CNA_FW:
8377ec0effdSAtul Deshmukh 			if (IS_CNA_CAPABLE(ha))
8387ec0effdSAtul Deshmukh 				ha->flt_region_fw = start;
8397ec0effdSAtul Deshmukh 			break;
840a9083016SGiridhar Malavali 		case FLT_REG_GOLD_FW_82XX:
841a9083016SGiridhar Malavali 			ha->flt_region_gold_fw = start;
842a9083016SGiridhar Malavali 			break;
843a9083016SGiridhar Malavali 		case FLT_REG_BOOTLOAD_82XX:
844a9083016SGiridhar Malavali 			ha->flt_region_bootload = start;
845a9083016SGiridhar Malavali 			break;
846a865c50aSSaurav Kashyap 		case FLT_REG_VPD_8XXX:
847a865c50aSSaurav Kashyap 			if (IS_CNA_CAPABLE(ha))
8486246b8a1SGiridhar Malavali 				ha->flt_region_vpd = start;
8496246b8a1SGiridhar Malavali 			break;
8506246b8a1SGiridhar Malavali 		case FLT_REG_FCOE_NVRAM_0:
8517ec0effdSAtul Deshmukh 			if (!(IS_QLA8031(ha) || IS_QLA8044(ha)))
8526246b8a1SGiridhar Malavali 				break;
853f73cb695SChad Dupuis 			if (ha->port_no == 0)
8546246b8a1SGiridhar Malavali 				ha->flt_region_nvram = start;
8556246b8a1SGiridhar Malavali 			break;
8566246b8a1SGiridhar Malavali 		case FLT_REG_FCOE_NVRAM_1:
8577ec0effdSAtul Deshmukh 			if (!(IS_QLA8031(ha) || IS_QLA8044(ha)))
8586246b8a1SGiridhar Malavali 				break;
859f73cb695SChad Dupuis 			if (ha->port_no == 1)
8606246b8a1SGiridhar Malavali 				ha->flt_region_nvram = start;
8616246b8a1SGiridhar Malavali 			break;
8624243c115SSawan Chandak 		case FLT_REG_IMG_PRI_27XX:
8630d6a536cSJoe Carnuccio 			if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
8644243c115SSawan Chandak 				ha->flt_region_img_status_pri = start;
8654243c115SSawan Chandak 			break;
8664243c115SSawan Chandak 		case FLT_REG_IMG_SEC_27XX:
8674e71dcaeSHimanshu Madhani 			if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
8684243c115SSawan Chandak 				ha->flt_region_img_status_sec = start;
8694243c115SSawan Chandak 			break;
8704243c115SSawan Chandak 		case FLT_REG_FW_SEC_27XX:
8714e71dcaeSHimanshu Madhani 			if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
8724243c115SSawan Chandak 				ha->flt_region_fw_sec = start;
8734243c115SSawan Chandak 			break;
8744243c115SSawan Chandak 		case FLT_REG_BOOTLOAD_SEC_27XX:
8754e71dcaeSHimanshu Madhani 			if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
8764243c115SSawan Chandak 				ha->flt_region_boot_sec = start;
8774243c115SSawan Chandak 			break;
8785fa8774cSJoe Carnuccio 		case FLT_REG_AUX_IMG_PRI_28XX:
8795fa8774cSJoe Carnuccio 			if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
8805fa8774cSJoe Carnuccio 				ha->flt_region_aux_img_status_pri = start;
8815fa8774cSJoe Carnuccio 			break;
8825fa8774cSJoe Carnuccio 		case FLT_REG_AUX_IMG_SEC_28XX:
8835fa8774cSJoe Carnuccio 			if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
8845fa8774cSJoe Carnuccio 				ha->flt_region_aux_img_status_sec = start;
8855fa8774cSJoe Carnuccio 			break;
8865fa8774cSJoe Carnuccio 		case FLT_REG_NVRAM_SEC_28XX_0:
8875fa8774cSJoe Carnuccio 			if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
8885fa8774cSJoe Carnuccio 				if (ha->port_no == 0)
8895fa8774cSJoe Carnuccio 					ha->flt_region_nvram_sec = start;
8905fa8774cSJoe Carnuccio 			break;
8915fa8774cSJoe Carnuccio 		case FLT_REG_NVRAM_SEC_28XX_1:
8925fa8774cSJoe Carnuccio 			if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
8935fa8774cSJoe Carnuccio 				if (ha->port_no == 1)
8945fa8774cSJoe Carnuccio 					ha->flt_region_nvram_sec = start;
8955fa8774cSJoe Carnuccio 			break;
8965fa8774cSJoe Carnuccio 		case FLT_REG_NVRAM_SEC_28XX_2:
8975fa8774cSJoe Carnuccio 			if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
8985fa8774cSJoe Carnuccio 				if (ha->port_no == 2)
8995fa8774cSJoe Carnuccio 					ha->flt_region_nvram_sec = start;
9005fa8774cSJoe Carnuccio 			break;
9015fa8774cSJoe Carnuccio 		case FLT_REG_NVRAM_SEC_28XX_3:
9025fa8774cSJoe Carnuccio 			if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
9035fa8774cSJoe Carnuccio 				if (ha->port_no == 3)
9045fa8774cSJoe Carnuccio 					ha->flt_region_nvram_sec = start;
9055fa8774cSJoe Carnuccio 			break;
9064243c115SSawan Chandak 		case FLT_REG_VPD_SEC_27XX_0:
9075fa8774cSJoe Carnuccio 		case FLT_REG_VPD_SEC_28XX_0:
9085fa8774cSJoe Carnuccio 			if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
9095fa8774cSJoe Carnuccio 				ha->flt_region_vpd_nvram_sec = start;
9105fa8774cSJoe Carnuccio 				if (ha->port_no == 0)
9114243c115SSawan Chandak 					ha->flt_region_vpd_sec = start;
9125fa8774cSJoe Carnuccio 			}
9134243c115SSawan Chandak 			break;
9144243c115SSawan Chandak 		case FLT_REG_VPD_SEC_27XX_1:
9155fa8774cSJoe Carnuccio 		case FLT_REG_VPD_SEC_28XX_1:
9165fa8774cSJoe Carnuccio 			if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
9175fa8774cSJoe Carnuccio 				if (ha->port_no == 1)
9184243c115SSawan Chandak 					ha->flt_region_vpd_sec = start;
9194243c115SSawan Chandak 			break;
9204243c115SSawan Chandak 		case FLT_REG_VPD_SEC_27XX_2:
9215fa8774cSJoe Carnuccio 		case FLT_REG_VPD_SEC_28XX_2:
9225fa8774cSJoe Carnuccio 			if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
9235fa8774cSJoe Carnuccio 				if (ha->port_no == 2)
9244243c115SSawan Chandak 					ha->flt_region_vpd_sec = start;
9254243c115SSawan Chandak 			break;
9264243c115SSawan Chandak 		case FLT_REG_VPD_SEC_27XX_3:
9275fa8774cSJoe Carnuccio 		case FLT_REG_VPD_SEC_28XX_3:
9285fa8774cSJoe Carnuccio 			if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
9295fa8774cSJoe Carnuccio 				if (ha->port_no == 3)
9304243c115SSawan Chandak 					ha->flt_region_vpd_sec = start;
9314243c115SSawan Chandak 			break;
932c00d8994SAndrew Vasquez 		}
933c00d8994SAndrew Vasquez 	}
934c00d8994SAndrew Vasquez 	goto done;
935c00d8994SAndrew Vasquez 
936c00d8994SAndrew Vasquez no_flash_data:
937c00d8994SAndrew Vasquez 	/* Use hardcoded defaults. */
938c00d8994SAndrew Vasquez 	loc = locations[0];
9393a03eb79SAndrew Vasquez 	ha->flt_region_fw = def_fw[def];
9403a03eb79SAndrew Vasquez 	ha->flt_region_boot = def_boot[def];
9413a03eb79SAndrew Vasquez 	ha->flt_region_vpd_nvram = def_vpd_nvram[def];
942f73cb695SChad Dupuis 	ha->flt_region_vpd = (ha->port_no == 0) ?
9433d79038fSAndrew Vasquez 	    def_vpd0[def] : def_vpd1[def];
944f73cb695SChad Dupuis 	ha->flt_region_nvram = (ha->port_no == 0) ?
9453d79038fSAndrew Vasquez 	    def_nvram0[def] : def_nvram1[def];
9463a03eb79SAndrew Vasquez 	ha->flt_region_fdt = def_fdt[def];
947f73cb695SChad Dupuis 	ha->flt_region_npiv_conf = (ha->port_no == 0) ?
9483a03eb79SAndrew Vasquez 	    def_npiv_conf0[def] : def_npiv_conf1[def];
949c00d8994SAndrew Vasquez done:
9507c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_init, vha, 0x004a,
9516246b8a1SGiridhar Malavali 	    "FLT[%s]: boot=0x%x fw=0x%x vpd_nvram=0x%x vpd=0x%x nvram=0x%x "
9526246b8a1SGiridhar Malavali 	    "fdt=0x%x flt=0x%x npiv=0x%x fcp_prif_cfg=0x%x.\n",
9536246b8a1SGiridhar Malavali 	    loc, ha->flt_region_boot, ha->flt_region_fw,
9546246b8a1SGiridhar Malavali 	    ha->flt_region_vpd_nvram, ha->flt_region_vpd, ha->flt_region_nvram,
9556246b8a1SGiridhar Malavali 	    ha->flt_region_fdt, ha->flt_region_flt, ha->flt_region_npiv_conf,
9566246b8a1SGiridhar Malavali 	    ha->flt_region_fcp_prio);
957c00d8994SAndrew Vasquez }
958c00d8994SAndrew Vasquez 
959c00d8994SAndrew Vasquez static void
qla2xxx_get_fdt_info(scsi_qla_host_t * vha)9607b867cf7SAnirban Chakraborty qla2xxx_get_fdt_info(scsi_qla_host_t *vha)
9617d232c74SAndrew Vasquez {
962821b3996SLalit Chandivade #define FLASH_BLK_SIZE_4K	0x1000
9637d232c74SAndrew Vasquez #define FLASH_BLK_SIZE_32K	0x8000
9647d232c74SAndrew Vasquez #define FLASH_BLK_SIZE_64K	0x10000
965c00d8994SAndrew Vasquez 	const char *loc, *locations[] = { "MID", "FDT" };
9667b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
96773208dfdSAnirban Chakraborty 	struct req_que *req = ha->req_q_map[0];
9683695310eSJoe Carnuccio 	uint16_t cnt, chksum;
9697ffa5b93SBart Van Assche 	__le16 *wptr = (__force __le16 *)req->ring;
970cb92cb16SQuinn Tran 	struct qla_fdt_layout *fdt = (struct qla_fdt_layout *)req->ring;
9713695310eSJoe Carnuccio 	uint8_t	man_id, flash_id;
9723695310eSJoe Carnuccio 	uint16_t mid = 0, fid = 0;
9737d232c74SAndrew Vasquez 
974cb92cb16SQuinn Tran 	ha->isp_ops->read_optrom(vha, fdt, ha->flt_region_fdt << 2,
9753695310eSJoe Carnuccio 	    OPTROM_BURST_DWORDS);
9763695310eSJoe Carnuccio 	if (le16_to_cpu(*wptr) == 0xffff)
9777d232c74SAndrew Vasquez 		goto no_flash_data;
9783695310eSJoe Carnuccio 	if (memcmp(fdt->sig, "QLID", 4))
9797d232c74SAndrew Vasquez 		goto no_flash_data;
9807d232c74SAndrew Vasquez 
981da08ef5cSJoe Carnuccio 	for (cnt = 0, chksum = 0; cnt < sizeof(*fdt) >> 1; cnt++, wptr++)
982da08ef5cSJoe Carnuccio 		chksum += le16_to_cpu(*wptr);
9837d232c74SAndrew Vasquez 	if (chksum) {
9847c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_init, vha, 0x004c,
9857c3df132SSaurav Kashyap 		    "Inconsistent FDT detected:"
9867c3df132SSaurav Kashyap 		    " checksum=0x%x id=%c version0x%x.\n", chksum,
9877c3df132SSaurav Kashyap 		    fdt->sig[0], le16_to_cpu(fdt->version));
9887c3df132SSaurav Kashyap 		ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x0113,
989f8f97b0cSJoe Carnuccio 		    fdt, sizeof(*fdt));
9907d232c74SAndrew Vasquez 		goto no_flash_data;
9917d232c74SAndrew Vasquez 	}
9927d232c74SAndrew Vasquez 
993c00d8994SAndrew Vasquez 	loc = locations[1];
994c00d8994SAndrew Vasquez 	mid = le16_to_cpu(fdt->man_id);
995c00d8994SAndrew Vasquez 	fid = le16_to_cpu(fdt->id);
9967d232c74SAndrew Vasquez 	ha->fdt_wrt_disable = fdt->wrt_disable_bits;
9977ec0effdSAtul Deshmukh 	ha->fdt_wrt_enable = fdt->wrt_enable_bits;
9987ec0effdSAtul Deshmukh 	ha->fdt_wrt_sts_reg_cmd = fdt->wrt_sts_reg_cmd;
9997ec0effdSAtul Deshmukh 	if (IS_QLA8044(ha))
10007ec0effdSAtul Deshmukh 		ha->fdt_erase_cmd = fdt->erase_cmd;
10017ec0effdSAtul Deshmukh 	else
10027ec0effdSAtul Deshmukh 		ha->fdt_erase_cmd =
10037ec0effdSAtul Deshmukh 		    flash_conf_addr(ha, 0x0300 | fdt->erase_cmd);
10047d232c74SAndrew Vasquez 	ha->fdt_block_size = le32_to_cpu(fdt->block_size);
10057d232c74SAndrew Vasquez 	if (fdt->unprotect_sec_cmd) {
10063a03eb79SAndrew Vasquez 		ha->fdt_unprotect_sec_cmd = flash_conf_addr(ha, 0x0300 |
10077d232c74SAndrew Vasquez 		    fdt->unprotect_sec_cmd);
10087d232c74SAndrew Vasquez 		ha->fdt_protect_sec_cmd = fdt->protect_sec_cmd ?
10093a03eb79SAndrew Vasquez 		    flash_conf_addr(ha, 0x0300 | fdt->protect_sec_cmd) :
10103a03eb79SAndrew Vasquez 		    flash_conf_addr(ha, 0x0336);
10117d232c74SAndrew Vasquez 	}
1012c00d8994SAndrew Vasquez 	goto done;
10137d232c74SAndrew Vasquez no_flash_data:
1014c00d8994SAndrew Vasquez 	loc = locations[0];
10157ec0effdSAtul Deshmukh 	if (IS_P3P_TYPE(ha)) {
1016a9083016SGiridhar Malavali 		ha->fdt_block_size = FLASH_BLK_SIZE_64K;
1017a9083016SGiridhar Malavali 		goto done;
1018a9083016SGiridhar Malavali 	}
10197d232c74SAndrew Vasquez 	qla24xx_get_flash_manufacturer(ha, &man_id, &flash_id);
1020c00d8994SAndrew Vasquez 	mid = man_id;
1021c00d8994SAndrew Vasquez 	fid = flash_id;
10227d232c74SAndrew Vasquez 	ha->fdt_wrt_disable = 0x9c;
10233a03eb79SAndrew Vasquez 	ha->fdt_erase_cmd = flash_conf_addr(ha, 0x03d8);
10247d232c74SAndrew Vasquez 	switch (man_id) {
10257d232c74SAndrew Vasquez 	case 0xbf: /* STT flash. */
10267d232c74SAndrew Vasquez 		if (flash_id == 0x8e)
10277d232c74SAndrew Vasquez 			ha->fdt_block_size = FLASH_BLK_SIZE_64K;
10287d232c74SAndrew Vasquez 		else
10297d232c74SAndrew Vasquez 			ha->fdt_block_size = FLASH_BLK_SIZE_32K;
10307d232c74SAndrew Vasquez 
10317d232c74SAndrew Vasquez 		if (flash_id == 0x80)
10323a03eb79SAndrew Vasquez 			ha->fdt_erase_cmd = flash_conf_addr(ha, 0x0352);
10337d232c74SAndrew Vasquez 		break;
10347d232c74SAndrew Vasquez 	case 0x13: /* ST M25P80. */
10357d232c74SAndrew Vasquez 		ha->fdt_block_size = FLASH_BLK_SIZE_64K;
10367d232c74SAndrew Vasquez 		break;
10377d232c74SAndrew Vasquez 	case 0x1f: /* Atmel 26DF081A. */
1038821b3996SLalit Chandivade 		ha->fdt_block_size = FLASH_BLK_SIZE_4K;
10393a03eb79SAndrew Vasquez 		ha->fdt_erase_cmd = flash_conf_addr(ha, 0x0320);
10403a03eb79SAndrew Vasquez 		ha->fdt_unprotect_sec_cmd = flash_conf_addr(ha, 0x0339);
10413a03eb79SAndrew Vasquez 		ha->fdt_protect_sec_cmd = flash_conf_addr(ha, 0x0336);
10427d232c74SAndrew Vasquez 		break;
10437d232c74SAndrew Vasquez 	default:
10447d232c74SAndrew Vasquez 		/* Default to 64 kb sector size. */
10457d232c74SAndrew Vasquez 		ha->fdt_block_size = FLASH_BLK_SIZE_64K;
10467d232c74SAndrew Vasquez 		break;
10477d232c74SAndrew Vasquez 	}
1048c00d8994SAndrew Vasquez done:
10497c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_init, vha, 0x004d,
1050d8424f68SJoe Perches 	    "FDT[%s]: (0x%x/0x%x) erase=0x%x "
1051d8424f68SJoe Perches 	    "pr=%x wrtd=0x%x blk=0x%x.\n",
1052d8424f68SJoe Perches 	    loc, mid, fid,
10537d232c74SAndrew Vasquez 	    ha->fdt_erase_cmd, ha->fdt_protect_sec_cmd,
10547c3df132SSaurav Kashyap 	    ha->fdt_wrt_disable, ha->fdt_block_size);
10557c3df132SSaurav Kashyap 
10567d232c74SAndrew Vasquez }
10577d232c74SAndrew Vasquez 
1058a9083016SGiridhar Malavali static void
qla2xxx_get_idc_param(scsi_qla_host_t * vha)1059a9083016SGiridhar Malavali qla2xxx_get_idc_param(scsi_qla_host_t *vha)
1060a9083016SGiridhar Malavali {
1061a9083016SGiridhar Malavali #define QLA82XX_IDC_PARAM_ADDR       0x003e885c
10627ffa5b93SBart Van Assche 	__le32 *wptr;
1063a9083016SGiridhar Malavali 	struct qla_hw_data *ha = vha->hw;
1064a9083016SGiridhar Malavali 	struct req_que *req = ha->req_q_map[0];
1065a9083016SGiridhar Malavali 
10667ec0effdSAtul Deshmukh 	if (!(IS_P3P_TYPE(ha)))
1067a9083016SGiridhar Malavali 		return;
1068a9083016SGiridhar Malavali 
10697ffa5b93SBart Van Assche 	wptr = (__force __le32 *)req->ring;
10703695310eSJoe Carnuccio 	ha->isp_ops->read_optrom(vha, req->ring, QLA82XX_IDC_PARAM_ADDR, 8);
1071a9083016SGiridhar Malavali 
1072ad950360SBart Van Assche 	if (*wptr == cpu_to_le32(0xffffffff)) {
10737d613ac6SSantosh Vernekar 		ha->fcoe_dev_init_timeout = QLA82XX_ROM_DEV_INIT_TIMEOUT;
10747d613ac6SSantosh Vernekar 		ha->fcoe_reset_timeout = QLA82XX_ROM_DRV_RESET_ACK_TIMEOUT;
1075a9083016SGiridhar Malavali 	} else {
1076da08ef5cSJoe Carnuccio 		ha->fcoe_dev_init_timeout = le32_to_cpu(*wptr);
1077da08ef5cSJoe Carnuccio 		wptr++;
10787d613ac6SSantosh Vernekar 		ha->fcoe_reset_timeout = le32_to_cpu(*wptr);
1079a9083016SGiridhar Malavali 	}
10807c3df132SSaurav Kashyap 	ql_dbg(ql_dbg_init, vha, 0x004e,
10817d613ac6SSantosh Vernekar 	    "fcoe_dev_init_timeout=%d "
10827d613ac6SSantosh Vernekar 	    "fcoe_reset_timeout=%d.\n", ha->fcoe_dev_init_timeout,
10837d613ac6SSantosh Vernekar 	    ha->fcoe_reset_timeout);
1084a9083016SGiridhar Malavali 	return;
1085a9083016SGiridhar Malavali }
1086a9083016SGiridhar Malavali 
1087c00d8994SAndrew Vasquez int
qla2xxx_get_flash_info(scsi_qla_host_t * vha)10887b867cf7SAnirban Chakraborty qla2xxx_get_flash_info(scsi_qla_host_t *vha)
1089c00d8994SAndrew Vasquez {
1090c00d8994SAndrew Vasquez 	int ret;
1091c00d8994SAndrew Vasquez 	uint32_t flt_addr;
10927b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
1093c00d8994SAndrew Vasquez 
10946246b8a1SGiridhar Malavali 	if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) &&
1095ecc89f25SJoe Carnuccio 	    !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha) &&
1096ecc89f25SJoe Carnuccio 	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
1097c00d8994SAndrew Vasquez 		return QLA_SUCCESS;
1098c00d8994SAndrew Vasquez 
10997b867cf7SAnirban Chakraborty 	ret = qla2xxx_find_flt_start(vha, &flt_addr);
1100c00d8994SAndrew Vasquez 	if (ret != QLA_SUCCESS)
1101c00d8994SAndrew Vasquez 		return ret;
1102c00d8994SAndrew Vasquez 
11037b867cf7SAnirban Chakraborty 	qla2xxx_get_flt_info(vha, flt_addr);
11047b867cf7SAnirban Chakraborty 	qla2xxx_get_fdt_info(vha);
1105a9083016SGiridhar Malavali 	qla2xxx_get_idc_param(vha);
1106c00d8994SAndrew Vasquez 
1107c00d8994SAndrew Vasquez 	return QLA_SUCCESS;
1108c00d8994SAndrew Vasquez }
1109c00d8994SAndrew Vasquez 
1110272976caSAndrew Vasquez void
qla2xxx_flash_npiv_conf(scsi_qla_host_t * vha)11117b867cf7SAnirban Chakraborty qla2xxx_flash_npiv_conf(scsi_qla_host_t *vha)
1112272976caSAndrew Vasquez {
1113272976caSAndrew Vasquez #define NPIV_CONFIG_SIZE	(16*1024)
1114272976caSAndrew Vasquez 	void *data;
11157ffa5b93SBart Van Assche 	__le16 *wptr;
1116272976caSAndrew Vasquez 	uint16_t cnt, chksum;
111773208dfdSAnirban Chakraborty 	int i;
1118272976caSAndrew Vasquez 	struct qla_npiv_header hdr;
1119272976caSAndrew Vasquez 	struct qla_npiv_entry *entry;
11207b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
1121272976caSAndrew Vasquez 
11226246b8a1SGiridhar Malavali 	if (!IS_QLA24XX_TYPE(ha) && !IS_QLA25XX(ha) &&
11236246b8a1SGiridhar Malavali 	    !IS_CNA_CAPABLE(ha) && !IS_QLA2031(ha))
1124272976caSAndrew Vasquez 		return;
1125272976caSAndrew Vasquez 
11267d613ac6SSantosh Vernekar 	if (ha->flags.nic_core_reset_hdlr_active)
1127a49393f2SGiridhar Malavali 		return;
1128a49393f2SGiridhar Malavali 
11297ec0effdSAtul Deshmukh 	if (IS_QLA8044(ha))
11307ec0effdSAtul Deshmukh 		return;
11317ec0effdSAtul Deshmukh 
11323695310eSJoe Carnuccio 	ha->isp_ops->read_optrom(vha, &hdr, ha->flt_region_npiv_conf << 2,
11333695310eSJoe Carnuccio 	    sizeof(struct qla_npiv_header));
1134ad950360SBart Van Assche 	if (hdr.version == cpu_to_le16(0xffff))
1135272976caSAndrew Vasquez 		return;
1136ad950360SBart Van Assche 	if (hdr.version != cpu_to_le16(1)) {
11377c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_user, vha, 0x7090,
11387c3df132SSaurav Kashyap 		    "Unsupported NPIV-Config "
1139272976caSAndrew Vasquez 		    "detected: version=0x%x entries=0x%x checksum=0x%x.\n",
1140272976caSAndrew Vasquez 		    le16_to_cpu(hdr.version), le16_to_cpu(hdr.entries),
11417c3df132SSaurav Kashyap 		    le16_to_cpu(hdr.checksum));
1142272976caSAndrew Vasquez 		return;
1143272976caSAndrew Vasquez 	}
1144272976caSAndrew Vasquez 
1145272976caSAndrew Vasquez 	data = kmalloc(NPIV_CONFIG_SIZE, GFP_KERNEL);
1146272976caSAndrew Vasquez 	if (!data) {
11477c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x7091,
11487c3df132SSaurav Kashyap 		    "Unable to allocate memory for data.\n");
1149272976caSAndrew Vasquez 		return;
1150272976caSAndrew Vasquez 	}
1151272976caSAndrew Vasquez 
11523695310eSJoe Carnuccio 	ha->isp_ops->read_optrom(vha, data, ha->flt_region_npiv_conf << 2,
11533695310eSJoe Carnuccio 	    NPIV_CONFIG_SIZE);
1154272976caSAndrew Vasquez 
1155da08ef5cSJoe Carnuccio 	cnt = (sizeof(hdr) + le16_to_cpu(hdr.entries) * sizeof(*entry)) >> 1;
1156da08ef5cSJoe Carnuccio 	for (wptr = data, chksum = 0; cnt--; wptr++)
1157da08ef5cSJoe Carnuccio 		chksum += le16_to_cpu(*wptr);
1158272976caSAndrew Vasquez 	if (chksum) {
11597c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_user, vha, 0x7092,
11607c3df132SSaurav Kashyap 		    "Inconsistent NPIV-Config "
1161272976caSAndrew Vasquez 		    "detected: version=0x%x entries=0x%x checksum=0x%x.\n",
1162272976caSAndrew Vasquez 		    le16_to_cpu(hdr.version), le16_to_cpu(hdr.entries),
11637c3df132SSaurav Kashyap 		    le16_to_cpu(hdr.checksum));
1164272976caSAndrew Vasquez 		goto done;
1165272976caSAndrew Vasquez 	}
1166272976caSAndrew Vasquez 
1167272976caSAndrew Vasquez 	entry = data + sizeof(struct qla_npiv_header);
1168272976caSAndrew Vasquez 	cnt = le16_to_cpu(hdr.entries);
116973208dfdSAnirban Chakraborty 	for (i = 0; cnt; cnt--, entry++, i++) {
1170272976caSAndrew Vasquez 		uint16_t flags;
1171272976caSAndrew Vasquez 		struct fc_vport_identifiers vid;
1172272976caSAndrew Vasquez 		struct fc_vport *vport;
1173272976caSAndrew Vasquez 
117440859ae5SAnirban Chakraborty 		memcpy(&ha->npiv_info[i], entry, sizeof(struct qla_npiv_entry));
117540859ae5SAnirban Chakraborty 
1176272976caSAndrew Vasquez 		flags = le16_to_cpu(entry->flags);
1177272976caSAndrew Vasquez 		if (flags == 0xffff)
1178272976caSAndrew Vasquez 			continue;
1179272976caSAndrew Vasquez 		if ((flags & BIT_0) == 0)
1180272976caSAndrew Vasquez 			continue;
1181272976caSAndrew Vasquez 
1182272976caSAndrew Vasquez 		memset(&vid, 0, sizeof(vid));
1183272976caSAndrew Vasquez 		vid.roles = FC_PORT_ROLE_FCP_INITIATOR;
1184272976caSAndrew Vasquez 		vid.vport_type = FC_PORTTYPE_NPIV;
1185272976caSAndrew Vasquez 		vid.disable = false;
1186272976caSAndrew Vasquez 		vid.port_name = wwn_to_u64(entry->port_name);
1187272976caSAndrew Vasquez 		vid.node_name = wwn_to_u64(entry->node_name);
1188272976caSAndrew Vasquez 
11897c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_user, vha, 0x7093,
11903695310eSJoe Carnuccio 		    "NPIV[%02x]: wwpn=%llx wwnn=%llx vf_id=%#x Q_qos=%#x F_qos=%#x.\n",
11913695310eSJoe Carnuccio 		    cnt, vid.port_name, vid.node_name,
119218020ba7SRandy Dunlap 		    le16_to_cpu(entry->vf_id),
11937c3df132SSaurav Kashyap 		    entry->q_qos, entry->f_qos);
119473208dfdSAnirban Chakraborty 
119573208dfdSAnirban Chakraborty 		if (i < QLA_PRECONFIG_VPORTS) {
11967b867cf7SAnirban Chakraborty 			vport = fc_vport_create(vha->host, 0, &vid);
1197272976caSAndrew Vasquez 			if (!vport)
11987c3df132SSaurav Kashyap 				ql_log(ql_log_warn, vha, 0x7094,
11993695310eSJoe Carnuccio 				    "NPIV-Config Failed to create vport [%02x]: wwpn=%llx wwnn=%llx.\n",
12003695310eSJoe Carnuccio 				    cnt, vid.port_name, vid.node_name);
1201272976caSAndrew Vasquez 		}
120273208dfdSAnirban Chakraborty 	}
1203272976caSAndrew Vasquez done:
1204272976caSAndrew Vasquez 	kfree(data);
1205272976caSAndrew Vasquez }
1206272976caSAndrew Vasquez 
12071d2874deSJoe Carnuccio static int
qla24xx_unprotect_flash(scsi_qla_host_t * vha)12081d2874deSJoe Carnuccio qla24xx_unprotect_flash(scsi_qla_host_t *vha)
1209cb8dacbfSAndrew Vasquez {
12101d2874deSJoe Carnuccio 	struct qla_hw_data *ha = vha->hw;
1211cb8dacbfSAndrew Vasquez 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
1212cb8dacbfSAndrew Vasquez 
12131d2874deSJoe Carnuccio 	if (ha->flags.fac_supported)
12141d2874deSJoe Carnuccio 		return qla81xx_fac_do_write_enable(vha, 1);
12151d2874deSJoe Carnuccio 
1216cb8dacbfSAndrew Vasquez 	/* Enable flash write. */
121704474d3aSBart Van Assche 	wrt_reg_dword(&reg->ctrl_status,
121804474d3aSBart Van Assche 	    rd_reg_dword(&reg->ctrl_status) | CSRX_FLASH_ENABLE);
121904474d3aSBart Van Assche 	rd_reg_dword(&reg->ctrl_status);	/* PCI Posting. */
1220cb8dacbfSAndrew Vasquez 
12217d232c74SAndrew Vasquez 	if (!ha->fdt_wrt_disable)
12221d2874deSJoe Carnuccio 		goto done;
12237d232c74SAndrew Vasquez 
1224b872ca40SJoe Carnuccio 	/* Disable flash write-protection, first clear SR protection bit */
12253a03eb79SAndrew Vasquez 	qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101), 0);
1226b872ca40SJoe Carnuccio 	/* Then write zero again to clear remaining SR bits.*/
12273a03eb79SAndrew Vasquez 	qla24xx_write_flash_dword(ha, flash_conf_addr(ha, 0x101), 0);
12281d2874deSJoe Carnuccio done:
12291d2874deSJoe Carnuccio 	return QLA_SUCCESS;
1230cb8dacbfSAndrew Vasquez }
1231cb8dacbfSAndrew Vasquez 
12321d2874deSJoe Carnuccio static int
qla24xx_protect_flash(scsi_qla_host_t * vha)12331d2874deSJoe Carnuccio qla24xx_protect_flash(scsi_qla_host_t *vha)
1234cb8dacbfSAndrew Vasquez {
12351d2874deSJoe Carnuccio 	struct qla_hw_data *ha = vha->hw;
1236cb8dacbfSAndrew Vasquez 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
12373695310eSJoe Carnuccio 	ulong cnt = 300;
12383695310eSJoe Carnuccio 	uint32_t faddr, dword;
1239cb8dacbfSAndrew Vasquez 
12401d2874deSJoe Carnuccio 	if (ha->flags.fac_supported)
12411d2874deSJoe Carnuccio 		return qla81xx_fac_do_write_enable(vha, 0);
12421d2874deSJoe Carnuccio 
12437d232c74SAndrew Vasquez 	if (!ha->fdt_wrt_disable)
12447d232c74SAndrew Vasquez 		goto skip_wrt_protect;
12457d232c74SAndrew Vasquez 
1246cb8dacbfSAndrew Vasquez 	/* Enable flash write-protection and wait for completion. */
12473695310eSJoe Carnuccio 	faddr = flash_conf_addr(ha, 0x101);
12483695310eSJoe Carnuccio 	qla24xx_write_flash_dword(ha, faddr, ha->fdt_wrt_disable);
12493695310eSJoe Carnuccio 	faddr = flash_conf_addr(ha, 0x5);
12503695310eSJoe Carnuccio 	while (cnt--) {
12513695310eSJoe Carnuccio 		if (!qla24xx_read_flash_dword(ha, faddr, &dword)) {
12523695310eSJoe Carnuccio 			if (!(dword & BIT_0))
12533695310eSJoe Carnuccio 				break;
12543695310eSJoe Carnuccio 		}
1255cb8dacbfSAndrew Vasquez 		udelay(10);
1256cb8dacbfSAndrew Vasquez 	}
1257cb8dacbfSAndrew Vasquez 
12587d232c74SAndrew Vasquez skip_wrt_protect:
1259cb8dacbfSAndrew Vasquez 	/* Disable flash write. */
126004474d3aSBart Van Assche 	wrt_reg_dword(&reg->ctrl_status,
126104474d3aSBart Van Assche 	    rd_reg_dword(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);
12621d2874deSJoe Carnuccio 
12631d2874deSJoe Carnuccio 	return QLA_SUCCESS;
12641d2874deSJoe Carnuccio }
12651d2874deSJoe Carnuccio 
12661d2874deSJoe Carnuccio static int
qla24xx_erase_sector(scsi_qla_host_t * vha,uint32_t fdata)12671d2874deSJoe Carnuccio qla24xx_erase_sector(scsi_qla_host_t *vha, uint32_t fdata)
12681d2874deSJoe Carnuccio {
12691d2874deSJoe Carnuccio 	struct qla_hw_data *ha = vha->hw;
12701d2874deSJoe Carnuccio 	uint32_t start, finish;
12711d2874deSJoe Carnuccio 
12721d2874deSJoe Carnuccio 	if (ha->flags.fac_supported) {
12731d2874deSJoe Carnuccio 		start = fdata >> 2;
12741d2874deSJoe Carnuccio 		finish = start + (ha->fdt_block_size >> 2) - 1;
12751d2874deSJoe Carnuccio 		return qla81xx_fac_erase_sector(vha, flash_data_addr(ha,
12761d2874deSJoe Carnuccio 		    start), flash_data_addr(ha, finish));
12771d2874deSJoe Carnuccio 	}
12781d2874deSJoe Carnuccio 
12791d2874deSJoe Carnuccio 	return qla24xx_write_flash_dword(ha, ha->fdt_erase_cmd,
12801d2874deSJoe Carnuccio 	    (fdata & 0xff00) | ((fdata << 16) & 0xff0000) |
12811d2874deSJoe Carnuccio 	    ((fdata >> 16) & 0xff));
1282cb8dacbfSAndrew Vasquez }
1283cb8dacbfSAndrew Vasquez 
1284e5f82ab8SAdrian Bunk static int
qla24xx_write_flash_data(scsi_qla_host_t * vha,__le32 * dwptr,uint32_t faddr,uint32_t dwords)12857ffa5b93SBart Van Assche qla24xx_write_flash_data(scsi_qla_host_t *vha, __le32 *dwptr, uint32_t faddr,
1286459c5378SAndrew Vasquez     uint32_t dwords)
1287459c5378SAndrew Vasquez {
1288459c5378SAndrew Vasquez 	int ret;
12893695310eSJoe Carnuccio 	ulong liter;
12903695310eSJoe Carnuccio 	ulong dburst = OPTROM_BURST_DWORDS; /* burst size in dwords */
12913695310eSJoe Carnuccio 	uint32_t sec_mask, rest_addr, fdata;
1292338c9161SAndrew Vasquez 	dma_addr_t optrom_dma;
1293338c9161SAndrew Vasquez 	void *optrom = NULL;
12947b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
1295459c5378SAndrew Vasquez 
12963695310eSJoe Carnuccio 	if (!IS_QLA25XX(ha) && !IS_QLA81XX(ha) && !IS_QLA83XX(ha) &&
12973695310eSJoe Carnuccio 	    !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
12983695310eSJoe Carnuccio 		goto next;
12993695310eSJoe Carnuccio 
13003695310eSJoe Carnuccio 	/* Allocate dma buffer for burst write */
1301338c9161SAndrew Vasquez 	optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
1302338c9161SAndrew Vasquez 	    &optrom_dma, GFP_KERNEL);
1303338c9161SAndrew Vasquez 	if (!optrom) {
13047c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x7095,
13053695310eSJoe Carnuccio 		    "Failed allocate burst (%x bytes)\n", OPTROM_BURST_SIZE);
1306338c9161SAndrew Vasquez 	}
13073695310eSJoe Carnuccio 
13083695310eSJoe Carnuccio next:
13093695310eSJoe Carnuccio 	ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
13103695310eSJoe Carnuccio 	    "Unprotect flash...\n");
13113695310eSJoe Carnuccio 	ret = qla24xx_unprotect_flash(vha);
13123695310eSJoe Carnuccio 	if (ret) {
13133695310eSJoe Carnuccio 		ql_log(ql_log_warn, vha, 0x7096,
13143695310eSJoe Carnuccio 		    "Failed to unprotect flash.\n");
13153695310eSJoe Carnuccio 		goto done;
1316338c9161SAndrew Vasquez 	}
1317338c9161SAndrew Vasquez 
13187d232c74SAndrew Vasquez 	rest_addr = (ha->fdt_block_size >> 2) - 1;
131985d0acbbSAndrew Vasquez 	sec_mask = ~rest_addr;
1320459c5378SAndrew Vasquez 	for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) {
132185d0acbbSAndrew Vasquez 		fdata = (faddr & sec_mask) << 2;
132245aeaf1eSRavi Anand 
1323459c5378SAndrew Vasquez 		/* Are we at the beginning of a sector? */
13243695310eSJoe Carnuccio 		if (!(faddr & rest_addr)) {
13253695310eSJoe Carnuccio 			ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
13263695310eSJoe Carnuccio 			    "Erase sector %#x...\n", faddr);
13273695310eSJoe Carnuccio 
13281d2874deSJoe Carnuccio 			ret = qla24xx_erase_sector(vha, fdata);
13293695310eSJoe Carnuccio 			if (ret) {
13307c3df132SSaurav Kashyap 				ql_dbg(ql_dbg_user, vha, 0x7007,
13313695310eSJoe Carnuccio 				    "Failed to erase sector %x.\n", faddr);
1332459c5378SAndrew Vasquez 				break;
1333459c5378SAndrew Vasquez 			}
1334459c5378SAndrew Vasquez 		}
1335338c9161SAndrew Vasquez 
13363695310eSJoe Carnuccio 		if (optrom) {
13373695310eSJoe Carnuccio 			/* If smaller than a burst remaining */
13383695310eSJoe Carnuccio 			if (dwords - liter < dburst)
13393695310eSJoe Carnuccio 				dburst = dwords - liter;
1340338c9161SAndrew Vasquez 
13413695310eSJoe Carnuccio 			/* Copy to dma buffer */
13423695310eSJoe Carnuccio 			memcpy(optrom, dwptr, dburst << 2);
13433695310eSJoe Carnuccio 
13443695310eSJoe Carnuccio 			/* Burst write */
13453695310eSJoe Carnuccio 			ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
13463695310eSJoe Carnuccio 			    "Write burst (%#lx dwords)...\n", dburst);
13477b867cf7SAnirban Chakraborty 			ret = qla2x00_load_ram(vha, optrom_dma,
13483695310eSJoe Carnuccio 			    flash_data_addr(ha, faddr), dburst);
13493695310eSJoe Carnuccio 			if (!ret) {
13503695310eSJoe Carnuccio 				liter += dburst - 1;
13513695310eSJoe Carnuccio 				faddr += dburst - 1;
13523695310eSJoe Carnuccio 				dwptr += dburst - 1;
13533695310eSJoe Carnuccio 				continue;
13543695310eSJoe Carnuccio 			}
13553695310eSJoe Carnuccio 
13567c3df132SSaurav Kashyap 			ql_log(ql_log_warn, vha, 0x7097,
13573695310eSJoe Carnuccio 			    "Failed burst-write at %x (%p/%#llx)....\n",
13583695310eSJoe Carnuccio 			    flash_data_addr(ha, faddr), optrom,
13593695310eSJoe Carnuccio 			    (u64)optrom_dma);
1360338c9161SAndrew Vasquez 
1361338c9161SAndrew Vasquez 			dma_free_coherent(&ha->pdev->dev,
1362338c9161SAndrew Vasquez 			    OPTROM_BURST_SIZE, optrom, optrom_dma);
1363338c9161SAndrew Vasquez 			optrom = NULL;
13643695310eSJoe Carnuccio 			if (IS_QLA27XX(ha) || IS_QLA28XX(ha))
13653695310eSJoe Carnuccio 				break;
13663695310eSJoe Carnuccio 			ql_log(ql_log_warn, vha, 0x7098,
13673695310eSJoe Carnuccio 			    "Reverting to slow write...\n");
1368338c9161SAndrew Vasquez 		}
1369338c9161SAndrew Vasquez 
13703695310eSJoe Carnuccio 		/* Slow write */
1371338c9161SAndrew Vasquez 		ret = qla24xx_write_flash_dword(ha,
13727ffa5b93SBart Van Assche 		    flash_data_addr(ha, faddr), le32_to_cpu(*dwptr));
13733695310eSJoe Carnuccio 		if (ret) {
13747c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_user, vha, 0x7006,
13750d6a536cSJoe Carnuccio 			    "Failed slow write %x (%x)\n", faddr, *dwptr);
1376459c5378SAndrew Vasquez 			break;
1377459c5378SAndrew Vasquez 		}
1378459c5378SAndrew Vasquez 	}
1379459c5378SAndrew Vasquez 
13803695310eSJoe Carnuccio 	ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
13813695310eSJoe Carnuccio 	    "Protect flash...\n");
13821d2874deSJoe Carnuccio 	ret = qla24xx_protect_flash(vha);
13833695310eSJoe Carnuccio 	if (ret)
13847c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x7099,
13853695310eSJoe Carnuccio 		    "Failed to protect flash\n");
13861d2874deSJoe Carnuccio done:
1387338c9161SAndrew Vasquez 	if (optrom)
1388338c9161SAndrew Vasquez 		dma_free_coherent(&ha->pdev->dev,
1389338c9161SAndrew Vasquez 		    OPTROM_BURST_SIZE, optrom, optrom_dma);
1390338c9161SAndrew Vasquez 
1391459c5378SAndrew Vasquez 	return ret;
1392459c5378SAndrew Vasquez }
1393459c5378SAndrew Vasquez 
1394459c5378SAndrew Vasquez uint8_t *
qla2x00_read_nvram_data(scsi_qla_host_t * vha,void * buf,uint32_t naddr,uint32_t bytes)13953695310eSJoe Carnuccio qla2x00_read_nvram_data(scsi_qla_host_t *vha, void *buf, uint32_t naddr,
1396459c5378SAndrew Vasquez     uint32_t bytes)
1397459c5378SAndrew Vasquez {
1398459c5378SAndrew Vasquez 	uint32_t i;
13997ffa5b93SBart Van Assche 	__le16 *wptr;
14007b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
1401459c5378SAndrew Vasquez 
1402459c5378SAndrew Vasquez 	/* Word reads to NVRAM via registers. */
14037ffa5b93SBart Van Assche 	wptr = buf;
1404459c5378SAndrew Vasquez 	qla2x00_lock_nvram_access(ha);
1405459c5378SAndrew Vasquez 	for (i = 0; i < bytes >> 1; i++, naddr++)
1406459c5378SAndrew Vasquez 		wptr[i] = cpu_to_le16(qla2x00_get_nvram_word(ha,
1407459c5378SAndrew Vasquez 		    naddr));
1408459c5378SAndrew Vasquez 	qla2x00_unlock_nvram_access(ha);
1409459c5378SAndrew Vasquez 
1410459c5378SAndrew Vasquez 	return buf;
1411459c5378SAndrew Vasquez }
1412459c5378SAndrew Vasquez 
1413459c5378SAndrew Vasquez uint8_t *
qla24xx_read_nvram_data(scsi_qla_host_t * vha,void * buf,uint32_t naddr,uint32_t bytes)14143695310eSJoe Carnuccio qla24xx_read_nvram_data(scsi_qla_host_t *vha, void *buf, uint32_t naddr,
1415459c5378SAndrew Vasquez     uint32_t bytes)
1416459c5378SAndrew Vasquez {
14173a03eb79SAndrew Vasquez 	struct qla_hw_data *ha = vha->hw;
14183695310eSJoe Carnuccio 	uint32_t *dwptr = buf;
14193695310eSJoe Carnuccio 	uint32_t i;
1420459c5378SAndrew Vasquez 
14217ec0effdSAtul Deshmukh 	if (IS_P3P_TYPE(ha))
1422a9083016SGiridhar Malavali 		return  buf;
1423a9083016SGiridhar Malavali 
1424459c5378SAndrew Vasquez 	/* Dword reads to flash. */
14253695310eSJoe Carnuccio 	naddr = nvram_data_addr(ha, naddr);
14263695310eSJoe Carnuccio 	bytes >>= 2;
14273695310eSJoe Carnuccio 	for (i = 0; i < bytes; i++, naddr++, dwptr++) {
14283695310eSJoe Carnuccio 		if (qla24xx_read_flash_dword(ha, naddr, dwptr))
14293695310eSJoe Carnuccio 			break;
14303695310eSJoe Carnuccio 		cpu_to_le32s(dwptr);
14313695310eSJoe Carnuccio 	}
1432459c5378SAndrew Vasquez 
1433459c5378SAndrew Vasquez 	return buf;
1434459c5378SAndrew Vasquez }
1435459c5378SAndrew Vasquez 
1436459c5378SAndrew Vasquez int
qla2x00_write_nvram_data(scsi_qla_host_t * vha,void * buf,uint32_t naddr,uint32_t bytes)14373695310eSJoe Carnuccio qla2x00_write_nvram_data(scsi_qla_host_t *vha, void *buf, uint32_t naddr,
1438459c5378SAndrew Vasquez     uint32_t bytes)
1439459c5378SAndrew Vasquez {
1440459c5378SAndrew Vasquez 	int ret, stat;
1441459c5378SAndrew Vasquez 	uint32_t i;
1442459c5378SAndrew Vasquez 	uint16_t *wptr;
14432c96d8d0SAndrew Vasquez 	unsigned long flags;
14447b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
1445459c5378SAndrew Vasquez 
1446459c5378SAndrew Vasquez 	ret = QLA_SUCCESS;
1447459c5378SAndrew Vasquez 
14482c96d8d0SAndrew Vasquez 	spin_lock_irqsave(&ha->hardware_lock, flags);
1449459c5378SAndrew Vasquez 	qla2x00_lock_nvram_access(ha);
1450459c5378SAndrew Vasquez 
1451459c5378SAndrew Vasquez 	/* Disable NVRAM write-protection. */
1452459c5378SAndrew Vasquez 	stat = qla2x00_clear_nvram_protection(ha);
1453459c5378SAndrew Vasquez 
1454459c5378SAndrew Vasquez 	wptr = (uint16_t *)buf;
1455459c5378SAndrew Vasquez 	for (i = 0; i < bytes >> 1; i++, naddr++) {
1456459c5378SAndrew Vasquez 		qla2x00_write_nvram_word(ha, naddr,
1457459c5378SAndrew Vasquez 		    cpu_to_le16(*wptr));
1458459c5378SAndrew Vasquez 		wptr++;
1459459c5378SAndrew Vasquez 	}
1460459c5378SAndrew Vasquez 
1461459c5378SAndrew Vasquez 	/* Enable NVRAM write-protection. */
1462459c5378SAndrew Vasquez 	qla2x00_set_nvram_protection(ha, stat);
1463459c5378SAndrew Vasquez 
1464459c5378SAndrew Vasquez 	qla2x00_unlock_nvram_access(ha);
14652c96d8d0SAndrew Vasquez 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
1466459c5378SAndrew Vasquez 
1467459c5378SAndrew Vasquez 	return ret;
1468459c5378SAndrew Vasquez }
1469459c5378SAndrew Vasquez 
1470459c5378SAndrew Vasquez int
qla24xx_write_nvram_data(scsi_qla_host_t * vha,void * buf,uint32_t naddr,uint32_t bytes)14713695310eSJoe Carnuccio qla24xx_write_nvram_data(scsi_qla_host_t *vha, void *buf, uint32_t naddr,
1472459c5378SAndrew Vasquez     uint32_t bytes)
1473459c5378SAndrew Vasquez {
14747b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
1475459c5378SAndrew Vasquez 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
14767ffa5b93SBart Van Assche 	__le32 *dwptr = buf;
14773695310eSJoe Carnuccio 	uint32_t i;
14783695310eSJoe Carnuccio 	int ret;
1479459c5378SAndrew Vasquez 
1480459c5378SAndrew Vasquez 	ret = QLA_SUCCESS;
1481459c5378SAndrew Vasquez 
14827ec0effdSAtul Deshmukh 	if (IS_P3P_TYPE(ha))
1483a9083016SGiridhar Malavali 		return ret;
1484a9083016SGiridhar Malavali 
1485459c5378SAndrew Vasquez 	/* Enable flash write. */
148604474d3aSBart Van Assche 	wrt_reg_dword(&reg->ctrl_status,
148704474d3aSBart Van Assche 	    rd_reg_dword(&reg->ctrl_status) | CSRX_FLASH_ENABLE);
148804474d3aSBart Van Assche 	rd_reg_dword(&reg->ctrl_status);	/* PCI Posting. */
1489459c5378SAndrew Vasquez 
1490459c5378SAndrew Vasquez 	/* Disable NVRAM write-protection. */
14913a03eb79SAndrew Vasquez 	qla24xx_write_flash_dword(ha, nvram_conf_addr(ha, 0x101), 0);
14923a03eb79SAndrew Vasquez 	qla24xx_write_flash_dword(ha, nvram_conf_addr(ha, 0x101), 0);
1493459c5378SAndrew Vasquez 
1494459c5378SAndrew Vasquez 	/* Dword writes to flash. */
14953695310eSJoe Carnuccio 	naddr = nvram_data_addr(ha, naddr);
14963695310eSJoe Carnuccio 	bytes >>= 2;
14973695310eSJoe Carnuccio 	for (i = 0; i < bytes; i++, naddr++, dwptr++) {
14987ffa5b93SBart Van Assche 		if (qla24xx_write_flash_dword(ha, naddr, le32_to_cpu(*dwptr))) {
14997c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_user, vha, 0x709a,
15007640335eSAndrew Vasquez 			    "Unable to program nvram address=%x data=%x.\n",
15017c3df132SSaurav Kashyap 			    naddr, *dwptr);
1502459c5378SAndrew Vasquez 			break;
1503459c5378SAndrew Vasquez 		}
1504459c5378SAndrew Vasquez 	}
1505459c5378SAndrew Vasquez 
1506459c5378SAndrew Vasquez 	/* Enable NVRAM write-protection. */
15073a03eb79SAndrew Vasquez 	qla24xx_write_flash_dword(ha, nvram_conf_addr(ha, 0x101), 0x8c);
1508459c5378SAndrew Vasquez 
1509459c5378SAndrew Vasquez 	/* Disable flash write. */
151004474d3aSBart Van Assche 	wrt_reg_dword(&reg->ctrl_status,
151104474d3aSBart Van Assche 	    rd_reg_dword(&reg->ctrl_status) & ~CSRX_FLASH_ENABLE);
151204474d3aSBart Van Assche 	rd_reg_dword(&reg->ctrl_status);	/* PCI Posting. */
1513459c5378SAndrew Vasquez 
1514459c5378SAndrew Vasquez 	return ret;
1515459c5378SAndrew Vasquez }
1516f6df144cSandrew.vasquez@qlogic.com 
1517c3a2f0dfSAndrew Vasquez uint8_t *
qla25xx_read_nvram_data(scsi_qla_host_t * vha,void * buf,uint32_t naddr,uint32_t bytes)15183695310eSJoe Carnuccio qla25xx_read_nvram_data(scsi_qla_host_t *vha, void *buf, uint32_t naddr,
1519c3a2f0dfSAndrew Vasquez     uint32_t bytes)
1520c3a2f0dfSAndrew Vasquez {
15217b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
15223695310eSJoe Carnuccio 	uint32_t *dwptr = buf;
15233695310eSJoe Carnuccio 	uint32_t i;
1524c3a2f0dfSAndrew Vasquez 
1525c3a2f0dfSAndrew Vasquez 	/* Dword reads to flash. */
15263695310eSJoe Carnuccio 	naddr = flash_data_addr(ha, ha->flt_region_vpd_nvram | naddr);
15273695310eSJoe Carnuccio 	bytes >>= 2;
15283695310eSJoe Carnuccio 	for (i = 0; i < bytes; i++, naddr++, dwptr++) {
15293695310eSJoe Carnuccio 		if (qla24xx_read_flash_dword(ha, naddr, dwptr))
15303695310eSJoe Carnuccio 			break;
15313695310eSJoe Carnuccio 
15323695310eSJoe Carnuccio 		cpu_to_le32s(dwptr);
15333695310eSJoe Carnuccio 	}
1534c3a2f0dfSAndrew Vasquez 
1535c3a2f0dfSAndrew Vasquez 	return buf;
1536c3a2f0dfSAndrew Vasquez }
1537c3a2f0dfSAndrew Vasquez 
15383695310eSJoe Carnuccio #define RMW_BUFFER_SIZE	(64 * 1024)
1539c3a2f0dfSAndrew Vasquez int
qla25xx_write_nvram_data(scsi_qla_host_t * vha,void * buf,uint32_t naddr,uint32_t bytes)15403695310eSJoe Carnuccio qla25xx_write_nvram_data(scsi_qla_host_t *vha, void *buf, uint32_t naddr,
1541c3a2f0dfSAndrew Vasquez     uint32_t bytes)
1542c3a2f0dfSAndrew Vasquez {
15437b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
15443695310eSJoe Carnuccio 	uint8_t *dbuf = vmalloc(RMW_BUFFER_SIZE);
15452c96d8d0SAndrew Vasquez 
15462c96d8d0SAndrew Vasquez 	if (!dbuf)
15472c96d8d0SAndrew Vasquez 		return QLA_MEMORY_ALLOC_FAILED;
15487b867cf7SAnirban Chakraborty 	ha->isp_ops->read_optrom(vha, dbuf, ha->flt_region_vpd_nvram << 2,
15492c96d8d0SAndrew Vasquez 	    RMW_BUFFER_SIZE);
15502c96d8d0SAndrew Vasquez 	memcpy(dbuf + (naddr << 2), buf, bytes);
15517b867cf7SAnirban Chakraborty 	ha->isp_ops->write_optrom(vha, dbuf, ha->flt_region_vpd_nvram << 2,
15522c96d8d0SAndrew Vasquez 	    RMW_BUFFER_SIZE);
15532c96d8d0SAndrew Vasquez 	vfree(dbuf);
15542c96d8d0SAndrew Vasquez 
15552c96d8d0SAndrew Vasquez 	return QLA_SUCCESS;
1556c3a2f0dfSAndrew Vasquez }
1557f6df144cSandrew.vasquez@qlogic.com 
1558f6df144cSandrew.vasquez@qlogic.com static inline void
qla2x00_flip_colors(struct qla_hw_data * ha,uint16_t * pflags)15597b867cf7SAnirban Chakraborty qla2x00_flip_colors(struct qla_hw_data *ha, uint16_t *pflags)
1560f6df144cSandrew.vasquez@qlogic.com {
1561f6df144cSandrew.vasquez@qlogic.com 	if (IS_QLA2322(ha)) {
1562f6df144cSandrew.vasquez@qlogic.com 		/* Flip all colors. */
1563f6df144cSandrew.vasquez@qlogic.com 		if (ha->beacon_color_state == QLA_LED_ALL_ON) {
1564f6df144cSandrew.vasquez@qlogic.com 			/* Turn off. */
1565f6df144cSandrew.vasquez@qlogic.com 			ha->beacon_color_state = 0;
1566f6df144cSandrew.vasquez@qlogic.com 			*pflags = GPIO_LED_ALL_OFF;
1567f6df144cSandrew.vasquez@qlogic.com 		} else {
1568f6df144cSandrew.vasquez@qlogic.com 			/* Turn on. */
1569f6df144cSandrew.vasquez@qlogic.com 			ha->beacon_color_state = QLA_LED_ALL_ON;
1570f6df144cSandrew.vasquez@qlogic.com 			*pflags = GPIO_LED_RGA_ON;
1571f6df144cSandrew.vasquez@qlogic.com 		}
1572f6df144cSandrew.vasquez@qlogic.com 	} else {
1573f6df144cSandrew.vasquez@qlogic.com 		/* Flip green led only. */
1574f6df144cSandrew.vasquez@qlogic.com 		if (ha->beacon_color_state == QLA_LED_GRN_ON) {
1575f6df144cSandrew.vasquez@qlogic.com 			/* Turn off. */
1576f6df144cSandrew.vasquez@qlogic.com 			ha->beacon_color_state = 0;
1577f6df144cSandrew.vasquez@qlogic.com 			*pflags = GPIO_LED_GREEN_OFF_AMBER_OFF;
1578f6df144cSandrew.vasquez@qlogic.com 		} else {
1579f6df144cSandrew.vasquez@qlogic.com 			/* Turn on. */
1580f6df144cSandrew.vasquez@qlogic.com 			ha->beacon_color_state = QLA_LED_GRN_ON;
1581f6df144cSandrew.vasquez@qlogic.com 			*pflags = GPIO_LED_GREEN_ON_AMBER_OFF;
1582f6df144cSandrew.vasquez@qlogic.com 		}
1583f6df144cSandrew.vasquez@qlogic.com 	}
1584f6df144cSandrew.vasquez@qlogic.com }
1585f6df144cSandrew.vasquez@qlogic.com 
1586948882f6SAndrew Vasquez #define PIO_REG(h, r) ((h)->pio_address + offsetof(struct device_reg_2xxx, r))
1587948882f6SAndrew Vasquez 
1588f6df144cSandrew.vasquez@qlogic.com void
qla2x00_beacon_blink(struct scsi_qla_host * vha)15897b867cf7SAnirban Chakraborty qla2x00_beacon_blink(struct scsi_qla_host *vha)
1590f6df144cSandrew.vasquez@qlogic.com {
1591f6df144cSandrew.vasquez@qlogic.com 	uint16_t gpio_enable;
1592f6df144cSandrew.vasquez@qlogic.com 	uint16_t gpio_data;
1593f6df144cSandrew.vasquez@qlogic.com 	uint16_t led_color = 0;
1594f6df144cSandrew.vasquez@qlogic.com 	unsigned long flags;
15957b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
1596f6df144cSandrew.vasquez@qlogic.com 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
1597f6df144cSandrew.vasquez@qlogic.com 
15987ec0effdSAtul Deshmukh 	if (IS_P3P_TYPE(ha))
1599a9083016SGiridhar Malavali 		return;
1600a9083016SGiridhar Malavali 
1601f6df144cSandrew.vasquez@qlogic.com 	spin_lock_irqsave(&ha->hardware_lock, flags);
1602f6df144cSandrew.vasquez@qlogic.com 
1603f6df144cSandrew.vasquez@qlogic.com 	/* Save the Original GPIOE. */
1604f6df144cSandrew.vasquez@qlogic.com 	if (ha->pio_address) {
1605948882f6SAndrew Vasquez 		gpio_enable = RD_REG_WORD_PIO(PIO_REG(ha, gpioe));
1606948882f6SAndrew Vasquez 		gpio_data = RD_REG_WORD_PIO(PIO_REG(ha, gpiod));
1607f6df144cSandrew.vasquez@qlogic.com 	} else {
160804474d3aSBart Van Assche 		gpio_enable = rd_reg_word(&reg->gpioe);
160904474d3aSBart Van Assche 		gpio_data = rd_reg_word(&reg->gpiod);
1610f6df144cSandrew.vasquez@qlogic.com 	}
1611f6df144cSandrew.vasquez@qlogic.com 
1612f6df144cSandrew.vasquez@qlogic.com 	/* Set the modified gpio_enable values */
1613f6df144cSandrew.vasquez@qlogic.com 	gpio_enable |= GPIO_LED_MASK;
1614f6df144cSandrew.vasquez@qlogic.com 
1615f6df144cSandrew.vasquez@qlogic.com 	if (ha->pio_address) {
1616948882f6SAndrew Vasquez 		WRT_REG_WORD_PIO(PIO_REG(ha, gpioe), gpio_enable);
1617f6df144cSandrew.vasquez@qlogic.com 	} else {
161804474d3aSBart Van Assche 		wrt_reg_word(&reg->gpioe, gpio_enable);
161904474d3aSBart Van Assche 		rd_reg_word(&reg->gpioe);
1620f6df144cSandrew.vasquez@qlogic.com 	}
1621f6df144cSandrew.vasquez@qlogic.com 
1622f6df144cSandrew.vasquez@qlogic.com 	qla2x00_flip_colors(ha, &led_color);
1623f6df144cSandrew.vasquez@qlogic.com 
1624f6df144cSandrew.vasquez@qlogic.com 	/* Clear out any previously set LED color. */
1625f6df144cSandrew.vasquez@qlogic.com 	gpio_data &= ~GPIO_LED_MASK;
1626f6df144cSandrew.vasquez@qlogic.com 
1627f6df144cSandrew.vasquez@qlogic.com 	/* Set the new input LED color to GPIOD. */
1628f6df144cSandrew.vasquez@qlogic.com 	gpio_data |= led_color;
1629f6df144cSandrew.vasquez@qlogic.com 
1630f6df144cSandrew.vasquez@qlogic.com 	/* Set the modified gpio_data values */
1631f6df144cSandrew.vasquez@qlogic.com 	if (ha->pio_address) {
1632948882f6SAndrew Vasquez 		WRT_REG_WORD_PIO(PIO_REG(ha, gpiod), gpio_data);
1633f6df144cSandrew.vasquez@qlogic.com 	} else {
163404474d3aSBart Van Assche 		wrt_reg_word(&reg->gpiod, gpio_data);
163504474d3aSBart Van Assche 		rd_reg_word(&reg->gpiod);
1636f6df144cSandrew.vasquez@qlogic.com 	}
1637f6df144cSandrew.vasquez@qlogic.com 
1638f6df144cSandrew.vasquez@qlogic.com 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
1639f6df144cSandrew.vasquez@qlogic.com }
1640f6df144cSandrew.vasquez@qlogic.com 
1641f6df144cSandrew.vasquez@qlogic.com int
qla2x00_beacon_on(struct scsi_qla_host * vha)16427b867cf7SAnirban Chakraborty qla2x00_beacon_on(struct scsi_qla_host *vha)
1643f6df144cSandrew.vasquez@qlogic.com {
1644f6df144cSandrew.vasquez@qlogic.com 	uint16_t gpio_enable;
1645f6df144cSandrew.vasquez@qlogic.com 	uint16_t gpio_data;
1646f6df144cSandrew.vasquez@qlogic.com 	unsigned long flags;
16477b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
1648f6df144cSandrew.vasquez@qlogic.com 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
1649f6df144cSandrew.vasquez@qlogic.com 
1650f6df144cSandrew.vasquez@qlogic.com 	ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING;
1651f6df144cSandrew.vasquez@qlogic.com 	ha->fw_options[1] |= FO1_DISABLE_GPIO6_7;
1652f6df144cSandrew.vasquez@qlogic.com 
16537b867cf7SAnirban Chakraborty 	if (qla2x00_set_fw_options(vha, ha->fw_options) != QLA_SUCCESS) {
16547c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x709b,
1655f6df144cSandrew.vasquez@qlogic.com 		    "Unable to update fw options (beacon on).\n");
1656f6df144cSandrew.vasquez@qlogic.com 		return QLA_FUNCTION_FAILED;
1657f6df144cSandrew.vasquez@qlogic.com 	}
1658f6df144cSandrew.vasquez@qlogic.com 
1659f6df144cSandrew.vasquez@qlogic.com 	/* Turn off LEDs. */
1660f6df144cSandrew.vasquez@qlogic.com 	spin_lock_irqsave(&ha->hardware_lock, flags);
1661f6df144cSandrew.vasquez@qlogic.com 	if (ha->pio_address) {
1662948882f6SAndrew Vasquez 		gpio_enable = RD_REG_WORD_PIO(PIO_REG(ha, gpioe));
1663948882f6SAndrew Vasquez 		gpio_data = RD_REG_WORD_PIO(PIO_REG(ha, gpiod));
1664f6df144cSandrew.vasquez@qlogic.com 	} else {
166504474d3aSBart Van Assche 		gpio_enable = rd_reg_word(&reg->gpioe);
166604474d3aSBart Van Assche 		gpio_data = rd_reg_word(&reg->gpiod);
1667f6df144cSandrew.vasquez@qlogic.com 	}
1668f6df144cSandrew.vasquez@qlogic.com 	gpio_enable |= GPIO_LED_MASK;
1669f6df144cSandrew.vasquez@qlogic.com 
1670f6df144cSandrew.vasquez@qlogic.com 	/* Set the modified gpio_enable values. */
1671f6df144cSandrew.vasquez@qlogic.com 	if (ha->pio_address) {
1672948882f6SAndrew Vasquez 		WRT_REG_WORD_PIO(PIO_REG(ha, gpioe), gpio_enable);
1673f6df144cSandrew.vasquez@qlogic.com 	} else {
167404474d3aSBart Van Assche 		wrt_reg_word(&reg->gpioe, gpio_enable);
167504474d3aSBart Van Assche 		rd_reg_word(&reg->gpioe);
1676f6df144cSandrew.vasquez@qlogic.com 	}
1677f6df144cSandrew.vasquez@qlogic.com 
1678f6df144cSandrew.vasquez@qlogic.com 	/* Clear out previously set LED colour. */
1679f6df144cSandrew.vasquez@qlogic.com 	gpio_data &= ~GPIO_LED_MASK;
1680f6df144cSandrew.vasquez@qlogic.com 	if (ha->pio_address) {
1681948882f6SAndrew Vasquez 		WRT_REG_WORD_PIO(PIO_REG(ha, gpiod), gpio_data);
1682f6df144cSandrew.vasquez@qlogic.com 	} else {
168304474d3aSBart Van Assche 		wrt_reg_word(&reg->gpiod, gpio_data);
168404474d3aSBart Van Assche 		rd_reg_word(&reg->gpiod);
1685f6df144cSandrew.vasquez@qlogic.com 	}
1686f6df144cSandrew.vasquez@qlogic.com 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
1687f6df144cSandrew.vasquez@qlogic.com 
1688f6df144cSandrew.vasquez@qlogic.com 	/*
1689f6df144cSandrew.vasquez@qlogic.com 	 * Let the per HBA timer kick off the blinking process based on
1690f6df144cSandrew.vasquez@qlogic.com 	 * the following flags. No need to do anything else now.
1691f6df144cSandrew.vasquez@qlogic.com 	 */
1692f6df144cSandrew.vasquez@qlogic.com 	ha->beacon_blink_led = 1;
1693f6df144cSandrew.vasquez@qlogic.com 	ha->beacon_color_state = 0;
1694f6df144cSandrew.vasquez@qlogic.com 
1695f6df144cSandrew.vasquez@qlogic.com 	return QLA_SUCCESS;
1696f6df144cSandrew.vasquez@qlogic.com }
1697f6df144cSandrew.vasquez@qlogic.com 
1698f6df144cSandrew.vasquez@qlogic.com int
qla2x00_beacon_off(struct scsi_qla_host * vha)16997b867cf7SAnirban Chakraborty qla2x00_beacon_off(struct scsi_qla_host *vha)
1700f6df144cSandrew.vasquez@qlogic.com {
1701f6df144cSandrew.vasquez@qlogic.com 	int rval = QLA_SUCCESS;
17027b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
1703f6df144cSandrew.vasquez@qlogic.com 
1704f6df144cSandrew.vasquez@qlogic.com 	ha->beacon_blink_led = 0;
1705f6df144cSandrew.vasquez@qlogic.com 
1706f6df144cSandrew.vasquez@qlogic.com 	/* Set the on flag so when it gets flipped it will be off. */
1707f6df144cSandrew.vasquez@qlogic.com 	if (IS_QLA2322(ha))
1708f6df144cSandrew.vasquez@qlogic.com 		ha->beacon_color_state = QLA_LED_ALL_ON;
1709f6df144cSandrew.vasquez@qlogic.com 	else
1710f6df144cSandrew.vasquez@qlogic.com 		ha->beacon_color_state = QLA_LED_GRN_ON;
1711f6df144cSandrew.vasquez@qlogic.com 
17127b867cf7SAnirban Chakraborty 	ha->isp_ops->beacon_blink(vha);	/* This turns green LED off */
1713f6df144cSandrew.vasquez@qlogic.com 
1714f6df144cSandrew.vasquez@qlogic.com 	ha->fw_options[1] &= ~FO1_SET_EMPHASIS_SWING;
1715f6df144cSandrew.vasquez@qlogic.com 	ha->fw_options[1] &= ~FO1_DISABLE_GPIO6_7;
1716f6df144cSandrew.vasquez@qlogic.com 
17177b867cf7SAnirban Chakraborty 	rval = qla2x00_set_fw_options(vha, ha->fw_options);
1718f6df144cSandrew.vasquez@qlogic.com 	if (rval != QLA_SUCCESS)
17197c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x709c,
1720f6df144cSandrew.vasquez@qlogic.com 		    "Unable to update fw options (beacon off).\n");
1721f6df144cSandrew.vasquez@qlogic.com 	return rval;
1722f6df144cSandrew.vasquez@qlogic.com }
1723f6df144cSandrew.vasquez@qlogic.com 
1724f6df144cSandrew.vasquez@qlogic.com 
1725f6df144cSandrew.vasquez@qlogic.com static inline void
qla24xx_flip_colors(struct qla_hw_data * ha,uint16_t * pflags)17267b867cf7SAnirban Chakraborty qla24xx_flip_colors(struct qla_hw_data *ha, uint16_t *pflags)
1727f6df144cSandrew.vasquez@qlogic.com {
1728f6df144cSandrew.vasquez@qlogic.com 	/* Flip all colors. */
1729f6df144cSandrew.vasquez@qlogic.com 	if (ha->beacon_color_state == QLA_LED_ALL_ON) {
1730f6df144cSandrew.vasquez@qlogic.com 		/* Turn off. */
1731f6df144cSandrew.vasquez@qlogic.com 		ha->beacon_color_state = 0;
1732f6df144cSandrew.vasquez@qlogic.com 		*pflags = 0;
1733f6df144cSandrew.vasquez@qlogic.com 	} else {
1734f6df144cSandrew.vasquez@qlogic.com 		/* Turn on. */
1735f6df144cSandrew.vasquez@qlogic.com 		ha->beacon_color_state = QLA_LED_ALL_ON;
1736f6df144cSandrew.vasquez@qlogic.com 		*pflags = GPDX_LED_YELLOW_ON | GPDX_LED_AMBER_ON;
1737f6df144cSandrew.vasquez@qlogic.com 	}
1738f6df144cSandrew.vasquez@qlogic.com }
1739f6df144cSandrew.vasquez@qlogic.com 
1740f6df144cSandrew.vasquez@qlogic.com void
qla24xx_beacon_blink(struct scsi_qla_host * vha)17417b867cf7SAnirban Chakraborty qla24xx_beacon_blink(struct scsi_qla_host *vha)
1742f6df144cSandrew.vasquez@qlogic.com {
1743f6df144cSandrew.vasquez@qlogic.com 	uint16_t led_color = 0;
1744f6df144cSandrew.vasquez@qlogic.com 	uint32_t gpio_data;
1745f6df144cSandrew.vasquez@qlogic.com 	unsigned long flags;
17467b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
1747f6df144cSandrew.vasquez@qlogic.com 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
1748f6df144cSandrew.vasquez@qlogic.com 
1749f6df144cSandrew.vasquez@qlogic.com 	/* Save the Original GPIOD. */
1750f6df144cSandrew.vasquez@qlogic.com 	spin_lock_irqsave(&ha->hardware_lock, flags);
175104474d3aSBart Van Assche 	gpio_data = rd_reg_dword(&reg->gpiod);
1752f6df144cSandrew.vasquez@qlogic.com 
1753f6df144cSandrew.vasquez@qlogic.com 	/* Enable the gpio_data reg for update. */
1754f6df144cSandrew.vasquez@qlogic.com 	gpio_data |= GPDX_LED_UPDATE_MASK;
1755f6df144cSandrew.vasquez@qlogic.com 
175604474d3aSBart Van Assche 	wrt_reg_dword(&reg->gpiod, gpio_data);
175704474d3aSBart Van Assche 	gpio_data = rd_reg_dword(&reg->gpiod);
1758f6df144cSandrew.vasquez@qlogic.com 
1759f6df144cSandrew.vasquez@qlogic.com 	/* Set the color bits. */
1760f6df144cSandrew.vasquez@qlogic.com 	qla24xx_flip_colors(ha, &led_color);
1761f6df144cSandrew.vasquez@qlogic.com 
1762f6df144cSandrew.vasquez@qlogic.com 	/* Clear out any previously set LED color. */
1763f6df144cSandrew.vasquez@qlogic.com 	gpio_data &= ~GPDX_LED_COLOR_MASK;
1764f6df144cSandrew.vasquez@qlogic.com 
1765f6df144cSandrew.vasquez@qlogic.com 	/* Set the new input LED color to GPIOD. */
1766f6df144cSandrew.vasquez@qlogic.com 	gpio_data |= led_color;
1767f6df144cSandrew.vasquez@qlogic.com 
1768f6df144cSandrew.vasquez@qlogic.com 	/* Set the modified gpio_data values. */
176904474d3aSBart Van Assche 	wrt_reg_dword(&reg->gpiod, gpio_data);
177004474d3aSBart Van Assche 	gpio_data = rd_reg_dword(&reg->gpiod);
1771f6df144cSandrew.vasquez@qlogic.com 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
1772f6df144cSandrew.vasquez@qlogic.com }
1773f6df144cSandrew.vasquez@qlogic.com 
17740143d8b7SChad Dupuis static uint32_t
qla83xx_select_led_port(struct qla_hw_data * ha)17750143d8b7SChad Dupuis qla83xx_select_led_port(struct qla_hw_data *ha)
17760143d8b7SChad Dupuis {
17770143d8b7SChad Dupuis 	uint32_t led_select_value = 0;
17780143d8b7SChad Dupuis 
1779ecc89f25SJoe Carnuccio 	if (!IS_QLA83XX(ha) && !IS_QLA27XX(ha) && !IS_QLA28XX(ha))
17800143d8b7SChad Dupuis 		goto out;
17810143d8b7SChad Dupuis 
1782f73cb695SChad Dupuis 	if (ha->port_no == 0)
17830143d8b7SChad Dupuis 		led_select_value = QLA83XX_LED_PORT0;
17840143d8b7SChad Dupuis 	else
17850143d8b7SChad Dupuis 		led_select_value = QLA83XX_LED_PORT1;
17860143d8b7SChad Dupuis 
17870143d8b7SChad Dupuis out:
17880143d8b7SChad Dupuis 	return led_select_value;
17890143d8b7SChad Dupuis }
17900143d8b7SChad Dupuis 
17916246b8a1SGiridhar Malavali void
qla83xx_beacon_blink(struct scsi_qla_host * vha)17926246b8a1SGiridhar Malavali qla83xx_beacon_blink(struct scsi_qla_host *vha)
17936246b8a1SGiridhar Malavali {
17946246b8a1SGiridhar Malavali 	uint32_t led_select_value;
17956246b8a1SGiridhar Malavali 	struct qla_hw_data *ha = vha->hw;
17966246b8a1SGiridhar Malavali 	uint16_t led_cfg[6];
17976246b8a1SGiridhar Malavali 	uint16_t orig_led_cfg[6];
17980143d8b7SChad Dupuis 	uint32_t led_10_value, led_43_value;
17996246b8a1SGiridhar Malavali 
1800ecc89f25SJoe Carnuccio 	if (!IS_QLA83XX(ha) && !IS_QLA81XX(ha) && !IS_QLA27XX(ha) &&
1801ecc89f25SJoe Carnuccio 	    !IS_QLA28XX(ha))
18026246b8a1SGiridhar Malavali 		return;
18036246b8a1SGiridhar Malavali 
18040143d8b7SChad Dupuis 	if (!ha->beacon_blink_led)
18050143d8b7SChad Dupuis 		return;
18060143d8b7SChad Dupuis 
1807ecc89f25SJoe Carnuccio 	if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
1808b21ba319SNigel Kirkland 		qla2x00_write_ram_word(vha, 0x1003, 0x40000230);
1809b21ba319SNigel Kirkland 		qla2x00_write_ram_word(vha, 0x1004, 0x40000230);
1810b21ba319SNigel Kirkland 	} else if (IS_QLA2031(ha)) {
18110143d8b7SChad Dupuis 		led_select_value = qla83xx_select_led_port(ha);
18126246b8a1SGiridhar Malavali 
181390b604f2SHimanshu Madani 		qla83xx_wr_reg(vha, led_select_value, 0x40000230);
181490b604f2SHimanshu Madani 		qla83xx_wr_reg(vha, led_select_value + 4, 0x40000230);
18150143d8b7SChad Dupuis 	} else if (IS_QLA8031(ha)) {
18160143d8b7SChad Dupuis 		led_select_value = qla83xx_select_led_port(ha);
18170143d8b7SChad Dupuis 
18180143d8b7SChad Dupuis 		qla83xx_rd_reg(vha, led_select_value, &led_10_value);
18190143d8b7SChad Dupuis 		qla83xx_rd_reg(vha, led_select_value + 0x10, &led_43_value);
18200143d8b7SChad Dupuis 		qla83xx_wr_reg(vha, led_select_value, 0x01f44000);
18210143d8b7SChad Dupuis 		msleep(500);
18220143d8b7SChad Dupuis 		qla83xx_wr_reg(vha, led_select_value, 0x400001f4);
18230143d8b7SChad Dupuis 		msleep(1000);
18240143d8b7SChad Dupuis 		qla83xx_wr_reg(vha, led_select_value, led_10_value);
18250143d8b7SChad Dupuis 		qla83xx_wr_reg(vha, led_select_value + 0x10, led_43_value);
18260143d8b7SChad Dupuis 	} else if (IS_QLA81XX(ha)) {
18276246b8a1SGiridhar Malavali 		int rval;
18286246b8a1SGiridhar Malavali 
18296246b8a1SGiridhar Malavali 		/* Save Current */
18306246b8a1SGiridhar Malavali 		rval = qla81xx_get_led_config(vha, orig_led_cfg);
18316246b8a1SGiridhar Malavali 		/* Do the blink */
18326246b8a1SGiridhar Malavali 		if (rval == QLA_SUCCESS) {
18336246b8a1SGiridhar Malavali 			if (IS_QLA81XX(ha)) {
18346246b8a1SGiridhar Malavali 				led_cfg[0] = 0x4000;
18356246b8a1SGiridhar Malavali 				led_cfg[1] = 0x2000;
18366246b8a1SGiridhar Malavali 				led_cfg[2] = 0;
18376246b8a1SGiridhar Malavali 				led_cfg[3] = 0;
18386246b8a1SGiridhar Malavali 				led_cfg[4] = 0;
18396246b8a1SGiridhar Malavali 				led_cfg[5] = 0;
18406246b8a1SGiridhar Malavali 			} else {
18416246b8a1SGiridhar Malavali 				led_cfg[0] = 0x4000;
18426246b8a1SGiridhar Malavali 				led_cfg[1] = 0x4000;
18436246b8a1SGiridhar Malavali 				led_cfg[2] = 0x4000;
18446246b8a1SGiridhar Malavali 				led_cfg[3] = 0x2000;
18456246b8a1SGiridhar Malavali 				led_cfg[4] = 0;
18466246b8a1SGiridhar Malavali 				led_cfg[5] = 0x2000;
18476246b8a1SGiridhar Malavali 			}
18486246b8a1SGiridhar Malavali 			rval = qla81xx_set_led_config(vha, led_cfg);
18496246b8a1SGiridhar Malavali 			msleep(1000);
18506246b8a1SGiridhar Malavali 			if (IS_QLA81XX(ha)) {
18516246b8a1SGiridhar Malavali 				led_cfg[0] = 0x4000;
18526246b8a1SGiridhar Malavali 				led_cfg[1] = 0x2000;
18536246b8a1SGiridhar Malavali 				led_cfg[2] = 0;
18546246b8a1SGiridhar Malavali 			} else {
18556246b8a1SGiridhar Malavali 				led_cfg[0] = 0x4000;
18566246b8a1SGiridhar Malavali 				led_cfg[1] = 0x2000;
18576246b8a1SGiridhar Malavali 				led_cfg[2] = 0x4000;
18586246b8a1SGiridhar Malavali 				led_cfg[3] = 0x4000;
18596246b8a1SGiridhar Malavali 				led_cfg[4] = 0;
18606246b8a1SGiridhar Malavali 				led_cfg[5] = 0x2000;
18616246b8a1SGiridhar Malavali 			}
18626246b8a1SGiridhar Malavali 			rval = qla81xx_set_led_config(vha, led_cfg);
18636246b8a1SGiridhar Malavali 		}
18646246b8a1SGiridhar Malavali 		/* On exit, restore original (presumes no status change) */
18656246b8a1SGiridhar Malavali 		qla81xx_set_led_config(vha, orig_led_cfg);
18666246b8a1SGiridhar Malavali 	}
18676246b8a1SGiridhar Malavali }
18686246b8a1SGiridhar Malavali 
1869f6df144cSandrew.vasquez@qlogic.com int
qla24xx_beacon_on(struct scsi_qla_host * vha)18707b867cf7SAnirban Chakraborty qla24xx_beacon_on(struct scsi_qla_host *vha)
1871f6df144cSandrew.vasquez@qlogic.com {
1872f6df144cSandrew.vasquez@qlogic.com 	uint32_t gpio_data;
1873f6df144cSandrew.vasquez@qlogic.com 	unsigned long flags;
18747b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
1875f6df144cSandrew.vasquez@qlogic.com 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
1876f6df144cSandrew.vasquez@qlogic.com 
18777ec0effdSAtul Deshmukh 	if (IS_P3P_TYPE(ha))
1878a9083016SGiridhar Malavali 		return QLA_SUCCESS;
1879a9083016SGiridhar Malavali 
18806246b8a1SGiridhar Malavali 	if (IS_QLA8031(ha) || IS_QLA81XX(ha))
18816246b8a1SGiridhar Malavali 		goto skip_gpio; /* let blink handle it */
18826246b8a1SGiridhar Malavali 
1883f6df144cSandrew.vasquez@qlogic.com 	if (ha->beacon_blink_led == 0) {
1884f6df144cSandrew.vasquez@qlogic.com 		/* Enable firmware for update */
1885f6df144cSandrew.vasquez@qlogic.com 		ha->fw_options[1] |= ADD_FO1_DISABLE_GPIO_LED_CTRL;
1886f6df144cSandrew.vasquez@qlogic.com 
18877b867cf7SAnirban Chakraborty 		if (qla2x00_set_fw_options(vha, ha->fw_options) != QLA_SUCCESS)
1888f6df144cSandrew.vasquez@qlogic.com 			return QLA_FUNCTION_FAILED;
1889f6df144cSandrew.vasquez@qlogic.com 
18907b867cf7SAnirban Chakraborty 		if (qla2x00_get_fw_options(vha, ha->fw_options) !=
1891f6df144cSandrew.vasquez@qlogic.com 		    QLA_SUCCESS) {
18927c3df132SSaurav Kashyap 			ql_log(ql_log_warn, vha, 0x7009,
1893f6df144cSandrew.vasquez@qlogic.com 			    "Unable to update fw options (beacon on).\n");
1894f6df144cSandrew.vasquez@qlogic.com 			return QLA_FUNCTION_FAILED;
1895f6df144cSandrew.vasquez@qlogic.com 		}
1896f6df144cSandrew.vasquez@qlogic.com 
1897ecc89f25SJoe Carnuccio 		if (IS_QLA2031(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
18986246b8a1SGiridhar Malavali 			goto skip_gpio;
18996246b8a1SGiridhar Malavali 
1900f6df144cSandrew.vasquez@qlogic.com 		spin_lock_irqsave(&ha->hardware_lock, flags);
190104474d3aSBart Van Assche 		gpio_data = rd_reg_dword(&reg->gpiod);
1902f6df144cSandrew.vasquez@qlogic.com 
1903f6df144cSandrew.vasquez@qlogic.com 		/* Enable the gpio_data reg for update. */
1904f6df144cSandrew.vasquez@qlogic.com 		gpio_data |= GPDX_LED_UPDATE_MASK;
190504474d3aSBart Van Assche 		wrt_reg_dword(&reg->gpiod, gpio_data);
190604474d3aSBart Van Assche 		rd_reg_dword(&reg->gpiod);
1907f6df144cSandrew.vasquez@qlogic.com 
1908f6df144cSandrew.vasquez@qlogic.com 		spin_unlock_irqrestore(&ha->hardware_lock, flags);
1909f6df144cSandrew.vasquez@qlogic.com 	}
1910f6df144cSandrew.vasquez@qlogic.com 
1911f6df144cSandrew.vasquez@qlogic.com 	/* So all colors blink together. */
1912f6df144cSandrew.vasquez@qlogic.com 	ha->beacon_color_state = 0;
1913f6df144cSandrew.vasquez@qlogic.com 
19146246b8a1SGiridhar Malavali skip_gpio:
1915f6df144cSandrew.vasquez@qlogic.com 	/* Let the per HBA timer kick off the blinking process. */
1916f6df144cSandrew.vasquez@qlogic.com 	ha->beacon_blink_led = 1;
1917f6df144cSandrew.vasquez@qlogic.com 
1918f6df144cSandrew.vasquez@qlogic.com 	return QLA_SUCCESS;
1919f6df144cSandrew.vasquez@qlogic.com }
1920f6df144cSandrew.vasquez@qlogic.com 
1921f6df144cSandrew.vasquez@qlogic.com int
qla24xx_beacon_off(struct scsi_qla_host * vha)19227b867cf7SAnirban Chakraborty qla24xx_beacon_off(struct scsi_qla_host *vha)
1923f6df144cSandrew.vasquez@qlogic.com {
1924f6df144cSandrew.vasquez@qlogic.com 	uint32_t gpio_data;
1925f6df144cSandrew.vasquez@qlogic.com 	unsigned long flags;
19267b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
1927f6df144cSandrew.vasquez@qlogic.com 	struct device_reg_24xx __iomem *reg = &ha->iobase->isp24;
1928f6df144cSandrew.vasquez@qlogic.com 
19297ec0effdSAtul Deshmukh 	if (IS_P3P_TYPE(ha))
1930a9083016SGiridhar Malavali 		return QLA_SUCCESS;
1931a9083016SGiridhar Malavali 
193245235022SQuinn Tran 	if (!ha->flags.fw_started)
193345235022SQuinn Tran 		return QLA_SUCCESS;
193445235022SQuinn Tran 
1935f6df144cSandrew.vasquez@qlogic.com 	ha->beacon_blink_led = 0;
19366246b8a1SGiridhar Malavali 
1937ecc89f25SJoe Carnuccio 	if (IS_QLA2031(ha) || IS_QLA27XX(ha) || IS_QLA28XX(ha))
19386246b8a1SGiridhar Malavali 		goto set_fw_options;
19396246b8a1SGiridhar Malavali 
19406246b8a1SGiridhar Malavali 	if (IS_QLA8031(ha) || IS_QLA81XX(ha))
19416246b8a1SGiridhar Malavali 		return QLA_SUCCESS;
19426246b8a1SGiridhar Malavali 
1943f6df144cSandrew.vasquez@qlogic.com 	ha->beacon_color_state = QLA_LED_ALL_ON;
1944f6df144cSandrew.vasquez@qlogic.com 
19457b867cf7SAnirban Chakraborty 	ha->isp_ops->beacon_blink(vha);	/* Will flip to all off. */
1946f6df144cSandrew.vasquez@qlogic.com 
1947f6df144cSandrew.vasquez@qlogic.com 	/* Give control back to firmware. */
1948f6df144cSandrew.vasquez@qlogic.com 	spin_lock_irqsave(&ha->hardware_lock, flags);
194904474d3aSBart Van Assche 	gpio_data = rd_reg_dword(&reg->gpiod);
1950f6df144cSandrew.vasquez@qlogic.com 
1951f6df144cSandrew.vasquez@qlogic.com 	/* Disable the gpio_data reg for update. */
1952f6df144cSandrew.vasquez@qlogic.com 	gpio_data &= ~GPDX_LED_UPDATE_MASK;
195304474d3aSBart Van Assche 	wrt_reg_dword(&reg->gpiod, gpio_data);
195404474d3aSBart Van Assche 	rd_reg_dword(&reg->gpiod);
1955f6df144cSandrew.vasquez@qlogic.com 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
1956f6df144cSandrew.vasquez@qlogic.com 
19576246b8a1SGiridhar Malavali set_fw_options:
1958f6df144cSandrew.vasquez@qlogic.com 	ha->fw_options[1] &= ~ADD_FO1_DISABLE_GPIO_LED_CTRL;
1959f6df144cSandrew.vasquez@qlogic.com 
19607b867cf7SAnirban Chakraborty 	if (qla2x00_set_fw_options(vha, ha->fw_options) != QLA_SUCCESS) {
19617c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x704d,
19627c3df132SSaurav Kashyap 		    "Unable to update fw options (beacon on).\n");
1963f6df144cSandrew.vasquez@qlogic.com 		return QLA_FUNCTION_FAILED;
1964f6df144cSandrew.vasquez@qlogic.com 	}
1965f6df144cSandrew.vasquez@qlogic.com 
19667b867cf7SAnirban Chakraborty 	if (qla2x00_get_fw_options(vha, ha->fw_options) != QLA_SUCCESS) {
19677c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x704e,
19687c3df132SSaurav Kashyap 		    "Unable to update fw options (beacon on).\n");
1969f6df144cSandrew.vasquez@qlogic.com 		return QLA_FUNCTION_FAILED;
1970f6df144cSandrew.vasquez@qlogic.com 	}
1971f6df144cSandrew.vasquez@qlogic.com 
1972f6df144cSandrew.vasquez@qlogic.com 	return QLA_SUCCESS;
1973f6df144cSandrew.vasquez@qlogic.com }
1974854165f4Sandrew.vasquez@qlogic.com 
1975854165f4Sandrew.vasquez@qlogic.com 
1976854165f4Sandrew.vasquez@qlogic.com /*
1977854165f4Sandrew.vasquez@qlogic.com  * Flash support routines
1978854165f4Sandrew.vasquez@qlogic.com  */
1979854165f4Sandrew.vasquez@qlogic.com 
1980854165f4Sandrew.vasquez@qlogic.com /**
1981854165f4Sandrew.vasquez@qlogic.com  * qla2x00_flash_enable() - Setup flash for reading and writing.
1982854165f4Sandrew.vasquez@qlogic.com  * @ha: HA context
1983854165f4Sandrew.vasquez@qlogic.com  */
1984854165f4Sandrew.vasquez@qlogic.com static void
qla2x00_flash_enable(struct qla_hw_data * ha)19857b867cf7SAnirban Chakraborty qla2x00_flash_enable(struct qla_hw_data *ha)
1986854165f4Sandrew.vasquez@qlogic.com {
1987854165f4Sandrew.vasquez@qlogic.com 	uint16_t data;
1988854165f4Sandrew.vasquez@qlogic.com 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
1989854165f4Sandrew.vasquez@qlogic.com 
199004474d3aSBart Van Assche 	data = rd_reg_word(&reg->ctrl_status);
1991854165f4Sandrew.vasquez@qlogic.com 	data |= CSR_FLASH_ENABLE;
199204474d3aSBart Van Assche 	wrt_reg_word(&reg->ctrl_status, data);
199304474d3aSBart Van Assche 	rd_reg_word(&reg->ctrl_status);		/* PCI Posting. */
1994854165f4Sandrew.vasquez@qlogic.com }
1995854165f4Sandrew.vasquez@qlogic.com 
1996854165f4Sandrew.vasquez@qlogic.com /**
1997854165f4Sandrew.vasquez@qlogic.com  * qla2x00_flash_disable() - Disable flash and allow RISC to run.
1998854165f4Sandrew.vasquez@qlogic.com  * @ha: HA context
1999854165f4Sandrew.vasquez@qlogic.com  */
2000854165f4Sandrew.vasquez@qlogic.com static void
qla2x00_flash_disable(struct qla_hw_data * ha)20017b867cf7SAnirban Chakraborty qla2x00_flash_disable(struct qla_hw_data *ha)
2002854165f4Sandrew.vasquez@qlogic.com {
2003854165f4Sandrew.vasquez@qlogic.com 	uint16_t data;
2004854165f4Sandrew.vasquez@qlogic.com 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
2005854165f4Sandrew.vasquez@qlogic.com 
200604474d3aSBart Van Assche 	data = rd_reg_word(&reg->ctrl_status);
2007854165f4Sandrew.vasquez@qlogic.com 	data &= ~(CSR_FLASH_ENABLE);
200804474d3aSBart Van Assche 	wrt_reg_word(&reg->ctrl_status, data);
200904474d3aSBart Van Assche 	rd_reg_word(&reg->ctrl_status);		/* PCI Posting. */
2010854165f4Sandrew.vasquez@qlogic.com }
2011854165f4Sandrew.vasquez@qlogic.com 
2012854165f4Sandrew.vasquez@qlogic.com /**
2013854165f4Sandrew.vasquez@qlogic.com  * qla2x00_read_flash_byte() - Reads a byte from flash
2014854165f4Sandrew.vasquez@qlogic.com  * @ha: HA context
2015854165f4Sandrew.vasquez@qlogic.com  * @addr: Address in flash to read
2016854165f4Sandrew.vasquez@qlogic.com  *
2017854165f4Sandrew.vasquez@qlogic.com  * A word is read from the chip, but, only the lower byte is valid.
2018854165f4Sandrew.vasquez@qlogic.com  *
2019854165f4Sandrew.vasquez@qlogic.com  * Returns the byte read from flash @addr.
2020854165f4Sandrew.vasquez@qlogic.com  */
2021854165f4Sandrew.vasquez@qlogic.com static uint8_t
qla2x00_read_flash_byte(struct qla_hw_data * ha,uint32_t addr)20227b867cf7SAnirban Chakraborty qla2x00_read_flash_byte(struct qla_hw_data *ha, uint32_t addr)
2023854165f4Sandrew.vasquez@qlogic.com {
2024854165f4Sandrew.vasquez@qlogic.com 	uint16_t data;
2025854165f4Sandrew.vasquez@qlogic.com 	uint16_t bank_select;
2026854165f4Sandrew.vasquez@qlogic.com 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
2027854165f4Sandrew.vasquez@qlogic.com 
202804474d3aSBart Van Assche 	bank_select = rd_reg_word(&reg->ctrl_status);
2029854165f4Sandrew.vasquez@qlogic.com 
2030854165f4Sandrew.vasquez@qlogic.com 	if (IS_QLA2322(ha) || IS_QLA6322(ha)) {
2031854165f4Sandrew.vasquez@qlogic.com 		/* Specify 64K address range: */
2032854165f4Sandrew.vasquez@qlogic.com 		/*  clear out Module Select and Flash Address bits [19:16]. */
2033854165f4Sandrew.vasquez@qlogic.com 		bank_select &= ~0xf8;
2034854165f4Sandrew.vasquez@qlogic.com 		bank_select |= addr >> 12 & 0xf0;
2035854165f4Sandrew.vasquez@qlogic.com 		bank_select |= CSR_FLASH_64K_BANK;
203604474d3aSBart Van Assche 		wrt_reg_word(&reg->ctrl_status, bank_select);
203704474d3aSBart Van Assche 		rd_reg_word(&reg->ctrl_status);	/* PCI Posting. */
2038854165f4Sandrew.vasquez@qlogic.com 
203904474d3aSBart Van Assche 		wrt_reg_word(&reg->flash_address, (uint16_t)addr);
204004474d3aSBart Van Assche 		data = rd_reg_word(&reg->flash_data);
2041854165f4Sandrew.vasquez@qlogic.com 
2042854165f4Sandrew.vasquez@qlogic.com 		return (uint8_t)data;
2043854165f4Sandrew.vasquez@qlogic.com 	}
2044854165f4Sandrew.vasquez@qlogic.com 
2045854165f4Sandrew.vasquez@qlogic.com 	/* Setup bit 16 of flash address. */
2046854165f4Sandrew.vasquez@qlogic.com 	if ((addr & BIT_16) && ((bank_select & CSR_FLASH_64K_BANK) == 0)) {
2047854165f4Sandrew.vasquez@qlogic.com 		bank_select |= CSR_FLASH_64K_BANK;
204804474d3aSBart Van Assche 		wrt_reg_word(&reg->ctrl_status, bank_select);
204904474d3aSBart Van Assche 		rd_reg_word(&reg->ctrl_status);	/* PCI Posting. */
2050854165f4Sandrew.vasquez@qlogic.com 	} else if (((addr & BIT_16) == 0) &&
2051854165f4Sandrew.vasquez@qlogic.com 	    (bank_select & CSR_FLASH_64K_BANK)) {
2052854165f4Sandrew.vasquez@qlogic.com 		bank_select &= ~(CSR_FLASH_64K_BANK);
205304474d3aSBart Van Assche 		wrt_reg_word(&reg->ctrl_status, bank_select);
205404474d3aSBart Van Assche 		rd_reg_word(&reg->ctrl_status);	/* PCI Posting. */
2055854165f4Sandrew.vasquez@qlogic.com 	}
2056854165f4Sandrew.vasquez@qlogic.com 
2057854165f4Sandrew.vasquez@qlogic.com 	/* Always perform IO mapped accesses to the FLASH registers. */
2058854165f4Sandrew.vasquez@qlogic.com 	if (ha->pio_address) {
2059854165f4Sandrew.vasquez@qlogic.com 		uint16_t data2;
2060854165f4Sandrew.vasquez@qlogic.com 
2061948882f6SAndrew Vasquez 		WRT_REG_WORD_PIO(PIO_REG(ha, flash_address), (uint16_t)addr);
2062854165f4Sandrew.vasquez@qlogic.com 		do {
2063948882f6SAndrew Vasquez 			data = RD_REG_WORD_PIO(PIO_REG(ha, flash_data));
2064854165f4Sandrew.vasquez@qlogic.com 			barrier();
2065854165f4Sandrew.vasquez@qlogic.com 			cpu_relax();
2066948882f6SAndrew Vasquez 			data2 = RD_REG_WORD_PIO(PIO_REG(ha, flash_data));
2067854165f4Sandrew.vasquez@qlogic.com 		} while (data != data2);
2068854165f4Sandrew.vasquez@qlogic.com 	} else {
206904474d3aSBart Van Assche 		wrt_reg_word(&reg->flash_address, (uint16_t)addr);
2070854165f4Sandrew.vasquez@qlogic.com 		data = qla2x00_debounce_register(&reg->flash_data);
2071854165f4Sandrew.vasquez@qlogic.com 	}
2072854165f4Sandrew.vasquez@qlogic.com 
2073854165f4Sandrew.vasquez@qlogic.com 	return (uint8_t)data;
2074854165f4Sandrew.vasquez@qlogic.com }
2075854165f4Sandrew.vasquez@qlogic.com 
2076854165f4Sandrew.vasquez@qlogic.com /**
2077854165f4Sandrew.vasquez@qlogic.com  * qla2x00_write_flash_byte() - Write a byte to flash
2078854165f4Sandrew.vasquez@qlogic.com  * @ha: HA context
2079854165f4Sandrew.vasquez@qlogic.com  * @addr: Address in flash to write
2080854165f4Sandrew.vasquez@qlogic.com  * @data: Data to write
2081854165f4Sandrew.vasquez@qlogic.com  */
2082854165f4Sandrew.vasquez@qlogic.com static void
qla2x00_write_flash_byte(struct qla_hw_data * ha,uint32_t addr,uint8_t data)20837b867cf7SAnirban Chakraborty qla2x00_write_flash_byte(struct qla_hw_data *ha, uint32_t addr, uint8_t data)
2084854165f4Sandrew.vasquez@qlogic.com {
2085854165f4Sandrew.vasquez@qlogic.com 	uint16_t bank_select;
2086854165f4Sandrew.vasquez@qlogic.com 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
2087854165f4Sandrew.vasquez@qlogic.com 
208804474d3aSBart Van Assche 	bank_select = rd_reg_word(&reg->ctrl_status);
2089854165f4Sandrew.vasquez@qlogic.com 	if (IS_QLA2322(ha) || IS_QLA6322(ha)) {
2090854165f4Sandrew.vasquez@qlogic.com 		/* Specify 64K address range: */
2091854165f4Sandrew.vasquez@qlogic.com 		/*  clear out Module Select and Flash Address bits [19:16]. */
2092854165f4Sandrew.vasquez@qlogic.com 		bank_select &= ~0xf8;
2093854165f4Sandrew.vasquez@qlogic.com 		bank_select |= addr >> 12 & 0xf0;
2094854165f4Sandrew.vasquez@qlogic.com 		bank_select |= CSR_FLASH_64K_BANK;
209504474d3aSBart Van Assche 		wrt_reg_word(&reg->ctrl_status, bank_select);
209604474d3aSBart Van Assche 		rd_reg_word(&reg->ctrl_status);	/* PCI Posting. */
2097854165f4Sandrew.vasquez@qlogic.com 
209804474d3aSBart Van Assche 		wrt_reg_word(&reg->flash_address, (uint16_t)addr);
209904474d3aSBart Van Assche 		rd_reg_word(&reg->ctrl_status);		/* PCI Posting. */
210004474d3aSBart Van Assche 		wrt_reg_word(&reg->flash_data, (uint16_t)data);
210104474d3aSBart Van Assche 		rd_reg_word(&reg->ctrl_status);		/* PCI Posting. */
2102854165f4Sandrew.vasquez@qlogic.com 
2103854165f4Sandrew.vasquez@qlogic.com 		return;
2104854165f4Sandrew.vasquez@qlogic.com 	}
2105854165f4Sandrew.vasquez@qlogic.com 
2106854165f4Sandrew.vasquez@qlogic.com 	/* Setup bit 16 of flash address. */
2107854165f4Sandrew.vasquez@qlogic.com 	if ((addr & BIT_16) && ((bank_select & CSR_FLASH_64K_BANK) == 0)) {
2108854165f4Sandrew.vasquez@qlogic.com 		bank_select |= CSR_FLASH_64K_BANK;
210904474d3aSBart Van Assche 		wrt_reg_word(&reg->ctrl_status, bank_select);
211004474d3aSBart Van Assche 		rd_reg_word(&reg->ctrl_status);	/* PCI Posting. */
2111854165f4Sandrew.vasquez@qlogic.com 	} else if (((addr & BIT_16) == 0) &&
2112854165f4Sandrew.vasquez@qlogic.com 	    (bank_select & CSR_FLASH_64K_BANK)) {
2113854165f4Sandrew.vasquez@qlogic.com 		bank_select &= ~(CSR_FLASH_64K_BANK);
211404474d3aSBart Van Assche 		wrt_reg_word(&reg->ctrl_status, bank_select);
211504474d3aSBart Van Assche 		rd_reg_word(&reg->ctrl_status);	/* PCI Posting. */
2116854165f4Sandrew.vasquez@qlogic.com 	}
2117854165f4Sandrew.vasquez@qlogic.com 
2118854165f4Sandrew.vasquez@qlogic.com 	/* Always perform IO mapped accesses to the FLASH registers. */
2119854165f4Sandrew.vasquez@qlogic.com 	if (ha->pio_address) {
2120948882f6SAndrew Vasquez 		WRT_REG_WORD_PIO(PIO_REG(ha, flash_address), (uint16_t)addr);
2121948882f6SAndrew Vasquez 		WRT_REG_WORD_PIO(PIO_REG(ha, flash_data), (uint16_t)data);
2122854165f4Sandrew.vasquez@qlogic.com 	} else {
212304474d3aSBart Van Assche 		wrt_reg_word(&reg->flash_address, (uint16_t)addr);
212404474d3aSBart Van Assche 		rd_reg_word(&reg->ctrl_status);		/* PCI Posting. */
212504474d3aSBart Van Assche 		wrt_reg_word(&reg->flash_data, (uint16_t)data);
212604474d3aSBart Van Assche 		rd_reg_word(&reg->ctrl_status);		/* PCI Posting. */
2127854165f4Sandrew.vasquez@qlogic.com 	}
2128854165f4Sandrew.vasquez@qlogic.com }
2129854165f4Sandrew.vasquez@qlogic.com 
2130854165f4Sandrew.vasquez@qlogic.com /**
2131854165f4Sandrew.vasquez@qlogic.com  * qla2x00_poll_flash() - Polls flash for completion.
2132854165f4Sandrew.vasquez@qlogic.com  * @ha: HA context
2133854165f4Sandrew.vasquez@qlogic.com  * @addr: Address in flash to poll
2134854165f4Sandrew.vasquez@qlogic.com  * @poll_data: Data to be polled
2135854165f4Sandrew.vasquez@qlogic.com  * @man_id: Flash manufacturer ID
2136854165f4Sandrew.vasquez@qlogic.com  * @flash_id: Flash ID
2137854165f4Sandrew.vasquez@qlogic.com  *
2138854165f4Sandrew.vasquez@qlogic.com  * This function polls the device until bit 7 of what is read matches data
2139854165f4Sandrew.vasquez@qlogic.com  * bit 7 or until data bit 5 becomes a 1.  If that hapens, the flash ROM timed
2140854165f4Sandrew.vasquez@qlogic.com  * out (a fatal error).  The flash book recommeds reading bit 7 again after
2141854165f4Sandrew.vasquez@qlogic.com  * reading bit 5 as a 1.
2142854165f4Sandrew.vasquez@qlogic.com  *
2143854165f4Sandrew.vasquez@qlogic.com  * Returns 0 on success, else non-zero.
2144854165f4Sandrew.vasquez@qlogic.com  */
2145854165f4Sandrew.vasquez@qlogic.com static int
qla2x00_poll_flash(struct qla_hw_data * ha,uint32_t addr,uint8_t poll_data,uint8_t man_id,uint8_t flash_id)21467b867cf7SAnirban Chakraborty qla2x00_poll_flash(struct qla_hw_data *ha, uint32_t addr, uint8_t poll_data,
2147854165f4Sandrew.vasquez@qlogic.com     uint8_t man_id, uint8_t flash_id)
2148854165f4Sandrew.vasquez@qlogic.com {
2149854165f4Sandrew.vasquez@qlogic.com 	int status;
2150854165f4Sandrew.vasquez@qlogic.com 	uint8_t flash_data;
2151854165f4Sandrew.vasquez@qlogic.com 	uint32_t cnt;
2152854165f4Sandrew.vasquez@qlogic.com 
2153854165f4Sandrew.vasquez@qlogic.com 	status = 1;
2154854165f4Sandrew.vasquez@qlogic.com 
2155854165f4Sandrew.vasquez@qlogic.com 	/* Wait for 30 seconds for command to finish. */
2156854165f4Sandrew.vasquez@qlogic.com 	poll_data &= BIT_7;
2157854165f4Sandrew.vasquez@qlogic.com 	for (cnt = 3000000; cnt; cnt--) {
2158854165f4Sandrew.vasquez@qlogic.com 		flash_data = qla2x00_read_flash_byte(ha, addr);
2159854165f4Sandrew.vasquez@qlogic.com 		if ((flash_data & BIT_7) == poll_data) {
2160854165f4Sandrew.vasquez@qlogic.com 			status = 0;
2161854165f4Sandrew.vasquez@qlogic.com 			break;
2162854165f4Sandrew.vasquez@qlogic.com 		}
2163854165f4Sandrew.vasquez@qlogic.com 
2164854165f4Sandrew.vasquez@qlogic.com 		if (man_id != 0x40 && man_id != 0xda) {
2165854165f4Sandrew.vasquez@qlogic.com 			if ((flash_data & BIT_5) && cnt > 2)
2166854165f4Sandrew.vasquez@qlogic.com 				cnt = 2;
2167854165f4Sandrew.vasquez@qlogic.com 		}
2168854165f4Sandrew.vasquez@qlogic.com 		udelay(10);
2169854165f4Sandrew.vasquez@qlogic.com 		barrier();
217040a2e34aSAndrew Vasquez 		cond_resched();
2171854165f4Sandrew.vasquez@qlogic.com 	}
2172854165f4Sandrew.vasquez@qlogic.com 	return status;
2173854165f4Sandrew.vasquez@qlogic.com }
2174854165f4Sandrew.vasquez@qlogic.com 
2175854165f4Sandrew.vasquez@qlogic.com /**
2176854165f4Sandrew.vasquez@qlogic.com  * qla2x00_program_flash_address() - Programs a flash address
2177854165f4Sandrew.vasquez@qlogic.com  * @ha: HA context
2178854165f4Sandrew.vasquez@qlogic.com  * @addr: Address in flash to program
2179854165f4Sandrew.vasquez@qlogic.com  * @data: Data to be written in flash
2180854165f4Sandrew.vasquez@qlogic.com  * @man_id: Flash manufacturer ID
2181854165f4Sandrew.vasquez@qlogic.com  * @flash_id: Flash ID
2182854165f4Sandrew.vasquez@qlogic.com  *
2183854165f4Sandrew.vasquez@qlogic.com  * Returns 0 on success, else non-zero.
2184854165f4Sandrew.vasquez@qlogic.com  */
2185854165f4Sandrew.vasquez@qlogic.com static int
qla2x00_program_flash_address(struct qla_hw_data * ha,uint32_t addr,uint8_t data,uint8_t man_id,uint8_t flash_id)21867b867cf7SAnirban Chakraborty qla2x00_program_flash_address(struct qla_hw_data *ha, uint32_t addr,
21877b867cf7SAnirban Chakraborty     uint8_t data, uint8_t man_id, uint8_t flash_id)
2188854165f4Sandrew.vasquez@qlogic.com {
2189854165f4Sandrew.vasquez@qlogic.com 	/* Write Program Command Sequence. */
2190854165f4Sandrew.vasquez@qlogic.com 	if (IS_OEM_001(ha)) {
2191854165f4Sandrew.vasquez@qlogic.com 		qla2x00_write_flash_byte(ha, 0xaaa, 0xaa);
2192854165f4Sandrew.vasquez@qlogic.com 		qla2x00_write_flash_byte(ha, 0x555, 0x55);
2193854165f4Sandrew.vasquez@qlogic.com 		qla2x00_write_flash_byte(ha, 0xaaa, 0xa0);
2194854165f4Sandrew.vasquez@qlogic.com 		qla2x00_write_flash_byte(ha, addr, data);
2195854165f4Sandrew.vasquez@qlogic.com 	} else {
2196854165f4Sandrew.vasquez@qlogic.com 		if (man_id == 0xda && flash_id == 0xc1) {
2197854165f4Sandrew.vasquez@qlogic.com 			qla2x00_write_flash_byte(ha, addr, data);
2198854165f4Sandrew.vasquez@qlogic.com 			if (addr & 0x7e)
2199854165f4Sandrew.vasquez@qlogic.com 				return 0;
2200854165f4Sandrew.vasquez@qlogic.com 		} else {
2201854165f4Sandrew.vasquez@qlogic.com 			qla2x00_write_flash_byte(ha, 0x5555, 0xaa);
2202854165f4Sandrew.vasquez@qlogic.com 			qla2x00_write_flash_byte(ha, 0x2aaa, 0x55);
2203854165f4Sandrew.vasquez@qlogic.com 			qla2x00_write_flash_byte(ha, 0x5555, 0xa0);
2204854165f4Sandrew.vasquez@qlogic.com 			qla2x00_write_flash_byte(ha, addr, data);
2205854165f4Sandrew.vasquez@qlogic.com 		}
2206854165f4Sandrew.vasquez@qlogic.com 	}
2207854165f4Sandrew.vasquez@qlogic.com 
2208854165f4Sandrew.vasquez@qlogic.com 	udelay(150);
2209854165f4Sandrew.vasquez@qlogic.com 
2210854165f4Sandrew.vasquez@qlogic.com 	/* Wait for write to complete. */
2211854165f4Sandrew.vasquez@qlogic.com 	return qla2x00_poll_flash(ha, addr, data, man_id, flash_id);
2212854165f4Sandrew.vasquez@qlogic.com }
2213854165f4Sandrew.vasquez@qlogic.com 
2214854165f4Sandrew.vasquez@qlogic.com /**
2215854165f4Sandrew.vasquez@qlogic.com  * qla2x00_erase_flash() - Erase the flash.
2216854165f4Sandrew.vasquez@qlogic.com  * @ha: HA context
2217854165f4Sandrew.vasquez@qlogic.com  * @man_id: Flash manufacturer ID
2218854165f4Sandrew.vasquez@qlogic.com  * @flash_id: Flash ID
2219854165f4Sandrew.vasquez@qlogic.com  *
2220854165f4Sandrew.vasquez@qlogic.com  * Returns 0 on success, else non-zero.
2221854165f4Sandrew.vasquez@qlogic.com  */
2222854165f4Sandrew.vasquez@qlogic.com static int
qla2x00_erase_flash(struct qla_hw_data * ha,uint8_t man_id,uint8_t flash_id)22237b867cf7SAnirban Chakraborty qla2x00_erase_flash(struct qla_hw_data *ha, uint8_t man_id, uint8_t flash_id)
2224854165f4Sandrew.vasquez@qlogic.com {
2225854165f4Sandrew.vasquez@qlogic.com 	/* Individual Sector Erase Command Sequence */
2226854165f4Sandrew.vasquez@qlogic.com 	if (IS_OEM_001(ha)) {
2227854165f4Sandrew.vasquez@qlogic.com 		qla2x00_write_flash_byte(ha, 0xaaa, 0xaa);
2228854165f4Sandrew.vasquez@qlogic.com 		qla2x00_write_flash_byte(ha, 0x555, 0x55);
2229854165f4Sandrew.vasquez@qlogic.com 		qla2x00_write_flash_byte(ha, 0xaaa, 0x80);
2230854165f4Sandrew.vasquez@qlogic.com 		qla2x00_write_flash_byte(ha, 0xaaa, 0xaa);
2231854165f4Sandrew.vasquez@qlogic.com 		qla2x00_write_flash_byte(ha, 0x555, 0x55);
2232854165f4Sandrew.vasquez@qlogic.com 		qla2x00_write_flash_byte(ha, 0xaaa, 0x10);
2233854165f4Sandrew.vasquez@qlogic.com 	} else {
2234854165f4Sandrew.vasquez@qlogic.com 		qla2x00_write_flash_byte(ha, 0x5555, 0xaa);
2235854165f4Sandrew.vasquez@qlogic.com 		qla2x00_write_flash_byte(ha, 0x2aaa, 0x55);
2236854165f4Sandrew.vasquez@qlogic.com 		qla2x00_write_flash_byte(ha, 0x5555, 0x80);
2237854165f4Sandrew.vasquez@qlogic.com 		qla2x00_write_flash_byte(ha, 0x5555, 0xaa);
2238854165f4Sandrew.vasquez@qlogic.com 		qla2x00_write_flash_byte(ha, 0x2aaa, 0x55);
2239854165f4Sandrew.vasquez@qlogic.com 		qla2x00_write_flash_byte(ha, 0x5555, 0x10);
2240854165f4Sandrew.vasquez@qlogic.com 	}
2241854165f4Sandrew.vasquez@qlogic.com 
2242854165f4Sandrew.vasquez@qlogic.com 	udelay(150);
2243854165f4Sandrew.vasquez@qlogic.com 
2244854165f4Sandrew.vasquez@qlogic.com 	/* Wait for erase to complete. */
2245854165f4Sandrew.vasquez@qlogic.com 	return qla2x00_poll_flash(ha, 0x00, 0x80, man_id, flash_id);
2246854165f4Sandrew.vasquez@qlogic.com }
2247854165f4Sandrew.vasquez@qlogic.com 
2248854165f4Sandrew.vasquez@qlogic.com /**
2249854165f4Sandrew.vasquez@qlogic.com  * qla2x00_erase_flash_sector() - Erase a flash sector.
2250854165f4Sandrew.vasquez@qlogic.com  * @ha: HA context
2251854165f4Sandrew.vasquez@qlogic.com  * @addr: Flash sector to erase
2252854165f4Sandrew.vasquez@qlogic.com  * @sec_mask: Sector address mask
2253854165f4Sandrew.vasquez@qlogic.com  * @man_id: Flash manufacturer ID
2254854165f4Sandrew.vasquez@qlogic.com  * @flash_id: Flash ID
2255854165f4Sandrew.vasquez@qlogic.com  *
2256854165f4Sandrew.vasquez@qlogic.com  * Returns 0 on success, else non-zero.
2257854165f4Sandrew.vasquez@qlogic.com  */
2258854165f4Sandrew.vasquez@qlogic.com static int
qla2x00_erase_flash_sector(struct qla_hw_data * ha,uint32_t addr,uint32_t sec_mask,uint8_t man_id,uint8_t flash_id)22597b867cf7SAnirban Chakraborty qla2x00_erase_flash_sector(struct qla_hw_data *ha, uint32_t addr,
2260854165f4Sandrew.vasquez@qlogic.com     uint32_t sec_mask, uint8_t man_id, uint8_t flash_id)
2261854165f4Sandrew.vasquez@qlogic.com {
2262854165f4Sandrew.vasquez@qlogic.com 	/* Individual Sector Erase Command Sequence */
2263854165f4Sandrew.vasquez@qlogic.com 	qla2x00_write_flash_byte(ha, 0x5555, 0xaa);
2264854165f4Sandrew.vasquez@qlogic.com 	qla2x00_write_flash_byte(ha, 0x2aaa, 0x55);
2265854165f4Sandrew.vasquez@qlogic.com 	qla2x00_write_flash_byte(ha, 0x5555, 0x80);
2266854165f4Sandrew.vasquez@qlogic.com 	qla2x00_write_flash_byte(ha, 0x5555, 0xaa);
2267854165f4Sandrew.vasquez@qlogic.com 	qla2x00_write_flash_byte(ha, 0x2aaa, 0x55);
2268854165f4Sandrew.vasquez@qlogic.com 	if (man_id == 0x1f && flash_id == 0x13)
2269854165f4Sandrew.vasquez@qlogic.com 		qla2x00_write_flash_byte(ha, addr & sec_mask, 0x10);
2270854165f4Sandrew.vasquez@qlogic.com 	else
2271854165f4Sandrew.vasquez@qlogic.com 		qla2x00_write_flash_byte(ha, addr & sec_mask, 0x30);
2272854165f4Sandrew.vasquez@qlogic.com 
2273854165f4Sandrew.vasquez@qlogic.com 	udelay(150);
2274854165f4Sandrew.vasquez@qlogic.com 
2275854165f4Sandrew.vasquez@qlogic.com 	/* Wait for erase to complete. */
2276854165f4Sandrew.vasquez@qlogic.com 	return qla2x00_poll_flash(ha, addr, 0x80, man_id, flash_id);
2277854165f4Sandrew.vasquez@qlogic.com }
2278854165f4Sandrew.vasquez@qlogic.com 
2279854165f4Sandrew.vasquez@qlogic.com /**
2280854165f4Sandrew.vasquez@qlogic.com  * qla2x00_get_flash_manufacturer() - Read manufacturer ID from flash chip.
2281807eb907SBart Van Assche  * @ha: host adapter
2282854165f4Sandrew.vasquez@qlogic.com  * @man_id: Flash manufacturer ID
2283854165f4Sandrew.vasquez@qlogic.com  * @flash_id: Flash ID
2284854165f4Sandrew.vasquez@qlogic.com  */
2285854165f4Sandrew.vasquez@qlogic.com static void
qla2x00_get_flash_manufacturer(struct qla_hw_data * ha,uint8_t * man_id,uint8_t * flash_id)22867b867cf7SAnirban Chakraborty qla2x00_get_flash_manufacturer(struct qla_hw_data *ha, uint8_t *man_id,
2287854165f4Sandrew.vasquez@qlogic.com     uint8_t *flash_id)
2288854165f4Sandrew.vasquez@qlogic.com {
2289854165f4Sandrew.vasquez@qlogic.com 	qla2x00_write_flash_byte(ha, 0x5555, 0xaa);
2290854165f4Sandrew.vasquez@qlogic.com 	qla2x00_write_flash_byte(ha, 0x2aaa, 0x55);
2291854165f4Sandrew.vasquez@qlogic.com 	qla2x00_write_flash_byte(ha, 0x5555, 0x90);
2292854165f4Sandrew.vasquez@qlogic.com 	*man_id = qla2x00_read_flash_byte(ha, 0x0000);
2293854165f4Sandrew.vasquez@qlogic.com 	*flash_id = qla2x00_read_flash_byte(ha, 0x0001);
2294854165f4Sandrew.vasquez@qlogic.com 	qla2x00_write_flash_byte(ha, 0x5555, 0xaa);
2295854165f4Sandrew.vasquez@qlogic.com 	qla2x00_write_flash_byte(ha, 0x2aaa, 0x55);
2296854165f4Sandrew.vasquez@qlogic.com 	qla2x00_write_flash_byte(ha, 0x5555, 0xf0);
2297854165f4Sandrew.vasquez@qlogic.com }
2298854165f4Sandrew.vasquez@qlogic.com 
229930c47662SAndrew Vasquez static void
qla2x00_read_flash_data(struct qla_hw_data * ha,uint8_t * tmp_buf,uint32_t saddr,uint32_t length)23007b867cf7SAnirban Chakraborty qla2x00_read_flash_data(struct qla_hw_data *ha, uint8_t *tmp_buf,
23017b867cf7SAnirban Chakraborty 	uint32_t saddr, uint32_t length)
230230c47662SAndrew Vasquez {
230330c47662SAndrew Vasquez 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
230430c47662SAndrew Vasquez 	uint32_t midpoint, ilength;
230530c47662SAndrew Vasquez 	uint8_t data;
230630c47662SAndrew Vasquez 
230730c47662SAndrew Vasquez 	midpoint = length / 2;
230830c47662SAndrew Vasquez 
230904474d3aSBart Van Assche 	wrt_reg_word(&reg->nvram, 0);
231004474d3aSBart Van Assche 	rd_reg_word(&reg->nvram);
231130c47662SAndrew Vasquez 	for (ilength = 0; ilength < length; saddr++, ilength++, tmp_buf++) {
231230c47662SAndrew Vasquez 		if (ilength == midpoint) {
231304474d3aSBart Van Assche 			wrt_reg_word(&reg->nvram, NVR_SELECT);
231404474d3aSBart Van Assche 			rd_reg_word(&reg->nvram);
231530c47662SAndrew Vasquez 		}
231630c47662SAndrew Vasquez 		data = qla2x00_read_flash_byte(ha, saddr);
231730c47662SAndrew Vasquez 		if (saddr % 100)
231830c47662SAndrew Vasquez 			udelay(10);
231930c47662SAndrew Vasquez 		*tmp_buf = data;
232040a2e34aSAndrew Vasquez 		cond_resched();
232130c47662SAndrew Vasquez 	}
232230c47662SAndrew Vasquez }
2323854165f4Sandrew.vasquez@qlogic.com 
2324854165f4Sandrew.vasquez@qlogic.com static inline void
qla2x00_suspend_hba(struct scsi_qla_host * vha)23257b867cf7SAnirban Chakraborty qla2x00_suspend_hba(struct scsi_qla_host *vha)
2326854165f4Sandrew.vasquez@qlogic.com {
2327854165f4Sandrew.vasquez@qlogic.com 	int cnt;
2328854165f4Sandrew.vasquez@qlogic.com 	unsigned long flags;
23297b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
2330854165f4Sandrew.vasquez@qlogic.com 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
2331854165f4Sandrew.vasquez@qlogic.com 
2332854165f4Sandrew.vasquez@qlogic.com 	/* Suspend HBA. */
23337b867cf7SAnirban Chakraborty 	scsi_block_requests(vha->host);
2334fd34f556SAndrew Vasquez 	ha->isp_ops->disable_intrs(ha);
2335854165f4Sandrew.vasquez@qlogic.com 	set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
2336854165f4Sandrew.vasquez@qlogic.com 
2337854165f4Sandrew.vasquez@qlogic.com 	/* Pause RISC. */
2338854165f4Sandrew.vasquez@qlogic.com 	spin_lock_irqsave(&ha->hardware_lock, flags);
233904474d3aSBart Van Assche 	wrt_reg_word(&reg->hccr, HCCR_PAUSE_RISC);
234004474d3aSBart Van Assche 	rd_reg_word(&reg->hccr);
2341854165f4Sandrew.vasquez@qlogic.com 	if (IS_QLA2100(ha) || IS_QLA2200(ha) || IS_QLA2300(ha)) {
2342854165f4Sandrew.vasquez@qlogic.com 		for (cnt = 0; cnt < 30000; cnt++) {
234304474d3aSBart Van Assche 			if ((rd_reg_word(&reg->hccr) & HCCR_RISC_PAUSE) != 0)
2344854165f4Sandrew.vasquez@qlogic.com 				break;
2345854165f4Sandrew.vasquez@qlogic.com 			udelay(100);
2346854165f4Sandrew.vasquez@qlogic.com 		}
2347854165f4Sandrew.vasquez@qlogic.com 	} else {
2348854165f4Sandrew.vasquez@qlogic.com 		udelay(10);
2349854165f4Sandrew.vasquez@qlogic.com 	}
2350854165f4Sandrew.vasquez@qlogic.com 	spin_unlock_irqrestore(&ha->hardware_lock, flags);
2351854165f4Sandrew.vasquez@qlogic.com }
2352854165f4Sandrew.vasquez@qlogic.com 
2353854165f4Sandrew.vasquez@qlogic.com static inline void
qla2x00_resume_hba(struct scsi_qla_host * vha)23547b867cf7SAnirban Chakraborty qla2x00_resume_hba(struct scsi_qla_host *vha)
2355854165f4Sandrew.vasquez@qlogic.com {
23567b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
23577b867cf7SAnirban Chakraborty 
2358854165f4Sandrew.vasquez@qlogic.com 	/* Resume HBA. */
2359854165f4Sandrew.vasquez@qlogic.com 	clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
23607b867cf7SAnirban Chakraborty 	set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
23617b867cf7SAnirban Chakraborty 	qla2xxx_wake_dpc(vha);
23622533cf67SLalit Chandivade 	qla2x00_wait_for_chip_reset(vha);
23637b867cf7SAnirban Chakraborty 	scsi_unblock_requests(vha->host);
2364854165f4Sandrew.vasquez@qlogic.com }
2365854165f4Sandrew.vasquez@qlogic.com 
23663695310eSJoe Carnuccio void *
qla2x00_read_optrom_data(struct scsi_qla_host * vha,void * buf,uint32_t offset,uint32_t length)23673695310eSJoe Carnuccio qla2x00_read_optrom_data(struct scsi_qla_host *vha, void *buf,
2368854165f4Sandrew.vasquez@qlogic.com     uint32_t offset, uint32_t length)
2369854165f4Sandrew.vasquez@qlogic.com {
2370854165f4Sandrew.vasquez@qlogic.com 	uint32_t addr, midpoint;
2371854165f4Sandrew.vasquez@qlogic.com 	uint8_t *data;
23727b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
2373854165f4Sandrew.vasquez@qlogic.com 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
2374854165f4Sandrew.vasquez@qlogic.com 
2375854165f4Sandrew.vasquez@qlogic.com 	/* Suspend HBA. */
23767b867cf7SAnirban Chakraborty 	qla2x00_suspend_hba(vha);
2377854165f4Sandrew.vasquez@qlogic.com 
2378854165f4Sandrew.vasquez@qlogic.com 	/* Go with read. */
2379854165f4Sandrew.vasquez@qlogic.com 	midpoint = ha->optrom_size / 2;
2380854165f4Sandrew.vasquez@qlogic.com 
2381854165f4Sandrew.vasquez@qlogic.com 	qla2x00_flash_enable(ha);
238204474d3aSBart Van Assche 	wrt_reg_word(&reg->nvram, 0);
238304474d3aSBart Van Assche 	rd_reg_word(&reg->nvram);		/* PCI Posting. */
2384854165f4Sandrew.vasquez@qlogic.com 	for (addr = offset, data = buf; addr < length; addr++, data++) {
2385854165f4Sandrew.vasquez@qlogic.com 		if (addr == midpoint) {
238604474d3aSBart Van Assche 			wrt_reg_word(&reg->nvram, NVR_SELECT);
238704474d3aSBart Van Assche 			rd_reg_word(&reg->nvram);	/* PCI Posting. */
2388854165f4Sandrew.vasquez@qlogic.com 		}
2389854165f4Sandrew.vasquez@qlogic.com 
2390854165f4Sandrew.vasquez@qlogic.com 		*data = qla2x00_read_flash_byte(ha, addr);
2391854165f4Sandrew.vasquez@qlogic.com 	}
2392854165f4Sandrew.vasquez@qlogic.com 	qla2x00_flash_disable(ha);
2393854165f4Sandrew.vasquez@qlogic.com 
2394854165f4Sandrew.vasquez@qlogic.com 	/* Resume HBA. */
23957b867cf7SAnirban Chakraborty 	qla2x00_resume_hba(vha);
2396854165f4Sandrew.vasquez@qlogic.com 
2397854165f4Sandrew.vasquez@qlogic.com 	return buf;
2398854165f4Sandrew.vasquez@qlogic.com }
2399854165f4Sandrew.vasquez@qlogic.com 
2400854165f4Sandrew.vasquez@qlogic.com int
qla2x00_write_optrom_data(struct scsi_qla_host * vha,void * buf,uint32_t offset,uint32_t length)24013695310eSJoe Carnuccio qla2x00_write_optrom_data(struct scsi_qla_host *vha, void *buf,
2402854165f4Sandrew.vasquez@qlogic.com     uint32_t offset, uint32_t length)
2403854165f4Sandrew.vasquez@qlogic.com {
2404854165f4Sandrew.vasquez@qlogic.com 
2405854165f4Sandrew.vasquez@qlogic.com 	int rval;
24063695310eSJoe Carnuccio 	uint8_t man_id, flash_id, sec_number, *data;
2407854165f4Sandrew.vasquez@qlogic.com 	uint16_t wd;
2408854165f4Sandrew.vasquez@qlogic.com 	uint32_t addr, liter, sec_mask, rest_addr;
24097b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
2410854165f4Sandrew.vasquez@qlogic.com 	struct device_reg_2xxx __iomem *reg = &ha->iobase->isp;
2411854165f4Sandrew.vasquez@qlogic.com 
2412854165f4Sandrew.vasquez@qlogic.com 	/* Suspend HBA. */
24137b867cf7SAnirban Chakraborty 	qla2x00_suspend_hba(vha);
2414854165f4Sandrew.vasquez@qlogic.com 
2415854165f4Sandrew.vasquez@qlogic.com 	rval = QLA_SUCCESS;
2416854165f4Sandrew.vasquez@qlogic.com 	sec_number = 0;
2417854165f4Sandrew.vasquez@qlogic.com 
2418854165f4Sandrew.vasquez@qlogic.com 	/* Reset ISP chip. */
241904474d3aSBart Van Assche 	wrt_reg_word(&reg->ctrl_status, CSR_ISP_SOFT_RESET);
2420854165f4Sandrew.vasquez@qlogic.com 	pci_read_config_word(ha->pdev, PCI_COMMAND, &wd);
2421854165f4Sandrew.vasquez@qlogic.com 
2422854165f4Sandrew.vasquez@qlogic.com 	/* Go with write. */
2423854165f4Sandrew.vasquez@qlogic.com 	qla2x00_flash_enable(ha);
2424854165f4Sandrew.vasquez@qlogic.com 	do {	/* Loop once to provide quick error exit */
2425854165f4Sandrew.vasquez@qlogic.com 		/* Structure of flash memory based on manufacturer */
2426854165f4Sandrew.vasquez@qlogic.com 		if (IS_OEM_001(ha)) {
2427854165f4Sandrew.vasquez@qlogic.com 			/* OEM variant with special flash part. */
2428854165f4Sandrew.vasquez@qlogic.com 			man_id = flash_id = 0;
2429854165f4Sandrew.vasquez@qlogic.com 			rest_addr = 0xffff;
2430854165f4Sandrew.vasquez@qlogic.com 			sec_mask   = 0x10000;
2431854165f4Sandrew.vasquez@qlogic.com 			goto update_flash;
2432854165f4Sandrew.vasquez@qlogic.com 		}
2433854165f4Sandrew.vasquez@qlogic.com 		qla2x00_get_flash_manufacturer(ha, &man_id, &flash_id);
2434854165f4Sandrew.vasquez@qlogic.com 		switch (man_id) {
2435854165f4Sandrew.vasquez@qlogic.com 		case 0x20: /* ST flash. */
2436854165f4Sandrew.vasquez@qlogic.com 			if (flash_id == 0xd2 || flash_id == 0xe3) {
2437854165f4Sandrew.vasquez@qlogic.com 				/*
2438854165f4Sandrew.vasquez@qlogic.com 				 * ST m29w008at part - 64kb sector size with
2439854165f4Sandrew.vasquez@qlogic.com 				 * 32kb,8kb,8kb,16kb sectors at memory address
2440854165f4Sandrew.vasquez@qlogic.com 				 * 0xf0000.
2441854165f4Sandrew.vasquez@qlogic.com 				 */
2442854165f4Sandrew.vasquez@qlogic.com 				rest_addr = 0xffff;
2443854165f4Sandrew.vasquez@qlogic.com 				sec_mask = 0x10000;
2444854165f4Sandrew.vasquez@qlogic.com 				break;
2445854165f4Sandrew.vasquez@qlogic.com 			}
2446854165f4Sandrew.vasquez@qlogic.com 			/*
2447854165f4Sandrew.vasquez@qlogic.com 			 * ST m29w010b part - 16kb sector size
2448854165f4Sandrew.vasquez@qlogic.com 			 * Default to 16kb sectors
2449854165f4Sandrew.vasquez@qlogic.com 			 */
2450854165f4Sandrew.vasquez@qlogic.com 			rest_addr = 0x3fff;
2451854165f4Sandrew.vasquez@qlogic.com 			sec_mask = 0x1c000;
2452854165f4Sandrew.vasquez@qlogic.com 			break;
2453854165f4Sandrew.vasquez@qlogic.com 		case 0x40: /* Mostel flash. */
2454854165f4Sandrew.vasquez@qlogic.com 			/* Mostel v29c51001 part - 512 byte sector size. */
2455854165f4Sandrew.vasquez@qlogic.com 			rest_addr = 0x1ff;
2456854165f4Sandrew.vasquez@qlogic.com 			sec_mask = 0x1fe00;
2457854165f4Sandrew.vasquez@qlogic.com 			break;
2458854165f4Sandrew.vasquez@qlogic.com 		case 0xbf: /* SST flash. */
2459854165f4Sandrew.vasquez@qlogic.com 			/* SST39sf10 part - 4kb sector size. */
2460854165f4Sandrew.vasquez@qlogic.com 			rest_addr = 0xfff;
2461854165f4Sandrew.vasquez@qlogic.com 			sec_mask = 0x1f000;
2462854165f4Sandrew.vasquez@qlogic.com 			break;
2463854165f4Sandrew.vasquez@qlogic.com 		case 0xda: /* Winbond flash. */
2464854165f4Sandrew.vasquez@qlogic.com 			/* Winbond W29EE011 part - 256 byte sector size. */
2465854165f4Sandrew.vasquez@qlogic.com 			rest_addr = 0x7f;
2466854165f4Sandrew.vasquez@qlogic.com 			sec_mask = 0x1ff80;
2467854165f4Sandrew.vasquez@qlogic.com 			break;
2468854165f4Sandrew.vasquez@qlogic.com 		case 0xc2: /* Macronix flash. */
2469854165f4Sandrew.vasquez@qlogic.com 			/* 64k sector size. */
2470854165f4Sandrew.vasquez@qlogic.com 			if (flash_id == 0x38 || flash_id == 0x4f) {
2471854165f4Sandrew.vasquez@qlogic.com 				rest_addr = 0xffff;
2472854165f4Sandrew.vasquez@qlogic.com 				sec_mask = 0x10000;
2473854165f4Sandrew.vasquez@qlogic.com 				break;
2474854165f4Sandrew.vasquez@qlogic.com 			}
2475df561f66SGustavo A. R. Silva 			fallthrough;
2476854165f4Sandrew.vasquez@qlogic.com 
2477854165f4Sandrew.vasquez@qlogic.com 		case 0x1f: /* Atmel flash. */
2478854165f4Sandrew.vasquez@qlogic.com 			/* 512k sector size. */
2479854165f4Sandrew.vasquez@qlogic.com 			if (flash_id == 0x13) {
2480854165f4Sandrew.vasquez@qlogic.com 				rest_addr = 0x7fffffff;
2481854165f4Sandrew.vasquez@qlogic.com 				sec_mask =   0x80000000;
2482854165f4Sandrew.vasquez@qlogic.com 				break;
2483854165f4Sandrew.vasquez@qlogic.com 			}
2484df561f66SGustavo A. R. Silva 			fallthrough;
2485854165f4Sandrew.vasquez@qlogic.com 
2486854165f4Sandrew.vasquez@qlogic.com 		case 0x01: /* AMD flash. */
2487854165f4Sandrew.vasquez@qlogic.com 			if (flash_id == 0x38 || flash_id == 0x40 ||
2488854165f4Sandrew.vasquez@qlogic.com 			    flash_id == 0x4f) {
2489854165f4Sandrew.vasquez@qlogic.com 				/* Am29LV081 part - 64kb sector size. */
2490854165f4Sandrew.vasquez@qlogic.com 				/* Am29LV002BT part - 64kb sector size. */
2491854165f4Sandrew.vasquez@qlogic.com 				rest_addr = 0xffff;
2492854165f4Sandrew.vasquez@qlogic.com 				sec_mask = 0x10000;
2493854165f4Sandrew.vasquez@qlogic.com 				break;
2494854165f4Sandrew.vasquez@qlogic.com 			} else if (flash_id == 0x3e) {
2495854165f4Sandrew.vasquez@qlogic.com 				/*
2496854165f4Sandrew.vasquez@qlogic.com 				 * Am29LV008b part - 64kb sector size with
2497854165f4Sandrew.vasquez@qlogic.com 				 * 32kb,8kb,8kb,16kb sector at memory address
2498854165f4Sandrew.vasquez@qlogic.com 				 * h0xf0000.
2499854165f4Sandrew.vasquez@qlogic.com 				 */
2500854165f4Sandrew.vasquez@qlogic.com 				rest_addr = 0xffff;
2501854165f4Sandrew.vasquez@qlogic.com 				sec_mask = 0x10000;
2502854165f4Sandrew.vasquez@qlogic.com 				break;
2503854165f4Sandrew.vasquez@qlogic.com 			} else if (flash_id == 0x20 || flash_id == 0x6e) {
2504854165f4Sandrew.vasquez@qlogic.com 				/*
2505854165f4Sandrew.vasquez@qlogic.com 				 * Am29LV010 part or AM29f010 - 16kb sector
2506854165f4Sandrew.vasquez@qlogic.com 				 * size.
2507854165f4Sandrew.vasquez@qlogic.com 				 */
2508854165f4Sandrew.vasquez@qlogic.com 				rest_addr = 0x3fff;
2509854165f4Sandrew.vasquez@qlogic.com 				sec_mask = 0x1c000;
2510854165f4Sandrew.vasquez@qlogic.com 				break;
2511854165f4Sandrew.vasquez@qlogic.com 			} else if (flash_id == 0x6d) {
2512854165f4Sandrew.vasquez@qlogic.com 				/* Am29LV001 part - 8kb sector size. */
2513854165f4Sandrew.vasquez@qlogic.com 				rest_addr = 0x1fff;
2514854165f4Sandrew.vasquez@qlogic.com 				sec_mask = 0x1e000;
2515854165f4Sandrew.vasquez@qlogic.com 				break;
2516854165f4Sandrew.vasquez@qlogic.com 			}
2517df561f66SGustavo A. R. Silva 			fallthrough;
2518854165f4Sandrew.vasquez@qlogic.com 		default:
2519854165f4Sandrew.vasquez@qlogic.com 			/* Default to 16 kb sector size. */
2520854165f4Sandrew.vasquez@qlogic.com 			rest_addr = 0x3fff;
2521854165f4Sandrew.vasquez@qlogic.com 			sec_mask = 0x1c000;
2522854165f4Sandrew.vasquez@qlogic.com 			break;
2523854165f4Sandrew.vasquez@qlogic.com 		}
2524854165f4Sandrew.vasquez@qlogic.com 
2525854165f4Sandrew.vasquez@qlogic.com update_flash:
2526854165f4Sandrew.vasquez@qlogic.com 		if (IS_QLA2322(ha) || IS_QLA6322(ha)) {
2527854165f4Sandrew.vasquez@qlogic.com 			if (qla2x00_erase_flash(ha, man_id, flash_id)) {
2528854165f4Sandrew.vasquez@qlogic.com 				rval = QLA_FUNCTION_FAILED;
2529854165f4Sandrew.vasquez@qlogic.com 				break;
2530854165f4Sandrew.vasquez@qlogic.com 			}
2531854165f4Sandrew.vasquez@qlogic.com 		}
2532854165f4Sandrew.vasquez@qlogic.com 
2533854165f4Sandrew.vasquez@qlogic.com 		for (addr = offset, liter = 0; liter < length; liter++,
2534854165f4Sandrew.vasquez@qlogic.com 		    addr++) {
25353695310eSJoe Carnuccio 			data = buf + liter;
2536854165f4Sandrew.vasquez@qlogic.com 			/* Are we at the beginning of a sector? */
2537854165f4Sandrew.vasquez@qlogic.com 			if ((addr & rest_addr) == 0) {
2538854165f4Sandrew.vasquez@qlogic.com 				if (IS_QLA2322(ha) || IS_QLA6322(ha)) {
2539854165f4Sandrew.vasquez@qlogic.com 					if (addr >= 0x10000UL) {
2540854165f4Sandrew.vasquez@qlogic.com 						if (((addr >> 12) & 0xf0) &&
2541854165f4Sandrew.vasquez@qlogic.com 						    ((man_id == 0x01 &&
2542854165f4Sandrew.vasquez@qlogic.com 							flash_id == 0x3e) ||
2543854165f4Sandrew.vasquez@qlogic.com 						     (man_id == 0x20 &&
2544854165f4Sandrew.vasquez@qlogic.com 							 flash_id == 0xd2))) {
2545854165f4Sandrew.vasquez@qlogic.com 							sec_number++;
2546854165f4Sandrew.vasquez@qlogic.com 							if (sec_number == 1) {
2547854165f4Sandrew.vasquez@qlogic.com 								rest_addr =
2548854165f4Sandrew.vasquez@qlogic.com 								    0x7fff;
2549854165f4Sandrew.vasquez@qlogic.com 								sec_mask =
2550854165f4Sandrew.vasquez@qlogic.com 								    0x18000;
2551854165f4Sandrew.vasquez@qlogic.com 							} else if (
2552854165f4Sandrew.vasquez@qlogic.com 							    sec_number == 2 ||
2553854165f4Sandrew.vasquez@qlogic.com 							    sec_number == 3) {
2554854165f4Sandrew.vasquez@qlogic.com 								rest_addr =
2555854165f4Sandrew.vasquez@qlogic.com 								    0x1fff;
2556854165f4Sandrew.vasquez@qlogic.com 								sec_mask =
2557854165f4Sandrew.vasquez@qlogic.com 								    0x1e000;
2558854165f4Sandrew.vasquez@qlogic.com 							} else if (
2559854165f4Sandrew.vasquez@qlogic.com 							    sec_number == 4) {
2560854165f4Sandrew.vasquez@qlogic.com 								rest_addr =
2561854165f4Sandrew.vasquez@qlogic.com 								    0x3fff;
2562854165f4Sandrew.vasquez@qlogic.com 								sec_mask =
2563854165f4Sandrew.vasquez@qlogic.com 								    0x1c000;
2564854165f4Sandrew.vasquez@qlogic.com 							}
2565854165f4Sandrew.vasquez@qlogic.com 						}
2566854165f4Sandrew.vasquez@qlogic.com 					}
2567854165f4Sandrew.vasquez@qlogic.com 				} else if (addr == ha->optrom_size / 2) {
256804474d3aSBart Van Assche 					wrt_reg_word(&reg->nvram, NVR_SELECT);
256904474d3aSBart Van Assche 					rd_reg_word(&reg->nvram);
2570854165f4Sandrew.vasquez@qlogic.com 				}
2571854165f4Sandrew.vasquez@qlogic.com 
2572854165f4Sandrew.vasquez@qlogic.com 				if (flash_id == 0xda && man_id == 0xc1) {
2573854165f4Sandrew.vasquez@qlogic.com 					qla2x00_write_flash_byte(ha, 0x5555,
2574854165f4Sandrew.vasquez@qlogic.com 					    0xaa);
2575854165f4Sandrew.vasquez@qlogic.com 					qla2x00_write_flash_byte(ha, 0x2aaa,
2576854165f4Sandrew.vasquez@qlogic.com 					    0x55);
2577854165f4Sandrew.vasquez@qlogic.com 					qla2x00_write_flash_byte(ha, 0x5555,
2578854165f4Sandrew.vasquez@qlogic.com 					    0xa0);
2579854165f4Sandrew.vasquez@qlogic.com 				} else if (!IS_QLA2322(ha) && !IS_QLA6322(ha)) {
2580854165f4Sandrew.vasquez@qlogic.com 					/* Then erase it */
2581854165f4Sandrew.vasquez@qlogic.com 					if (qla2x00_erase_flash_sector(ha,
2582854165f4Sandrew.vasquez@qlogic.com 					    addr, sec_mask, man_id,
2583854165f4Sandrew.vasquez@qlogic.com 					    flash_id)) {
2584854165f4Sandrew.vasquez@qlogic.com 						rval = QLA_FUNCTION_FAILED;
2585854165f4Sandrew.vasquez@qlogic.com 						break;
2586854165f4Sandrew.vasquez@qlogic.com 					}
2587854165f4Sandrew.vasquez@qlogic.com 					if (man_id == 0x01 && flash_id == 0x6d)
2588854165f4Sandrew.vasquez@qlogic.com 						sec_number++;
2589854165f4Sandrew.vasquez@qlogic.com 				}
2590854165f4Sandrew.vasquez@qlogic.com 			}
2591854165f4Sandrew.vasquez@qlogic.com 
2592854165f4Sandrew.vasquez@qlogic.com 			if (man_id == 0x01 && flash_id == 0x6d) {
2593854165f4Sandrew.vasquez@qlogic.com 				if (sec_number == 1 &&
2594854165f4Sandrew.vasquez@qlogic.com 				    addr == (rest_addr - 1)) {
2595854165f4Sandrew.vasquez@qlogic.com 					rest_addr = 0x0fff;
2596854165f4Sandrew.vasquez@qlogic.com 					sec_mask   = 0x1f000;
2597854165f4Sandrew.vasquez@qlogic.com 				} else if (sec_number == 3 && (addr & 0x7ffe)) {
2598854165f4Sandrew.vasquez@qlogic.com 					rest_addr = 0x3fff;
2599854165f4Sandrew.vasquez@qlogic.com 					sec_mask   = 0x1c000;
2600854165f4Sandrew.vasquez@qlogic.com 				}
2601854165f4Sandrew.vasquez@qlogic.com 			}
2602854165f4Sandrew.vasquez@qlogic.com 
26033695310eSJoe Carnuccio 			if (qla2x00_program_flash_address(ha, addr, *data,
2604854165f4Sandrew.vasquez@qlogic.com 			    man_id, flash_id)) {
2605854165f4Sandrew.vasquez@qlogic.com 				rval = QLA_FUNCTION_FAILED;
2606854165f4Sandrew.vasquez@qlogic.com 				break;
2607854165f4Sandrew.vasquez@qlogic.com 			}
260840a2e34aSAndrew Vasquez 			cond_resched();
2609854165f4Sandrew.vasquez@qlogic.com 		}
2610854165f4Sandrew.vasquez@qlogic.com 	} while (0);
2611854165f4Sandrew.vasquez@qlogic.com 	qla2x00_flash_disable(ha);
2612854165f4Sandrew.vasquez@qlogic.com 
2613854165f4Sandrew.vasquez@qlogic.com 	/* Resume HBA. */
26147b867cf7SAnirban Chakraborty 	qla2x00_resume_hba(vha);
2615854165f4Sandrew.vasquez@qlogic.com 
2616854165f4Sandrew.vasquez@qlogic.com 	return rval;
2617854165f4Sandrew.vasquez@qlogic.com }
2618854165f4Sandrew.vasquez@qlogic.com 
26193695310eSJoe Carnuccio void *
qla24xx_read_optrom_data(struct scsi_qla_host * vha,void * buf,uint32_t offset,uint32_t length)26203695310eSJoe Carnuccio qla24xx_read_optrom_data(struct scsi_qla_host *vha, void *buf,
2621854165f4Sandrew.vasquez@qlogic.com     uint32_t offset, uint32_t length)
2622854165f4Sandrew.vasquez@qlogic.com {
26237b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
2624*bf192b8bSQuinn Tran 	int rc;
26257b867cf7SAnirban Chakraborty 
2626854165f4Sandrew.vasquez@qlogic.com 	/* Suspend HBA. */
26277b867cf7SAnirban Chakraborty 	scsi_block_requests(vha->host);
2628854165f4Sandrew.vasquez@qlogic.com 	set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
2629854165f4Sandrew.vasquez@qlogic.com 
2630854165f4Sandrew.vasquez@qlogic.com 	/* Go with read. */
2631*bf192b8bSQuinn Tran 	rc = qla24xx_read_flash_data(vha, buf, offset >> 2, length >> 2);
2632*bf192b8bSQuinn Tran 	if (rc) {
2633*bf192b8bSQuinn Tran 		ql_log(ql_log_info, vha, 0x01a0,
2634*bf192b8bSQuinn Tran 		    "Unable to perform optrom read(%x).\n", rc);
2635*bf192b8bSQuinn Tran 	}
2636854165f4Sandrew.vasquez@qlogic.com 
2637854165f4Sandrew.vasquez@qlogic.com 	/* Resume HBA. */
2638854165f4Sandrew.vasquez@qlogic.com 	clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
26397b867cf7SAnirban Chakraborty 	scsi_unblock_requests(vha->host);
2640854165f4Sandrew.vasquez@qlogic.com 
2641854165f4Sandrew.vasquez@qlogic.com 	return buf;
2642854165f4Sandrew.vasquez@qlogic.com }
2643854165f4Sandrew.vasquez@qlogic.com 
26443f006ac3SMichael Hernandez static int
qla28xx_extract_sfub_and_verify(struct scsi_qla_host * vha,__le32 * buf,uint32_t len,uint32_t buf_size_without_sfub,uint8_t * sfub_buf)264537ce4f35SBart Van Assche qla28xx_extract_sfub_and_verify(struct scsi_qla_host *vha, __le32 *buf,
26463f006ac3SMichael Hernandez     uint32_t len, uint32_t buf_size_without_sfub, uint8_t *sfub_buf)
26473f006ac3SMichael Hernandez {
264837ce4f35SBart Van Assche 	uint32_t check_sum = 0;
264937ce4f35SBart Van Assche 	__le32 *p;
26503f006ac3SMichael Hernandez 	int i;
26513f006ac3SMichael Hernandez 
26523f006ac3SMichael Hernandez 	p = buf + buf_size_without_sfub;
26533f006ac3SMichael Hernandez 
26543f006ac3SMichael Hernandez 	/* Extract SFUB from end of file */
26553f006ac3SMichael Hernandez 	memcpy(sfub_buf, (uint8_t *)p,
26563f006ac3SMichael Hernandez 	    sizeof(struct secure_flash_update_block));
26573f006ac3SMichael Hernandez 
26583f006ac3SMichael Hernandez 	for (i = 0; i < (sizeof(struct secure_flash_update_block) >> 2); i++)
26590bc17251SArun Easi 		check_sum += le32_to_cpu(p[i]);
26603f006ac3SMichael Hernandez 
26613f006ac3SMichael Hernandez 	check_sum = (~check_sum) + 1;
26623f006ac3SMichael Hernandez 
26630bc17251SArun Easi 	if (check_sum != le32_to_cpu(p[i])) {
26643f006ac3SMichael Hernandez 		ql_log(ql_log_warn, vha, 0x7097,
26653f006ac3SMichael Hernandez 		    "SFUB checksum failed, 0x%x, 0x%x\n",
26660bc17251SArun Easi 		    check_sum, le32_to_cpu(p[i]));
26673f006ac3SMichael Hernandez 		return QLA_COMMAND_ERROR;
26683f006ac3SMichael Hernandez 	}
26693f006ac3SMichael Hernandez 
26703f006ac3SMichael Hernandez 	return QLA_SUCCESS;
26713f006ac3SMichael Hernandez }
26723f006ac3SMichael Hernandez 
26733f006ac3SMichael Hernandez static int
qla28xx_get_flash_region(struct scsi_qla_host * vha,uint32_t start,struct qla_flt_region * region)26743f006ac3SMichael Hernandez qla28xx_get_flash_region(struct scsi_qla_host *vha, uint32_t start,
26753f006ac3SMichael Hernandez     struct qla_flt_region *region)
26763f006ac3SMichael Hernandez {
26773f006ac3SMichael Hernandez 	struct qla_hw_data *ha = vha->hw;
2678a27747a2SBart Van Assche 	struct qla_flt_header *flt = ha->flt;
2679a27747a2SBart Van Assche 	struct qla_flt_region *flt_reg = &flt->region[0];
26803f006ac3SMichael Hernandez 	uint16_t cnt;
26813f006ac3SMichael Hernandez 	int rval = QLA_FUNCTION_FAILED;
26823f006ac3SMichael Hernandez 
26833f006ac3SMichael Hernandez 	if (!ha->flt)
26843f006ac3SMichael Hernandez 		return QLA_FUNCTION_FAILED;
26853f006ac3SMichael Hernandez 
26863f006ac3SMichael Hernandez 	cnt = le16_to_cpu(flt->length) / sizeof(struct qla_flt_region);
26873f006ac3SMichael Hernandez 	for (; cnt; cnt--, flt_reg++) {
26887ffa5b93SBart Van Assche 		if (le32_to_cpu(flt_reg->start) == start) {
26893f006ac3SMichael Hernandez 			memcpy((uint8_t *)region, flt_reg,
26903f006ac3SMichael Hernandez 			    sizeof(struct qla_flt_region));
26913f006ac3SMichael Hernandez 			rval = QLA_SUCCESS;
26923f006ac3SMichael Hernandez 			break;
26933f006ac3SMichael Hernandez 		}
26943f006ac3SMichael Hernandez 	}
26953f006ac3SMichael Hernandez 
26963f006ac3SMichael Hernandez 	return rval;
26973f006ac3SMichael Hernandez }
26983f006ac3SMichael Hernandez 
26993f006ac3SMichael Hernandez static int
qla28xx_write_flash_data(scsi_qla_host_t * vha,uint32_t * dwptr,uint32_t faddr,uint32_t dwords)27003f006ac3SMichael Hernandez qla28xx_write_flash_data(scsi_qla_host_t *vha, uint32_t *dwptr, uint32_t faddr,
27013f006ac3SMichael Hernandez     uint32_t dwords)
27023f006ac3SMichael Hernandez {
27033f006ac3SMichael Hernandez 	struct qla_hw_data *ha = vha->hw;
27043f006ac3SMichael Hernandez 	ulong liter;
27053f006ac3SMichael Hernandez 	ulong dburst = OPTROM_BURST_DWORDS; /* burst size in dwords */
27063f006ac3SMichael Hernandez 	uint32_t sec_mask, rest_addr, fdata;
27073f006ac3SMichael Hernandez 	void *optrom = NULL;
27083f006ac3SMichael Hernandez 	dma_addr_t optrom_dma;
27091b81e7f3SMichael Hernandez 	int rval, ret;
27103f006ac3SMichael Hernandez 	struct secure_flash_update_block *sfub;
27113f006ac3SMichael Hernandez 	dma_addr_t sfub_dma;
27123f006ac3SMichael Hernandez 	uint32_t offset = faddr << 2;
27133f006ac3SMichael Hernandez 	uint32_t buf_size_without_sfub = 0;
27143f006ac3SMichael Hernandez 	struct qla_flt_region region;
27153f006ac3SMichael Hernandez 	bool reset_to_rom = false;
27163f006ac3SMichael Hernandez 	uint32_t risc_size, risc_attr = 0;
27177ffa5b93SBart Van Assche 	__be32 *fw_array = NULL;
27183f006ac3SMichael Hernandez 
27193f006ac3SMichael Hernandez 	/* Retrieve region info - must be a start address passed in */
27203f006ac3SMichael Hernandez 	rval = qla28xx_get_flash_region(vha, offset, &region);
27213f006ac3SMichael Hernandez 
27223f006ac3SMichael Hernandez 	if (rval != QLA_SUCCESS) {
27233f006ac3SMichael Hernandez 		ql_log(ql_log_warn, vha, 0xffff,
27243f006ac3SMichael Hernandez 		    "Invalid address %x - not a region start address\n",
27253f006ac3SMichael Hernandez 		    offset);
27263f006ac3SMichael Hernandez 		goto done;
27273f006ac3SMichael Hernandez 	}
27283f006ac3SMichael Hernandez 
27293f006ac3SMichael Hernandez 	/* Allocate dma buffer for burst write */
27303f006ac3SMichael Hernandez 	optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
27313f006ac3SMichael Hernandez 	    &optrom_dma, GFP_KERNEL);
27323f006ac3SMichael Hernandez 	if (!optrom) {
27333f006ac3SMichael Hernandez 		ql_log(ql_log_warn, vha, 0x7095,
27343f006ac3SMichael Hernandez 		    "Failed allocate burst (%x bytes)\n", OPTROM_BURST_SIZE);
27353f006ac3SMichael Hernandez 		rval = QLA_COMMAND_ERROR;
27363f006ac3SMichael Hernandez 		goto done;
27373f006ac3SMichael Hernandez 	}
27383f006ac3SMichael Hernandez 
27393f006ac3SMichael Hernandez 	/*
27403f006ac3SMichael Hernandez 	 * If adapter supports secure flash and region is secure
27413f006ac3SMichael Hernandez 	 * extract secure flash update block (SFUB) and verify
27423f006ac3SMichael Hernandez 	 */
27433f006ac3SMichael Hernandez 	if (ha->flags.secure_adapter && region.attribute) {
27443f006ac3SMichael Hernandez 
27453f006ac3SMichael Hernandez 		ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
27460bc17251SArun Easi 		    "Region %x is secure\n", le16_to_cpu(region.code));
27473f006ac3SMichael Hernandez 
27487ffa5b93SBart Van Assche 		switch (le16_to_cpu(region.code)) {
2749a530bf69SMichael Hernandez 		case FLT_REG_FW:
2750a530bf69SMichael Hernandez 		case FLT_REG_FW_SEC_27XX:
2751a530bf69SMichael Hernandez 		case FLT_REG_MPI_PRI_28XX:
2752a530bf69SMichael Hernandez 		case FLT_REG_MPI_SEC_28XX:
27537ffa5b93SBart Van Assche 			fw_array = (__force __be32 *)dwptr;
27543f006ac3SMichael Hernandez 
27553f006ac3SMichael Hernandez 			/* 1st fw array */
27563f006ac3SMichael Hernandez 			risc_size = be32_to_cpu(fw_array[3]);
27573f006ac3SMichael Hernandez 			risc_attr = be32_to_cpu(fw_array[9]);
27583f006ac3SMichael Hernandez 
27593f006ac3SMichael Hernandez 			buf_size_without_sfub = risc_size;
27603f006ac3SMichael Hernandez 			fw_array += risc_size;
27613f006ac3SMichael Hernandez 
27623f006ac3SMichael Hernandez 			/* 2nd fw array */
27633f006ac3SMichael Hernandez 			risc_size = be32_to_cpu(fw_array[3]);
27643f006ac3SMichael Hernandez 
27653f006ac3SMichael Hernandez 			buf_size_without_sfub += risc_size;
27663f006ac3SMichael Hernandez 			fw_array += risc_size;
27673f006ac3SMichael Hernandez 
27683f006ac3SMichael Hernandez 			/* 1st dump template */
27693f006ac3SMichael Hernandez 			risc_size = be32_to_cpu(fw_array[2]);
27703f006ac3SMichael Hernandez 
27713f006ac3SMichael Hernandez 			/* skip header and ignore checksum */
27723f006ac3SMichael Hernandez 			buf_size_without_sfub += risc_size;
27733f006ac3SMichael Hernandez 			fw_array += risc_size;
27743f006ac3SMichael Hernandez 
27753f006ac3SMichael Hernandez 			if (risc_attr & BIT_9) {
27763f006ac3SMichael Hernandez 				/* 2nd dump template */
27773f006ac3SMichael Hernandez 				risc_size = be32_to_cpu(fw_array[2]);
27783f006ac3SMichael Hernandez 
27793f006ac3SMichael Hernandez 				/* skip header and ignore checksum */
27803f006ac3SMichael Hernandez 				buf_size_without_sfub += risc_size;
27813f006ac3SMichael Hernandez 				fw_array += risc_size;
27823f006ac3SMichael Hernandez 			}
2783a530bf69SMichael Hernandez 			break;
2784a530bf69SMichael Hernandez 
2785a530bf69SMichael Hernandez 		case FLT_REG_PEP_PRI_28XX:
2786a530bf69SMichael Hernandez 		case FLT_REG_PEP_SEC_28XX:
27877ffa5b93SBart Van Assche 			fw_array = (__force __be32 *)dwptr;
2788a530bf69SMichael Hernandez 
2789a530bf69SMichael Hernandez 			/* 1st fw array */
2790a530bf69SMichael Hernandez 			risc_size = be32_to_cpu(fw_array[3]);
2791a530bf69SMichael Hernandez 			risc_attr = be32_to_cpu(fw_array[9]);
2792a530bf69SMichael Hernandez 
2793a530bf69SMichael Hernandez 			buf_size_without_sfub = risc_size;
2794a530bf69SMichael Hernandez 			fw_array += risc_size;
2795a530bf69SMichael Hernandez 			break;
2796a530bf69SMichael Hernandez 
2797a530bf69SMichael Hernandez 		default:
2798a530bf69SMichael Hernandez 			ql_log(ql_log_warn + ql_dbg_verbose, vha,
2799a530bf69SMichael Hernandez 			    0xffff, "Secure region %x not supported\n",
28000bc17251SArun Easi 			    le16_to_cpu(region.code));
28013f006ac3SMichael Hernandez 			rval = QLA_COMMAND_ERROR;
28023f006ac3SMichael Hernandez 			goto done;
28033f006ac3SMichael Hernandez 		}
28043f006ac3SMichael Hernandez 
28053f006ac3SMichael Hernandez 		sfub = dma_alloc_coherent(&ha->pdev->dev,
28063f006ac3SMichael Hernandez 			sizeof(struct secure_flash_update_block), &sfub_dma,
28073f006ac3SMichael Hernandez 			GFP_KERNEL);
28083f006ac3SMichael Hernandez 		if (!sfub) {
28093f006ac3SMichael Hernandez 			ql_log(ql_log_warn, vha, 0xffff,
28103f006ac3SMichael Hernandez 			    "Unable to allocate memory for SFUB\n");
28113f006ac3SMichael Hernandez 			rval = QLA_COMMAND_ERROR;
28123f006ac3SMichael Hernandez 			goto done;
28133f006ac3SMichael Hernandez 		}
28143f006ac3SMichael Hernandez 
281537ce4f35SBart Van Assche 		rval = qla28xx_extract_sfub_and_verify(vha, (__le32 *)dwptr,
281637ce4f35SBart Van Assche 			dwords, buf_size_without_sfub, (uint8_t *)sfub);
28173f006ac3SMichael Hernandez 
28183f006ac3SMichael Hernandez 		if (rval != QLA_SUCCESS)
28193f006ac3SMichael Hernandez 			goto done;
28203f006ac3SMichael Hernandez 
28213f006ac3SMichael Hernandez 		ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
28223f006ac3SMichael Hernandez 		    "SFUB extract and verify successful\n");
28233f006ac3SMichael Hernandez 	}
28243f006ac3SMichael Hernandez 
28253f006ac3SMichael Hernandez 	rest_addr = (ha->fdt_block_size >> 2) - 1;
28263f006ac3SMichael Hernandez 	sec_mask = ~rest_addr;
28273f006ac3SMichael Hernandez 
28283f006ac3SMichael Hernandez 	/* Lock semaphore */
28293f006ac3SMichael Hernandez 	rval = qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_LOCK);
28303f006ac3SMichael Hernandez 	if (rval != QLA_SUCCESS) {
28313f006ac3SMichael Hernandez 		ql_log(ql_log_warn, vha, 0xffff,
28323f006ac3SMichael Hernandez 		    "Unable to lock flash semaphore.");
28333f006ac3SMichael Hernandez 		goto done;
28343f006ac3SMichael Hernandez 	}
28353f006ac3SMichael Hernandez 
28363f006ac3SMichael Hernandez 	ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
28373f006ac3SMichael Hernandez 	    "Unprotect flash...\n");
28383f006ac3SMichael Hernandez 	rval = qla24xx_unprotect_flash(vha);
28393f006ac3SMichael Hernandez 	if (rval) {
28403f006ac3SMichael Hernandez 		qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_UNLOCK);
28413f006ac3SMichael Hernandez 		ql_log(ql_log_warn, vha, 0x7096, "Failed unprotect flash\n");
28423f006ac3SMichael Hernandez 		goto done;
28433f006ac3SMichael Hernandez 	}
28443f006ac3SMichael Hernandez 
28453f006ac3SMichael Hernandez 	for (liter = 0; liter < dwords; liter++, faddr++) {
28463f006ac3SMichael Hernandez 		fdata = (faddr & sec_mask) << 2;
28473f006ac3SMichael Hernandez 
28483f006ac3SMichael Hernandez 		/* If start of sector */
28493f006ac3SMichael Hernandez 		if (!(faddr & rest_addr)) {
28503f006ac3SMichael Hernandez 			ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
28513f006ac3SMichael Hernandez 			    "Erase sector %#x...\n", faddr);
28523f006ac3SMichael Hernandez 			rval = qla24xx_erase_sector(vha, fdata);
28533f006ac3SMichael Hernandez 			if (rval) {
28543f006ac3SMichael Hernandez 				ql_dbg(ql_dbg_user, vha, 0x7007,
28553f006ac3SMichael Hernandez 				    "Failed erase sector %#x\n", faddr);
28563f006ac3SMichael Hernandez 				goto write_protect;
28573f006ac3SMichael Hernandez 			}
28583f006ac3SMichael Hernandez 		}
28593f006ac3SMichael Hernandez 	}
28603f006ac3SMichael Hernandez 
28613f006ac3SMichael Hernandez 	if (ha->flags.secure_adapter) {
28623f006ac3SMichael Hernandez 		/*
28633f006ac3SMichael Hernandez 		 * If adapter supports secure flash but FW doesn't,
28643f006ac3SMichael Hernandez 		 * disable write protect, release semaphore and reset
28653f006ac3SMichael Hernandez 		 * chip to execute ROM code in order to update region securely
28663f006ac3SMichael Hernandez 		 */
28673f006ac3SMichael Hernandez 		if (!ha->flags.secure_fw) {
28683f006ac3SMichael Hernandez 			ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
28693f006ac3SMichael Hernandez 			    "Disable Write and Release Semaphore.");
28703f006ac3SMichael Hernandez 			rval = qla24xx_protect_flash(vha);
28713f006ac3SMichael Hernandez 			if (rval != QLA_SUCCESS) {
28723f006ac3SMichael Hernandez 				qla81xx_fac_semaphore_access(vha,
28733f006ac3SMichael Hernandez 					FAC_SEMAPHORE_UNLOCK);
28743f006ac3SMichael Hernandez 				ql_log(ql_log_warn, vha, 0xffff,
28753f006ac3SMichael Hernandez 				    "Unable to protect flash.");
28763f006ac3SMichael Hernandez 				goto done;
28773f006ac3SMichael Hernandez 			}
28783f006ac3SMichael Hernandez 
28793f006ac3SMichael Hernandez 			ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
28803f006ac3SMichael Hernandez 			    "Reset chip to ROM.");
28813f006ac3SMichael Hernandez 			set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
28823f006ac3SMichael Hernandez 			set_bit(ISP_ABORT_TO_ROM, &vha->dpc_flags);
28833f006ac3SMichael Hernandez 			qla2xxx_wake_dpc(vha);
28843f006ac3SMichael Hernandez 			rval = qla2x00_wait_for_chip_reset(vha);
28853f006ac3SMichael Hernandez 			if (rval != QLA_SUCCESS) {
28863f006ac3SMichael Hernandez 				ql_log(ql_log_warn, vha, 0xffff,
28873f006ac3SMichael Hernandez 				    "Unable to reset to ROM code.");
28883f006ac3SMichael Hernandez 				goto done;
28893f006ac3SMichael Hernandez 			}
28903f006ac3SMichael Hernandez 			reset_to_rom = true;
28913f006ac3SMichael Hernandez 			ha->flags.fac_supported = 0;
28923f006ac3SMichael Hernandez 
28933f006ac3SMichael Hernandez 			ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
28943f006ac3SMichael Hernandez 			    "Lock Semaphore");
28953f006ac3SMichael Hernandez 			rval = qla2xxx_write_remote_register(vha,
28963f006ac3SMichael Hernandez 			    FLASH_SEMAPHORE_REGISTER_ADDR, 0x00020002);
28973f006ac3SMichael Hernandez 			if (rval != QLA_SUCCESS) {
28983f006ac3SMichael Hernandez 				ql_log(ql_log_warn, vha, 0xffff,
28993f006ac3SMichael Hernandez 				    "Unable to lock flash semaphore.");
29003f006ac3SMichael Hernandez 				goto done;
29013f006ac3SMichael Hernandez 			}
29023f006ac3SMichael Hernandez 
29033f006ac3SMichael Hernandez 			/* Unprotect flash */
29043f006ac3SMichael Hernandez 			ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
29053f006ac3SMichael Hernandez 			    "Enable Write.");
29063f006ac3SMichael Hernandez 			rval = qla2x00_write_ram_word(vha, 0x7ffd0101, 0);
29073f006ac3SMichael Hernandez 			if (rval) {
29083f006ac3SMichael Hernandez 				ql_log(ql_log_warn, vha, 0x7096,
29093f006ac3SMichael Hernandez 				    "Failed unprotect flash\n");
29103f006ac3SMichael Hernandez 				goto done;
29113f006ac3SMichael Hernandez 			}
29123f006ac3SMichael Hernandez 		}
29133f006ac3SMichael Hernandez 
29143f006ac3SMichael Hernandez 		/* If region is secure, send Secure Flash MB Cmd */
29153f006ac3SMichael Hernandez 		if (region.attribute && buf_size_without_sfub) {
29163f006ac3SMichael Hernandez 			ql_log(ql_log_warn + ql_dbg_verbose, vha, 0xffff,
29173f006ac3SMichael Hernandez 			    "Sending Secure Flash MB Cmd\n");
29187ffa5b93SBart Van Assche 			rval = qla28xx_secure_flash_update(vha, 0,
29197ffa5b93SBart Van Assche 				le16_to_cpu(region.code),
29203f006ac3SMichael Hernandez 				buf_size_without_sfub, sfub_dma,
2921c868907eSMichael Hernandez 				sizeof(struct secure_flash_update_block) >> 2);
29223f006ac3SMichael Hernandez 			if (rval != QLA_SUCCESS) {
29233f006ac3SMichael Hernandez 				ql_log(ql_log_warn, vha, 0xffff,
29243f006ac3SMichael Hernandez 				    "Secure Flash MB Cmd failed %x.", rval);
29253f006ac3SMichael Hernandez 				goto write_protect;
29263f006ac3SMichael Hernandez 			}
29273f006ac3SMichael Hernandez 		}
29283f006ac3SMichael Hernandez 
29293f006ac3SMichael Hernandez 	}
29303f006ac3SMichael Hernandez 
29313f006ac3SMichael Hernandez 	/* re-init flash offset */
29323f006ac3SMichael Hernandez 	faddr = offset >> 2;
29333f006ac3SMichael Hernandez 
29343f006ac3SMichael Hernandez 	for (liter = 0; liter < dwords; liter++, faddr++, dwptr++) {
29353f006ac3SMichael Hernandez 		fdata = (faddr & sec_mask) << 2;
29363f006ac3SMichael Hernandez 
29373f006ac3SMichael Hernandez 		/* If smaller than a burst remaining */
29383f006ac3SMichael Hernandez 		if (dwords - liter < dburst)
29393f006ac3SMichael Hernandez 			dburst = dwords - liter;
29403f006ac3SMichael Hernandez 
29413f006ac3SMichael Hernandez 		/* Copy to dma buffer */
29423f006ac3SMichael Hernandez 		memcpy(optrom, dwptr, dburst << 2);
29433f006ac3SMichael Hernandez 
29443f006ac3SMichael Hernandez 		/* Burst write */
29453f006ac3SMichael Hernandez 		ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
29463f006ac3SMichael Hernandez 		    "Write burst (%#lx dwords)...\n", dburst);
29473f006ac3SMichael Hernandez 		rval = qla2x00_load_ram(vha, optrom_dma,
29483f006ac3SMichael Hernandez 		    flash_data_addr(ha, faddr), dburst);
29493f006ac3SMichael Hernandez 		if (rval != QLA_SUCCESS) {
29503f006ac3SMichael Hernandez 			ql_log(ql_log_warn, vha, 0x7097,
29513f006ac3SMichael Hernandez 			    "Failed burst write at %x (%p/%#llx)...\n",
29523f006ac3SMichael Hernandez 			    flash_data_addr(ha, faddr), optrom,
29533f006ac3SMichael Hernandez 			    (u64)optrom_dma);
29543f006ac3SMichael Hernandez 			break;
29553f006ac3SMichael Hernandez 		}
29563f006ac3SMichael Hernandez 
29573f006ac3SMichael Hernandez 		liter += dburst - 1;
29583f006ac3SMichael Hernandez 		faddr += dburst - 1;
29593f006ac3SMichael Hernandez 		dwptr += dburst - 1;
29603f006ac3SMichael Hernandez 	}
29613f006ac3SMichael Hernandez 
29623f006ac3SMichael Hernandez write_protect:
29633f006ac3SMichael Hernandez 	ql_log(ql_log_warn + ql_dbg_verbose, vha, 0x7095,
29643f006ac3SMichael Hernandez 	    "Protect flash...\n");
29651b81e7f3SMichael Hernandez 	ret = qla24xx_protect_flash(vha);
29661b81e7f3SMichael Hernandez 	if (ret) {
29673f006ac3SMichael Hernandez 		qla81xx_fac_semaphore_access(vha, FAC_SEMAPHORE_UNLOCK);
29683f006ac3SMichael Hernandez 		ql_log(ql_log_warn, vha, 0x7099,
29693f006ac3SMichael Hernandez 		    "Failed protect flash\n");
29701b81e7f3SMichael Hernandez 		rval = QLA_COMMAND_ERROR;
29713f006ac3SMichael Hernandez 	}
29723f006ac3SMichael Hernandez 
29733f006ac3SMichael Hernandez 	if (reset_to_rom == true) {
29743f006ac3SMichael Hernandez 		/* Schedule DPC to restart the RISC */
29753f006ac3SMichael Hernandez 		set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
29763f006ac3SMichael Hernandez 		qla2xxx_wake_dpc(vha);
29773f006ac3SMichael Hernandez 
29781b81e7f3SMichael Hernandez 		ret = qla2x00_wait_for_hba_online(vha);
29791b81e7f3SMichael Hernandez 		if (ret != QLA_SUCCESS) {
29803f006ac3SMichael Hernandez 			ql_log(ql_log_warn, vha, 0xffff,
29813f006ac3SMichael Hernandez 			    "Adapter did not come out of reset\n");
29821b81e7f3SMichael Hernandez 			rval = QLA_COMMAND_ERROR;
29831b81e7f3SMichael Hernandez 		}
29843f006ac3SMichael Hernandez 	}
29853f006ac3SMichael Hernandez 
29863f006ac3SMichael Hernandez done:
29873f006ac3SMichael Hernandez 	if (optrom)
29883f006ac3SMichael Hernandez 		dma_free_coherent(&ha->pdev->dev,
29893f006ac3SMichael Hernandez 		    OPTROM_BURST_SIZE, optrom, optrom_dma);
29903f006ac3SMichael Hernandez 
29913f006ac3SMichael Hernandez 	return rval;
29923f006ac3SMichael Hernandez }
29933f006ac3SMichael Hernandez 
2994854165f4Sandrew.vasquez@qlogic.com int
qla24xx_write_optrom_data(struct scsi_qla_host * vha,void * buf,uint32_t offset,uint32_t length)29953695310eSJoe Carnuccio qla24xx_write_optrom_data(struct scsi_qla_host *vha, void *buf,
2996854165f4Sandrew.vasquez@qlogic.com     uint32_t offset, uint32_t length)
2997854165f4Sandrew.vasquez@qlogic.com {
2998854165f4Sandrew.vasquez@qlogic.com 	int rval;
29997b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
3000854165f4Sandrew.vasquez@qlogic.com 
3001854165f4Sandrew.vasquez@qlogic.com 	/* Suspend HBA. */
30027b867cf7SAnirban Chakraborty 	scsi_block_requests(vha->host);
3003854165f4Sandrew.vasquez@qlogic.com 	set_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
3004854165f4Sandrew.vasquez@qlogic.com 
3005854165f4Sandrew.vasquez@qlogic.com 	/* Go with write. */
30063f006ac3SMichael Hernandez 	if (IS_QLA28XX(ha))
30077ffa5b93SBart Van Assche 		rval = qla28xx_write_flash_data(vha, buf, offset >> 2,
30087ffa5b93SBart Van Assche 						length >> 2);
30093f006ac3SMichael Hernandez 	else
30107ffa5b93SBart Van Assche 		rval = qla24xx_write_flash_data(vha, buf, offset >> 2,
30117ffa5b93SBart Van Assche 						length >> 2);
3012854165f4Sandrew.vasquez@qlogic.com 
3013854165f4Sandrew.vasquez@qlogic.com 	clear_bit(MBX_UPDATE_FLASH_ACTIVE, &ha->mbx_cmd_flags);
30147b867cf7SAnirban Chakraborty 	scsi_unblock_requests(vha->host);
3015854165f4Sandrew.vasquez@qlogic.com 
3016854165f4Sandrew.vasquez@qlogic.com 	return rval;
3017854165f4Sandrew.vasquez@qlogic.com }
301830c47662SAndrew Vasquez 
30193695310eSJoe Carnuccio void *
qla25xx_read_optrom_data(struct scsi_qla_host * vha,void * buf,uint32_t offset,uint32_t length)30203695310eSJoe Carnuccio qla25xx_read_optrom_data(struct scsi_qla_host *vha, void *buf,
3021338c9161SAndrew Vasquez     uint32_t offset, uint32_t length)
3022338c9161SAndrew Vasquez {
3023338c9161SAndrew Vasquez 	int rval;
3024338c9161SAndrew Vasquez 	dma_addr_t optrom_dma;
3025338c9161SAndrew Vasquez 	void *optrom;
3026338c9161SAndrew Vasquez 	uint8_t *pbuf;
3027338c9161SAndrew Vasquez 	uint32_t faddr, left, burst;
30287b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
3029338c9161SAndrew Vasquez 
3030420854b3SChad Dupuis 	if (IS_QLA25XX(ha) || IS_QLA81XX(ha) || IS_QLA83XX(ha) ||
3031ecc89f25SJoe Carnuccio 	    IS_QLA27XX(ha) || IS_QLA28XX(ha))
3032368bbe07SAndrew Vasquez 		goto try_fast;
3033b7cc176cSJoe Carnuccio 	if (offset & 0xfff)
3034338c9161SAndrew Vasquez 		goto slow_read;
3035338c9161SAndrew Vasquez 	if (length < OPTROM_BURST_SIZE)
3036338c9161SAndrew Vasquez 		goto slow_read;
3037338c9161SAndrew Vasquez 
3038368bbe07SAndrew Vasquez try_fast:
3039a28d9e4eSJoe Carnuccio 	if (offset & 0xff)
3040a28d9e4eSJoe Carnuccio 		goto slow_read;
3041338c9161SAndrew Vasquez 	optrom = dma_alloc_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
3042338c9161SAndrew Vasquez 	    &optrom_dma, GFP_KERNEL);
3043338c9161SAndrew Vasquez 	if (!optrom) {
30447c3df132SSaurav Kashyap 		ql_log(ql_log_warn, vha, 0x00cc,
30457c3df132SSaurav Kashyap 		    "Unable to allocate memory for optrom burst read (%x KB).\n",
30467c3df132SSaurav Kashyap 		    OPTROM_BURST_SIZE / 1024);
3047338c9161SAndrew Vasquez 		goto slow_read;
3048338c9161SAndrew Vasquez 	}
3049338c9161SAndrew Vasquez 
3050338c9161SAndrew Vasquez 	pbuf = buf;
3051338c9161SAndrew Vasquez 	faddr = offset >> 2;
3052338c9161SAndrew Vasquez 	left = length >> 2;
3053338c9161SAndrew Vasquez 	burst = OPTROM_BURST_DWORDS;
3054338c9161SAndrew Vasquez 	while (left != 0) {
3055338c9161SAndrew Vasquez 		if (burst > left)
3056338c9161SAndrew Vasquez 			burst = left;
3057338c9161SAndrew Vasquez 
30587b867cf7SAnirban Chakraborty 		rval = qla2x00_dump_ram(vha, optrom_dma,
30593a03eb79SAndrew Vasquez 		    flash_data_addr(ha, faddr), burst);
3060338c9161SAndrew Vasquez 		if (rval) {
30617c3df132SSaurav Kashyap 			ql_log(ql_log_warn, vha, 0x00f5,
30627c3df132SSaurav Kashyap 			    "Unable to burst-read optrom segment (%x/%x/%llx).\n",
30637c3df132SSaurav Kashyap 			    rval, flash_data_addr(ha, faddr),
3064875baf3cSAndrew Morton 			    (unsigned long long)optrom_dma);
30657c3df132SSaurav Kashyap 			ql_log(ql_log_warn, vha, 0x00f6,
3066338c9161SAndrew Vasquez 			    "Reverting to slow-read.\n");
3067338c9161SAndrew Vasquez 
3068338c9161SAndrew Vasquez 			dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE,
3069338c9161SAndrew Vasquez 			    optrom, optrom_dma);
3070338c9161SAndrew Vasquez 			goto slow_read;
3071338c9161SAndrew Vasquez 		}
3072338c9161SAndrew Vasquez 
3073338c9161SAndrew Vasquez 		memcpy(pbuf, optrom, burst * 4);
3074338c9161SAndrew Vasquez 
3075338c9161SAndrew Vasquez 		left -= burst;
3076338c9161SAndrew Vasquez 		faddr += burst;
3077338c9161SAndrew Vasquez 		pbuf += burst * 4;
3078338c9161SAndrew Vasquez 	}
3079338c9161SAndrew Vasquez 
3080338c9161SAndrew Vasquez 	dma_free_coherent(&ha->pdev->dev, OPTROM_BURST_SIZE, optrom,
3081338c9161SAndrew Vasquez 	    optrom_dma);
3082338c9161SAndrew Vasquez 
3083338c9161SAndrew Vasquez 	return buf;
3084338c9161SAndrew Vasquez 
3085338c9161SAndrew Vasquez slow_read:
30867b867cf7SAnirban Chakraborty     return qla24xx_read_optrom_data(vha, buf, offset, length);
3087338c9161SAndrew Vasquez }
3088338c9161SAndrew Vasquez 
308930c47662SAndrew Vasquez /**
309030c47662SAndrew Vasquez  * qla2x00_get_fcode_version() - Determine an FCODE image's version.
309130c47662SAndrew Vasquez  * @ha: HA context
309230c47662SAndrew Vasquez  * @pcids: Pointer to the FCODE PCI data structure
309330c47662SAndrew Vasquez  *
309430c47662SAndrew Vasquez  * The process of retrieving the FCODE version information is at best
309530c47662SAndrew Vasquez  * described as interesting.
309630c47662SAndrew Vasquez  *
309730c47662SAndrew Vasquez  * Within the first 100h bytes of the image an ASCII string is present
309830c47662SAndrew Vasquez  * which contains several pieces of information including the FCODE
309930c47662SAndrew Vasquez  * version.  Unfortunately it seems the only reliable way to retrieve
310030c47662SAndrew Vasquez  * the version is by scanning for another sentinel within the string,
310130c47662SAndrew Vasquez  * the FCODE build date:
310230c47662SAndrew Vasquez  *
310330c47662SAndrew Vasquez  *	... 2.00.02 10/17/02 ...
310430c47662SAndrew Vasquez  *
310530c47662SAndrew Vasquez  * Returns QLA_SUCCESS on successful retrieval of version.
310630c47662SAndrew Vasquez  */
310730c47662SAndrew Vasquez static void
qla2x00_get_fcode_version(struct qla_hw_data * ha,uint32_t pcids)31087b867cf7SAnirban Chakraborty qla2x00_get_fcode_version(struct qla_hw_data *ha, uint32_t pcids)
310930c47662SAndrew Vasquez {
311030c47662SAndrew Vasquez 	int ret = QLA_FUNCTION_FAILED;
311130c47662SAndrew Vasquez 	uint32_t istart, iend, iter, vend;
311230c47662SAndrew Vasquez 	uint8_t do_next, rbyte, *vbyte;
311330c47662SAndrew Vasquez 
311430c47662SAndrew Vasquez 	memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
311530c47662SAndrew Vasquez 
311630c47662SAndrew Vasquez 	/* Skip the PCI data structure. */
311730c47662SAndrew Vasquez 	istart = pcids +
311830c47662SAndrew Vasquez 	    ((qla2x00_read_flash_byte(ha, pcids + 0x0B) << 8) |
311930c47662SAndrew Vasquez 		qla2x00_read_flash_byte(ha, pcids + 0x0A));
312030c47662SAndrew Vasquez 	iend = istart + 0x100;
312130c47662SAndrew Vasquez 	do {
312230c47662SAndrew Vasquez 		/* Scan for the sentinel date string...eeewww. */
312330c47662SAndrew Vasquez 		do_next = 0;
312430c47662SAndrew Vasquez 		iter = istart;
312530c47662SAndrew Vasquez 		while ((iter < iend) && !do_next) {
312630c47662SAndrew Vasquez 			iter++;
312730c47662SAndrew Vasquez 			if (qla2x00_read_flash_byte(ha, iter) == '/') {
312830c47662SAndrew Vasquez 				if (qla2x00_read_flash_byte(ha, iter + 2) ==
312930c47662SAndrew Vasquez 				    '/')
313030c47662SAndrew Vasquez 					do_next++;
313130c47662SAndrew Vasquez 				else if (qla2x00_read_flash_byte(ha,
313230c47662SAndrew Vasquez 				    iter + 3) == '/')
313330c47662SAndrew Vasquez 					do_next++;
313430c47662SAndrew Vasquez 			}
313530c47662SAndrew Vasquez 		}
313630c47662SAndrew Vasquez 		if (!do_next)
313730c47662SAndrew Vasquez 			break;
313830c47662SAndrew Vasquez 
313930c47662SAndrew Vasquez 		/* Backtrack to previous ' ' (space). */
314030c47662SAndrew Vasquez 		do_next = 0;
314130c47662SAndrew Vasquez 		while ((iter > istart) && !do_next) {
314230c47662SAndrew Vasquez 			iter--;
314330c47662SAndrew Vasquez 			if (qla2x00_read_flash_byte(ha, iter) == ' ')
314430c47662SAndrew Vasquez 				do_next++;
314530c47662SAndrew Vasquez 		}
314630c47662SAndrew Vasquez 		if (!do_next)
314730c47662SAndrew Vasquez 			break;
314830c47662SAndrew Vasquez 
314930c47662SAndrew Vasquez 		/*
315030c47662SAndrew Vasquez 		 * Mark end of version tag, and find previous ' ' (space) or
315130c47662SAndrew Vasquez 		 * string length (recent FCODE images -- major hack ahead!!!).
315230c47662SAndrew Vasquez 		 */
315330c47662SAndrew Vasquez 		vend = iter - 1;
315430c47662SAndrew Vasquez 		do_next = 0;
315530c47662SAndrew Vasquez 		while ((iter > istart) && !do_next) {
315630c47662SAndrew Vasquez 			iter--;
315730c47662SAndrew Vasquez 			rbyte = qla2x00_read_flash_byte(ha, iter);
315830c47662SAndrew Vasquez 			if (rbyte == ' ' || rbyte == 0xd || rbyte == 0x10)
315930c47662SAndrew Vasquez 				do_next++;
316030c47662SAndrew Vasquez 		}
316130c47662SAndrew Vasquez 		if (!do_next)
316230c47662SAndrew Vasquez 			break;
316330c47662SAndrew Vasquez 
316430c47662SAndrew Vasquez 		/* Mark beginning of version tag, and copy data. */
316530c47662SAndrew Vasquez 		iter++;
316630c47662SAndrew Vasquez 		if ((vend - iter) &&
316730c47662SAndrew Vasquez 		    ((vend - iter) < sizeof(ha->fcode_revision))) {
316830c47662SAndrew Vasquez 			vbyte = ha->fcode_revision;
316930c47662SAndrew Vasquez 			while (iter <= vend) {
317030c47662SAndrew Vasquez 				*vbyte++ = qla2x00_read_flash_byte(ha, iter);
317130c47662SAndrew Vasquez 				iter++;
317230c47662SAndrew Vasquez 			}
317330c47662SAndrew Vasquez 			ret = QLA_SUCCESS;
317430c47662SAndrew Vasquez 		}
317530c47662SAndrew Vasquez 	} while (0);
317630c47662SAndrew Vasquez 
317730c47662SAndrew Vasquez 	if (ret != QLA_SUCCESS)
317830c47662SAndrew Vasquez 		memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
317930c47662SAndrew Vasquez }
318030c47662SAndrew Vasquez 
318130c47662SAndrew Vasquez int
qla2x00_get_flash_version(scsi_qla_host_t * vha,void * mbuf)31827b867cf7SAnirban Chakraborty qla2x00_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
318330c47662SAndrew Vasquez {
318430c47662SAndrew Vasquez 	int ret = QLA_SUCCESS;
318530c47662SAndrew Vasquez 	uint8_t code_type, last_image;
318630c47662SAndrew Vasquez 	uint32_t pcihdr, pcids;
318730c47662SAndrew Vasquez 	uint8_t *dbyte;
318830c47662SAndrew Vasquez 	uint16_t *dcode;
31897b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
319030c47662SAndrew Vasquez 
319130c47662SAndrew Vasquez 	if (!ha->pio_address || !mbuf)
319230c47662SAndrew Vasquez 		return QLA_FUNCTION_FAILED;
319330c47662SAndrew Vasquez 
319430c47662SAndrew Vasquez 	memset(ha->bios_revision, 0, sizeof(ha->bios_revision));
319530c47662SAndrew Vasquez 	memset(ha->efi_revision, 0, sizeof(ha->efi_revision));
319630c47662SAndrew Vasquez 	memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
319730c47662SAndrew Vasquez 	memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
319830c47662SAndrew Vasquez 
319930c47662SAndrew Vasquez 	qla2x00_flash_enable(ha);
320030c47662SAndrew Vasquez 
320130c47662SAndrew Vasquez 	/* Begin with first PCI expansion ROM header. */
320230c47662SAndrew Vasquez 	pcihdr = 0;
320330c47662SAndrew Vasquez 	last_image = 1;
320430c47662SAndrew Vasquez 	do {
320530c47662SAndrew Vasquez 		/* Verify PCI expansion ROM header. */
320630c47662SAndrew Vasquez 		if (qla2x00_read_flash_byte(ha, pcihdr) != 0x55 ||
320730c47662SAndrew Vasquez 		    qla2x00_read_flash_byte(ha, pcihdr + 0x01) != 0xaa) {
320830c47662SAndrew Vasquez 			/* No signature */
32097c3df132SSaurav Kashyap 			ql_log(ql_log_fatal, vha, 0x0050,
32107c3df132SSaurav Kashyap 			    "No matching ROM signature.\n");
321130c47662SAndrew Vasquez 			ret = QLA_FUNCTION_FAILED;
321230c47662SAndrew Vasquez 			break;
321330c47662SAndrew Vasquez 		}
321430c47662SAndrew Vasquez 
321530c47662SAndrew Vasquez 		/* Locate PCI data structure. */
321630c47662SAndrew Vasquez 		pcids = pcihdr +
321730c47662SAndrew Vasquez 		    ((qla2x00_read_flash_byte(ha, pcihdr + 0x19) << 8) |
321830c47662SAndrew Vasquez 			qla2x00_read_flash_byte(ha, pcihdr + 0x18));
321930c47662SAndrew Vasquez 
322030c47662SAndrew Vasquez 		/* Validate signature of PCI data structure. */
322130c47662SAndrew Vasquez 		if (qla2x00_read_flash_byte(ha, pcids) != 'P' ||
322230c47662SAndrew Vasquez 		    qla2x00_read_flash_byte(ha, pcids + 0x1) != 'C' ||
322330c47662SAndrew Vasquez 		    qla2x00_read_flash_byte(ha, pcids + 0x2) != 'I' ||
322430c47662SAndrew Vasquez 		    qla2x00_read_flash_byte(ha, pcids + 0x3) != 'R') {
322530c47662SAndrew Vasquez 			/* Incorrect header. */
32267c3df132SSaurav Kashyap 			ql_log(ql_log_fatal, vha, 0x0051,
32277c3df132SSaurav Kashyap 			    "PCI data struct not found pcir_adr=%x.\n", pcids);
322830c47662SAndrew Vasquez 			ret = QLA_FUNCTION_FAILED;
322930c47662SAndrew Vasquez 			break;
323030c47662SAndrew Vasquez 		}
323130c47662SAndrew Vasquez 
323230c47662SAndrew Vasquez 		/* Read version */
323330c47662SAndrew Vasquez 		code_type = qla2x00_read_flash_byte(ha, pcids + 0x14);
323430c47662SAndrew Vasquez 		switch (code_type) {
323530c47662SAndrew Vasquez 		case ROM_CODE_TYPE_BIOS:
323630c47662SAndrew Vasquez 			/* Intel x86, PC-AT compatible. */
323730c47662SAndrew Vasquez 			ha->bios_revision[0] =
323830c47662SAndrew Vasquez 			    qla2x00_read_flash_byte(ha, pcids + 0x12);
323930c47662SAndrew Vasquez 			ha->bios_revision[1] =
324030c47662SAndrew Vasquez 			    qla2x00_read_flash_byte(ha, pcids + 0x13);
32417c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_init, vha, 0x0052,
32427c3df132SSaurav Kashyap 			    "Read BIOS %d.%d.\n",
32437c3df132SSaurav Kashyap 			    ha->bios_revision[1], ha->bios_revision[0]);
324430c47662SAndrew Vasquez 			break;
324530c47662SAndrew Vasquez 		case ROM_CODE_TYPE_FCODE:
324630c47662SAndrew Vasquez 			/* Open Firmware standard for PCI (FCode). */
324730c47662SAndrew Vasquez 			/* Eeeewww... */
324830c47662SAndrew Vasquez 			qla2x00_get_fcode_version(ha, pcids);
324930c47662SAndrew Vasquez 			break;
325030c47662SAndrew Vasquez 		case ROM_CODE_TYPE_EFI:
325130c47662SAndrew Vasquez 			/* Extensible Firmware Interface (EFI). */
325230c47662SAndrew Vasquez 			ha->efi_revision[0] =
325330c47662SAndrew Vasquez 			    qla2x00_read_flash_byte(ha, pcids + 0x12);
325430c47662SAndrew Vasquez 			ha->efi_revision[1] =
325530c47662SAndrew Vasquez 			    qla2x00_read_flash_byte(ha, pcids + 0x13);
32567c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_init, vha, 0x0053,
32577c3df132SSaurav Kashyap 			    "Read EFI %d.%d.\n",
32587c3df132SSaurav Kashyap 			    ha->efi_revision[1], ha->efi_revision[0]);
325930c47662SAndrew Vasquez 			break;
326030c47662SAndrew Vasquez 		default:
32617c3df132SSaurav Kashyap 			ql_log(ql_log_warn, vha, 0x0054,
32627c3df132SSaurav Kashyap 			    "Unrecognized code type %x at pcids %x.\n",
32637c3df132SSaurav Kashyap 			    code_type, pcids);
326430c47662SAndrew Vasquez 			break;
326530c47662SAndrew Vasquez 		}
326630c47662SAndrew Vasquez 
326730c47662SAndrew Vasquez 		last_image = qla2x00_read_flash_byte(ha, pcids + 0x15) & BIT_7;
326830c47662SAndrew Vasquez 
326930c47662SAndrew Vasquez 		/* Locate next PCI expansion ROM. */
327030c47662SAndrew Vasquez 		pcihdr += ((qla2x00_read_flash_byte(ha, pcids + 0x11) << 8) |
327130c47662SAndrew Vasquez 		    qla2x00_read_flash_byte(ha, pcids + 0x10)) * 512;
327230c47662SAndrew Vasquez 	} while (!last_image);
327330c47662SAndrew Vasquez 
327430c47662SAndrew Vasquez 	if (IS_QLA2322(ha)) {
327530c47662SAndrew Vasquez 		/* Read firmware image information. */
327630c47662SAndrew Vasquez 		memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
327730c47662SAndrew Vasquez 		dbyte = mbuf;
327830c47662SAndrew Vasquez 		memset(dbyte, 0, 8);
327930c47662SAndrew Vasquez 		dcode = (uint16_t *)dbyte;
328030c47662SAndrew Vasquez 
3281c00d8994SAndrew Vasquez 		qla2x00_read_flash_data(ha, dbyte, ha->flt_region_fw * 4 + 10,
328230c47662SAndrew Vasquez 		    8);
32837c3df132SSaurav Kashyap 		ql_dbg(ql_dbg_init + ql_dbg_buffer, vha, 0x010a,
32847c3df132SSaurav Kashyap 		    "Dumping fw "
32857c3df132SSaurav Kashyap 		    "ver from flash:.\n");
32867c3df132SSaurav Kashyap 		ql_dump_buffer(ql_dbg_init + ql_dbg_buffer, vha, 0x010b,
32873695310eSJoe Carnuccio 		    dbyte, 32);
328830c47662SAndrew Vasquez 
328930c47662SAndrew Vasquez 		if ((dcode[0] == 0xffff && dcode[1] == 0xffff &&
329030c47662SAndrew Vasquez 		    dcode[2] == 0xffff && dcode[3] == 0xffff) ||
329130c47662SAndrew Vasquez 		    (dcode[0] == 0 && dcode[1] == 0 && dcode[2] == 0 &&
329230c47662SAndrew Vasquez 		    dcode[3] == 0)) {
32937c3df132SSaurav Kashyap 			ql_log(ql_log_warn, vha, 0x0057,
32947c3df132SSaurav Kashyap 			    "Unrecognized fw revision at %x.\n",
32957c3df132SSaurav Kashyap 			    ha->flt_region_fw * 4);
329630c47662SAndrew Vasquez 		} else {
329730c47662SAndrew Vasquez 			/* values are in big endian */
329830c47662SAndrew Vasquez 			ha->fw_revision[0] = dbyte[0] << 16 | dbyte[1];
329930c47662SAndrew Vasquez 			ha->fw_revision[1] = dbyte[2] << 16 | dbyte[3];
330030c47662SAndrew Vasquez 			ha->fw_revision[2] = dbyte[4] << 16 | dbyte[5];
33017c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_init, vha, 0x0058,
33027c3df132SSaurav Kashyap 			    "FW Version: "
33037c3df132SSaurav Kashyap 			    "%d.%d.%d.\n", ha->fw_revision[0],
33047c3df132SSaurav Kashyap 			    ha->fw_revision[1], ha->fw_revision[2]);
330530c47662SAndrew Vasquez 		}
330630c47662SAndrew Vasquez 	}
330730c47662SAndrew Vasquez 
330830c47662SAndrew Vasquez 	qla2x00_flash_disable(ha);
330930c47662SAndrew Vasquez 
331030c47662SAndrew Vasquez 	return ret;
331130c47662SAndrew Vasquez }
331230c47662SAndrew Vasquez 
331330c47662SAndrew Vasquez int
qla82xx_get_flash_version(scsi_qla_host_t * vha,void * mbuf)33147ec0effdSAtul Deshmukh qla82xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
33157ec0effdSAtul Deshmukh {
33167ec0effdSAtul Deshmukh 	int ret = QLA_SUCCESS;
33177ec0effdSAtul Deshmukh 	uint32_t pcihdr, pcids;
33183695310eSJoe Carnuccio 	uint32_t *dcode = mbuf;
33193695310eSJoe Carnuccio 	uint8_t *bcode = mbuf;
33207ec0effdSAtul Deshmukh 	uint8_t code_type, last_image;
33217ec0effdSAtul Deshmukh 	struct qla_hw_data *ha = vha->hw;
33227ec0effdSAtul Deshmukh 
33237ec0effdSAtul Deshmukh 	if (!mbuf)
33247ec0effdSAtul Deshmukh 		return QLA_FUNCTION_FAILED;
33257ec0effdSAtul Deshmukh 
33267ec0effdSAtul Deshmukh 	memset(ha->bios_revision, 0, sizeof(ha->bios_revision));
33277ec0effdSAtul Deshmukh 	memset(ha->efi_revision, 0, sizeof(ha->efi_revision));
33287ec0effdSAtul Deshmukh 	memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
33297ec0effdSAtul Deshmukh 	memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
33307ec0effdSAtul Deshmukh 
33317ec0effdSAtul Deshmukh 	/* Begin with first PCI expansion ROM header. */
33327ec0effdSAtul Deshmukh 	pcihdr = ha->flt_region_boot << 2;
33337ec0effdSAtul Deshmukh 	last_image = 1;
33347ec0effdSAtul Deshmukh 	do {
33357ec0effdSAtul Deshmukh 		/* Verify PCI expansion ROM header. */
33363695310eSJoe Carnuccio 		ha->isp_ops->read_optrom(vha, dcode, pcihdr, 0x20 * 4);
33377ec0effdSAtul Deshmukh 		bcode = mbuf + (pcihdr % 4);
33383695310eSJoe Carnuccio 		if (memcmp(bcode, "\x55\xaa", 2)) {
33397ec0effdSAtul Deshmukh 			/* No signature */
33407ec0effdSAtul Deshmukh 			ql_log(ql_log_fatal, vha, 0x0154,
33417ec0effdSAtul Deshmukh 			    "No matching ROM signature.\n");
33427ec0effdSAtul Deshmukh 			ret = QLA_FUNCTION_FAILED;
33437ec0effdSAtul Deshmukh 			break;
33447ec0effdSAtul Deshmukh 		}
33457ec0effdSAtul Deshmukh 
33467ec0effdSAtul Deshmukh 		/* Locate PCI data structure. */
33477ec0effdSAtul Deshmukh 		pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]);
33487ec0effdSAtul Deshmukh 
33493695310eSJoe Carnuccio 		ha->isp_ops->read_optrom(vha, dcode, pcids, 0x20 * 4);
33507ec0effdSAtul Deshmukh 		bcode = mbuf + (pcihdr % 4);
33517ec0effdSAtul Deshmukh 
33527ec0effdSAtul Deshmukh 		/* Validate signature of PCI data structure. */
33533695310eSJoe Carnuccio 		if (memcmp(bcode, "PCIR", 4)) {
33547ec0effdSAtul Deshmukh 			/* Incorrect header. */
33557ec0effdSAtul Deshmukh 			ql_log(ql_log_fatal, vha, 0x0155,
33567ec0effdSAtul Deshmukh 			    "PCI data struct not found pcir_adr=%x.\n", pcids);
33577ec0effdSAtul Deshmukh 			ret = QLA_FUNCTION_FAILED;
33587ec0effdSAtul Deshmukh 			break;
33597ec0effdSAtul Deshmukh 		}
33607ec0effdSAtul Deshmukh 
33617ec0effdSAtul Deshmukh 		/* Read version */
33627ec0effdSAtul Deshmukh 		code_type = bcode[0x14];
33637ec0effdSAtul Deshmukh 		switch (code_type) {
33647ec0effdSAtul Deshmukh 		case ROM_CODE_TYPE_BIOS:
33657ec0effdSAtul Deshmukh 			/* Intel x86, PC-AT compatible. */
33667ec0effdSAtul Deshmukh 			ha->bios_revision[0] = bcode[0x12];
33677ec0effdSAtul Deshmukh 			ha->bios_revision[1] = bcode[0x13];
33687ec0effdSAtul Deshmukh 			ql_dbg(ql_dbg_init, vha, 0x0156,
33697ec0effdSAtul Deshmukh 			    "Read BIOS %d.%d.\n",
33707ec0effdSAtul Deshmukh 			    ha->bios_revision[1], ha->bios_revision[0]);
33717ec0effdSAtul Deshmukh 			break;
33727ec0effdSAtul Deshmukh 		case ROM_CODE_TYPE_FCODE:
33737ec0effdSAtul Deshmukh 			/* Open Firmware standard for PCI (FCode). */
33747ec0effdSAtul Deshmukh 			ha->fcode_revision[0] = bcode[0x12];
33757ec0effdSAtul Deshmukh 			ha->fcode_revision[1] = bcode[0x13];
33767ec0effdSAtul Deshmukh 			ql_dbg(ql_dbg_init, vha, 0x0157,
33777ec0effdSAtul Deshmukh 			    "Read FCODE %d.%d.\n",
33787ec0effdSAtul Deshmukh 			    ha->fcode_revision[1], ha->fcode_revision[0]);
33797ec0effdSAtul Deshmukh 			break;
33807ec0effdSAtul Deshmukh 		case ROM_CODE_TYPE_EFI:
33817ec0effdSAtul Deshmukh 			/* Extensible Firmware Interface (EFI). */
33827ec0effdSAtul Deshmukh 			ha->efi_revision[0] = bcode[0x12];
33837ec0effdSAtul Deshmukh 			ha->efi_revision[1] = bcode[0x13];
33847ec0effdSAtul Deshmukh 			ql_dbg(ql_dbg_init, vha, 0x0158,
33857ec0effdSAtul Deshmukh 			    "Read EFI %d.%d.\n",
33867ec0effdSAtul Deshmukh 			    ha->efi_revision[1], ha->efi_revision[0]);
33877ec0effdSAtul Deshmukh 			break;
33887ec0effdSAtul Deshmukh 		default:
33897ec0effdSAtul Deshmukh 			ql_log(ql_log_warn, vha, 0x0159,
33907ec0effdSAtul Deshmukh 			    "Unrecognized code type %x at pcids %x.\n",
33917ec0effdSAtul Deshmukh 			    code_type, pcids);
33927ec0effdSAtul Deshmukh 			break;
33937ec0effdSAtul Deshmukh 		}
33947ec0effdSAtul Deshmukh 
33957ec0effdSAtul Deshmukh 		last_image = bcode[0x15] & BIT_7;
33967ec0effdSAtul Deshmukh 
33977ec0effdSAtul Deshmukh 		/* Locate next PCI expansion ROM. */
33987ec0effdSAtul Deshmukh 		pcihdr += ((bcode[0x11] << 8) | bcode[0x10]) * 512;
33997ec0effdSAtul Deshmukh 	} while (!last_image);
34007ec0effdSAtul Deshmukh 
34017ec0effdSAtul Deshmukh 	/* Read firmware image information. */
34027ec0effdSAtul Deshmukh 	memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
34037ec0effdSAtul Deshmukh 	dcode = mbuf;
34043695310eSJoe Carnuccio 	ha->isp_ops->read_optrom(vha, dcode, ha->flt_region_fw << 2, 0x20);
34057ec0effdSAtul Deshmukh 	bcode = mbuf + (pcihdr % 4);
34067ec0effdSAtul Deshmukh 
34077ec0effdSAtul Deshmukh 	/* Validate signature of PCI data structure. */
34087ec0effdSAtul Deshmukh 	if (bcode[0x0] == 0x3 && bcode[0x1] == 0x0 &&
34097ec0effdSAtul Deshmukh 	    bcode[0x2] == 0x40 && bcode[0x3] == 0x40) {
34107ec0effdSAtul Deshmukh 		ha->fw_revision[0] = bcode[0x4];
34117ec0effdSAtul Deshmukh 		ha->fw_revision[1] = bcode[0x5];
34127ec0effdSAtul Deshmukh 		ha->fw_revision[2] = bcode[0x6];
34136ddcfef7SSaurav Kashyap 		ql_dbg(ql_dbg_init, vha, 0x0153,
34147ec0effdSAtul Deshmukh 		    "Firmware revision %d.%d.%d\n",
34157ec0effdSAtul Deshmukh 		    ha->fw_revision[0], ha->fw_revision[1],
34167ec0effdSAtul Deshmukh 		    ha->fw_revision[2]);
34177ec0effdSAtul Deshmukh 	}
34187ec0effdSAtul Deshmukh 
34197ec0effdSAtul Deshmukh 	return ret;
34207ec0effdSAtul Deshmukh }
34217ec0effdSAtul Deshmukh 
34227ec0effdSAtul Deshmukh int
qla24xx_get_flash_version(scsi_qla_host_t * vha,void * mbuf)34237b867cf7SAnirban Chakraborty qla24xx_get_flash_version(scsi_qla_host_t *vha, void *mbuf)
342430c47662SAndrew Vasquez {
342530c47662SAndrew Vasquez 	int ret = QLA_SUCCESS;
34263695310eSJoe Carnuccio 	uint32_t pcihdr = 0, pcids = 0;
34273695310eSJoe Carnuccio 	uint32_t *dcode = mbuf;
34283695310eSJoe Carnuccio 	uint8_t *bcode = mbuf;
342930c47662SAndrew Vasquez 	uint8_t code_type, last_image;
343030c47662SAndrew Vasquez 	int i;
34317b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
34324243c115SSawan Chandak 	uint32_t faddr = 0;
34335fa8774cSJoe Carnuccio 	struct active_regions active_regions = { };
34344243c115SSawan Chandak 
34357ec0effdSAtul Deshmukh 	if (IS_P3P_TYPE(ha))
3436*bf192b8bSQuinn Tran 		return QLA_SUCCESS;
3437a9083016SGiridhar Malavali 
343830c47662SAndrew Vasquez 	if (!mbuf)
343930c47662SAndrew Vasquez 		return QLA_FUNCTION_FAILED;
344030c47662SAndrew Vasquez 
344130c47662SAndrew Vasquez 	memset(ha->bios_revision, 0, sizeof(ha->bios_revision));
344230c47662SAndrew Vasquez 	memset(ha->efi_revision, 0, sizeof(ha->efi_revision));
344330c47662SAndrew Vasquez 	memset(ha->fcode_revision, 0, sizeof(ha->fcode_revision));
344430c47662SAndrew Vasquez 	memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
344530c47662SAndrew Vasquez 
34466315a5f8SHarish Zunjarrao 	pcihdr = ha->flt_region_boot << 2;
34475fa8774cSJoe Carnuccio 	if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
34485fa8774cSJoe Carnuccio 		qla27xx_get_active_image(vha, &active_regions);
34495fa8774cSJoe Carnuccio 		if (active_regions.global == QLA27XX_SECONDARY_IMAGE) {
34504243c115SSawan Chandak 			pcihdr = ha->flt_region_boot_sec << 2;
34515fa8774cSJoe Carnuccio 		}
34525fa8774cSJoe Carnuccio 	}
34534243c115SSawan Chandak 
345430c47662SAndrew Vasquez 	do {
345530c47662SAndrew Vasquez 		/* Verify PCI expansion ROM header. */
3456*bf192b8bSQuinn Tran 		ret = qla24xx_read_flash_data(vha, dcode, pcihdr >> 2, 0x20);
3457*bf192b8bSQuinn Tran 		if (ret) {
3458*bf192b8bSQuinn Tran 			ql_log(ql_log_info, vha, 0x017d,
3459*bf192b8bSQuinn Tran 			    "Unable to read PCI EXP Rom Header(%x).\n", ret);
3460*bf192b8bSQuinn Tran 			return QLA_FUNCTION_FAILED;
3461*bf192b8bSQuinn Tran 		}
3462*bf192b8bSQuinn Tran 
346330c47662SAndrew Vasquez 		bcode = mbuf + (pcihdr % 4);
34643695310eSJoe Carnuccio 		if (memcmp(bcode, "\x55\xaa", 2)) {
346530c47662SAndrew Vasquez 			/* No signature */
34667c3df132SSaurav Kashyap 			ql_log(ql_log_fatal, vha, 0x0059,
34677c3df132SSaurav Kashyap 			    "No matching ROM signature.\n");
3468*bf192b8bSQuinn Tran 			return QLA_FUNCTION_FAILED;
346930c47662SAndrew Vasquez 		}
347030c47662SAndrew Vasquez 
347130c47662SAndrew Vasquez 		/* Locate PCI data structure. */
347230c47662SAndrew Vasquez 		pcids = pcihdr + ((bcode[0x19] << 8) | bcode[0x18]);
347330c47662SAndrew Vasquez 
3474*bf192b8bSQuinn Tran 		ret = qla24xx_read_flash_data(vha, dcode, pcids >> 2, 0x20);
3475*bf192b8bSQuinn Tran 		if (ret) {
3476*bf192b8bSQuinn Tran 			ql_log(ql_log_info, vha, 0x018e,
3477*bf192b8bSQuinn Tran 			    "Unable to read PCI Data Structure (%x).\n", ret);
3478*bf192b8bSQuinn Tran 			return QLA_FUNCTION_FAILED;
3479*bf192b8bSQuinn Tran 		}
3480*bf192b8bSQuinn Tran 
348130c47662SAndrew Vasquez 		bcode = mbuf + (pcihdr % 4);
348230c47662SAndrew Vasquez 
348330c47662SAndrew Vasquez 		/* Validate signature of PCI data structure. */
34843695310eSJoe Carnuccio 		if (memcmp(bcode, "PCIR", 4)) {
348530c47662SAndrew Vasquez 			/* Incorrect header. */
34867c3df132SSaurav Kashyap 			ql_log(ql_log_fatal, vha, 0x005a,
34877c3df132SSaurav Kashyap 			    "PCI data struct not found pcir_adr=%x.\n", pcids);
34883695310eSJoe Carnuccio 			ql_dump_buffer(ql_dbg_init, vha, 0x0059, dcode, 32);
3489*bf192b8bSQuinn Tran 			return QLA_FUNCTION_FAILED;
349030c47662SAndrew Vasquez 		}
349130c47662SAndrew Vasquez 
349230c47662SAndrew Vasquez 		/* Read version */
349330c47662SAndrew Vasquez 		code_type = bcode[0x14];
349430c47662SAndrew Vasquez 		switch (code_type) {
349530c47662SAndrew Vasquez 		case ROM_CODE_TYPE_BIOS:
349630c47662SAndrew Vasquez 			/* Intel x86, PC-AT compatible. */
349730c47662SAndrew Vasquez 			ha->bios_revision[0] = bcode[0x12];
349830c47662SAndrew Vasquez 			ha->bios_revision[1] = bcode[0x13];
34997c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_init, vha, 0x005b,
35007c3df132SSaurav Kashyap 			    "Read BIOS %d.%d.\n",
35017c3df132SSaurav Kashyap 			    ha->bios_revision[1], ha->bios_revision[0]);
350230c47662SAndrew Vasquez 			break;
350330c47662SAndrew Vasquez 		case ROM_CODE_TYPE_FCODE:
350430c47662SAndrew Vasquez 			/* Open Firmware standard for PCI (FCode). */
350530c47662SAndrew Vasquez 			ha->fcode_revision[0] = bcode[0x12];
350630c47662SAndrew Vasquez 			ha->fcode_revision[1] = bcode[0x13];
35077c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_init, vha, 0x005c,
35087c3df132SSaurav Kashyap 			    "Read FCODE %d.%d.\n",
35097c3df132SSaurav Kashyap 			    ha->fcode_revision[1], ha->fcode_revision[0]);
351030c47662SAndrew Vasquez 			break;
351130c47662SAndrew Vasquez 		case ROM_CODE_TYPE_EFI:
351230c47662SAndrew Vasquez 			/* Extensible Firmware Interface (EFI). */
351330c47662SAndrew Vasquez 			ha->efi_revision[0] = bcode[0x12];
351430c47662SAndrew Vasquez 			ha->efi_revision[1] = bcode[0x13];
35157c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_init, vha, 0x005d,
35167c3df132SSaurav Kashyap 			    "Read EFI %d.%d.\n",
35177c3df132SSaurav Kashyap 			    ha->efi_revision[1], ha->efi_revision[0]);
351830c47662SAndrew Vasquez 			break;
351930c47662SAndrew Vasquez 		default:
35207c3df132SSaurav Kashyap 			ql_log(ql_log_warn, vha, 0x005e,
35217c3df132SSaurav Kashyap 			    "Unrecognized code type %x at pcids %x.\n",
35227c3df132SSaurav Kashyap 			    code_type, pcids);
352330c47662SAndrew Vasquez 			break;
352430c47662SAndrew Vasquez 		}
352530c47662SAndrew Vasquez 
352630c47662SAndrew Vasquez 		last_image = bcode[0x15] & BIT_7;
352730c47662SAndrew Vasquez 
352830c47662SAndrew Vasquez 		/* Locate next PCI expansion ROM. */
352930c47662SAndrew Vasquez 		pcihdr += ((bcode[0x11] << 8) | bcode[0x10]) * 512;
353030c47662SAndrew Vasquez 	} while (!last_image);
353130c47662SAndrew Vasquez 
353230c47662SAndrew Vasquez 	/* Read firmware image information. */
353330c47662SAndrew Vasquez 	memset(ha->fw_revision, 0, sizeof(ha->fw_revision));
35344243c115SSawan Chandak 	faddr = ha->flt_region_fw;
35355fa8774cSJoe Carnuccio 	if (IS_QLA27XX(ha) || IS_QLA28XX(ha)) {
35363f006ac3SMichael Hernandez 		qla27xx_get_active_image(vha, &active_regions);
35375fa8774cSJoe Carnuccio 		if (active_regions.global == QLA27XX_SECONDARY_IMAGE)
35384243c115SSawan Chandak 			faddr = ha->flt_region_fw_sec;
35395fa8774cSJoe Carnuccio 	}
354030c47662SAndrew Vasquez 
3541*bf192b8bSQuinn Tran 	ret = qla24xx_read_flash_data(vha, dcode, faddr, 8);
3542*bf192b8bSQuinn Tran 	if (ret) {
3543*bf192b8bSQuinn Tran 		ql_log(ql_log_info, vha, 0x019e,
3544*bf192b8bSQuinn Tran 		    "Unable to read FW version (%x).\n", ret);
3545*bf192b8bSQuinn Tran 		return ret;
3546*bf192b8bSQuinn Tran 	} else {
3547f8f97b0cSJoe Carnuccio 		if (qla24xx_risc_firmware_invalid(dcode)) {
35487c3df132SSaurav Kashyap 			ql_log(ql_log_warn, vha, 0x005f,
35497c3df132SSaurav Kashyap 			    "Unrecognized fw revision at %x.\n",
35507c3df132SSaurav Kashyap 			    ha->flt_region_fw * 4);
35513695310eSJoe Carnuccio 			ql_dump_buffer(ql_dbg_init, vha, 0x005f, dcode, 32);
355230c47662SAndrew Vasquez 		} else {
3553f8f97b0cSJoe Carnuccio 			for (i = 0; i < 4; i++)
35547ffa5b93SBart Van Assche 				ha->fw_revision[i] =
35557ffa5b93SBart Van Assche 				be32_to_cpu((__force __be32)dcode[4+i]);
35567c3df132SSaurav Kashyap 			ql_dbg(ql_dbg_init, vha, 0x0060,
35573695310eSJoe Carnuccio 			    "Firmware revision (flash) %u.%u.%u (%x).\n",
35587c3df132SSaurav Kashyap 			    ha->fw_revision[0], ha->fw_revision[1],
35597c3df132SSaurav Kashyap 			    ha->fw_revision[2], ha->fw_revision[3]);
356030c47662SAndrew Vasquez 		}
3561*bf192b8bSQuinn Tran 	}
356230c47662SAndrew Vasquez 
35630f2d962fSMadhuranath Iyengar 	/* Check for golden firmware and get version if available */
35640f2d962fSMadhuranath Iyengar 	if (!IS_QLA81XX(ha)) {
35650f2d962fSMadhuranath Iyengar 		/* Golden firmware is not present in non 81XX adapters */
35660f2d962fSMadhuranath Iyengar 		return ret;
35670f2d962fSMadhuranath Iyengar 	}
35680f2d962fSMadhuranath Iyengar 
35690f2d962fSMadhuranath Iyengar 	memset(ha->gold_fw_version, 0, sizeof(ha->gold_fw_version));
35703695310eSJoe Carnuccio 	faddr = ha->flt_region_gold_fw;
3571*bf192b8bSQuinn Tran 	ret = qla24xx_read_flash_data(vha, dcode, ha->flt_region_gold_fw, 8);
3572*bf192b8bSQuinn Tran 	if (ret) {
3573*bf192b8bSQuinn Tran 		ql_log(ql_log_info, vha, 0x019f,
3574*bf192b8bSQuinn Tran 		    "Unable to read Gold FW version (%x).\n", ret);
3575*bf192b8bSQuinn Tran 		return ret;
3576*bf192b8bSQuinn Tran 	} else {
3577f8f97b0cSJoe Carnuccio 		if (qla24xx_risc_firmware_invalid(dcode)) {
35787c3df132SSaurav Kashyap 			ql_log(ql_log_warn, vha, 0x0056,
35793695310eSJoe Carnuccio 			    "Unrecognized golden fw at %#x.\n", faddr);
35803695310eSJoe Carnuccio 			ql_dump_buffer(ql_dbg_init, vha, 0x0056, dcode, 32);
3581*bf192b8bSQuinn Tran 			return QLA_FUNCTION_FAILED;
35820f2d962fSMadhuranath Iyengar 		}
35830f2d962fSMadhuranath Iyengar 
3584f8f97b0cSJoe Carnuccio 		for (i = 0; i < 4; i++)
35857ffa5b93SBart Van Assche 			ha->gold_fw_version[i] =
35867ffa5b93SBart Van Assche 			   be32_to_cpu((__force __be32)dcode[4+i]);
3587*bf192b8bSQuinn Tran 	}
358830c47662SAndrew Vasquez 	return ret;
358930c47662SAndrew Vasquez }
3590cb8dacbfSAndrew Vasquez 
3591cb8dacbfSAndrew Vasquez static int
qla2xxx_is_vpd_valid(uint8_t * pos,uint8_t * end)35921ee27146SJoe Carnuccio qla2xxx_is_vpd_valid(uint8_t *pos, uint8_t *end)
35931ee27146SJoe Carnuccio {
35941ee27146SJoe Carnuccio 	if (pos >= end || *pos != 0x82)
35951ee27146SJoe Carnuccio 		return 0;
35961ee27146SJoe Carnuccio 
35971ee27146SJoe Carnuccio 	pos += 3 + pos[1];
35981ee27146SJoe Carnuccio 	if (pos >= end || *pos != 0x90)
35991ee27146SJoe Carnuccio 		return 0;
36001ee27146SJoe Carnuccio 
36011ee27146SJoe Carnuccio 	pos += 3 + pos[1];
36021ee27146SJoe Carnuccio 	if (pos >= end || *pos != 0x78)
36031ee27146SJoe Carnuccio 		return 0;
36041ee27146SJoe Carnuccio 
36051ee27146SJoe Carnuccio 	return 1;
36061ee27146SJoe Carnuccio }
36071ee27146SJoe Carnuccio 
36081ee27146SJoe Carnuccio int
qla2xxx_get_vpd_field(scsi_qla_host_t * vha,char * key,char * str,size_t size)36097b867cf7SAnirban Chakraborty qla2xxx_get_vpd_field(scsi_qla_host_t *vha, char *key, char *str, size_t size)
36101ee27146SJoe Carnuccio {
36117b867cf7SAnirban Chakraborty 	struct qla_hw_data *ha = vha->hw;
36121ee27146SJoe Carnuccio 	uint8_t *pos = ha->vpd;
36131ee27146SJoe Carnuccio 	uint8_t *end = pos + ha->vpd_size;
36141ee27146SJoe Carnuccio 	int len = 0;
36151ee27146SJoe Carnuccio 
36161ee27146SJoe Carnuccio 	if (!IS_FWI2_CAPABLE(ha) || !qla2xxx_is_vpd_valid(pos, end))
36171ee27146SJoe Carnuccio 		return 0;
36181ee27146SJoe Carnuccio 
36191ee27146SJoe Carnuccio 	while (pos < end && *pos != 0x78) {
36201ee27146SJoe Carnuccio 		len = (*pos == 0x82) ? pos[1] : pos[2];
36211ee27146SJoe Carnuccio 
36221ee27146SJoe Carnuccio 		if (!strncmp(pos, key, strlen(key)))
36231ee27146SJoe Carnuccio 			break;
36241ee27146SJoe Carnuccio 
36251ee27146SJoe Carnuccio 		if (*pos != 0x90 && *pos != 0x91)
36261ee27146SJoe Carnuccio 			pos += len;
36271ee27146SJoe Carnuccio 
36281ee27146SJoe Carnuccio 		pos += 3;
36291ee27146SJoe Carnuccio 	}
36301ee27146SJoe Carnuccio 
36311ee27146SJoe Carnuccio 	if (pos < end - len && *pos != 0x78)
3632efcdf9f5SJoe Carnuccio 		return scnprintf(str, size, "%.*s", len, pos + 3);
36331ee27146SJoe Carnuccio 
36341ee27146SJoe Carnuccio 	return 0;
36351ee27146SJoe Carnuccio }
363609ff701aSSarang Radke 
363709ff701aSSarang Radke int
qla24xx_read_fcp_prio_cfg(scsi_qla_host_t * vha)363809ff701aSSarang Radke qla24xx_read_fcp_prio_cfg(scsi_qla_host_t *vha)
363909ff701aSSarang Radke {
364009ff701aSSarang Radke 	int len, max_len;
364109ff701aSSarang Radke 	uint32_t fcp_prio_addr;
364209ff701aSSarang Radke 	struct qla_hw_data *ha = vha->hw;
364309ff701aSSarang Radke 
364409ff701aSSarang Radke 	if (!ha->fcp_prio_cfg) {
364509ff701aSSarang Radke 		ha->fcp_prio_cfg = vmalloc(FCP_PRIO_CFG_SIZE);
364609ff701aSSarang Radke 		if (!ha->fcp_prio_cfg) {
36477c3df132SSaurav Kashyap 			ql_log(ql_log_warn, vha, 0x00d5,
3648c01e0159SMasanari Iida 			    "Unable to allocate memory for fcp priority data (%x).\n",
36497c3df132SSaurav Kashyap 			    FCP_PRIO_CFG_SIZE);
365009ff701aSSarang Radke 			return QLA_FUNCTION_FAILED;
365109ff701aSSarang Radke 		}
365209ff701aSSarang Radke 	}
365309ff701aSSarang Radke 	memset(ha->fcp_prio_cfg, 0, FCP_PRIO_CFG_SIZE);
365409ff701aSSarang Radke 
365509ff701aSSarang Radke 	fcp_prio_addr = ha->flt_region_fcp_prio;
365609ff701aSSarang Radke 
365709ff701aSSarang Radke 	/* first read the fcp priority data header from flash */
36583695310eSJoe Carnuccio 	ha->isp_ops->read_optrom(vha, ha->fcp_prio_cfg,
365909ff701aSSarang Radke 			fcp_prio_addr << 2, FCP_PRIO_CFG_HDR_SIZE);
366009ff701aSSarang Radke 
36617c3df132SSaurav Kashyap 	if (!qla24xx_fcp_prio_cfg_valid(vha, ha->fcp_prio_cfg, 0))
366209ff701aSSarang Radke 		goto fail;
366309ff701aSSarang Radke 
366409ff701aSSarang Radke 	/* read remaining FCP CMD config data from flash */
366509ff701aSSarang Radke 	fcp_prio_addr += (FCP_PRIO_CFG_HDR_SIZE >> 2);
3666e544b720SBart Van Assche 	len = ha->fcp_prio_cfg->num_entries * sizeof(struct qla_fcp_prio_entry);
366709ff701aSSarang Radke 	max_len = FCP_PRIO_CFG_SIZE - FCP_PRIO_CFG_HDR_SIZE;
366809ff701aSSarang Radke 
36693695310eSJoe Carnuccio 	ha->isp_ops->read_optrom(vha, &ha->fcp_prio_cfg->entry[0],
367009ff701aSSarang Radke 			fcp_prio_addr << 2, (len < max_len ? len : max_len));
367109ff701aSSarang Radke 
367209ff701aSSarang Radke 	/* revalidate the entire FCP priority config data, including entries */
36737c3df132SSaurav Kashyap 	if (!qla24xx_fcp_prio_cfg_valid(vha, ha->fcp_prio_cfg, 1))
367409ff701aSSarang Radke 		goto fail;
367509ff701aSSarang Radke 
367609ff701aSSarang Radke 	ha->flags.fcp_prio_enabled = 1;
367709ff701aSSarang Radke 	return QLA_SUCCESS;
367809ff701aSSarang Radke fail:
367909ff701aSSarang Radke 	vfree(ha->fcp_prio_cfg);
368009ff701aSSarang Radke 	ha->fcp_prio_cfg = NULL;
368109ff701aSSarang Radke 	return QLA_FUNCTION_FAILED;
368209ff701aSSarang Radke }
3683