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