1331722Seadler/*
2250340Sdavidcs * Copyright (c) 2011-2013 Qlogic Corporation
3227064Sbz * All rights reserved.
4227064Sbz *
5227064Sbz *  Redistribution and use in source and binary forms, with or without
6227064Sbz *  modification, are permitted provided that the following conditions
7227064Sbz *  are met:
8227064Sbz *
9227064Sbz *  1. Redistributions of source code must retain the above copyright
10227064Sbz *     notice, this list of conditions and the following disclaimer.
11227064Sbz *  2. Redistributions in binary form must reproduce the above copyright
12227064Sbz *     notice, this list of conditions and the following disclaimer in the
13227064Sbz *     documentation and/or other materials provided with the distribution.
14227064Sbz *
15227064Sbz *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16227064Sbz *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17227064Sbz *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18227064Sbz *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
19227064Sbz *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20227064Sbz *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21227064Sbz *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22227064Sbz *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23227064Sbz *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24227064Sbz *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25227064Sbz *  POSSIBILITY OF SUCH DAMAGE.
26227064Sbz */
27227064Sbz/*
28227064Sbz * File : qla_misc.c
29227064Sbz * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656.
30227064Sbz */
31227064Sbz
32227064Sbz#include <sys/cdefs.h>
33227064Sbz__FBSDID("$FreeBSD$");
34227064Sbz
35227064Sbz#include "qla_os.h"
36227064Sbz#include "qla_reg.h"
37227064Sbz#include "qla_hw.h"
38227064Sbz#include "qla_def.h"
39227064Sbz#include "qla_reg.h"
40227064Sbz#include "qla_inline.h"
41227064Sbz#include "qla_glbl.h"
42227064Sbz#include "qla_dbg.h"
43227064Sbz
44227064Sbz/*
45227064Sbz * structure encapsulating the value to read/write to offchip memory
46227064Sbz */
47227064Sbztypedef struct _offchip_mem_val {
48227064Sbz        uint32_t data_lo;
49227064Sbz        uint32_t data_hi;
50227064Sbz        uint32_t data_ulo;
51227064Sbz        uint32_t data_uhi;
52227064Sbz} offchip_mem_val_t;
53227064Sbz
54227064Sbz#define Q8_ADDR_UNDEFINED		0xFFFFFFFF
55227064Sbz
56227064Sbz/*
57227064Sbz * The index to this table is Bits 20-27 of the indirect register address
58227064Sbz */
59227064Sbzstatic uint32_t indirect_to_base_map[] =
60227064Sbz	{
61227064Sbz		Q8_ADDR_UNDEFINED,	/* 0x00 */
62227064Sbz		0x77300000,		/* 0x01 */
63227064Sbz		0x29500000,		/* 0x02 */
64227064Sbz		0x2A500000,		/* 0x03 */
65227064Sbz		Q8_ADDR_UNDEFINED,	/* 0x04 */
66227064Sbz		0x0D000000,		/* 0x05 */
67227064Sbz		0x1B100000,		/* 0x06 */
68227064Sbz		0x0E600000,		/* 0x07 */
69227064Sbz		0x0E000000,		/* 0x08 */
70227064Sbz		0x0E100000,		/* 0x09 */
71227064Sbz		0x0E200000,		/* 0x0A */
72227064Sbz		0x0E300000,		/* 0x0B */
73227064Sbz		0x42000000,		/* 0x0C */
74227064Sbz		0x41700000,		/* 0x0D */
75227064Sbz		0x42100000,		/* 0x0E */
76227064Sbz		0x34B00000,		/* 0x0F */
77227064Sbz		0x40500000,		/* 0x10 */
78227064Sbz		0x34000000,		/* 0x11 */
79227064Sbz		0x34100000,		/* 0x12 */
80227064Sbz		0x34200000,		/* 0x13 */
81227064Sbz		0x34300000,		/* 0x14 */
82227064Sbz		0x34500000,		/* 0x15 */
83227064Sbz		0x34400000,		/* 0x16 */
84227064Sbz		0x3C000000,		/* 0x17 */
85227064Sbz		0x3C100000,		/* 0x18 */
86227064Sbz		0x3C200000,		/* 0x19 */
87227064Sbz		0x3C300000,		/* 0x1A */
88227064Sbz		Q8_ADDR_UNDEFINED,	/* 0x1B */
89227064Sbz		0x3C400000,		/* 0x1C */
90227064Sbz		0x41000000,		/* 0x1D */
91227064Sbz		Q8_ADDR_UNDEFINED,	/* 0x1E */
92227064Sbz		0x0D100000,		/* 0x1F */
93227064Sbz		Q8_ADDR_UNDEFINED,	/* 0x20 */
94227064Sbz		0x77300000,		/* 0x21 */
95227064Sbz		0x41600000,		/* 0x22 */
96227064Sbz		Q8_ADDR_UNDEFINED,	/* 0x23 */
97227064Sbz		Q8_ADDR_UNDEFINED,	/* 0x24 */
98227064Sbz		Q8_ADDR_UNDEFINED,	/* 0x25 */
99227064Sbz		Q8_ADDR_UNDEFINED,	/* 0x26 */
100227064Sbz		Q8_ADDR_UNDEFINED,	/* 0x27 */
101227064Sbz		0x41700000,		/* 0x28 */
102227064Sbz		Q8_ADDR_UNDEFINED,	/* 0x29 */
103227064Sbz		0x08900000,		/* 0x2A */
104227064Sbz		0x70A00000,		/* 0x2B */
105227064Sbz		0x70B00000,		/* 0x2C */
106227064Sbz		0x70C00000,		/* 0x2D */
107227064Sbz		0x08D00000,		/* 0x2E */
108227064Sbz		0x08E00000,		/* 0x2F */
109227064Sbz		0x70F00000,		/* 0x30 */
110227064Sbz		0x40500000,		/* 0x31 */
111227064Sbz		0x42000000,		/* 0x32 */
112227064Sbz		0x42100000,		/* 0x33 */
113227064Sbz		Q8_ADDR_UNDEFINED,	/* 0x34 */
114227064Sbz		0x08800000,		/* 0x35 */
115227064Sbz		0x09100000,		/* 0x36 */
116227064Sbz		0x71200000,		/* 0x37 */
117227064Sbz		0x40600000,		/* 0x38 */
118227064Sbz		Q8_ADDR_UNDEFINED,	/* 0x39 */
119227064Sbz		0x71800000,		/* 0x3A */
120227064Sbz		0x19900000,		/* 0x3B */
121227064Sbz		0x1A900000,		/* 0x3C */
122227064Sbz		Q8_ADDR_UNDEFINED,	/* 0x3D */
123227064Sbz		0x34600000,		/* 0x3E */
124227064Sbz		Q8_ADDR_UNDEFINED,	/* 0x3F */
125227064Sbz	};
126227064Sbz
127227064Sbz/*
128227064Sbz * Address Translation Table for CRB to offsets from PCI BAR0
129227064Sbz */
130227064Sbztypedef struct _crb_to_pci {
131227064Sbz	uint32_t crb_addr;
132227064Sbz	uint32_t pci_addr;
133227064Sbz} crb_to_pci_t;
134227064Sbz
135227064Sbzstatic crb_to_pci_t crbinit_to_pciaddr[] = {
136227064Sbz	{(0x088 << 20), (0x035 << 20)},
137227064Sbz	{(0x089 << 20), (0x02A << 20)},
138227064Sbz	{(0x08D << 20), (0x02E << 20)},
139227064Sbz	{(0x08E << 20), (0x02F << 20)},
140227064Sbz	{(0x0C6 << 20), (0x023 << 20)},
141227064Sbz	{(0x0C7 << 20), (0x024 << 20)},
142227064Sbz	{(0x0C8 << 20), (0x025 << 20)},
143227064Sbz	{(0x0D0 << 20), (0x005 << 20)},
144227064Sbz	{(0x0D1 << 20), (0x01F << 20)},
145227064Sbz	{(0x0E0 << 20), (0x008 << 20)},
146227064Sbz	{(0x0E1 << 20), (0x009 << 20)},
147227064Sbz	{(0x0E2 << 20), (0x00A << 20)},
148227064Sbz	{(0x0E3 << 20), (0x00B << 20)},
149227064Sbz	{(0x0E6 << 20), (0x007 << 20)},
150227064Sbz	{(0x199 << 20), (0x03B << 20)},
151227064Sbz	{(0x1B1 << 20), (0x006 << 20)},
152227064Sbz	{(0x295 << 20), (0x002 << 20)},
153227064Sbz	{(0x29A << 20), (0x000 << 20)},
154227064Sbz	{(0x2A5 << 20), (0x003 << 20)},
155227064Sbz	{(0x340 << 20), (0x011 << 20)},
156227064Sbz	{(0x341 << 20), (0x012 << 20)},
157227064Sbz	{(0x342 << 20), (0x013 << 20)},
158227064Sbz	{(0x343 << 20), (0x014 << 20)},
159227064Sbz	{(0x344 << 20), (0x016 << 20)},
160227064Sbz	{(0x345 << 20), (0x015 << 20)},
161227064Sbz	{(0x3C0 << 20), (0x017 << 20)},
162227064Sbz	{(0x3C1 << 20), (0x018 << 20)},
163227064Sbz	{(0x3C2 << 20), (0x019 << 20)},
164227064Sbz	{(0x3C3 << 20), (0x01A << 20)},
165227064Sbz	{(0x3C4 << 20), (0x01C << 20)},
166227064Sbz	{(0x3C5 << 20), (0x01B << 20)},
167227064Sbz	{(0x405 << 20), (0x031 << 20)},
168227064Sbz	{(0x406 << 20), (0x038 << 20)},
169227064Sbz	{(0x410 << 20), (0x01D << 20)},
170227064Sbz	{(0x416 << 20), (0x022 << 20)},
171227064Sbz	{(0x417 << 20), (0x028 << 20)},
172227064Sbz	{(0x420 << 20), (0x032 << 20)},
173227064Sbz	{(0x421 << 20), (0x033 << 20)},
174227064Sbz	{(0x700 << 20), (0x00C << 20)},
175227064Sbz	{(0x701 << 20), (0x00D << 20)},
176227064Sbz	{(0x702 << 20), (0x00E << 20)},
177227064Sbz	{(0x703 << 20), (0x00F << 20)},
178227064Sbz	{(0x704 << 20), (0x010 << 20)},
179227064Sbz	{(0x70A << 20), (0x02B << 20)},
180227064Sbz	{(0x70B << 20), (0x02C << 20)},
181227064Sbz	{(0x70C << 20), (0x02D << 20)},
182227064Sbz	{(0x70F << 20), (0x030 << 20)},
183227064Sbz	{(0x718 << 20), (0x03A << 20)},
184227064Sbz	{(0x758 << 20), (0x026 << 20)},
185227064Sbz	{(0x759 << 20), (0x027 << 20)},
186227064Sbz	{(0x773 << 20), (0x001 << 20)}
187227064Sbz};
188227064Sbz
189227064Sbz#define Q8_INVALID_ADDRESS	(-1)
190227064Sbz#define Q8_ADDR_MASK		(0xFFF << 20)
191227064Sbz
192227064Sbztypedef struct _addr_val {
193227064Sbz	uint32_t addr;
194227064Sbz	uint32_t value;
195227064Sbz	uint32_t pci_addr;
196227064Sbz	uint32_t ind_addr;
197227064Sbz} addr_val_t;
198227064Sbz
199227064Sbz/*
200227064Sbz * Name: qla_rdwr_indreg32
201227064Sbz * Function: Read/Write an Indirect Register
202227064Sbz */
203227064Sbzint
204227064Sbzqla_rdwr_indreg32(qla_host_t *ha, uint32_t addr, uint32_t *val, uint32_t rd)
205227064Sbz{
206227064Sbz	uint32_t offset;
207227064Sbz	int count = 100;
208227064Sbz
209227064Sbz	offset = (addr & 0xFFF00000) >> 20;
210227064Sbz
211227064Sbz	if (offset > 0x3F) {
212227064Sbz		device_printf(ha->pci_dev, "%s: invalid addr 0x%08x\n",
213227064Sbz			__func__, addr);
214227064Sbz		return -1;
215227064Sbz	}
216227064Sbz
217227064Sbz	offset = indirect_to_base_map[offset];
218227064Sbz	if (offset == Q8_ADDR_UNDEFINED) {
219227064Sbz		device_printf(ha->pci_dev, "%s: undefined map 0x%08x\n",
220227064Sbz			__func__, addr);
221227064Sbz		return -1;
222227064Sbz	}
223227064Sbz
224227064Sbz	offset = offset | (addr & 0x000F0000);
225227064Sbz
226227064Sbz	if (qla_sem_lock(ha, Q8_SEM7_LOCK, 0, 0)) {
227227064Sbz		device_printf(ha->pci_dev, "%s: SEM7_LOCK failed\n", __func__);
228227064Sbz		return (-1);
229227064Sbz	}
230227064Sbz
231227064Sbz	WRITE_OFFSET32(ha, Q8_CRB_WINDOW_2M, offset);
232227064Sbz
233227064Sbz	while (offset != (READ_OFFSET32(ha, Q8_CRB_WINDOW_2M))) {
234227064Sbz		count--;
235227064Sbz		if (!count) {
236227064Sbz			qla_sem_unlock(ha, Q8_SEM7_UNLOCK);
237227064Sbz			return -1;
238227064Sbz		}
239227064Sbz
240227064Sbz		qla_mdelay(__func__, 1);
241227064Sbz	}
242227064Sbz
243227064Sbz	if (rd) {
244227064Sbz		*val = READ_OFFSET32(ha, ((addr & 0xFFFF) | 0x1E0000));
245227064Sbz	} else {
246227064Sbz		WRITE_OFFSET32(ha, ((addr & 0xFFFF) | 0x1E0000), *val);
247227064Sbz	}
248227064Sbz
249227064Sbz	qla_sem_unlock(ha, Q8_SEM7_UNLOCK);
250227064Sbz	return 0;
251227064Sbz}
252227064Sbz
253227064Sbz/*
254227064Sbz * Name: qla_rdwr_offchip_mem
255227064Sbz * Function: Read/Write OffChip Memory
256227064Sbz */
257227064Sbzstatic int
258227064Sbzqla_rdwr_offchip_mem(qla_host_t *ha, uint64_t addr, offchip_mem_val_t *val,
259227064Sbz	uint32_t rd)
260227064Sbz{
261227064Sbz	uint32_t count = 100;
262227064Sbz	uint32_t data;
263227064Sbz
264227064Sbz	WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_ADDR_LO, (uint32_t)addr);
265227064Sbz	WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_ADDR_HI, (uint32_t)(addr >> 32));
266227064Sbz
267227064Sbz	if (!rd) {
268227064Sbz		WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_WRDATA_LO, val->data_lo);
269227064Sbz		WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_WRDATA_HI, val->data_hi);
270227064Sbz		WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_WRDATA_ULO, val->data_ulo);
271227064Sbz		WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_WRDATA_UHI, val->data_uhi);
272227064Sbz		WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_CTRL, 0x07); /* Write */
273227064Sbz	} else {
274227064Sbz		WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_CTRL, 0x03); /* Read */
275227064Sbz	}
276227064Sbz
277227064Sbz	while (count--) {
278227064Sbz		data = READ_OFFSET32(ha, Q8_MIU_TEST_AGT_CTRL);
279227064Sbz		if (!(data & BIT_3)) {
280227064Sbz			if (rd) {
281227064Sbz				val->data_lo = READ_OFFSET32(ha, \
282227064Sbz						Q8_MIU_TEST_AGT_RDDATA_LO);
283227064Sbz				val->data_hi = READ_OFFSET32(ha, \
284227064Sbz						Q8_MIU_TEST_AGT_RDDATA_HI);
285227064Sbz				val->data_ulo = READ_OFFSET32(ha, \
286227064Sbz						Q8_MIU_TEST_AGT_RDDATA_ULO);
287227064Sbz				val->data_uhi = READ_OFFSET32(ha, \
288227064Sbz						Q8_MIU_TEST_AGT_RDDATA_UHI);
289227064Sbz			}
290227064Sbz			return 0;
291227064Sbz		} else
292227064Sbz			qla_mdelay(__func__, 1);
293227064Sbz	}
294227064Sbz
295227064Sbz	device_printf(ha->pci_dev, "%s: failed[0x%08x]\n", __func__, data);
296227064Sbz	return (-1);
297227064Sbz}
298227064Sbz
299227064Sbz/*
300227064Sbz * Name: qla_rd_flash32
301227064Sbz * Function: Read Flash Memory
302227064Sbz */
303227064Sbzint
304227064Sbzqla_rd_flash32(qla_host_t *ha, uint32_t addr, uint32_t *data)
305227064Sbz{
306227064Sbz	uint32_t val;
307227064Sbz	uint32_t count = 100;
308227064Sbz
309227064Sbz	if (qla_sem_lock(ha, Q8_SEM2_LOCK, 0, 0)) {
310227064Sbz		device_printf(ha->pci_dev, "%s: SEM2_LOCK failed\n", __func__);
311227064Sbz		return (-1);
312227064Sbz	}
313227064Sbz	WRITE_OFFSET32(ha, Q8_ROM_LOCKID, 0xa5a5a5a5);
314227064Sbz
315227064Sbz	val = addr;
316227064Sbz	qla_rdwr_indreg32(ha, Q8_ROM_ADDRESS, &val, 0);
317227064Sbz	val = 0;
318227064Sbz	qla_rdwr_indreg32(ha, Q8_ROM_DUMMY_BYTE_COUNT, &val, 0);
319227064Sbz	val = 3;
320227064Sbz	qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
321227064Sbz
322227064Sbz	QLA_USEC_DELAY(100);
323227064Sbz
324227064Sbz	val = ROM_OPCODE_FAST_RD;
325227064Sbz	qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
326227064Sbz
327227064Sbz	while (!((val = READ_OFFSET32(ha, Q8_ROM_STATUS)) & BIT_1)) {
328227064Sbz		count--;
329227064Sbz		if (!count) {
330227064Sbz			qla_sem_unlock(ha, Q8_SEM7_UNLOCK);
331227064Sbz			return -1;
332227064Sbz		}
333227064Sbz	}
334227064Sbz
335227064Sbz	val = 0;
336227064Sbz	qla_rdwr_indreg32(ha, Q8_ROM_DUMMY_BYTE_COUNT, &val, 0);
337227064Sbz	qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
338227064Sbz
339227064Sbz	QLA_USEC_DELAY(100);
340227064Sbz
341227064Sbz	qla_rdwr_indreg32(ha, Q8_ROM_RD_DATA, data, 1);
342227064Sbz
343227064Sbz	qla_sem_unlock(ha, Q8_SEM2_UNLOCK);
344227064Sbz	return 0;
345227064Sbz}
346227064Sbz
347250340Sdavidcsstatic int
348250340Sdavidcsqla_p3p_sem_lock2(qla_host_t *ha)
349250340Sdavidcs{
350250340Sdavidcs        if (qla_sem_lock(ha, Q8_SEM2_LOCK, 0, 0)) {
351250340Sdavidcs                device_printf(ha->pci_dev, "%s: SEM2_LOCK failed\n", __func__);
352250340Sdavidcs                return (-1);
353250340Sdavidcs        }
354250340Sdavidcs        WRITE_OFFSET32(ha, Q8_ROM_LOCKID, 0xa5a5a5a5);
355250340Sdavidcs        return (0);
356250340Sdavidcs}
357250340Sdavidcs
358227064Sbz/*
359227064Sbz * Name: qla_int_to_pci_addr_map
360227064Sbz * Function: Convert's Internal(CRB) Address to Indirect Address
361227064Sbz */
362227064Sbzstatic uint32_t
363227064Sbzqla_int_to_pci_addr_map(qla_host_t *ha, uint32_t int_addr)
364227064Sbz{
365227064Sbz	uint32_t crb_to_pci_table_size, i;
366227064Sbz	uint32_t addr;
367227064Sbz
368227064Sbz	crb_to_pci_table_size = sizeof(crbinit_to_pciaddr)/sizeof(crb_to_pci_t);
369227064Sbz	addr = int_addr & Q8_ADDR_MASK;
370227064Sbz
371227064Sbz	for (i = 0; i < crb_to_pci_table_size; i++) {
372227064Sbz		if (crbinit_to_pciaddr[i].crb_addr == addr) {
373227064Sbz			addr = (int_addr & ~Q8_ADDR_MASK) |
374227064Sbz					crbinit_to_pciaddr[i].pci_addr;
375227064Sbz			return (addr);
376227064Sbz		}
377227064Sbz	}
378227064Sbz	return (Q8_INVALID_ADDRESS);
379227064Sbz}
380227064Sbz
381227064Sbz/*
382227064Sbz * Name: qla_filter_pci_addr
383227064Sbz * Function: Filter's out Indirect Addresses which are not writeable
384227064Sbz */
385227064Sbzstatic uint32_t
386227064Sbzqla_filter_pci_addr(qla_host_t *ha, uint32_t addr)
387227064Sbz{
388227064Sbz	if ((addr == Q8_INVALID_ADDRESS) ||
389227064Sbz		(addr == 0x00112040) ||
390227064Sbz		(addr == 0x00112048) ||
391227064Sbz		((addr & 0xFFFF0FFF) == 0x001100C4) ||
392227064Sbz		((addr & 0xFFFF0FFF) == 0x001100C8) ||
393227064Sbz		((addr & 0x0FF00000) == 0x00200000) ||
394227064Sbz		(addr == 0x022021FC) ||
395227064Sbz		(addr == 0x0330001C) ||
396227064Sbz		(addr == 0x03300024) ||
397227064Sbz		(addr == 0x033000A8) ||
398227064Sbz		(addr == 0x033000C8) ||
399227064Sbz		(addr == 0x033000BC) ||
400227064Sbz		((addr & 0x0FF00000) == 0x03A00000) ||
401227064Sbz		(addr == 0x03B0001C))
402227064Sbz		return (Q8_INVALID_ADDRESS);
403227064Sbz	else
404227064Sbz		return (addr);
405227064Sbz}
406227064Sbz
407227064Sbz/*
408227064Sbz * Name: qla_crb_init
409227064Sbz * Function: CRB Initialization - first step in the initialization after reset
410227064Sbz *	Essentially reads the address/value pairs from address = 0x00 and
411227064Sbz *	writes the value into address in the addr/value pair.
412227064Sbz */
413227064Sbzstatic int
414227064Sbzqla_crb_init(qla_host_t *ha)
415227064Sbz{
416250340Sdavidcs	uint32_t val = 0, sig = 0;
417227064Sbz	uint32_t offset, count, i;
418227064Sbz	addr_val_t *addr_val_map, *avmap;
419227064Sbz
420227064Sbz	qla_rd_flash32(ha, 0, &sig);
421229423Sdim	QL_DPRINT2((ha->pci_dev, "%s: val[0] = 0x%08x\n", __func__, sig));
422227064Sbz
423227064Sbz	qla_rd_flash32(ha, 4, &val);
424227064Sbz	QL_DPRINT2((ha->pci_dev, "%s: val[4] = 0x%08x\n", __func__, val));
425227064Sbz
426227064Sbz	count = val >> 16;
427227064Sbz	offset = val & 0xFFFF;
428227064Sbz	offset = offset << 2;
429227064Sbz
430227064Sbz	QL_DPRINT2((ha->pci_dev, "%s: [sig,val]=[0x%08x, 0x%08x] %d pairs\n",
431227064Sbz		__func__, sig, val, count));
432227064Sbz
433227064Sbz	addr_val_map = avmap = malloc((sizeof(addr_val_t) * count),
434227064Sbz					M_QLA8XXXBUF, M_NOWAIT);
435227064Sbz
436227064Sbz	if (addr_val_map == NULL) {
437227064Sbz		device_printf(ha->pci_dev, "%s: malloc failed\n", __func__);
438227064Sbz		return (-1);
439227064Sbz	}
440227064Sbz	memset(avmap, 0, (sizeof(addr_val_t) * count));
441227064Sbz
442227064Sbz	count = count << 1;
443227064Sbz	for (i = 0; i < count; ) {
444227064Sbz		qla_rd_flash32(ha, (offset + (i * 4)), &avmap->value);
445227064Sbz		i++;
446227064Sbz		qla_rd_flash32(ha, (offset + (i * 4)), &avmap->addr);
447227064Sbz		i++;
448227064Sbz
449227064Sbz		avmap->pci_addr = qla_int_to_pci_addr_map(ha, avmap->addr);
450227064Sbz		avmap->ind_addr = qla_filter_pci_addr(ha, avmap->pci_addr);
451227064Sbz
452227064Sbz		QL_DPRINT2((ha->pci_dev,
453227064Sbz			"%s: [0x%02x][0x%08x:0x%08x:0x%08x] 0x%08x\n",
454227064Sbz			__func__, (i >> 1), avmap->addr, avmap->pci_addr,
455227064Sbz			avmap->ind_addr, avmap->value));
456227064Sbz
457227064Sbz		if (avmap->ind_addr != Q8_INVALID_ADDRESS) {
458227064Sbz			qla_rdwr_indreg32(ha, avmap->ind_addr, &avmap->value,0);
459227064Sbz			qla_mdelay(__func__, 1);
460227064Sbz		}
461227064Sbz		avmap++;
462227064Sbz	}
463227064Sbz
464227064Sbz	free (addr_val_map, M_QLA8XXXBUF);
465227064Sbz	return (0);
466227064Sbz}
467227064Sbz
468227064Sbz/*
469227064Sbz * Name: qla_init_peg_regs
470227064Sbz * Function: Protocol Engine Register Initialization
471227064Sbz */
472227064Sbzstatic void
473227064Sbzqla_init_peg_regs(qla_host_t *ha)
474227064Sbz{
475227064Sbz	WRITE_OFFSET32(ha, Q8_PEG_D_RESET1, 0x001E);
476227064Sbz	WRITE_OFFSET32(ha, Q8_PEG_D_RESET2, 0x0008);
477227064Sbz	WRITE_OFFSET32(ha, Q8_PEG_I_RESET, 0x0008);
478227064Sbz	WRITE_OFFSET32(ha, Q8_PEG_0_CLR1, 0x0000);
479227064Sbz	WRITE_OFFSET32(ha, Q8_PEG_0_CLR2, 0x0000);
480227064Sbz	WRITE_OFFSET32(ha, Q8_PEG_1_CLR1, 0x0000);
481227064Sbz	WRITE_OFFSET32(ha, Q8_PEG_1_CLR2, 0x0000);
482227064Sbz	WRITE_OFFSET32(ha, Q8_PEG_2_CLR1, 0x0000);
483227064Sbz	WRITE_OFFSET32(ha, Q8_PEG_2_CLR2, 0x0000);
484227064Sbz	WRITE_OFFSET32(ha, Q8_PEG_3_CLR1, 0x0000);
485227064Sbz	WRITE_OFFSET32(ha, Q8_PEG_3_CLR2, 0x0000);
486227064Sbz	WRITE_OFFSET32(ha, Q8_PEG_4_CLR1, 0x0000);
487227064Sbz	WRITE_OFFSET32(ha, Q8_PEG_4_CLR2, 0x0000);
488227064Sbz}
489227064Sbz
490227064Sbz/*
491227064Sbz * Name: qla_load_fw_from_flash
492227064Sbz * Function: Reads the Bootloader from Flash and Loads into Offchip Memory
493227064Sbz */
494227064Sbzstatic void
495227064Sbzqla_load_fw_from_flash(qla_host_t *ha)
496227064Sbz{
497227064Sbz	uint64_t mem_off	= 0x10000;
498227064Sbz	uint32_t flash_off	= 0x10000;
499227064Sbz	uint32_t count;
500227064Sbz	offchip_mem_val_t val;
501227064Sbz
502227064Sbz
503227064Sbz	/* only bootloader needs to be loaded into memory */
504227064Sbz	for (count = 0; count < 0x20000 ; ) {
505227064Sbz		qla_rd_flash32(ha, flash_off, &val.data_lo);
506227064Sbz		count = count + 4;
507227064Sbz		flash_off = flash_off + 4;
508227064Sbz
509227064Sbz		qla_rd_flash32(ha, flash_off, &val.data_hi);
510227064Sbz		count = count + 4;
511227064Sbz		flash_off = flash_off + 4;
512227064Sbz
513227064Sbz		qla_rd_flash32(ha, flash_off, &val.data_ulo);
514227064Sbz		count = count + 4;
515227064Sbz		flash_off = flash_off + 4;
516227064Sbz
517227064Sbz		qla_rd_flash32(ha, flash_off, &val.data_uhi);
518227064Sbz		count = count + 4;
519227064Sbz		flash_off = flash_off + 4;
520227064Sbz
521227064Sbz		qla_rdwr_offchip_mem(ha, mem_off, &val, 0);
522227064Sbz
523227064Sbz		mem_off = mem_off + 16;
524227064Sbz	}
525227064Sbz	return;
526227064Sbz}
527227064Sbz
528227064Sbz/*
529227064Sbz * Name: qla_init_from_flash
530227064Sbz * Function: Performs Initialization which consists of the following sequence
531227064Sbz *	- reset
532227064Sbz *	- CRB Init
533227064Sbz *	- Peg Init
534227064Sbz *	- Read the Bootloader from Flash and Load into Offchip Memory
535227064Sbz *	- Kick start the bootloader which loads the rest of the firmware
536227064Sbz *		and performs the remaining steps in the initialization process.
537227064Sbz */
538227064Sbzstatic int
539227064Sbzqla_init_from_flash(qla_host_t *ha)
540227064Sbz{
541227064Sbz	uint32_t delay = 300;
542227064Sbz	uint32_t data;
543227064Sbz
544227064Sbz	qla_hw_reset(ha);
545227064Sbz	qla_mdelay(__func__, 100);
546227064Sbz
547227064Sbz	qla_crb_init(ha);
548227064Sbz	qla_mdelay(__func__, 10);
549227064Sbz
550227064Sbz	qla_init_peg_regs(ha);
551227064Sbz	qla_mdelay(__func__, 10);
552227064Sbz
553227064Sbz	qla_load_fw_from_flash(ha);
554227064Sbz
555227064Sbz	WRITE_OFFSET32(ha, Q8_CMDPEG_STATE, 0x00000000);
556227064Sbz	WRITE_OFFSET32(ha, Q8_PEG_0_RESET, 0x00001020);
557227064Sbz	WRITE_OFFSET32(ha, Q8_ASIC_RESET, 0x0080001E);
558227064Sbz	qla_mdelay(__func__, 100);
559227064Sbz
560227064Sbz	do {
561227064Sbz		data = READ_OFFSET32(ha, Q8_CMDPEG_STATE);
562227064Sbz
563227064Sbz		QL_DPRINT2((ha->pci_dev, "%s: func[%d] cmdpegstate 0x%08x\n",
564227064Sbz				__func__, ha->pci_func, data));
565227064Sbz		if (data == CMDPEG_PHAN_INIT_COMPLETE) {
566227064Sbz			QL_DPRINT2((ha->pci_dev,
567227064Sbz				"%s: func[%d] init complete\n",
568227064Sbz				__func__, ha->pci_func));
569227064Sbz			return(0);
570227064Sbz		}
571227064Sbz		qla_mdelay(__func__, 100);
572227064Sbz	} while (delay--);
573227064Sbz
574227064Sbz	device_printf(ha->pci_dev,
575227064Sbz		"%s: func[%d] Q8_PEG_HALT_STATUS1[0x%08x] STATUS2[0x%08x]"
576227064Sbz		" HEARTBEAT[0x%08x] RCVPEG_STATE[0x%08x]"
577227064Sbz		" CMDPEG_STATE[0x%08x]\n",
578227064Sbz		__func__, ha->pci_func,
579227064Sbz		(READ_OFFSET32(ha, Q8_PEG_HALT_STATUS1)),
580227064Sbz		(READ_OFFSET32(ha, Q8_PEG_HALT_STATUS2)),
581227064Sbz		(READ_OFFSET32(ha, Q8_FIRMWARE_HEARTBEAT)),
582227064Sbz		(READ_OFFSET32(ha, Q8_RCVPEG_STATE)), data);
583227064Sbz
584227064Sbz	return (-1);
585227064Sbz}
586227064Sbz
587227064Sbz/*
588227064Sbz * Name: qla_init_hw
589227064Sbz * Function: Initializes P3+ hardware.
590227064Sbz */
591227064Sbzint
592227064Sbzqla_init_hw(qla_host_t *ha)
593227064Sbz{
594227064Sbz        device_t dev;
595227064Sbz        int ret = 0;
596227064Sbz        uint32_t val, delay = 300;
597227064Sbz
598227064Sbz        dev = ha->pci_dev;
599227064Sbz
600227064Sbz        QL_DPRINT1((dev, "%s: enter\n", __func__));
601227064Sbz
602227064Sbz	qla_mdelay(__func__, 100);
603227064Sbz
604227064Sbz	if (ha->pci_func & 0x1) {
605227064Sbz        	while ((ha->pci_func & 0x1) && delay--) {
606227064Sbz			val = READ_OFFSET32(ha, Q8_CMDPEG_STATE);
607227064Sbz
608227064Sbz			if (val == CMDPEG_PHAN_INIT_COMPLETE) {
609227064Sbz				QL_DPRINT2((dev,
610227064Sbz					"%s: func = %d init complete\n",
611227064Sbz					__func__, ha->pci_func));
612227064Sbz				qla_mdelay(__func__, 100);
613227064Sbz				goto qla_init_exit;
614227064Sbz			}
615227064Sbz			qla_mdelay(__func__, 100);
616227064Sbz		}
617227064Sbz		return (-1);
618227064Sbz	}
619227064Sbz
620227064Sbz	val = READ_OFFSET32(ha, Q8_CMDPEG_STATE);
621227064Sbz
622227064Sbz	if (val != CMDPEG_PHAN_INIT_COMPLETE) {
623227064Sbz        	ret = qla_init_from_flash(ha);
624227064Sbz		qla_mdelay(__func__, 100);
625250340Sdavidcs	} else {
626250340Sdavidcs        	ha->fw_ver_major = READ_OFFSET32(ha, Q8_FW_VER_MAJOR);
627250340Sdavidcs        	ha->fw_ver_minor = READ_OFFSET32(ha, Q8_FW_VER_MINOR);
628250340Sdavidcs		ha->fw_ver_sub = READ_OFFSET32(ha, Q8_FW_VER_SUB);
629250340Sdavidcs
630250340Sdavidcs		if (qla_rd_flash32(ha, 0x100004, &val) == 0) {
631250340Sdavidcs
632250340Sdavidcs			if (((val & 0xFF) != ha->fw_ver_major) ||
633250340Sdavidcs				(((val >> 8) & 0xFF) != ha->fw_ver_minor) ||
634250340Sdavidcs				(((val >> 16) & 0xFF) != ha->fw_ver_sub)) {
635250340Sdavidcs
636250340Sdavidcs        			ret = qla_init_from_flash(ha);
637250340Sdavidcs				qla_mdelay(__func__, 100);
638250340Sdavidcs			}
639250340Sdavidcs		}
640227064Sbz	}
641227064Sbz
642227064Sbzqla_init_exit:
643227064Sbz        ha->fw_ver_major = READ_OFFSET32(ha, Q8_FW_VER_MAJOR);
644227064Sbz        ha->fw_ver_minor = READ_OFFSET32(ha, Q8_FW_VER_MINOR);
645227064Sbz        ha->fw_ver_sub = READ_OFFSET32(ha, Q8_FW_VER_SUB);
646227064Sbz        ha->fw_ver_build = READ_OFFSET32(ha, Q8_FW_VER_BUILD);
647227064Sbz
648227064Sbz        return (ret);
649227064Sbz}
650227064Sbz
651250340Sdavidcsstatic int
652250340Sdavidcsqla_wait_for_flash_busy(qla_host_t *ha)
653250340Sdavidcs{
654250340Sdavidcs	uint32_t count = 100;
655250340Sdavidcs	uint32_t val;
656250340Sdavidcs
657250340Sdavidcs	QLA_USEC_DELAY(100);
658250340Sdavidcs
659250340Sdavidcs	while (count--) {
660250340Sdavidcs		val = READ_OFFSET32(ha, Q8_ROM_STATUS);
661250340Sdavidcs
662250340Sdavidcs		if (val & BIT_1)
663250340Sdavidcs			return 0;
664250340Sdavidcs		qla_mdelay(__func__, 1);
665250340Sdavidcs	}
666250340Sdavidcs	return -1;
667250340Sdavidcs}
668250340Sdavidcs
669250340Sdavidcsstatic int
670250340Sdavidcsqla_flash_write_enable(qla_host_t *ha)
671250340Sdavidcs{
672250340Sdavidcs	uint32_t val, rval;
673250340Sdavidcs
674250340Sdavidcs	val = 0;
675250340Sdavidcs	qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
676250340Sdavidcs
677250340Sdavidcs	val = ROM_OPCODE_WR_ENABLE;
678250340Sdavidcs	qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
679250340Sdavidcs
680250340Sdavidcs	rval = qla_wait_for_flash_busy(ha);
681250340Sdavidcs
682250340Sdavidcs	if (rval)
683250340Sdavidcs		device_printf(ha->pci_dev, "%s: failed \n", __func__);
684250340Sdavidcs
685250340Sdavidcs	return (rval);
686250340Sdavidcs}
687250340Sdavidcs
688250340Sdavidcsstatic int
689250340Sdavidcsqla_flash_unprotect(qla_host_t *ha)
690250340Sdavidcs{
691250340Sdavidcs	uint32_t val, rval;
692250340Sdavidcs
693250340Sdavidcs	if (qla_flash_write_enable(ha) != 0)
694250340Sdavidcs		return(-1);
695250340Sdavidcs
696250340Sdavidcs	val = 0;
697250340Sdavidcs	qla_rdwr_indreg32(ha, Q8_ROM_WR_DATA, &val, 0);
698250340Sdavidcs
699250340Sdavidcs	val = ROM_OPCODE_WR_STATUS_REG;
700250340Sdavidcs	qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
701250340Sdavidcs
702250340Sdavidcs	rval = qla_wait_for_flash_busy(ha);
703250340Sdavidcs
704250340Sdavidcs	if (rval) {
705250340Sdavidcs		device_printf(ha->pci_dev, "%s: failed \n", __func__);
706250340Sdavidcs		return rval;
707250340Sdavidcs	}
708250340Sdavidcs
709250340Sdavidcs	if (qla_flash_write_enable(ha) != 0)
710250340Sdavidcs		return(-1);
711250340Sdavidcs
712250340Sdavidcs	val = 0;
713250340Sdavidcs	qla_rdwr_indreg32(ha, Q8_ROM_WR_DATA, &val, 0);
714250340Sdavidcs
715250340Sdavidcs	val = ROM_OPCODE_WR_STATUS_REG;
716250340Sdavidcs	qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
717250340Sdavidcs
718250340Sdavidcs	rval = qla_wait_for_flash_busy(ha);
719250340Sdavidcs
720250340Sdavidcs	if (rval)
721250340Sdavidcs		device_printf(ha->pci_dev, "%s: failed \n", __func__);
722250340Sdavidcs
723250340Sdavidcs	return rval;
724250340Sdavidcs}
725250340Sdavidcs
726250340Sdavidcsstatic int
727250340Sdavidcsqla_flash_protect(qla_host_t *ha)
728250340Sdavidcs{
729250340Sdavidcs	uint32_t val, rval;
730250340Sdavidcs
731250340Sdavidcs	if (qla_flash_write_enable(ha) != 0)
732250340Sdavidcs		return(-1);
733250340Sdavidcs
734250340Sdavidcs	val = 0x9C;
735250340Sdavidcs	qla_rdwr_indreg32(ha, Q8_ROM_WR_DATA, &val, 0);
736250340Sdavidcs
737250340Sdavidcs	val = ROM_OPCODE_WR_STATUS_REG;
738250340Sdavidcs	qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
739250340Sdavidcs
740250340Sdavidcs	rval = qla_wait_for_flash_busy(ha);
741250340Sdavidcs
742250340Sdavidcs	if (rval)
743250340Sdavidcs		device_printf(ha->pci_dev, "%s: failed \n", __func__);
744250340Sdavidcs
745250340Sdavidcs	return rval;
746250340Sdavidcs}
747250340Sdavidcs
748250340Sdavidcsstatic uint32_t
749250340Sdavidcsqla_flash_get_status(qla_host_t *ha)
750250340Sdavidcs{
751250340Sdavidcs	uint32_t count = 1000;
752250340Sdavidcs	uint32_t val, rval;
753250340Sdavidcs
754250340Sdavidcs	while (count--) {
755250340Sdavidcs		val = 0;
756250340Sdavidcs		qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
757250340Sdavidcs
758250340Sdavidcs		val = ROM_OPCODE_RD_STATUS_REG;
759250340Sdavidcs		qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
760250340Sdavidcs
761250340Sdavidcs		rval = qla_wait_for_flash_busy(ha);
762250340Sdavidcs
763250340Sdavidcs		if (rval == 0) {
764250340Sdavidcs			qla_rdwr_indreg32(ha, Q8_ROM_RD_DATA, &val, 1);
765250340Sdavidcs
766250340Sdavidcs			if ((val & BIT_0) == 0)
767250340Sdavidcs				return (val);
768250340Sdavidcs		}
769250340Sdavidcs		qla_mdelay(__func__, 1);
770250340Sdavidcs	}
771250340Sdavidcs	return -1;
772250340Sdavidcs}
773250340Sdavidcs
774250340Sdavidcsstatic int
775250340Sdavidcsqla_wait_for_flash_unprotect(qla_host_t *ha)
776250340Sdavidcs{
777250340Sdavidcs	uint32_t delay = 1000;
778250340Sdavidcs
779250340Sdavidcs	while (delay--) {
780250340Sdavidcs
781250340Sdavidcs		if (qla_flash_get_status(ha) == 0)
782250340Sdavidcs			return 0;
783250340Sdavidcs
784250340Sdavidcs		qla_mdelay(__func__, 1);
785250340Sdavidcs	}
786250340Sdavidcs
787250340Sdavidcs	return -1;
788250340Sdavidcs}
789250340Sdavidcs
790250340Sdavidcsstatic int
791250340Sdavidcsqla_wait_for_flash_protect(qla_host_t *ha)
792250340Sdavidcs{
793250340Sdavidcs	uint32_t delay = 1000;
794250340Sdavidcs
795250340Sdavidcs	while (delay--) {
796250340Sdavidcs
797250340Sdavidcs		if (qla_flash_get_status(ha) == 0x9C)
798250340Sdavidcs			return 0;
799250340Sdavidcs
800250340Sdavidcs		qla_mdelay(__func__, 1);
801250340Sdavidcs	}
802250340Sdavidcs
803250340Sdavidcs	return -1;
804250340Sdavidcs}
805250340Sdavidcs
806250340Sdavidcsstatic int
807250340Sdavidcsqla_erase_flash_sector(qla_host_t *ha, uint32_t start)
808250340Sdavidcs{
809250340Sdavidcs	uint32_t val;
810250340Sdavidcs	int rval;
811250340Sdavidcs
812250340Sdavidcs	if (qla_flash_write_enable(ha) != 0)
813250340Sdavidcs		return(-1);
814250340Sdavidcs
815250340Sdavidcs        val = start;
816250340Sdavidcs        qla_rdwr_indreg32(ha, Q8_ROM_ADDRESS, &val, 0);
817250340Sdavidcs
818250340Sdavidcs        val = 3;
819250340Sdavidcs        qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
820250340Sdavidcs
821250340Sdavidcs        val = ROM_OPCODE_SECTOR_ERASE;
822250340Sdavidcs        qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
823250340Sdavidcs
824250340Sdavidcs	rval = qla_wait_for_flash_busy(ha);
825250340Sdavidcs
826250340Sdavidcs	if (rval)
827250340Sdavidcs		device_printf(ha->pci_dev, "%s: failed \n", __func__);
828250340Sdavidcs	return rval;
829250340Sdavidcs}
830250340Sdavidcs
831250340Sdavidcs#define Q8_FLASH_SECTOR_SIZE 0x10000
832250340Sdavidcsint
833250340Sdavidcsqla_erase_flash(qla_host_t *ha, uint32_t off, uint32_t size)
834250340Sdavidcs{
835250340Sdavidcs	int rval = 0;
836250340Sdavidcs	uint32_t start;
837250340Sdavidcs
838250340Sdavidcs	if (off & (Q8_FLASH_SECTOR_SIZE -1))
839250340Sdavidcs		return -1;
840250340Sdavidcs
841250340Sdavidcs	if ((rval = qla_p3p_sem_lock2(ha)))
842250340Sdavidcs		goto qla_erase_flash_exit;
843250340Sdavidcs
844250340Sdavidcs	if ((rval = qla_flash_unprotect(ha)))
845250340Sdavidcs		goto qla_erase_flash_unlock_exit;
846250340Sdavidcs
847250340Sdavidcs	if ((rval = qla_wait_for_flash_unprotect(ha)))
848250340Sdavidcs		goto qla_erase_flash_unlock_exit;
849250340Sdavidcs
850250340Sdavidcs	for (start = off; start < (off + size); start = start + 0x10000) {
851250340Sdavidcs		if (qla_erase_flash_sector(ha, start)) {
852250340Sdavidcs			rval = -1;
853250340Sdavidcs			break;
854250340Sdavidcs		}
855250340Sdavidcs	}
856250340Sdavidcs
857250340Sdavidcs	rval = qla_flash_protect(ha);
858250340Sdavidcs
859250340Sdavidcsqla_erase_flash_unlock_exit:
860250340Sdavidcs	qla_sem_unlock(ha, Q8_SEM2_UNLOCK);
861250340Sdavidcs
862250340Sdavidcsqla_erase_flash_exit:
863250340Sdavidcs	return (rval);
864250340Sdavidcs}
865250340Sdavidcs
866250340Sdavidcsstatic int
867250340Sdavidcsqla_flash_write32(qla_host_t *ha, uint32_t off, uint32_t data)
868250340Sdavidcs{
869250340Sdavidcs	uint32_t val;
870250340Sdavidcs	int rval = 0;
871250340Sdavidcs
872250340Sdavidcs        val = data;
873250340Sdavidcs        qla_rdwr_indreg32(ha, Q8_ROM_WR_DATA, &val, 0);
874250340Sdavidcs
875250340Sdavidcs        val = off;
876250340Sdavidcs        qla_rdwr_indreg32(ha, Q8_ROM_ADDRESS, &val, 0);
877250340Sdavidcs
878250340Sdavidcs        val = 3;
879250340Sdavidcs        qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
880250340Sdavidcs
881250340Sdavidcs        val = ROM_OPCODE_PROG_PAGE;
882250340Sdavidcs        qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
883250340Sdavidcs
884250340Sdavidcs	rval = qla_wait_for_flash_busy(ha);
885250340Sdavidcs
886250340Sdavidcs	if (rval)
887250340Sdavidcs		device_printf(ha->pci_dev, "%s: failed \n", __func__);
888250340Sdavidcs
889250340Sdavidcs	return rval;
890250340Sdavidcs}
891250340Sdavidcs
892250340Sdavidcsstatic int
893250340Sdavidcsqla_flash_wait_for_write_complete(qla_host_t *ha)
894250340Sdavidcs{
895250340Sdavidcs	uint32_t val, count = 1000;
896250340Sdavidcs	int rval = 0;
897250340Sdavidcs
898250340Sdavidcs	while (count--) {
899250340Sdavidcs
900250340Sdavidcs		val = 0;
901250340Sdavidcs		qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
902250340Sdavidcs
903250340Sdavidcs		val = ROM_OPCODE_RD_STATUS_REG;
904250340Sdavidcs		qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
905250340Sdavidcs
906250340Sdavidcs
907250340Sdavidcs		rval = qla_wait_for_flash_busy(ha);
908250340Sdavidcs
909250340Sdavidcs		if (rval == 0) {
910250340Sdavidcs			qla_rdwr_indreg32(ha, Q8_ROM_RD_DATA, &val, 1);
911250340Sdavidcs
912250340Sdavidcs			if ((val & BIT_0) == 0)
913250340Sdavidcs				return (0);
914250340Sdavidcs		}
915250340Sdavidcs		qla_mdelay(__func__, 1);
916250340Sdavidcs	}
917250340Sdavidcs	return -1;
918250340Sdavidcs}
919250340Sdavidcs
920250340Sdavidcsstatic int
921250340Sdavidcsqla_flash_write(qla_host_t *ha, uint32_t off, uint32_t data)
922250340Sdavidcs{
923250340Sdavidcs	if (qla_flash_write_enable(ha) != 0)
924250340Sdavidcs		return(-1);
925250340Sdavidcs
926250340Sdavidcs	if (qla_flash_write32(ha, off, data) != 0)
927250340Sdavidcs		return -1;
928250340Sdavidcs
929250340Sdavidcs	if (qla_flash_wait_for_write_complete(ha))
930250340Sdavidcs		return -1;
931250340Sdavidcs
932250340Sdavidcs	return 0;
933250340Sdavidcs}
934250340Sdavidcs
935250340Sdavidcs
936250340Sdavidcsstatic int
937250340Sdavidcsqla_flash_write_pattern(qla_host_t *ha, uint32_t off, uint32_t size,
938250340Sdavidcs	uint32_t pattern)
939250340Sdavidcs{
940250340Sdavidcs	int rval = 0;
941250340Sdavidcs	uint32_t start;
942250340Sdavidcs
943250340Sdavidcs
944250340Sdavidcs	if ((rval = qla_p3p_sem_lock2(ha)))
945250340Sdavidcs		goto qla_wr_pattern_exit;
946250340Sdavidcs
947250340Sdavidcs	if ((rval = qla_flash_unprotect(ha)))
948250340Sdavidcs		goto qla_wr_pattern_unlock_exit;
949250340Sdavidcs
950250340Sdavidcs	if ((rval = qla_wait_for_flash_unprotect(ha)))
951250340Sdavidcs		goto qla_wr_pattern_unlock_exit;
952250340Sdavidcs
953250340Sdavidcs	for (start = off; start < (off + size); start = start + 4) {
954250340Sdavidcs		if (qla_flash_write(ha, start, pattern)) {
955250340Sdavidcs			rval = -1;
956250340Sdavidcs			break;
957250340Sdavidcs		}
958250340Sdavidcs	}
959250340Sdavidcs
960250340Sdavidcs	rval = qla_flash_protect(ha);
961250340Sdavidcs
962250340Sdavidcs	if (rval == 0)
963250340Sdavidcs		rval = qla_wait_for_flash_protect(ha);
964250340Sdavidcs
965250340Sdavidcsqla_wr_pattern_unlock_exit:
966250340Sdavidcs	qla_sem_unlock(ha, Q8_SEM2_UNLOCK);
967250340Sdavidcs
968250340Sdavidcsqla_wr_pattern_exit:
969250340Sdavidcs	return (rval);
970250340Sdavidcs}
971250340Sdavidcs
972250340Sdavidcsstatic int
973250340Sdavidcsqla_flash_write_data(qla_host_t *ha, uint32_t off, uint32_t size,
974250340Sdavidcs	void *data)
975250340Sdavidcs{
976250340Sdavidcs	int rval = 0;
977250340Sdavidcs	uint32_t start;
978250340Sdavidcs	uint32_t *data32 = data;
979250340Sdavidcs
980250340Sdavidcs
981250340Sdavidcs	if ((rval = qla_p3p_sem_lock2(ha)))
982250340Sdavidcs		goto qla_wr_pattern_exit;
983250340Sdavidcs
984250340Sdavidcs	if ((rval = qla_flash_unprotect(ha)))
985250340Sdavidcs		goto qla_wr_pattern_unlock_exit;
986250340Sdavidcs
987250340Sdavidcs	if ((rval = qla_wait_for_flash_unprotect(ha)))
988250340Sdavidcs		goto qla_wr_pattern_unlock_exit;
989250340Sdavidcs
990250340Sdavidcs	for (start = off; start < (off + size); start = start + 4) {
991250340Sdavidcs
992250340Sdavidcs		if (*data32 != 0xFFFFFFFF) {
993250340Sdavidcs			if (qla_flash_write(ha, start, *data32)) {
994250340Sdavidcs				rval = -1;
995250340Sdavidcs				break;
996250340Sdavidcs			}
997250340Sdavidcs		}
998250340Sdavidcs		data32++;
999250340Sdavidcs	}
1000250340Sdavidcs
1001250340Sdavidcs	rval = qla_flash_protect(ha);
1002250340Sdavidcs
1003250340Sdavidcs	if (rval == 0)
1004250340Sdavidcs		rval = qla_wait_for_flash_protect(ha);
1005250340Sdavidcs
1006250340Sdavidcsqla_wr_pattern_unlock_exit:
1007250340Sdavidcs	qla_sem_unlock(ha, Q8_SEM2_UNLOCK);
1008250340Sdavidcs
1009250340Sdavidcsqla_wr_pattern_exit:
1010250340Sdavidcs	return (rval);
1011250340Sdavidcs}
1012250340Sdavidcs
1013250340Sdavidcsint
1014250340Sdavidcsqla_wr_flash_buffer(qla_host_t *ha, uint32_t off, uint32_t size, void *buf,
1015250340Sdavidcs	uint32_t pattern)
1016250340Sdavidcs{
1017250340Sdavidcs	int rval = 0;
1018250340Sdavidcs	void *data;
1019250340Sdavidcs
1020250340Sdavidcs
1021250340Sdavidcs	if (size == 0)
1022250340Sdavidcs		return 0;
1023250340Sdavidcs
1024250340Sdavidcs	size = size << 2;
1025250340Sdavidcs
1026250340Sdavidcs	if (buf == NULL) {
1027250340Sdavidcs		rval = qla_flash_write_pattern(ha, off, size, pattern);
1028250340Sdavidcs		return (rval);
1029250340Sdavidcs	}
1030250340Sdavidcs
1031250340Sdavidcs	if ((data = malloc(size, M_QLA8XXXBUF, M_NOWAIT)) == NULL) {
1032250340Sdavidcs		device_printf(ha->pci_dev, "%s: malloc failed \n", __func__);
1033250340Sdavidcs		rval = -1;
1034250340Sdavidcs		goto qla_wr_flash_buffer_exit;
1035250340Sdavidcs	}
1036250340Sdavidcs
1037250340Sdavidcs	if ((rval = copyin(buf, data, size))) {
1038250340Sdavidcs		device_printf(ha->pci_dev, "%s copyin failed\n", __func__);
1039250340Sdavidcs		goto qla_wr_flash_buffer_free_exit;
1040250340Sdavidcs	}
1041250340Sdavidcs
1042250340Sdavidcs	rval = qla_flash_write_data(ha, off, size, data);
1043250340Sdavidcs
1044250340Sdavidcsqla_wr_flash_buffer_free_exit:
1045250340Sdavidcs	free(data, M_QLA8XXXBUF);
1046250340Sdavidcs
1047250340Sdavidcsqla_wr_flash_buffer_exit:
1048250340Sdavidcs	return (rval);
1049250340Sdavidcs}
1050250340Sdavidcs
1051