xref: /freebsd/sys/dev/qlxgb/qla_misc.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
1718cf2ccSPedro F. Giffuni /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
4088fc971SDavid C Somayajulu  * Copyright (c) 2011-2013 Qlogic Corporation
50bc7cf6fSBjoern A. Zeeb  * All rights reserved.
60bc7cf6fSBjoern A. Zeeb  *
70bc7cf6fSBjoern A. Zeeb  *  Redistribution and use in source and binary forms, with or without
80bc7cf6fSBjoern A. Zeeb  *  modification, are permitted provided that the following conditions
90bc7cf6fSBjoern A. Zeeb  *  are met:
100bc7cf6fSBjoern A. Zeeb  *
110bc7cf6fSBjoern A. Zeeb  *  1. Redistributions of source code must retain the above copyright
120bc7cf6fSBjoern A. Zeeb  *     notice, this list of conditions and the following disclaimer.
130bc7cf6fSBjoern A. Zeeb  *  2. Redistributions in binary form must reproduce the above copyright
140bc7cf6fSBjoern A. Zeeb  *     notice, this list of conditions and the following disclaimer in the
150bc7cf6fSBjoern A. Zeeb  *     documentation and/or other materials provided with the distribution.
160bc7cf6fSBjoern A. Zeeb  *
170bc7cf6fSBjoern A. Zeeb  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
180bc7cf6fSBjoern A. Zeeb  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
190bc7cf6fSBjoern A. Zeeb  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
200bc7cf6fSBjoern A. Zeeb  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
210bc7cf6fSBjoern A. Zeeb  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
220bc7cf6fSBjoern A. Zeeb  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
230bc7cf6fSBjoern A. Zeeb  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
240bc7cf6fSBjoern A. Zeeb  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
250bc7cf6fSBjoern A. Zeeb  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
260bc7cf6fSBjoern A. Zeeb  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
270bc7cf6fSBjoern A. Zeeb  *  POSSIBILITY OF SUCH DAMAGE.
280bc7cf6fSBjoern A. Zeeb  */
290bc7cf6fSBjoern A. Zeeb /*
300bc7cf6fSBjoern A. Zeeb  * File : qla_misc.c
310bc7cf6fSBjoern A. Zeeb  * Author : David C Somayajulu, Qlogic Corporation, Aliso Viejo, CA 92656.
320bc7cf6fSBjoern A. Zeeb  */
330bc7cf6fSBjoern A. Zeeb 
340bc7cf6fSBjoern A. Zeeb #include <sys/cdefs.h>
350bc7cf6fSBjoern A. Zeeb #include "qla_os.h"
360bc7cf6fSBjoern A. Zeeb #include "qla_reg.h"
370bc7cf6fSBjoern A. Zeeb #include "qla_hw.h"
380bc7cf6fSBjoern A. Zeeb #include "qla_def.h"
390bc7cf6fSBjoern A. Zeeb #include "qla_reg.h"
400bc7cf6fSBjoern A. Zeeb #include "qla_inline.h"
410bc7cf6fSBjoern A. Zeeb #include "qla_glbl.h"
420bc7cf6fSBjoern A. Zeeb #include "qla_dbg.h"
430bc7cf6fSBjoern A. Zeeb 
440bc7cf6fSBjoern A. Zeeb /*
450bc7cf6fSBjoern A. Zeeb  * structure encapsulating the value to read/write to offchip memory
460bc7cf6fSBjoern A. Zeeb  */
470bc7cf6fSBjoern A. Zeeb typedef struct _offchip_mem_val {
480bc7cf6fSBjoern A. Zeeb         uint32_t data_lo;
490bc7cf6fSBjoern A. Zeeb         uint32_t data_hi;
500bc7cf6fSBjoern A. Zeeb         uint32_t data_ulo;
510bc7cf6fSBjoern A. Zeeb         uint32_t data_uhi;
520bc7cf6fSBjoern A. Zeeb } offchip_mem_val_t;
530bc7cf6fSBjoern A. Zeeb 
540bc7cf6fSBjoern A. Zeeb #define Q8_ADDR_UNDEFINED		0xFFFFFFFF
550bc7cf6fSBjoern A. Zeeb 
560bc7cf6fSBjoern A. Zeeb /*
570bc7cf6fSBjoern A. Zeeb  * The index to this table is Bits 20-27 of the indirect register address
580bc7cf6fSBjoern A. Zeeb  */
590bc7cf6fSBjoern A. Zeeb static uint32_t indirect_to_base_map[] =
600bc7cf6fSBjoern A. Zeeb 	{
610bc7cf6fSBjoern A. Zeeb 		Q8_ADDR_UNDEFINED,	/* 0x00 */
620bc7cf6fSBjoern A. Zeeb 		0x77300000,		/* 0x01 */
630bc7cf6fSBjoern A. Zeeb 		0x29500000,		/* 0x02 */
640bc7cf6fSBjoern A. Zeeb 		0x2A500000,		/* 0x03 */
650bc7cf6fSBjoern A. Zeeb 		Q8_ADDR_UNDEFINED,	/* 0x04 */
660bc7cf6fSBjoern A. Zeeb 		0x0D000000,		/* 0x05 */
670bc7cf6fSBjoern A. Zeeb 		0x1B100000,		/* 0x06 */
680bc7cf6fSBjoern A. Zeeb 		0x0E600000,		/* 0x07 */
690bc7cf6fSBjoern A. Zeeb 		0x0E000000,		/* 0x08 */
700bc7cf6fSBjoern A. Zeeb 		0x0E100000,		/* 0x09 */
710bc7cf6fSBjoern A. Zeeb 		0x0E200000,		/* 0x0A */
720bc7cf6fSBjoern A. Zeeb 		0x0E300000,		/* 0x0B */
730bc7cf6fSBjoern A. Zeeb 		0x42000000,		/* 0x0C */
740bc7cf6fSBjoern A. Zeeb 		0x41700000,		/* 0x0D */
750bc7cf6fSBjoern A. Zeeb 		0x42100000,		/* 0x0E */
760bc7cf6fSBjoern A. Zeeb 		0x34B00000,		/* 0x0F */
770bc7cf6fSBjoern A. Zeeb 		0x40500000,		/* 0x10 */
780bc7cf6fSBjoern A. Zeeb 		0x34000000,		/* 0x11 */
790bc7cf6fSBjoern A. Zeeb 		0x34100000,		/* 0x12 */
800bc7cf6fSBjoern A. Zeeb 		0x34200000,		/* 0x13 */
810bc7cf6fSBjoern A. Zeeb 		0x34300000,		/* 0x14 */
820bc7cf6fSBjoern A. Zeeb 		0x34500000,		/* 0x15 */
830bc7cf6fSBjoern A. Zeeb 		0x34400000,		/* 0x16 */
840bc7cf6fSBjoern A. Zeeb 		0x3C000000,		/* 0x17 */
850bc7cf6fSBjoern A. Zeeb 		0x3C100000,		/* 0x18 */
860bc7cf6fSBjoern A. Zeeb 		0x3C200000,		/* 0x19 */
870bc7cf6fSBjoern A. Zeeb 		0x3C300000,		/* 0x1A */
880bc7cf6fSBjoern A. Zeeb 		Q8_ADDR_UNDEFINED,	/* 0x1B */
890bc7cf6fSBjoern A. Zeeb 		0x3C400000,		/* 0x1C */
900bc7cf6fSBjoern A. Zeeb 		0x41000000,		/* 0x1D */
910bc7cf6fSBjoern A. Zeeb 		Q8_ADDR_UNDEFINED,	/* 0x1E */
920bc7cf6fSBjoern A. Zeeb 		0x0D100000,		/* 0x1F */
930bc7cf6fSBjoern A. Zeeb 		Q8_ADDR_UNDEFINED,	/* 0x20 */
940bc7cf6fSBjoern A. Zeeb 		0x77300000,		/* 0x21 */
950bc7cf6fSBjoern A. Zeeb 		0x41600000,		/* 0x22 */
960bc7cf6fSBjoern A. Zeeb 		Q8_ADDR_UNDEFINED,	/* 0x23 */
970bc7cf6fSBjoern A. Zeeb 		Q8_ADDR_UNDEFINED,	/* 0x24 */
980bc7cf6fSBjoern A. Zeeb 		Q8_ADDR_UNDEFINED,	/* 0x25 */
990bc7cf6fSBjoern A. Zeeb 		Q8_ADDR_UNDEFINED,	/* 0x26 */
1000bc7cf6fSBjoern A. Zeeb 		Q8_ADDR_UNDEFINED,	/* 0x27 */
1010bc7cf6fSBjoern A. Zeeb 		0x41700000,		/* 0x28 */
1020bc7cf6fSBjoern A. Zeeb 		Q8_ADDR_UNDEFINED,	/* 0x29 */
1030bc7cf6fSBjoern A. Zeeb 		0x08900000,		/* 0x2A */
1040bc7cf6fSBjoern A. Zeeb 		0x70A00000,		/* 0x2B */
1050bc7cf6fSBjoern A. Zeeb 		0x70B00000,		/* 0x2C */
1060bc7cf6fSBjoern A. Zeeb 		0x70C00000,		/* 0x2D */
1070bc7cf6fSBjoern A. Zeeb 		0x08D00000,		/* 0x2E */
1080bc7cf6fSBjoern A. Zeeb 		0x08E00000,		/* 0x2F */
1090bc7cf6fSBjoern A. Zeeb 		0x70F00000,		/* 0x30 */
1100bc7cf6fSBjoern A. Zeeb 		0x40500000,		/* 0x31 */
1110bc7cf6fSBjoern A. Zeeb 		0x42000000,		/* 0x32 */
1120bc7cf6fSBjoern A. Zeeb 		0x42100000,		/* 0x33 */
1130bc7cf6fSBjoern A. Zeeb 		Q8_ADDR_UNDEFINED,	/* 0x34 */
1140bc7cf6fSBjoern A. Zeeb 		0x08800000,		/* 0x35 */
1150bc7cf6fSBjoern A. Zeeb 		0x09100000,		/* 0x36 */
1160bc7cf6fSBjoern A. Zeeb 		0x71200000,		/* 0x37 */
1170bc7cf6fSBjoern A. Zeeb 		0x40600000,		/* 0x38 */
1180bc7cf6fSBjoern A. Zeeb 		Q8_ADDR_UNDEFINED,	/* 0x39 */
1190bc7cf6fSBjoern A. Zeeb 		0x71800000,		/* 0x3A */
1200bc7cf6fSBjoern A. Zeeb 		0x19900000,		/* 0x3B */
1210bc7cf6fSBjoern A. Zeeb 		0x1A900000,		/* 0x3C */
1220bc7cf6fSBjoern A. Zeeb 		Q8_ADDR_UNDEFINED,	/* 0x3D */
1230bc7cf6fSBjoern A. Zeeb 		0x34600000,		/* 0x3E */
1240bc7cf6fSBjoern A. Zeeb 		Q8_ADDR_UNDEFINED,	/* 0x3F */
1250bc7cf6fSBjoern A. Zeeb 	};
1260bc7cf6fSBjoern A. Zeeb 
1270bc7cf6fSBjoern A. Zeeb /*
1280bc7cf6fSBjoern A. Zeeb  * Address Translation Table for CRB to offsets from PCI BAR0
1290bc7cf6fSBjoern A. Zeeb  */
1300bc7cf6fSBjoern A. Zeeb typedef struct _crb_to_pci {
1310bc7cf6fSBjoern A. Zeeb 	uint32_t crb_addr;
1320bc7cf6fSBjoern A. Zeeb 	uint32_t pci_addr;
1330bc7cf6fSBjoern A. Zeeb } crb_to_pci_t;
1340bc7cf6fSBjoern A. Zeeb 
1350bc7cf6fSBjoern A. Zeeb static crb_to_pci_t crbinit_to_pciaddr[] = {
1360bc7cf6fSBjoern A. Zeeb 	{(0x088 << 20), (0x035 << 20)},
1370bc7cf6fSBjoern A. Zeeb 	{(0x089 << 20), (0x02A << 20)},
1380bc7cf6fSBjoern A. Zeeb 	{(0x08D << 20), (0x02E << 20)},
1390bc7cf6fSBjoern A. Zeeb 	{(0x08E << 20), (0x02F << 20)},
1400bc7cf6fSBjoern A. Zeeb 	{(0x0C6 << 20), (0x023 << 20)},
1410bc7cf6fSBjoern A. Zeeb 	{(0x0C7 << 20), (0x024 << 20)},
1420bc7cf6fSBjoern A. Zeeb 	{(0x0C8 << 20), (0x025 << 20)},
1430bc7cf6fSBjoern A. Zeeb 	{(0x0D0 << 20), (0x005 << 20)},
1440bc7cf6fSBjoern A. Zeeb 	{(0x0D1 << 20), (0x01F << 20)},
1450bc7cf6fSBjoern A. Zeeb 	{(0x0E0 << 20), (0x008 << 20)},
1460bc7cf6fSBjoern A. Zeeb 	{(0x0E1 << 20), (0x009 << 20)},
1470bc7cf6fSBjoern A. Zeeb 	{(0x0E2 << 20), (0x00A << 20)},
1480bc7cf6fSBjoern A. Zeeb 	{(0x0E3 << 20), (0x00B << 20)},
1490bc7cf6fSBjoern A. Zeeb 	{(0x0E6 << 20), (0x007 << 20)},
1500bc7cf6fSBjoern A. Zeeb 	{(0x199 << 20), (0x03B << 20)},
1510bc7cf6fSBjoern A. Zeeb 	{(0x1B1 << 20), (0x006 << 20)},
1520bc7cf6fSBjoern A. Zeeb 	{(0x295 << 20), (0x002 << 20)},
1530bc7cf6fSBjoern A. Zeeb 	{(0x29A << 20), (0x000 << 20)},
1540bc7cf6fSBjoern A. Zeeb 	{(0x2A5 << 20), (0x003 << 20)},
1550bc7cf6fSBjoern A. Zeeb 	{(0x340 << 20), (0x011 << 20)},
1560bc7cf6fSBjoern A. Zeeb 	{(0x341 << 20), (0x012 << 20)},
1570bc7cf6fSBjoern A. Zeeb 	{(0x342 << 20), (0x013 << 20)},
1580bc7cf6fSBjoern A. Zeeb 	{(0x343 << 20), (0x014 << 20)},
1590bc7cf6fSBjoern A. Zeeb 	{(0x344 << 20), (0x016 << 20)},
1600bc7cf6fSBjoern A. Zeeb 	{(0x345 << 20), (0x015 << 20)},
1610bc7cf6fSBjoern A. Zeeb 	{(0x3C0 << 20), (0x017 << 20)},
1620bc7cf6fSBjoern A. Zeeb 	{(0x3C1 << 20), (0x018 << 20)},
1630bc7cf6fSBjoern A. Zeeb 	{(0x3C2 << 20), (0x019 << 20)},
1640bc7cf6fSBjoern A. Zeeb 	{(0x3C3 << 20), (0x01A << 20)},
1650bc7cf6fSBjoern A. Zeeb 	{(0x3C4 << 20), (0x01C << 20)},
1660bc7cf6fSBjoern A. Zeeb 	{(0x3C5 << 20), (0x01B << 20)},
1670bc7cf6fSBjoern A. Zeeb 	{(0x405 << 20), (0x031 << 20)},
1680bc7cf6fSBjoern A. Zeeb 	{(0x406 << 20), (0x038 << 20)},
1690bc7cf6fSBjoern A. Zeeb 	{(0x410 << 20), (0x01D << 20)},
1700bc7cf6fSBjoern A. Zeeb 	{(0x416 << 20), (0x022 << 20)},
1710bc7cf6fSBjoern A. Zeeb 	{(0x417 << 20), (0x028 << 20)},
1720bc7cf6fSBjoern A. Zeeb 	{(0x420 << 20), (0x032 << 20)},
1730bc7cf6fSBjoern A. Zeeb 	{(0x421 << 20), (0x033 << 20)},
1740bc7cf6fSBjoern A. Zeeb 	{(0x700 << 20), (0x00C << 20)},
1750bc7cf6fSBjoern A. Zeeb 	{(0x701 << 20), (0x00D << 20)},
1760bc7cf6fSBjoern A. Zeeb 	{(0x702 << 20), (0x00E << 20)},
1770bc7cf6fSBjoern A. Zeeb 	{(0x703 << 20), (0x00F << 20)},
1780bc7cf6fSBjoern A. Zeeb 	{(0x704 << 20), (0x010 << 20)},
1790bc7cf6fSBjoern A. Zeeb 	{(0x70A << 20), (0x02B << 20)},
1800bc7cf6fSBjoern A. Zeeb 	{(0x70B << 20), (0x02C << 20)},
1810bc7cf6fSBjoern A. Zeeb 	{(0x70C << 20), (0x02D << 20)},
1820bc7cf6fSBjoern A. Zeeb 	{(0x70F << 20), (0x030 << 20)},
1830bc7cf6fSBjoern A. Zeeb 	{(0x718 << 20), (0x03A << 20)},
1840bc7cf6fSBjoern A. Zeeb 	{(0x758 << 20), (0x026 << 20)},
1850bc7cf6fSBjoern A. Zeeb 	{(0x759 << 20), (0x027 << 20)},
1860bc7cf6fSBjoern A. Zeeb 	{(0x773 << 20), (0x001 << 20)}
1870bc7cf6fSBjoern A. Zeeb };
1880bc7cf6fSBjoern A. Zeeb 
1890bc7cf6fSBjoern A. Zeeb #define Q8_INVALID_ADDRESS	(-1)
1900bc7cf6fSBjoern A. Zeeb #define Q8_ADDR_MASK		(0xFFF << 20)
1910bc7cf6fSBjoern A. Zeeb 
1920bc7cf6fSBjoern A. Zeeb typedef struct _addr_val {
1930bc7cf6fSBjoern A. Zeeb 	uint32_t addr;
1940bc7cf6fSBjoern A. Zeeb 	uint32_t value;
1950bc7cf6fSBjoern A. Zeeb 	uint32_t pci_addr;
1960bc7cf6fSBjoern A. Zeeb 	uint32_t ind_addr;
1970bc7cf6fSBjoern A. Zeeb } addr_val_t;
1980bc7cf6fSBjoern A. Zeeb 
1990bc7cf6fSBjoern A. Zeeb /*
2000bc7cf6fSBjoern A. Zeeb  * Name: qla_rdwr_indreg32
2010bc7cf6fSBjoern A. Zeeb  * Function: Read/Write an Indirect Register
2020bc7cf6fSBjoern A. Zeeb  */
2030bc7cf6fSBjoern A. Zeeb int
qla_rdwr_indreg32(qla_host_t * ha,uint32_t addr,uint32_t * val,uint32_t rd)2040bc7cf6fSBjoern A. Zeeb qla_rdwr_indreg32(qla_host_t *ha, uint32_t addr, uint32_t *val, uint32_t rd)
2050bc7cf6fSBjoern A. Zeeb {
2060bc7cf6fSBjoern A. Zeeb 	uint32_t offset;
2070bc7cf6fSBjoern A. Zeeb 	int count = 100;
2080bc7cf6fSBjoern A. Zeeb 
2090bc7cf6fSBjoern A. Zeeb 	offset = (addr & 0xFFF00000) >> 20;
2100bc7cf6fSBjoern A. Zeeb 
2110bc7cf6fSBjoern A. Zeeb 	if (offset > 0x3F) {
2120bc7cf6fSBjoern A. Zeeb 		device_printf(ha->pci_dev, "%s: invalid addr 0x%08x\n",
2130bc7cf6fSBjoern A. Zeeb 			__func__, addr);
2140bc7cf6fSBjoern A. Zeeb 		return -1;
2150bc7cf6fSBjoern A. Zeeb 	}
2160bc7cf6fSBjoern A. Zeeb 
2170bc7cf6fSBjoern A. Zeeb 	offset = indirect_to_base_map[offset];
2180bc7cf6fSBjoern A. Zeeb 	if (offset == Q8_ADDR_UNDEFINED) {
2190bc7cf6fSBjoern A. Zeeb 		device_printf(ha->pci_dev, "%s: undefined map 0x%08x\n",
2200bc7cf6fSBjoern A. Zeeb 			__func__, addr);
2210bc7cf6fSBjoern A. Zeeb 		return -1;
2220bc7cf6fSBjoern A. Zeeb 	}
2230bc7cf6fSBjoern A. Zeeb 
2240bc7cf6fSBjoern A. Zeeb 	offset = offset | (addr & 0x000F0000);
2250bc7cf6fSBjoern A. Zeeb 
2260bc7cf6fSBjoern A. Zeeb 	if (qla_sem_lock(ha, Q8_SEM7_LOCK, 0, 0)) {
2270bc7cf6fSBjoern A. Zeeb 		device_printf(ha->pci_dev, "%s: SEM7_LOCK failed\n", __func__);
2280bc7cf6fSBjoern A. Zeeb 		return (-1);
2290bc7cf6fSBjoern A. Zeeb 	}
2300bc7cf6fSBjoern A. Zeeb 
2310bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_CRB_WINDOW_2M, offset);
2320bc7cf6fSBjoern A. Zeeb 
2330bc7cf6fSBjoern A. Zeeb 	while (offset != (READ_OFFSET32(ha, Q8_CRB_WINDOW_2M))) {
2340bc7cf6fSBjoern A. Zeeb 		count--;
2350bc7cf6fSBjoern A. Zeeb 		if (!count) {
2360bc7cf6fSBjoern A. Zeeb 			qla_sem_unlock(ha, Q8_SEM7_UNLOCK);
2370bc7cf6fSBjoern A. Zeeb 			return -1;
2380bc7cf6fSBjoern A. Zeeb 		}
2390bc7cf6fSBjoern A. Zeeb 
2400bc7cf6fSBjoern A. Zeeb 		qla_mdelay(__func__, 1);
2410bc7cf6fSBjoern A. Zeeb 	}
2420bc7cf6fSBjoern A. Zeeb 
2430bc7cf6fSBjoern A. Zeeb 	if (rd) {
2440bc7cf6fSBjoern A. Zeeb 		*val = READ_OFFSET32(ha, ((addr & 0xFFFF) | 0x1E0000));
2450bc7cf6fSBjoern A. Zeeb 	} else {
2460bc7cf6fSBjoern A. Zeeb 		WRITE_OFFSET32(ha, ((addr & 0xFFFF) | 0x1E0000), *val);
2470bc7cf6fSBjoern A. Zeeb 	}
2480bc7cf6fSBjoern A. Zeeb 
2490bc7cf6fSBjoern A. Zeeb 	qla_sem_unlock(ha, Q8_SEM7_UNLOCK);
2500bc7cf6fSBjoern A. Zeeb 	return 0;
2510bc7cf6fSBjoern A. Zeeb }
2520bc7cf6fSBjoern A. Zeeb 
2530bc7cf6fSBjoern A. Zeeb /*
2540bc7cf6fSBjoern A. Zeeb  * Name: qla_rdwr_offchip_mem
2550bc7cf6fSBjoern A. Zeeb  * Function: Read/Write OffChip Memory
2560bc7cf6fSBjoern A. Zeeb  */
2570bc7cf6fSBjoern A. Zeeb static int
qla_rdwr_offchip_mem(qla_host_t * ha,uint64_t addr,offchip_mem_val_t * val,uint32_t rd)2580bc7cf6fSBjoern A. Zeeb qla_rdwr_offchip_mem(qla_host_t *ha, uint64_t addr, offchip_mem_val_t *val,
2590bc7cf6fSBjoern A. Zeeb 	uint32_t rd)
2600bc7cf6fSBjoern A. Zeeb {
2610bc7cf6fSBjoern A. Zeeb 	uint32_t count = 100;
2620bc7cf6fSBjoern A. Zeeb 	uint32_t data;
2630bc7cf6fSBjoern A. Zeeb 
2640bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_ADDR_LO, (uint32_t)addr);
2650bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_ADDR_HI, (uint32_t)(addr >> 32));
2660bc7cf6fSBjoern A. Zeeb 
2670bc7cf6fSBjoern A. Zeeb 	if (!rd) {
2680bc7cf6fSBjoern A. Zeeb 		WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_WRDATA_LO, val->data_lo);
2690bc7cf6fSBjoern A. Zeeb 		WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_WRDATA_HI, val->data_hi);
2700bc7cf6fSBjoern A. Zeeb 		WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_WRDATA_ULO, val->data_ulo);
2710bc7cf6fSBjoern A. Zeeb 		WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_WRDATA_UHI, val->data_uhi);
2720bc7cf6fSBjoern A. Zeeb 		WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_CTRL, 0x07); /* Write */
2730bc7cf6fSBjoern A. Zeeb 	} else {
2740bc7cf6fSBjoern A. Zeeb 		WRITE_OFFSET32(ha, Q8_MIU_TEST_AGT_CTRL, 0x03); /* Read */
2750bc7cf6fSBjoern A. Zeeb 	}
2760bc7cf6fSBjoern A. Zeeb 
2770bc7cf6fSBjoern A. Zeeb 	while (count--) {
2780bc7cf6fSBjoern A. Zeeb 		data = READ_OFFSET32(ha, Q8_MIU_TEST_AGT_CTRL);
2790bc7cf6fSBjoern A. Zeeb 		if (!(data & BIT_3)) {
2800bc7cf6fSBjoern A. Zeeb 			if (rd) {
2810bc7cf6fSBjoern A. Zeeb 				val->data_lo = READ_OFFSET32(ha, \
2820bc7cf6fSBjoern A. Zeeb 						Q8_MIU_TEST_AGT_RDDATA_LO);
2830bc7cf6fSBjoern A. Zeeb 				val->data_hi = READ_OFFSET32(ha, \
2840bc7cf6fSBjoern A. Zeeb 						Q8_MIU_TEST_AGT_RDDATA_HI);
2850bc7cf6fSBjoern A. Zeeb 				val->data_ulo = READ_OFFSET32(ha, \
2860bc7cf6fSBjoern A. Zeeb 						Q8_MIU_TEST_AGT_RDDATA_ULO);
2870bc7cf6fSBjoern A. Zeeb 				val->data_uhi = READ_OFFSET32(ha, \
2880bc7cf6fSBjoern A. Zeeb 						Q8_MIU_TEST_AGT_RDDATA_UHI);
2890bc7cf6fSBjoern A. Zeeb 			}
2900bc7cf6fSBjoern A. Zeeb 			return 0;
2910bc7cf6fSBjoern A. Zeeb 		} else
2920bc7cf6fSBjoern A. Zeeb 			qla_mdelay(__func__, 1);
2930bc7cf6fSBjoern A. Zeeb 	}
2940bc7cf6fSBjoern A. Zeeb 
2950bc7cf6fSBjoern A. Zeeb 	device_printf(ha->pci_dev, "%s: failed[0x%08x]\n", __func__, data);
2960bc7cf6fSBjoern A. Zeeb 	return (-1);
2970bc7cf6fSBjoern A. Zeeb }
2980bc7cf6fSBjoern A. Zeeb 
2990bc7cf6fSBjoern A. Zeeb /*
3000bc7cf6fSBjoern A. Zeeb  * Name: qla_rd_flash32
3010bc7cf6fSBjoern A. Zeeb  * Function: Read Flash Memory
3020bc7cf6fSBjoern A. Zeeb  */
3030bc7cf6fSBjoern A. Zeeb int
qla_rd_flash32(qla_host_t * ha,uint32_t addr,uint32_t * data)3040bc7cf6fSBjoern A. Zeeb qla_rd_flash32(qla_host_t *ha, uint32_t addr, uint32_t *data)
3050bc7cf6fSBjoern A. Zeeb {
3060bc7cf6fSBjoern A. Zeeb 	uint32_t val;
3070bc7cf6fSBjoern A. Zeeb 	uint32_t count = 100;
3080bc7cf6fSBjoern A. Zeeb 
3090bc7cf6fSBjoern A. Zeeb 	if (qla_sem_lock(ha, Q8_SEM2_LOCK, 0, 0)) {
3100bc7cf6fSBjoern A. Zeeb 		device_printf(ha->pci_dev, "%s: SEM2_LOCK failed\n", __func__);
3110bc7cf6fSBjoern A. Zeeb 		return (-1);
3120bc7cf6fSBjoern A. Zeeb 	}
3130bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_ROM_LOCKID, 0xa5a5a5a5);
3140bc7cf6fSBjoern A. Zeeb 
3150bc7cf6fSBjoern A. Zeeb 	val = addr;
3160bc7cf6fSBjoern A. Zeeb 	qla_rdwr_indreg32(ha, Q8_ROM_ADDRESS, &val, 0);
3170bc7cf6fSBjoern A. Zeeb 	val = 0;
3180bc7cf6fSBjoern A. Zeeb 	qla_rdwr_indreg32(ha, Q8_ROM_DUMMY_BYTE_COUNT, &val, 0);
3190bc7cf6fSBjoern A. Zeeb 	val = 3;
3200bc7cf6fSBjoern A. Zeeb 	qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
3210bc7cf6fSBjoern A. Zeeb 
3220bc7cf6fSBjoern A. Zeeb 	QLA_USEC_DELAY(100);
3230bc7cf6fSBjoern A. Zeeb 
3240bc7cf6fSBjoern A. Zeeb 	val = ROM_OPCODE_FAST_RD;
3250bc7cf6fSBjoern A. Zeeb 	qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
3260bc7cf6fSBjoern A. Zeeb 
3270bc7cf6fSBjoern A. Zeeb 	while (!((val = READ_OFFSET32(ha, Q8_ROM_STATUS)) & BIT_1)) {
3280bc7cf6fSBjoern A. Zeeb 		count--;
3290bc7cf6fSBjoern A. Zeeb 		if (!count) {
3300bc7cf6fSBjoern A. Zeeb 			qla_sem_unlock(ha, Q8_SEM7_UNLOCK);
3310bc7cf6fSBjoern A. Zeeb 			return -1;
3320bc7cf6fSBjoern A. Zeeb 		}
3330bc7cf6fSBjoern A. Zeeb 	}
3340bc7cf6fSBjoern A. Zeeb 
3350bc7cf6fSBjoern A. Zeeb 	val = 0;
3360bc7cf6fSBjoern A. Zeeb 	qla_rdwr_indreg32(ha, Q8_ROM_DUMMY_BYTE_COUNT, &val, 0);
3370bc7cf6fSBjoern A. Zeeb 	qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
3380bc7cf6fSBjoern A. Zeeb 
3390bc7cf6fSBjoern A. Zeeb 	QLA_USEC_DELAY(100);
3400bc7cf6fSBjoern A. Zeeb 
3410bc7cf6fSBjoern A. Zeeb 	qla_rdwr_indreg32(ha, Q8_ROM_RD_DATA, data, 1);
3420bc7cf6fSBjoern A. Zeeb 
3430bc7cf6fSBjoern A. Zeeb 	qla_sem_unlock(ha, Q8_SEM2_UNLOCK);
3440bc7cf6fSBjoern A. Zeeb 	return 0;
3450bc7cf6fSBjoern A. Zeeb }
3460bc7cf6fSBjoern A. Zeeb 
347088fc971SDavid C Somayajulu static int
qla_p3p_sem_lock2(qla_host_t * ha)348088fc971SDavid C Somayajulu qla_p3p_sem_lock2(qla_host_t *ha)
349088fc971SDavid C Somayajulu {
350088fc971SDavid C Somayajulu         if (qla_sem_lock(ha, Q8_SEM2_LOCK, 0, 0)) {
351088fc971SDavid C Somayajulu                 device_printf(ha->pci_dev, "%s: SEM2_LOCK failed\n", __func__);
352088fc971SDavid C Somayajulu                 return (-1);
353088fc971SDavid C Somayajulu         }
354088fc971SDavid C Somayajulu         WRITE_OFFSET32(ha, Q8_ROM_LOCKID, 0xa5a5a5a5);
355088fc971SDavid C Somayajulu         return (0);
356088fc971SDavid C Somayajulu }
357088fc971SDavid C Somayajulu 
3580bc7cf6fSBjoern A. Zeeb /*
3590bc7cf6fSBjoern A. Zeeb  * Name: qla_int_to_pci_addr_map
3600bc7cf6fSBjoern A. Zeeb  * Function: Convert's Internal(CRB) Address to Indirect Address
3610bc7cf6fSBjoern A. Zeeb  */
3620bc7cf6fSBjoern A. Zeeb static uint32_t
qla_int_to_pci_addr_map(qla_host_t * ha,uint32_t int_addr)3630bc7cf6fSBjoern A. Zeeb qla_int_to_pci_addr_map(qla_host_t *ha, uint32_t int_addr)
3640bc7cf6fSBjoern A. Zeeb {
3650bc7cf6fSBjoern A. Zeeb 	uint32_t crb_to_pci_table_size, i;
3660bc7cf6fSBjoern A. Zeeb 	uint32_t addr;
3670bc7cf6fSBjoern A. Zeeb 
3680bc7cf6fSBjoern A. Zeeb 	crb_to_pci_table_size = sizeof(crbinit_to_pciaddr)/sizeof(crb_to_pci_t);
3690bc7cf6fSBjoern A. Zeeb 	addr = int_addr & Q8_ADDR_MASK;
3700bc7cf6fSBjoern A. Zeeb 
3710bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < crb_to_pci_table_size; i++) {
3720bc7cf6fSBjoern A. Zeeb 		if (crbinit_to_pciaddr[i].crb_addr == addr) {
3730bc7cf6fSBjoern A. Zeeb 			addr = (int_addr & ~Q8_ADDR_MASK) |
3740bc7cf6fSBjoern A. Zeeb 					crbinit_to_pciaddr[i].pci_addr;
3750bc7cf6fSBjoern A. Zeeb 			return (addr);
3760bc7cf6fSBjoern A. Zeeb 		}
3770bc7cf6fSBjoern A. Zeeb 	}
3780bc7cf6fSBjoern A. Zeeb 	return (Q8_INVALID_ADDRESS);
3790bc7cf6fSBjoern A. Zeeb }
3800bc7cf6fSBjoern A. Zeeb 
3810bc7cf6fSBjoern A. Zeeb /*
3820bc7cf6fSBjoern A. Zeeb  * Name: qla_filter_pci_addr
3830bc7cf6fSBjoern A. Zeeb  * Function: Filter's out Indirect Addresses which are not writeable
3840bc7cf6fSBjoern A. Zeeb  */
3850bc7cf6fSBjoern A. Zeeb static uint32_t
qla_filter_pci_addr(qla_host_t * ha,uint32_t addr)3860bc7cf6fSBjoern A. Zeeb qla_filter_pci_addr(qla_host_t *ha, uint32_t addr)
3870bc7cf6fSBjoern A. Zeeb {
3880bc7cf6fSBjoern A. Zeeb 	if ((addr == Q8_INVALID_ADDRESS) ||
3890bc7cf6fSBjoern A. Zeeb 		(addr == 0x00112040) ||
3900bc7cf6fSBjoern A. Zeeb 		(addr == 0x00112048) ||
3910bc7cf6fSBjoern A. Zeeb 		((addr & 0xFFFF0FFF) == 0x001100C4) ||
3920bc7cf6fSBjoern A. Zeeb 		((addr & 0xFFFF0FFF) == 0x001100C8) ||
3930bc7cf6fSBjoern A. Zeeb 		((addr & 0x0FF00000) == 0x00200000) ||
3940bc7cf6fSBjoern A. Zeeb 		(addr == 0x022021FC) ||
3950bc7cf6fSBjoern A. Zeeb 		(addr == 0x0330001C) ||
3960bc7cf6fSBjoern A. Zeeb 		(addr == 0x03300024) ||
3970bc7cf6fSBjoern A. Zeeb 		(addr == 0x033000A8) ||
3980bc7cf6fSBjoern A. Zeeb 		(addr == 0x033000C8) ||
3990bc7cf6fSBjoern A. Zeeb 		(addr == 0x033000BC) ||
4000bc7cf6fSBjoern A. Zeeb 		((addr & 0x0FF00000) == 0x03A00000) ||
4010bc7cf6fSBjoern A. Zeeb 		(addr == 0x03B0001C))
4020bc7cf6fSBjoern A. Zeeb 		return (Q8_INVALID_ADDRESS);
4030bc7cf6fSBjoern A. Zeeb 	else
4040bc7cf6fSBjoern A. Zeeb 		return (addr);
4050bc7cf6fSBjoern A. Zeeb }
4060bc7cf6fSBjoern A. Zeeb 
4070bc7cf6fSBjoern A. Zeeb /*
4080bc7cf6fSBjoern A. Zeeb  * Name: qla_crb_init
4090bc7cf6fSBjoern A. Zeeb  * Function: CRB Initialization - first step in the initialization after reset
4100bc7cf6fSBjoern A. Zeeb  *	Essentially reads the address/value pairs from address = 0x00 and
4110bc7cf6fSBjoern A. Zeeb  *	writes the value into address in the addr/value pair.
4120bc7cf6fSBjoern A. Zeeb  */
4130bc7cf6fSBjoern A. Zeeb static int
qla_crb_init(qla_host_t * ha)4140bc7cf6fSBjoern A. Zeeb qla_crb_init(qla_host_t *ha)
4150bc7cf6fSBjoern A. Zeeb {
416088fc971SDavid C Somayajulu 	uint32_t val = 0, sig = 0;
4170bc7cf6fSBjoern A. Zeeb 	uint32_t offset, count, i;
4180bc7cf6fSBjoern A. Zeeb 	addr_val_t *addr_val_map, *avmap;
4190bc7cf6fSBjoern A. Zeeb 
4200bc7cf6fSBjoern A. Zeeb 	qla_rd_flash32(ha, 0, &sig);
4217c864d7dSDimitry Andric 	QL_DPRINT2((ha->pci_dev, "%s: val[0] = 0x%08x\n", __func__, sig));
4220bc7cf6fSBjoern A. Zeeb 
4230bc7cf6fSBjoern A. Zeeb 	qla_rd_flash32(ha, 4, &val);
4240bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((ha->pci_dev, "%s: val[4] = 0x%08x\n", __func__, val));
4250bc7cf6fSBjoern A. Zeeb 
4260bc7cf6fSBjoern A. Zeeb 	count = val >> 16;
4270bc7cf6fSBjoern A. Zeeb 	offset = val & 0xFFFF;
4280bc7cf6fSBjoern A. Zeeb 	offset = offset << 2;
4290bc7cf6fSBjoern A. Zeeb 
4300bc7cf6fSBjoern A. Zeeb 	QL_DPRINT2((ha->pci_dev, "%s: [sig,val]=[0x%08x, 0x%08x] %d pairs\n",
4310bc7cf6fSBjoern A. Zeeb 		__func__, sig, val, count));
4320bc7cf6fSBjoern A. Zeeb 
4330bc7cf6fSBjoern A. Zeeb 	addr_val_map = avmap = malloc((sizeof(addr_val_t) * count),
4340bc7cf6fSBjoern A. Zeeb 					M_QLA8XXXBUF, M_NOWAIT);
4350bc7cf6fSBjoern A. Zeeb 
4360bc7cf6fSBjoern A. Zeeb 	if (addr_val_map == NULL) {
4370bc7cf6fSBjoern A. Zeeb 		device_printf(ha->pci_dev, "%s: malloc failed\n", __func__);
4380bc7cf6fSBjoern A. Zeeb 		return (-1);
4390bc7cf6fSBjoern A. Zeeb 	}
4400bc7cf6fSBjoern A. Zeeb 	memset(avmap, 0, (sizeof(addr_val_t) * count));
4410bc7cf6fSBjoern A. Zeeb 
4420bc7cf6fSBjoern A. Zeeb 	count = count << 1;
4430bc7cf6fSBjoern A. Zeeb 	for (i = 0; i < count; ) {
4440bc7cf6fSBjoern A. Zeeb 		qla_rd_flash32(ha, (offset + (i * 4)), &avmap->value);
4450bc7cf6fSBjoern A. Zeeb 		i++;
4460bc7cf6fSBjoern A. Zeeb 		qla_rd_flash32(ha, (offset + (i * 4)), &avmap->addr);
4470bc7cf6fSBjoern A. Zeeb 		i++;
4480bc7cf6fSBjoern A. Zeeb 
4490bc7cf6fSBjoern A. Zeeb 		avmap->pci_addr = qla_int_to_pci_addr_map(ha, avmap->addr);
4500bc7cf6fSBjoern A. Zeeb 		avmap->ind_addr = qla_filter_pci_addr(ha, avmap->pci_addr);
4510bc7cf6fSBjoern A. Zeeb 
4520bc7cf6fSBjoern A. Zeeb 		QL_DPRINT2((ha->pci_dev,
4530bc7cf6fSBjoern A. Zeeb 			"%s: [0x%02x][0x%08x:0x%08x:0x%08x] 0x%08x\n",
4540bc7cf6fSBjoern A. Zeeb 			__func__, (i >> 1), avmap->addr, avmap->pci_addr,
4550bc7cf6fSBjoern A. Zeeb 			avmap->ind_addr, avmap->value));
4560bc7cf6fSBjoern A. Zeeb 
4570bc7cf6fSBjoern A. Zeeb 		if (avmap->ind_addr != Q8_INVALID_ADDRESS) {
4580bc7cf6fSBjoern A. Zeeb 			qla_rdwr_indreg32(ha, avmap->ind_addr, &avmap->value,0);
4590bc7cf6fSBjoern A. Zeeb 			qla_mdelay(__func__, 1);
4600bc7cf6fSBjoern A. Zeeb 		}
4610bc7cf6fSBjoern A. Zeeb 		avmap++;
4620bc7cf6fSBjoern A. Zeeb 	}
4630bc7cf6fSBjoern A. Zeeb 
4640bc7cf6fSBjoern A. Zeeb 	free (addr_val_map, M_QLA8XXXBUF);
4650bc7cf6fSBjoern A. Zeeb 	return (0);
4660bc7cf6fSBjoern A. Zeeb }
4670bc7cf6fSBjoern A. Zeeb 
4680bc7cf6fSBjoern A. Zeeb /*
4690bc7cf6fSBjoern A. Zeeb  * Name: qla_init_peg_regs
4700bc7cf6fSBjoern A. Zeeb  * Function: Protocol Engine Register Initialization
4710bc7cf6fSBjoern A. Zeeb  */
4720bc7cf6fSBjoern A. Zeeb static void
qla_init_peg_regs(qla_host_t * ha)4730bc7cf6fSBjoern A. Zeeb qla_init_peg_regs(qla_host_t *ha)
4740bc7cf6fSBjoern A. Zeeb {
4750bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_PEG_D_RESET1, 0x001E);
4760bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_PEG_D_RESET2, 0x0008);
4770bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_PEG_I_RESET, 0x0008);
4780bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_PEG_0_CLR1, 0x0000);
4790bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_PEG_0_CLR2, 0x0000);
4800bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_PEG_1_CLR1, 0x0000);
4810bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_PEG_1_CLR2, 0x0000);
4820bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_PEG_2_CLR1, 0x0000);
4830bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_PEG_2_CLR2, 0x0000);
4840bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_PEG_3_CLR1, 0x0000);
4850bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_PEG_3_CLR2, 0x0000);
4860bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_PEG_4_CLR1, 0x0000);
4870bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_PEG_4_CLR2, 0x0000);
4880bc7cf6fSBjoern A. Zeeb }
4890bc7cf6fSBjoern A. Zeeb 
4900bc7cf6fSBjoern A. Zeeb /*
4910bc7cf6fSBjoern A. Zeeb  * Name: qla_load_fw_from_flash
4920bc7cf6fSBjoern A. Zeeb  * Function: Reads the Bootloader from Flash and Loads into Offchip Memory
4930bc7cf6fSBjoern A. Zeeb  */
4940bc7cf6fSBjoern A. Zeeb static void
qla_load_fw_from_flash(qla_host_t * ha)4950bc7cf6fSBjoern A. Zeeb qla_load_fw_from_flash(qla_host_t *ha)
4960bc7cf6fSBjoern A. Zeeb {
4970bc7cf6fSBjoern A. Zeeb 	uint64_t mem_off	= 0x10000;
4980bc7cf6fSBjoern A. Zeeb 	uint32_t flash_off	= 0x10000;
4990bc7cf6fSBjoern A. Zeeb 	uint32_t count;
5000bc7cf6fSBjoern A. Zeeb 	offchip_mem_val_t val;
5010bc7cf6fSBjoern A. Zeeb 
5020bc7cf6fSBjoern A. Zeeb 	/* only bootloader needs to be loaded into memory */
5030bc7cf6fSBjoern A. Zeeb 	for (count = 0; count < 0x20000 ; ) {
5040bc7cf6fSBjoern A. Zeeb 		qla_rd_flash32(ha, flash_off, &val.data_lo);
5050bc7cf6fSBjoern A. Zeeb 		count = count + 4;
5060bc7cf6fSBjoern A. Zeeb 		flash_off = flash_off + 4;
5070bc7cf6fSBjoern A. Zeeb 
5080bc7cf6fSBjoern A. Zeeb 		qla_rd_flash32(ha, flash_off, &val.data_hi);
5090bc7cf6fSBjoern A. Zeeb 		count = count + 4;
5100bc7cf6fSBjoern A. Zeeb 		flash_off = flash_off + 4;
5110bc7cf6fSBjoern A. Zeeb 
5120bc7cf6fSBjoern A. Zeeb 		qla_rd_flash32(ha, flash_off, &val.data_ulo);
5130bc7cf6fSBjoern A. Zeeb 		count = count + 4;
5140bc7cf6fSBjoern A. Zeeb 		flash_off = flash_off + 4;
5150bc7cf6fSBjoern A. Zeeb 
5160bc7cf6fSBjoern A. Zeeb 		qla_rd_flash32(ha, flash_off, &val.data_uhi);
5170bc7cf6fSBjoern A. Zeeb 		count = count + 4;
5180bc7cf6fSBjoern A. Zeeb 		flash_off = flash_off + 4;
5190bc7cf6fSBjoern A. Zeeb 
5200bc7cf6fSBjoern A. Zeeb 		qla_rdwr_offchip_mem(ha, mem_off, &val, 0);
5210bc7cf6fSBjoern A. Zeeb 
5220bc7cf6fSBjoern A. Zeeb 		mem_off = mem_off + 16;
5230bc7cf6fSBjoern A. Zeeb 	}
5240bc7cf6fSBjoern A. Zeeb 	return;
5250bc7cf6fSBjoern A. Zeeb }
5260bc7cf6fSBjoern A. Zeeb 
5270bc7cf6fSBjoern A. Zeeb /*
5280bc7cf6fSBjoern A. Zeeb  * Name: qla_init_from_flash
5290bc7cf6fSBjoern A. Zeeb  * Function: Performs Initialization which consists of the following sequence
5300bc7cf6fSBjoern A. Zeeb  *	- reset
5310bc7cf6fSBjoern A. Zeeb  *	- CRB Init
5320bc7cf6fSBjoern A. Zeeb  *	- Peg Init
5330bc7cf6fSBjoern A. Zeeb  *	- Read the Bootloader from Flash and Load into Offchip Memory
5340bc7cf6fSBjoern A. Zeeb  *	- Kick start the bootloader which loads the rest of the firmware
5350bc7cf6fSBjoern A. Zeeb  *		and performs the remaining steps in the initialization process.
5360bc7cf6fSBjoern A. Zeeb  */
5370bc7cf6fSBjoern A. Zeeb static int
qla_init_from_flash(qla_host_t * ha)5380bc7cf6fSBjoern A. Zeeb qla_init_from_flash(qla_host_t *ha)
5390bc7cf6fSBjoern A. Zeeb {
5400bc7cf6fSBjoern A. Zeeb 	uint32_t delay = 300;
5410bc7cf6fSBjoern A. Zeeb 	uint32_t data;
5420bc7cf6fSBjoern A. Zeeb 
5430bc7cf6fSBjoern A. Zeeb 	qla_hw_reset(ha);
5440bc7cf6fSBjoern A. Zeeb 	qla_mdelay(__func__, 100);
5450bc7cf6fSBjoern A. Zeeb 
5460bc7cf6fSBjoern A. Zeeb 	qla_crb_init(ha);
5470bc7cf6fSBjoern A. Zeeb 	qla_mdelay(__func__, 10);
5480bc7cf6fSBjoern A. Zeeb 
5490bc7cf6fSBjoern A. Zeeb 	qla_init_peg_regs(ha);
5500bc7cf6fSBjoern A. Zeeb 	qla_mdelay(__func__, 10);
5510bc7cf6fSBjoern A. Zeeb 
5520bc7cf6fSBjoern A. Zeeb 	qla_load_fw_from_flash(ha);
5530bc7cf6fSBjoern A. Zeeb 
5540bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_CMDPEG_STATE, 0x00000000);
5550bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_PEG_0_RESET, 0x00001020);
5560bc7cf6fSBjoern A. Zeeb 	WRITE_OFFSET32(ha, Q8_ASIC_RESET, 0x0080001E);
5570bc7cf6fSBjoern A. Zeeb 	qla_mdelay(__func__, 100);
5580bc7cf6fSBjoern A. Zeeb 
5590bc7cf6fSBjoern A. Zeeb 	do {
5600bc7cf6fSBjoern A. Zeeb 		data = READ_OFFSET32(ha, Q8_CMDPEG_STATE);
5610bc7cf6fSBjoern A. Zeeb 
5620bc7cf6fSBjoern A. Zeeb 		QL_DPRINT2((ha->pci_dev, "%s: func[%d] cmdpegstate 0x%08x\n",
5630bc7cf6fSBjoern A. Zeeb 				__func__, ha->pci_func, data));
5640bc7cf6fSBjoern A. Zeeb 		if (data == CMDPEG_PHAN_INIT_COMPLETE) {
5650bc7cf6fSBjoern A. Zeeb 			QL_DPRINT2((ha->pci_dev,
5660bc7cf6fSBjoern A. Zeeb 				"%s: func[%d] init complete\n",
5670bc7cf6fSBjoern A. Zeeb 				__func__, ha->pci_func));
5680bc7cf6fSBjoern A. Zeeb 			return(0);
5690bc7cf6fSBjoern A. Zeeb 		}
5700bc7cf6fSBjoern A. Zeeb 		qla_mdelay(__func__, 100);
5710bc7cf6fSBjoern A. Zeeb 	} while (delay--);
5720bc7cf6fSBjoern A. Zeeb 
5730bc7cf6fSBjoern A. Zeeb 	device_printf(ha->pci_dev,
5740bc7cf6fSBjoern A. Zeeb 		"%s: func[%d] Q8_PEG_HALT_STATUS1[0x%08x] STATUS2[0x%08x]"
5750bc7cf6fSBjoern A. Zeeb 		" HEARTBEAT[0x%08x] RCVPEG_STATE[0x%08x]"
5760bc7cf6fSBjoern A. Zeeb 		" CMDPEG_STATE[0x%08x]\n",
5770bc7cf6fSBjoern A. Zeeb 		__func__, ha->pci_func,
5780bc7cf6fSBjoern A. Zeeb 		(READ_OFFSET32(ha, Q8_PEG_HALT_STATUS1)),
5790bc7cf6fSBjoern A. Zeeb 		(READ_OFFSET32(ha, Q8_PEG_HALT_STATUS2)),
5800bc7cf6fSBjoern A. Zeeb 		(READ_OFFSET32(ha, Q8_FIRMWARE_HEARTBEAT)),
5810bc7cf6fSBjoern A. Zeeb 		(READ_OFFSET32(ha, Q8_RCVPEG_STATE)), data);
5820bc7cf6fSBjoern A. Zeeb 
5830bc7cf6fSBjoern A. Zeeb 	return (-1);
5840bc7cf6fSBjoern A. Zeeb }
5850bc7cf6fSBjoern A. Zeeb 
5860bc7cf6fSBjoern A. Zeeb /*
5870bc7cf6fSBjoern A. Zeeb  * Name: qla_init_hw
5880bc7cf6fSBjoern A. Zeeb  * Function: Initializes P3+ hardware.
5890bc7cf6fSBjoern A. Zeeb  */
5900bc7cf6fSBjoern A. Zeeb int
qla_init_hw(qla_host_t * ha)5910bc7cf6fSBjoern A. Zeeb qla_init_hw(qla_host_t *ha)
5920bc7cf6fSBjoern A. Zeeb {
5930bc7cf6fSBjoern A. Zeeb         device_t dev;
5940bc7cf6fSBjoern A. Zeeb         int ret = 0;
5950bc7cf6fSBjoern A. Zeeb         uint32_t val, delay = 300;
5960bc7cf6fSBjoern A. Zeeb 
5970bc7cf6fSBjoern A. Zeeb         dev = ha->pci_dev;
5980bc7cf6fSBjoern A. Zeeb 
5990bc7cf6fSBjoern A. Zeeb         QL_DPRINT1((dev, "%s: enter\n", __func__));
6000bc7cf6fSBjoern A. Zeeb 
6010bc7cf6fSBjoern A. Zeeb 	qla_mdelay(__func__, 100);
6020bc7cf6fSBjoern A. Zeeb 
6030bc7cf6fSBjoern A. Zeeb 	if (ha->pci_func & 0x1) {
6040bc7cf6fSBjoern A. Zeeb         	while ((ha->pci_func & 0x1) && delay--) {
6050bc7cf6fSBjoern A. Zeeb 			val = READ_OFFSET32(ha, Q8_CMDPEG_STATE);
6060bc7cf6fSBjoern A. Zeeb 
6070bc7cf6fSBjoern A. Zeeb 			if (val == CMDPEG_PHAN_INIT_COMPLETE) {
6080bc7cf6fSBjoern A. Zeeb 				QL_DPRINT2((dev,
6090bc7cf6fSBjoern A. Zeeb 					"%s: func = %d init complete\n",
6100bc7cf6fSBjoern A. Zeeb 					__func__, ha->pci_func));
6110bc7cf6fSBjoern A. Zeeb 				qla_mdelay(__func__, 100);
6120bc7cf6fSBjoern A. Zeeb 				goto qla_init_exit;
6130bc7cf6fSBjoern A. Zeeb 			}
6140bc7cf6fSBjoern A. Zeeb 			qla_mdelay(__func__, 100);
6150bc7cf6fSBjoern A. Zeeb 		}
6160bc7cf6fSBjoern A. Zeeb 		return (-1);
6170bc7cf6fSBjoern A. Zeeb 	}
6180bc7cf6fSBjoern A. Zeeb 
6190bc7cf6fSBjoern A. Zeeb 	val = READ_OFFSET32(ha, Q8_CMDPEG_STATE);
6200bc7cf6fSBjoern A. Zeeb 
6210bc7cf6fSBjoern A. Zeeb 	if (val != CMDPEG_PHAN_INIT_COMPLETE) {
6220bc7cf6fSBjoern A. Zeeb         	ret = qla_init_from_flash(ha);
6230bc7cf6fSBjoern A. Zeeb 		qla_mdelay(__func__, 100);
624088fc971SDavid C Somayajulu 	} else {
625088fc971SDavid C Somayajulu         	ha->fw_ver_major = READ_OFFSET32(ha, Q8_FW_VER_MAJOR);
626088fc971SDavid C Somayajulu         	ha->fw_ver_minor = READ_OFFSET32(ha, Q8_FW_VER_MINOR);
627088fc971SDavid C Somayajulu 		ha->fw_ver_sub = READ_OFFSET32(ha, Q8_FW_VER_SUB);
628088fc971SDavid C Somayajulu 
629088fc971SDavid C Somayajulu 		if (qla_rd_flash32(ha, 0x100004, &val) == 0) {
630088fc971SDavid C Somayajulu 			if (((val & 0xFF) != ha->fw_ver_major) ||
631088fc971SDavid C Somayajulu 				(((val >> 8) & 0xFF) != ha->fw_ver_minor) ||
632088fc971SDavid C Somayajulu 				(((val >> 16) & 0xFF) != ha->fw_ver_sub)) {
633088fc971SDavid C Somayajulu         			ret = qla_init_from_flash(ha);
634088fc971SDavid C Somayajulu 				qla_mdelay(__func__, 100);
635088fc971SDavid C Somayajulu 			}
636088fc971SDavid C Somayajulu 		}
6370bc7cf6fSBjoern A. Zeeb 	}
6380bc7cf6fSBjoern A. Zeeb 
6390bc7cf6fSBjoern A. Zeeb qla_init_exit:
6400bc7cf6fSBjoern A. Zeeb         ha->fw_ver_major = READ_OFFSET32(ha, Q8_FW_VER_MAJOR);
6410bc7cf6fSBjoern A. Zeeb         ha->fw_ver_minor = READ_OFFSET32(ha, Q8_FW_VER_MINOR);
6420bc7cf6fSBjoern A. Zeeb         ha->fw_ver_sub = READ_OFFSET32(ha, Q8_FW_VER_SUB);
6430bc7cf6fSBjoern A. Zeeb         ha->fw_ver_build = READ_OFFSET32(ha, Q8_FW_VER_BUILD);
6440bc7cf6fSBjoern A. Zeeb 
6450bc7cf6fSBjoern A. Zeeb         return (ret);
6460bc7cf6fSBjoern A. Zeeb }
6470bc7cf6fSBjoern A. Zeeb 
648088fc971SDavid C Somayajulu static int
qla_wait_for_flash_busy(qla_host_t * ha)649088fc971SDavid C Somayajulu qla_wait_for_flash_busy(qla_host_t *ha)
650088fc971SDavid C Somayajulu {
651088fc971SDavid C Somayajulu 	uint32_t count = 100;
652088fc971SDavid C Somayajulu 	uint32_t val;
653088fc971SDavid C Somayajulu 
654088fc971SDavid C Somayajulu 	QLA_USEC_DELAY(100);
655088fc971SDavid C Somayajulu 
656088fc971SDavid C Somayajulu 	while (count--) {
657088fc971SDavid C Somayajulu 		val = READ_OFFSET32(ha, Q8_ROM_STATUS);
658088fc971SDavid C Somayajulu 
659088fc971SDavid C Somayajulu 		if (val & BIT_1)
660088fc971SDavid C Somayajulu 			return 0;
661088fc971SDavid C Somayajulu 		qla_mdelay(__func__, 1);
662088fc971SDavid C Somayajulu 	}
663088fc971SDavid C Somayajulu 	return -1;
664088fc971SDavid C Somayajulu }
665088fc971SDavid C Somayajulu 
666088fc971SDavid C Somayajulu static int
qla_flash_write_enable(qla_host_t * ha)667088fc971SDavid C Somayajulu qla_flash_write_enable(qla_host_t *ha)
668088fc971SDavid C Somayajulu {
669088fc971SDavid C Somayajulu 	uint32_t val, rval;
670088fc971SDavid C Somayajulu 
671088fc971SDavid C Somayajulu 	val = 0;
672088fc971SDavid C Somayajulu 	qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
673088fc971SDavid C Somayajulu 
674088fc971SDavid C Somayajulu 	val = ROM_OPCODE_WR_ENABLE;
675088fc971SDavid C Somayajulu 	qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
676088fc971SDavid C Somayajulu 
677088fc971SDavid C Somayajulu 	rval = qla_wait_for_flash_busy(ha);
678088fc971SDavid C Somayajulu 
679088fc971SDavid C Somayajulu 	if (rval)
680088fc971SDavid C Somayajulu 		device_printf(ha->pci_dev, "%s: failed \n", __func__);
681088fc971SDavid C Somayajulu 
682088fc971SDavid C Somayajulu 	return (rval);
683088fc971SDavid C Somayajulu }
684088fc971SDavid C Somayajulu 
685088fc971SDavid C Somayajulu static int
qla_flash_unprotect(qla_host_t * ha)686088fc971SDavid C Somayajulu qla_flash_unprotect(qla_host_t *ha)
687088fc971SDavid C Somayajulu {
688088fc971SDavid C Somayajulu 	uint32_t val, rval;
689088fc971SDavid C Somayajulu 
690088fc971SDavid C Somayajulu 	if (qla_flash_write_enable(ha) != 0)
691088fc971SDavid C Somayajulu 		return(-1);
692088fc971SDavid C Somayajulu 
693088fc971SDavid C Somayajulu 	val = 0;
694088fc971SDavid C Somayajulu 	qla_rdwr_indreg32(ha, Q8_ROM_WR_DATA, &val, 0);
695088fc971SDavid C Somayajulu 
696088fc971SDavid C Somayajulu 	val = ROM_OPCODE_WR_STATUS_REG;
697088fc971SDavid C Somayajulu 	qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
698088fc971SDavid C Somayajulu 
699088fc971SDavid C Somayajulu 	rval = qla_wait_for_flash_busy(ha);
700088fc971SDavid C Somayajulu 
701088fc971SDavid C Somayajulu 	if (rval) {
702088fc971SDavid C Somayajulu 		device_printf(ha->pci_dev, "%s: failed \n", __func__);
703088fc971SDavid C Somayajulu 		return rval;
704088fc971SDavid C Somayajulu 	}
705088fc971SDavid C Somayajulu 
706088fc971SDavid C Somayajulu 	if (qla_flash_write_enable(ha) != 0)
707088fc971SDavid C Somayajulu 		return(-1);
708088fc971SDavid C Somayajulu 
709088fc971SDavid C Somayajulu 	val = 0;
710088fc971SDavid C Somayajulu 	qla_rdwr_indreg32(ha, Q8_ROM_WR_DATA, &val, 0);
711088fc971SDavid C Somayajulu 
712088fc971SDavid C Somayajulu 	val = ROM_OPCODE_WR_STATUS_REG;
713088fc971SDavid C Somayajulu 	qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
714088fc971SDavid C Somayajulu 
715088fc971SDavid C Somayajulu 	rval = qla_wait_for_flash_busy(ha);
716088fc971SDavid C Somayajulu 
717088fc971SDavid C Somayajulu 	if (rval)
718088fc971SDavid C Somayajulu 		device_printf(ha->pci_dev, "%s: failed \n", __func__);
719088fc971SDavid C Somayajulu 
720088fc971SDavid C Somayajulu 	return rval;
721088fc971SDavid C Somayajulu }
722088fc971SDavid C Somayajulu 
723088fc971SDavid C Somayajulu static int
qla_flash_protect(qla_host_t * ha)724088fc971SDavid C Somayajulu qla_flash_protect(qla_host_t *ha)
725088fc971SDavid C Somayajulu {
726088fc971SDavid C Somayajulu 	uint32_t val, rval;
727088fc971SDavid C Somayajulu 
728088fc971SDavid C Somayajulu 	if (qla_flash_write_enable(ha) != 0)
729088fc971SDavid C Somayajulu 		return(-1);
730088fc971SDavid C Somayajulu 
731088fc971SDavid C Somayajulu 	val = 0x9C;
732088fc971SDavid C Somayajulu 	qla_rdwr_indreg32(ha, Q8_ROM_WR_DATA, &val, 0);
733088fc971SDavid C Somayajulu 
734088fc971SDavid C Somayajulu 	val = ROM_OPCODE_WR_STATUS_REG;
735088fc971SDavid C Somayajulu 	qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
736088fc971SDavid C Somayajulu 
737088fc971SDavid C Somayajulu 	rval = qla_wait_for_flash_busy(ha);
738088fc971SDavid C Somayajulu 
739088fc971SDavid C Somayajulu 	if (rval)
740088fc971SDavid C Somayajulu 		device_printf(ha->pci_dev, "%s: failed \n", __func__);
741088fc971SDavid C Somayajulu 
742088fc971SDavid C Somayajulu 	return rval;
743088fc971SDavid C Somayajulu }
744088fc971SDavid C Somayajulu 
745088fc971SDavid C Somayajulu static uint32_t
qla_flash_get_status(qla_host_t * ha)746088fc971SDavid C Somayajulu qla_flash_get_status(qla_host_t *ha)
747088fc971SDavid C Somayajulu {
748088fc971SDavid C Somayajulu 	uint32_t count = 1000;
749088fc971SDavid C Somayajulu 	uint32_t val, rval;
750088fc971SDavid C Somayajulu 
751088fc971SDavid C Somayajulu 	while (count--) {
752088fc971SDavid C Somayajulu 		val = 0;
753088fc971SDavid C Somayajulu 		qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
754088fc971SDavid C Somayajulu 
755088fc971SDavid C Somayajulu 		val = ROM_OPCODE_RD_STATUS_REG;
756088fc971SDavid C Somayajulu 		qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
757088fc971SDavid C Somayajulu 
758088fc971SDavid C Somayajulu 		rval = qla_wait_for_flash_busy(ha);
759088fc971SDavid C Somayajulu 
760088fc971SDavid C Somayajulu 		if (rval == 0) {
761088fc971SDavid C Somayajulu 			qla_rdwr_indreg32(ha, Q8_ROM_RD_DATA, &val, 1);
762088fc971SDavid C Somayajulu 
763088fc971SDavid C Somayajulu 			if ((val & BIT_0) == 0)
764088fc971SDavid C Somayajulu 				return (val);
765088fc971SDavid C Somayajulu 		}
766088fc971SDavid C Somayajulu 		qla_mdelay(__func__, 1);
767088fc971SDavid C Somayajulu 	}
768088fc971SDavid C Somayajulu 	return -1;
769088fc971SDavid C Somayajulu }
770088fc971SDavid C Somayajulu 
771088fc971SDavid C Somayajulu static int
qla_wait_for_flash_unprotect(qla_host_t * ha)772088fc971SDavid C Somayajulu qla_wait_for_flash_unprotect(qla_host_t *ha)
773088fc971SDavid C Somayajulu {
774088fc971SDavid C Somayajulu 	uint32_t delay = 1000;
775088fc971SDavid C Somayajulu 
776088fc971SDavid C Somayajulu 	while (delay--) {
777088fc971SDavid C Somayajulu 		if (qla_flash_get_status(ha) == 0)
778088fc971SDavid C Somayajulu 			return 0;
779088fc971SDavid C Somayajulu 
780088fc971SDavid C Somayajulu 		qla_mdelay(__func__, 1);
781088fc971SDavid C Somayajulu 	}
782088fc971SDavid C Somayajulu 
783088fc971SDavid C Somayajulu 	return -1;
784088fc971SDavid C Somayajulu }
785088fc971SDavid C Somayajulu 
786088fc971SDavid C Somayajulu static int
qla_wait_for_flash_protect(qla_host_t * ha)787088fc971SDavid C Somayajulu qla_wait_for_flash_protect(qla_host_t *ha)
788088fc971SDavid C Somayajulu {
789088fc971SDavid C Somayajulu 	uint32_t delay = 1000;
790088fc971SDavid C Somayajulu 
791088fc971SDavid C Somayajulu 	while (delay--) {
792088fc971SDavid C Somayajulu 		if (qla_flash_get_status(ha) == 0x9C)
793088fc971SDavid C Somayajulu 			return 0;
794088fc971SDavid C Somayajulu 
795088fc971SDavid C Somayajulu 		qla_mdelay(__func__, 1);
796088fc971SDavid C Somayajulu 	}
797088fc971SDavid C Somayajulu 
798088fc971SDavid C Somayajulu 	return -1;
799088fc971SDavid C Somayajulu }
800088fc971SDavid C Somayajulu 
801088fc971SDavid C Somayajulu static int
qla_erase_flash_sector(qla_host_t * ha,uint32_t start)802088fc971SDavid C Somayajulu qla_erase_flash_sector(qla_host_t *ha, uint32_t start)
803088fc971SDavid C Somayajulu {
804088fc971SDavid C Somayajulu 	uint32_t val;
805088fc971SDavid C Somayajulu 	int rval;
806088fc971SDavid C Somayajulu 
807088fc971SDavid C Somayajulu 	if (qla_flash_write_enable(ha) != 0)
808088fc971SDavid C Somayajulu 		return(-1);
809088fc971SDavid C Somayajulu 
810088fc971SDavid C Somayajulu         val = start;
811088fc971SDavid C Somayajulu         qla_rdwr_indreg32(ha, Q8_ROM_ADDRESS, &val, 0);
812088fc971SDavid C Somayajulu 
813088fc971SDavid C Somayajulu         val = 3;
814088fc971SDavid C Somayajulu         qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
815088fc971SDavid C Somayajulu 
816088fc971SDavid C Somayajulu         val = ROM_OPCODE_SECTOR_ERASE;
817088fc971SDavid C Somayajulu         qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
818088fc971SDavid C Somayajulu 
819088fc971SDavid C Somayajulu 	rval = qla_wait_for_flash_busy(ha);
820088fc971SDavid C Somayajulu 
821088fc971SDavid C Somayajulu 	if (rval)
822088fc971SDavid C Somayajulu 		device_printf(ha->pci_dev, "%s: failed \n", __func__);
823088fc971SDavid C Somayajulu 	return rval;
824088fc971SDavid C Somayajulu }
825088fc971SDavid C Somayajulu 
826088fc971SDavid C Somayajulu #define Q8_FLASH_SECTOR_SIZE 0x10000
827088fc971SDavid C Somayajulu int
qla_erase_flash(qla_host_t * ha,uint32_t off,uint32_t size)828088fc971SDavid C Somayajulu qla_erase_flash(qla_host_t *ha, uint32_t off, uint32_t size)
829088fc971SDavid C Somayajulu {
830088fc971SDavid C Somayajulu 	int rval = 0;
831088fc971SDavid C Somayajulu 	uint32_t start;
832088fc971SDavid C Somayajulu 
833088fc971SDavid C Somayajulu 	if (off & (Q8_FLASH_SECTOR_SIZE -1))
834088fc971SDavid C Somayajulu 		return -1;
835088fc971SDavid C Somayajulu 
836088fc971SDavid C Somayajulu 	if ((rval = qla_p3p_sem_lock2(ha)))
837088fc971SDavid C Somayajulu 		goto qla_erase_flash_exit;
838088fc971SDavid C Somayajulu 
839088fc971SDavid C Somayajulu 	if ((rval = qla_flash_unprotect(ha)))
840088fc971SDavid C Somayajulu 		goto qla_erase_flash_unlock_exit;
841088fc971SDavid C Somayajulu 
842088fc971SDavid C Somayajulu 	if ((rval = qla_wait_for_flash_unprotect(ha)))
843088fc971SDavid C Somayajulu 		goto qla_erase_flash_unlock_exit;
844088fc971SDavid C Somayajulu 
845088fc971SDavid C Somayajulu 	for (start = off; start < (off + size); start = start + 0x10000) {
846088fc971SDavid C Somayajulu 		if (qla_erase_flash_sector(ha, start)) {
847088fc971SDavid C Somayajulu 			rval = -1;
848088fc971SDavid C Somayajulu 			break;
849088fc971SDavid C Somayajulu 		}
850088fc971SDavid C Somayajulu 	}
851088fc971SDavid C Somayajulu 
852088fc971SDavid C Somayajulu 	rval = qla_flash_protect(ha);
853088fc971SDavid C Somayajulu 
854088fc971SDavid C Somayajulu qla_erase_flash_unlock_exit:
855088fc971SDavid C Somayajulu 	qla_sem_unlock(ha, Q8_SEM2_UNLOCK);
856088fc971SDavid C Somayajulu 
857088fc971SDavid C Somayajulu qla_erase_flash_exit:
858088fc971SDavid C Somayajulu 	return (rval);
859088fc971SDavid C Somayajulu }
860088fc971SDavid C Somayajulu 
861088fc971SDavid C Somayajulu static int
qla_flash_write32(qla_host_t * ha,uint32_t off,uint32_t data)862088fc971SDavid C Somayajulu qla_flash_write32(qla_host_t *ha, uint32_t off, uint32_t data)
863088fc971SDavid C Somayajulu {
864088fc971SDavid C Somayajulu 	uint32_t val;
865088fc971SDavid C Somayajulu 	int rval = 0;
866088fc971SDavid C Somayajulu 
867088fc971SDavid C Somayajulu         val = data;
868088fc971SDavid C Somayajulu         qla_rdwr_indreg32(ha, Q8_ROM_WR_DATA, &val, 0);
869088fc971SDavid C Somayajulu 
870088fc971SDavid C Somayajulu         val = off;
871088fc971SDavid C Somayajulu         qla_rdwr_indreg32(ha, Q8_ROM_ADDRESS, &val, 0);
872088fc971SDavid C Somayajulu 
873088fc971SDavid C Somayajulu         val = 3;
874088fc971SDavid C Somayajulu         qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
875088fc971SDavid C Somayajulu 
876088fc971SDavid C Somayajulu         val = ROM_OPCODE_PROG_PAGE;
877088fc971SDavid C Somayajulu         qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
878088fc971SDavid C Somayajulu 
879088fc971SDavid C Somayajulu 	rval = qla_wait_for_flash_busy(ha);
880088fc971SDavid C Somayajulu 
881088fc971SDavid C Somayajulu 	if (rval)
882088fc971SDavid C Somayajulu 		device_printf(ha->pci_dev, "%s: failed \n", __func__);
883088fc971SDavid C Somayajulu 
884088fc971SDavid C Somayajulu 	return rval;
885088fc971SDavid C Somayajulu }
886088fc971SDavid C Somayajulu 
887088fc971SDavid C Somayajulu static int
qla_flash_wait_for_write_complete(qla_host_t * ha)888088fc971SDavid C Somayajulu qla_flash_wait_for_write_complete(qla_host_t *ha)
889088fc971SDavid C Somayajulu {
890088fc971SDavid C Somayajulu 	uint32_t val, count = 1000;
891088fc971SDavid C Somayajulu 	int rval = 0;
892088fc971SDavid C Somayajulu 
893088fc971SDavid C Somayajulu 	while (count--) {
894088fc971SDavid C Somayajulu 		val = 0;
895088fc971SDavid C Somayajulu 		qla_rdwr_indreg32(ha, Q8_ROM_ADDR_BYTE_COUNT, &val, 0);
896088fc971SDavid C Somayajulu 
897088fc971SDavid C Somayajulu 		val = ROM_OPCODE_RD_STATUS_REG;
898088fc971SDavid C Somayajulu 		qla_rdwr_indreg32(ha, Q8_ROM_INSTR_OPCODE, &val, 0);
899088fc971SDavid C Somayajulu 
900088fc971SDavid C Somayajulu 
901088fc971SDavid C Somayajulu 		rval = qla_wait_for_flash_busy(ha);
902088fc971SDavid C Somayajulu 
903088fc971SDavid C Somayajulu 		if (rval == 0) {
904088fc971SDavid C Somayajulu 			qla_rdwr_indreg32(ha, Q8_ROM_RD_DATA, &val, 1);
905088fc971SDavid C Somayajulu 
906088fc971SDavid C Somayajulu 			if ((val & BIT_0) == 0)
907088fc971SDavid C Somayajulu 				return (0);
908088fc971SDavid C Somayajulu 		}
909088fc971SDavid C Somayajulu 		qla_mdelay(__func__, 1);
910088fc971SDavid C Somayajulu 	}
911088fc971SDavid C Somayajulu 	return -1;
912088fc971SDavid C Somayajulu }
913088fc971SDavid C Somayajulu 
914088fc971SDavid C Somayajulu static int
qla_flash_write(qla_host_t * ha,uint32_t off,uint32_t data)915088fc971SDavid C Somayajulu qla_flash_write(qla_host_t *ha, uint32_t off, uint32_t data)
916088fc971SDavid C Somayajulu {
917088fc971SDavid C Somayajulu 	if (qla_flash_write_enable(ha) != 0)
918088fc971SDavid C Somayajulu 		return(-1);
919088fc971SDavid C Somayajulu 
920088fc971SDavid C Somayajulu 	if (qla_flash_write32(ha, off, data) != 0)
921088fc971SDavid C Somayajulu 		return -1;
922088fc971SDavid C Somayajulu 
923088fc971SDavid C Somayajulu 	if (qla_flash_wait_for_write_complete(ha))
924088fc971SDavid C Somayajulu 		return -1;
925088fc971SDavid C Somayajulu 
926088fc971SDavid C Somayajulu 	return 0;
927088fc971SDavid C Somayajulu }
928088fc971SDavid C Somayajulu 
929088fc971SDavid C Somayajulu static int
qla_flash_write_pattern(qla_host_t * ha,uint32_t off,uint32_t size,uint32_t pattern)930088fc971SDavid C Somayajulu qla_flash_write_pattern(qla_host_t *ha, uint32_t off, uint32_t size,
931088fc971SDavid C Somayajulu 	uint32_t pattern)
932088fc971SDavid C Somayajulu {
933088fc971SDavid C Somayajulu 	int rval = 0;
934088fc971SDavid C Somayajulu 	uint32_t start;
935088fc971SDavid C Somayajulu 
936088fc971SDavid C Somayajulu 	if ((rval = qla_p3p_sem_lock2(ha)))
937088fc971SDavid C Somayajulu 		goto qla_wr_pattern_exit;
938088fc971SDavid C Somayajulu 
939088fc971SDavid C Somayajulu 	if ((rval = qla_flash_unprotect(ha)))
940088fc971SDavid C Somayajulu 		goto qla_wr_pattern_unlock_exit;
941088fc971SDavid C Somayajulu 
942088fc971SDavid C Somayajulu 	if ((rval = qla_wait_for_flash_unprotect(ha)))
943088fc971SDavid C Somayajulu 		goto qla_wr_pattern_unlock_exit;
944088fc971SDavid C Somayajulu 
945088fc971SDavid C Somayajulu 	for (start = off; start < (off + size); start = start + 4) {
946088fc971SDavid C Somayajulu 		if (qla_flash_write(ha, start, pattern)) {
947088fc971SDavid C Somayajulu 			rval = -1;
948088fc971SDavid C Somayajulu 			break;
949088fc971SDavid C Somayajulu 		}
950088fc971SDavid C Somayajulu 	}
951088fc971SDavid C Somayajulu 
952088fc971SDavid C Somayajulu 	rval = qla_flash_protect(ha);
953088fc971SDavid C Somayajulu 
954088fc971SDavid C Somayajulu 	if (rval == 0)
955088fc971SDavid C Somayajulu 		rval = qla_wait_for_flash_protect(ha);
956088fc971SDavid C Somayajulu 
957088fc971SDavid C Somayajulu qla_wr_pattern_unlock_exit:
958088fc971SDavid C Somayajulu 	qla_sem_unlock(ha, Q8_SEM2_UNLOCK);
959088fc971SDavid C Somayajulu 
960088fc971SDavid C Somayajulu qla_wr_pattern_exit:
961088fc971SDavid C Somayajulu 	return (rval);
962088fc971SDavid C Somayajulu }
963088fc971SDavid C Somayajulu 
964088fc971SDavid C Somayajulu static int
qla_flash_write_data(qla_host_t * ha,uint32_t off,uint32_t size,void * data)965088fc971SDavid C Somayajulu qla_flash_write_data(qla_host_t *ha, uint32_t off, uint32_t size,
966088fc971SDavid C Somayajulu 	void *data)
967088fc971SDavid C Somayajulu {
968088fc971SDavid C Somayajulu 	int rval = 0;
969088fc971SDavid C Somayajulu 	uint32_t start;
970088fc971SDavid C Somayajulu 	uint32_t *data32 = data;
971088fc971SDavid C Somayajulu 
972088fc971SDavid C Somayajulu 	if ((rval = qla_p3p_sem_lock2(ha)))
973088fc971SDavid C Somayajulu 		goto qla_wr_pattern_exit;
974088fc971SDavid C Somayajulu 
975088fc971SDavid C Somayajulu 	if ((rval = qla_flash_unprotect(ha)))
976088fc971SDavid C Somayajulu 		goto qla_wr_pattern_unlock_exit;
977088fc971SDavid C Somayajulu 
978088fc971SDavid C Somayajulu 	if ((rval = qla_wait_for_flash_unprotect(ha)))
979088fc971SDavid C Somayajulu 		goto qla_wr_pattern_unlock_exit;
980088fc971SDavid C Somayajulu 
981088fc971SDavid C Somayajulu 	for (start = off; start < (off + size); start = start + 4) {
982088fc971SDavid C Somayajulu 
983088fc971SDavid C Somayajulu 		if (*data32 != 0xFFFFFFFF) {
984088fc971SDavid C Somayajulu 			if (qla_flash_write(ha, start, *data32)) {
985088fc971SDavid C Somayajulu 				rval = -1;
986088fc971SDavid C Somayajulu 				break;
987088fc971SDavid C Somayajulu 			}
988088fc971SDavid C Somayajulu 		}
989088fc971SDavid C Somayajulu 		data32++;
990088fc971SDavid C Somayajulu 	}
991088fc971SDavid C Somayajulu 
992088fc971SDavid C Somayajulu 	rval = qla_flash_protect(ha);
993088fc971SDavid C Somayajulu 
994088fc971SDavid C Somayajulu 	if (rval == 0)
995088fc971SDavid C Somayajulu 		rval = qla_wait_for_flash_protect(ha);
996088fc971SDavid C Somayajulu 
997088fc971SDavid C Somayajulu qla_wr_pattern_unlock_exit:
998088fc971SDavid C Somayajulu 	qla_sem_unlock(ha, Q8_SEM2_UNLOCK);
999088fc971SDavid C Somayajulu 
1000088fc971SDavid C Somayajulu qla_wr_pattern_exit:
1001088fc971SDavid C Somayajulu 	return (rval);
1002088fc971SDavid C Somayajulu }
1003088fc971SDavid C Somayajulu 
1004088fc971SDavid C Somayajulu int
qla_wr_flash_buffer(qla_host_t * ha,uint32_t off,uint32_t size,void * buf,uint32_t pattern)1005088fc971SDavid C Somayajulu qla_wr_flash_buffer(qla_host_t *ha, uint32_t off, uint32_t size, void *buf,
1006088fc971SDavid C Somayajulu 	uint32_t pattern)
1007088fc971SDavid C Somayajulu {
1008088fc971SDavid C Somayajulu 	int rval = 0;
1009088fc971SDavid C Somayajulu 	void *data;
1010088fc971SDavid C Somayajulu 
1011088fc971SDavid C Somayajulu 	if (size == 0)
1012088fc971SDavid C Somayajulu 		return 0;
1013088fc971SDavid C Somayajulu 
1014088fc971SDavid C Somayajulu 	size = size << 2;
1015088fc971SDavid C Somayajulu 
1016088fc971SDavid C Somayajulu 	if (buf == NULL) {
1017088fc971SDavid C Somayajulu 		rval = qla_flash_write_pattern(ha, off, size, pattern);
1018088fc971SDavid C Somayajulu 		return (rval);
1019088fc971SDavid C Somayajulu 	}
1020088fc971SDavid C Somayajulu 
1021088fc971SDavid C Somayajulu 	if ((data = malloc(size, M_QLA8XXXBUF, M_NOWAIT)) == NULL) {
1022088fc971SDavid C Somayajulu 		device_printf(ha->pci_dev, "%s: malloc failed \n", __func__);
1023088fc971SDavid C Somayajulu 		rval = -1;
1024088fc971SDavid C Somayajulu 		goto qla_wr_flash_buffer_exit;
1025088fc971SDavid C Somayajulu 	}
1026088fc971SDavid C Somayajulu 
1027088fc971SDavid C Somayajulu 	if ((rval = copyin(buf, data, size))) {
1028088fc971SDavid C Somayajulu 		device_printf(ha->pci_dev, "%s copyin failed\n", __func__);
1029088fc971SDavid C Somayajulu 		goto qla_wr_flash_buffer_free_exit;
1030088fc971SDavid C Somayajulu 	}
1031088fc971SDavid C Somayajulu 
1032088fc971SDavid C Somayajulu 	rval = qla_flash_write_data(ha, off, size, data);
1033088fc971SDavid C Somayajulu 
1034088fc971SDavid C Somayajulu qla_wr_flash_buffer_free_exit:
1035088fc971SDavid C Somayajulu 	free(data, M_QLA8XXXBUF);
1036088fc971SDavid C Somayajulu 
1037088fc971SDavid C Somayajulu qla_wr_flash_buffer_exit:
1038088fc971SDavid C Somayajulu 	return (rval);
1039088fc971SDavid C Somayajulu }
1040