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(®->nvram);
291da177e4SLinus Torvalds while (data & NVR_BUSY) {
301da177e4SLinus Torvalds udelay(100);
3104474d3aSBart Van Assche data = rd_reg_word(®->nvram);
321da177e4SLinus Torvalds }
331da177e4SLinus Torvalds
341da177e4SLinus Torvalds /* Lock resource */
3504474d3aSBart Van Assche wrt_reg_word(®->u.isp2300.host_semaphore, 0x1);
3604474d3aSBart Van Assche rd_reg_word(®->u.isp2300.host_semaphore);
371da177e4SLinus Torvalds udelay(5);
3804474d3aSBart Van Assche data = rd_reg_word(®->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(®->u.isp2300.host_semaphore, 0x1);
4304474d3aSBart Van Assche rd_reg_word(®->u.isp2300.host_semaphore);
441da177e4SLinus Torvalds udelay(5);
4504474d3aSBart Van Assche data = rd_reg_word(®->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(®->u.isp2300.host_semaphore, 0);
6104474d3aSBart Van Assche rd_reg_word(®->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(®->nvram, data | NVR_SELECT | NVR_WRT_ENABLE);
7604474d3aSBart Van Assche rd_reg_word(®->nvram); /* PCI Posting. */
777b867cf7SAnirban Chakraborty NVRAM_DELAY();
7804474d3aSBart Van Assche wrt_reg_word(®->nvram, data | NVR_SELECT | NVR_CLOCK |
797b867cf7SAnirban Chakraborty NVR_WRT_ENABLE);
8004474d3aSBart Van Assche rd_reg_word(®->nvram); /* PCI Posting. */
817b867cf7SAnirban Chakraborty NVRAM_DELAY();
8204474d3aSBart Van Assche wrt_reg_word(®->nvram, data | NVR_SELECT | NVR_WRT_ENABLE);
8304474d3aSBart Van Assche rd_reg_word(®->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(®->nvram, NVR_SELECT | NVR_CLOCK);
12304474d3aSBart Van Assche rd_reg_word(®->nvram); /* PCI Posting. */
1247b867cf7SAnirban Chakraborty NVRAM_DELAY();
1257b867cf7SAnirban Chakraborty data <<= 1;
12604474d3aSBart Van Assche reg_data = rd_reg_word(®->nvram);
1277b867cf7SAnirban Chakraborty if (reg_data & NVR_DATA_IN)
1287b867cf7SAnirban Chakraborty data |= BIT_0;
12904474d3aSBart Van Assche wrt_reg_word(®->nvram, NVR_SELECT);
13004474d3aSBart Van Assche rd_reg_word(®->nvram); /* PCI Posting. */
1317b867cf7SAnirban Chakraborty NVRAM_DELAY();
1327b867cf7SAnirban Chakraborty }
1337b867cf7SAnirban Chakraborty
1347b867cf7SAnirban Chakraborty /* Deselect chip. */
13504474d3aSBart Van Assche wrt_reg_word(®->nvram, NVR_DESELECT);
13604474d3aSBart Van Assche rd_reg_word(®->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(®->nvram, NVR_DESELECT);
17404474d3aSBart Van Assche rd_reg_word(®->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(®->nvram, NVR_SELECT);
21904474d3aSBart Van Assche rd_reg_word(®->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(®->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(®->nvram, NVR_SELECT);
27804474d3aSBart Van Assche rd_reg_word(®->nvram); /* PCI Posting. */
279459c5378SAndrew Vasquez do {
280459c5378SAndrew Vasquez NVRAM_DELAY();
28104474d3aSBart Van Assche word = rd_reg_word(®->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(®->nvram, NVR_SELECT);
35004474d3aSBart Van Assche rd_reg_word(®->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(®->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(®->nvram, NVR_SELECT);
41004474d3aSBart Van Assche rd_reg_word(®->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(®->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(®->flash_addr, addr & ~FARX_DATA_FLAG);
4593695310eSJoe Carnuccio
4603695310eSJoe Carnuccio while (cnt--) {
46104474d3aSBart Van Assche if (rd_reg_dword(®->flash_addr) & FARX_DATA_FLAG) {
46204474d3aSBart Van Assche *data = rd_reg_dword(®->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(®->flash_data, data);
50204474d3aSBart Van Assche wrt_reg_dword(®->flash_addr, addr | FARX_DATA_FLAG);
5033695310eSJoe Carnuccio
5043695310eSJoe Carnuccio while (cnt--) {
50504474d3aSBart Van Assche if (!(rd_reg_dword(®->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(®->ctrl_status,
121804474d3aSBart Van Assche rd_reg_dword(®->ctrl_status) | CSRX_FLASH_ENABLE);
121904474d3aSBart Van Assche rd_reg_dword(®->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(®->ctrl_status,
126104474d3aSBart Van Assche rd_reg_dword(®->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(®->ctrl_status,
148704474d3aSBart Van Assche rd_reg_dword(®->ctrl_status) | CSRX_FLASH_ENABLE);
148804474d3aSBart Van Assche rd_reg_dword(®->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(®->ctrl_status,
151104474d3aSBart Van Assche rd_reg_dword(®->ctrl_status) & ~CSRX_FLASH_ENABLE);
151204474d3aSBart Van Assche rd_reg_dword(®->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(®->gpioe);
160904474d3aSBart Van Assche gpio_data = rd_reg_word(®->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(®->gpioe, gpio_enable);
161904474d3aSBart Van Assche rd_reg_word(®->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(®->gpiod, gpio_data);
163504474d3aSBart Van Assche rd_reg_word(®->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(®->gpioe);
166604474d3aSBart Van Assche gpio_data = rd_reg_word(®->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(®->gpioe, gpio_enable);
167504474d3aSBart Van Assche rd_reg_word(®->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(®->gpiod, gpio_data);
168404474d3aSBart Van Assche rd_reg_word(®->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(®->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(®->gpiod, gpio_data);
175704474d3aSBart Van Assche gpio_data = rd_reg_dword(®->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(®->gpiod, gpio_data);
177004474d3aSBart Van Assche gpio_data = rd_reg_dword(®->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(®->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(®->gpiod, gpio_data);
190604474d3aSBart Van Assche rd_reg_dword(®->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(®->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(®->gpiod, gpio_data);
195404474d3aSBart Van Assche rd_reg_dword(®->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(®->ctrl_status);
1991854165f4Sandrew.vasquez@qlogic.com data |= CSR_FLASH_ENABLE;
199204474d3aSBart Van Assche wrt_reg_word(®->ctrl_status, data);
199304474d3aSBart Van Assche rd_reg_word(®->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(®->ctrl_status);
2007854165f4Sandrew.vasquez@qlogic.com data &= ~(CSR_FLASH_ENABLE);
200804474d3aSBart Van Assche wrt_reg_word(®->ctrl_status, data);
200904474d3aSBart Van Assche rd_reg_word(®->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(®->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(®->ctrl_status, bank_select);
203704474d3aSBart Van Assche rd_reg_word(®->ctrl_status); /* PCI Posting. */
2038854165f4Sandrew.vasquez@qlogic.com
203904474d3aSBart Van Assche wrt_reg_word(®->flash_address, (uint16_t)addr);
204004474d3aSBart Van Assche data = rd_reg_word(®->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(®->ctrl_status, bank_select);
204904474d3aSBart Van Assche rd_reg_word(®->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(®->ctrl_status, bank_select);
205404474d3aSBart Van Assche rd_reg_word(®->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(®->flash_address, (uint16_t)addr);
2070854165f4Sandrew.vasquez@qlogic.com data = qla2x00_debounce_register(®->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(®->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(®->ctrl_status, bank_select);
209604474d3aSBart Van Assche rd_reg_word(®->ctrl_status); /* PCI Posting. */
2097854165f4Sandrew.vasquez@qlogic.com
209804474d3aSBart Van Assche wrt_reg_word(®->flash_address, (uint16_t)addr);
209904474d3aSBart Van Assche rd_reg_word(®->ctrl_status); /* PCI Posting. */
210004474d3aSBart Van Assche wrt_reg_word(®->flash_data, (uint16_t)data);
210104474d3aSBart Van Assche rd_reg_word(®->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(®->ctrl_status, bank_select);
211004474d3aSBart Van Assche rd_reg_word(®->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(®->ctrl_status, bank_select);
211504474d3aSBart Van Assche rd_reg_word(®->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(®->flash_address, (uint16_t)addr);
212404474d3aSBart Van Assche rd_reg_word(®->ctrl_status); /* PCI Posting. */
212504474d3aSBart Van Assche wrt_reg_word(®->flash_data, (uint16_t)data);
212604474d3aSBart Van Assche rd_reg_word(®->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(®->nvram, 0);
231004474d3aSBart Van Assche rd_reg_word(®->nvram);
231130c47662SAndrew Vasquez for (ilength = 0; ilength < length; saddr++, ilength++, tmp_buf++) {
231230c47662SAndrew Vasquez if (ilength == midpoint) {
231304474d3aSBart Van Assche wrt_reg_word(®->nvram, NVR_SELECT);
231404474d3aSBart Van Assche rd_reg_word(®->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(®->hccr, HCCR_PAUSE_RISC);
234004474d3aSBart Van Assche rd_reg_word(®->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(®->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(®->nvram, 0);
238304474d3aSBart Van Assche rd_reg_word(®->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(®->nvram, NVR_SELECT);
238704474d3aSBart Van Assche rd_reg_word(®->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(®->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(®->nvram, NVR_SELECT);
256904474d3aSBart Van Assche rd_reg_word(®->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, ®ion);
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