/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2010 QLogic Corporation. All rights reserved.
*/
#include <qlge.h>
/*
* Local Function Prototypes.
*/
static int ql_protect_flash(qlge_t *);
static int ql_unprotect_flash(qlge_t *);
/*
* ql_flash_id
* The flash memory chip exports 3 ID bytes in the order of manufacturer, id,
* capability
*/
int
{
int rval;
/*
* Send Restore command (0xAB) to release Flash from
* possible deep power down state
*/
&fdata);
fdata = 0;
/* 0x9F */
&fdata);
} else {
" flash id 0x%x, flash cap 0x%x\n",
}
return (rval);
}
/*
* qlge_dump_fcode
* Dumps fcode from flash.
*/
int
{
/* make sure startpos+size doesn't exceed flash */
return (DDI_FAILURE);
}
/* check start addr is 32 bit or 4 byte aligned for M25Pxx */
if ((startpos & 0x3) != 0) {
return (DDI_FAILURE);
}
/* adjust flash start addr for 32 bit words */
/* Read fcode data from flash. */
/* Allow other system activity. */
if (cnt % 0x1000 == 0) {
drv_usecwait(1);
}
if (rval != DDI_SUCCESS) {
break;
}
cnt += 4;
}
if (rval != DDI_SUCCESS) {
}
return (rval);
}
int
{
/* start address must be 32 bit word aligned */
if ((faddr & 0x3) != 0) {
return (DDI_FAILURE);
}
/* setup mask of address range within a sector */
/*
* Write data to flash.
*/
cnt = 0;
/* Beginning of a sector? do a sector erase */
/* 64k bytes sector erase */
fdata);
if (rval != DDI_SUCCESS) {
"address=%xh", faddr);
goto out;
}
}
/* Write data */
if (rval != DDI_SUCCESS) {
"address=%xh data=%xh", faddr,
*dp);
goto out;
}
cnt++;
faddr++;
/* Allow other system activity. */
if (cnt % 0x1000 == 0) {
qlge_delay(10000);
}
}
rval = DDI_SUCCESS;
out:
if (rval != DDI_SUCCESS) {
}
return (rval);
}
void
{
}
/*
* qlge_load_flash
* Write "size" bytes from memory "dp" to flash address "faddr".
* faddr = 32bit word flash address.
*/
int
{
return (DDI_FAILURE);
}
/* Get semaphore to access Flash Address and Flash Data Registers */
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
(void) ql_unprotect_flash(qlge);
("%s(%d) sector_size 0x%x, sector read addr %x\n",
/* read one whole sector flash data to buffer */
num * sector_size);
if (start_byte < faddr)
start_byte = faddr;
/* write the whole sector data to flash */
goto out;
}
rval = DDI_SUCCESS;
out:
(void) ql_protect_flash(qlge);
if (rval != DDI_SUCCESS) {
}
return (rval);
}
/*
* ql_check_pci
* checks the passed buffer for a valid pci signature and
* expected (and in range) pci length values.
* On successful pci check, nextpos adjusted to next pci header.
*/
static int
{
} else {
return (STOP_SEARCH);
}
/* get the pci header image length */
doff <<= 8;
/* some header section sanity check */
return (STOP_SEARCH);
}
/* a slight sanity data section check */
return (STOP_SEARCH);
}
PCI_SECTOR_SIZE /* 512 */;
case PCI_CODE_X86PC:
break;
case PCI_CODE_FCODE:
break;
case PCI_CODE_EFI:
break;
case PCI_CODE_HPPA:
break;
default:
break;
}
} else {
}
/* Get the next flash image address */
*nextpos += image_size;
return (rval);
}
/*
* ql_find_flash_layout_table_data_structure
* Find Flash Layout Table Data Structure (FLTDS) that
* is located at the end of last boot image.
* Assume FLTDS is located with first 2M bytes.
* Note:
* Driver must be in stalled state prior to entering or
* add code to this function prior to calling ql_setup_flash()
*/
int
{
if (qlge->flash_fltds_addr != 0) {
return (DDI_SUCCESS);
}
/*
* Temporarily set the fdesc.flash_size to
* 1M flash size to avoid failing of ql_dump_focde.
*/
while (result == CONTINUE_SEARCH) {
!= DDI_SUCCESS) {
" pos=%xh rval=%xh",
break;
}
/*
* checkout the pci boot image format
* and get next read address
*/
/*
* find last image? If so, then the freadpos
* is the address of FLTDS
*/
if (result == LAST_IMAGE_FOUND) {
("%s(%d) flash layout table data structure "
"(FLTDS) address is at %x \n", __func__,
rval = DDI_SUCCESS;
break;
} else if (result == STOP_SEARCH) {
"stop searching",
break;
}
}
return (rval);
}
/*
* ql_flash_fltds
* Get flash layout table data structure table.
*/
static int
{
int rval;
if (rval != DDI_SUCCESS) {
return (rval);
}
chksum = 0;
data = 0;
bp++;
}
/* QFLT */
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* ql_flash_flt
* Get flash layout table.
*/
int
{
addr <<= 16;
/* first read flt header to know how long the table is */
sizeof (ql_flt_header_t), addr);
if (rval != DDI_SUCCESS) {
return (rval);
}
return (DDI_FAILURE);
}
/* 2.allocate memory to save all flt table entries */
goto err;
}
/* how many tables? */
sizeof (ql_flt_entry_t));
/* 3. read the rest of flt table */
addr);
if (rval != DDI_SUCCESS) {
goto err;
}
entry++;
}
/* TO Do :4. Checksum verification */
/* 5.search index of Flash Descriptor Table in the Flash Layout Table */
qlge->flash_fdt_addr = 0;
" %x, addr %x,size %x \n", __func__,
break;
}
entry++;
}
if (qlge->flash_fdt_addr == 0) {
goto err;
}
/* 6.search index of Nic Config. Table in the Flash Layout Table */
else
"flash_flt_nic_config_table_index "
"is %x, address %x, size %x \n",
break;
}
entry++;
}
if (qlge->flash_nic_config_table_addr == 0) {
goto err;
}
return (DDI_SUCCESS);
err:
}
return (DDI_FAILURE);
}
/*
* ql_flash_desc
* Get flash descriptor table.
*/
static int
{
int rval;
sizeof (flash_desc_t), addr);
if (rval != DDI_SUCCESS) {
return (rval);
}
chksum = 0;
data = 0;
bp++;
}
/* endian adjustment */
/* flash size in desc table is in 1024 bytes */
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* ql_flash_nic_config
* Get flash NIC Configuration table.
*/
static int
{
int rval;
sizeof (ql_nic_config_t), addr);
if (rval != DDI_SUCCESS) {
return (rval);
}
chksum = 0;
data = 0;
bp++;
}
("(%d): factory mac=%02x %02x %02x %02x %02x %02x h\n",
"invalid flash nic configuration table: chksum %x, "
"signature %x, version %x",
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
int
{
int rval;
return (DDI_FAILURE);
}
if (!qlge->flash_vpd_addr) {
else
}
if (rval != DDI_SUCCESS) {
return (rval);
}
chksum = 0;
data = 0;
bp++;
}
if (chksum != 0) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
int
{
/* Get semaphore to access Flash Address and Flash Data Registers */
rval = DDI_FAILURE;
goto out;
}
/* do test read of flash ID */
if (rval != DDI_SUCCESS)
goto out;
/*
* Temporarily set the fdesc.flash_size to
* 4M flash size to avoid failing of ql_dump_focde.
*/
/* Default flash descriptor table. */
/* ! todo : should read from fltds! */
/* !ql_get_flash_params(qlge); */
/* read all other tables from Flash memory */
/* 0x140200 */
else
/* 0x140600 */
}
}
(void) ql_flash_desc(qlge);
(void) ql_flash_nic_config(qlge);
out:
return (rval);
}
/*
* ql_setup_flash
* Gets the manufacturer and id number of the flash chip,
* and sets up the size parameter.
*/
int
{
if (qlge->flash_fltds_addr != 0) {
return (rval);
}
rval = DDI_FAILURE;
goto out;
}
/* try reading flash ID */
if (rval != DDI_SUCCESS)
goto out;
/* Default flash descriptor table. */
/* 1 Get the location of Flash Layout Table Data Structure (FLTDS) */
== DDI_SUCCESS) {
/* 2,read fltds */
/*
* 3,search for flash descriptor table (FDT)
* and Nic Configuration Table indices
*/
if ((qlge->flash_fdt_addr == 0) ||
(qlge->flash_nic_config_table_addr == 0)) {
if (rval == DDI_SUCCESS) {
(void) ql_flash_desc(qlge);
(void) ql_flash_nic_config(qlge);
} else {
rval = DDI_FAILURE;
goto out;
}
}
} else {
rval = DDI_FAILURE;
goto out;
}
} else {
rval = DDI_FAILURE;
goto out;
}
out:
return (rval);
}
/*
* ql_change_endian
* Change endianess of byte array.
*/
void
{
cnt1--;
}
}
static int
{
do {
if (reg_status & FLASH_ERR_FLAG) {
"%s(%d) flash address register error bit set!",
break;
}
if (reg_status & wait_bit) {
break;
}
drv_usecwait(10);
} while (--delay);
if (delay == 0) {
}
}
return (rtn_val);
}
/*
* ql_read_flash
* Reads a 32bit word from FLASH.
*/
static int
{
/* Wait for READ cycle to complete. */
if (rval == DDI_SUCCESS) {
}
return (rval);
}
static int
{
!= DDI_SUCCESS) {
return (rtn_val);
}
return (rtn_val);
}
return (rtn_val);
}
static int
{
!= DDI_SUCCESS) {
return (rtn_val);
}
/* wait for WEL bit set */
== DDI_SUCCESS) {
do {
if (reg_status & BIT_1)
break;
drv_usecwait(10);
} while (--delay);
}
if (delay == 0) {
"%s(%d) timeout error! flash status reg: %x",
}
return (rtn_val);
}
static int
{
!= DDI_SUCCESS) {
return (rtn_val);
}
== DDI_SUCCESS) {
/* wait Write In Progress (WIP) bit to reset */
do {
break;
drv_usecwait(10);
} while (--delay);
} else {
return (rtn_val);
}
if (delay == 0) {
"%s(%d) timeout error! flash status reg: %x",
}
return (rtn_val);
}
/*
* ql_write_flash
* Writes a 32bit word to FLASH.
*/
static int
{
== DDI_SUCCESS) {
/* wait Write In Progress (WIP) bit to reset */
do {
(void) ql_read_flash_status(qlge,
&flash_status);
break;
drv_usecwait(10);
} while (--delay);
}
} else {
return (rval);
}
if (delay == 0) {
"%s(%d) timeout error! flash status reg: %x",
rval = DDI_FAILURE;
}
return (rval);
}
/*
* ql_unprotect_flash
* Enable writes
*/
static int
{
return (rtn_val);
}
!= DDI_SUCCESS) {
return (rtn_val);
}
/*
* Remove block write protection (SST and ST) and
* Unprotect sectors.
*/
(void) ql_write_flash(qlge,
}
}
return (rtn_val);
}
/*
* ql_protect_flash
* Disable writes
*/
static int
{
return (rtn_val);
}
!= DDI_SUCCESS) {
return (rtn_val);
}
/*
* Protect sectors.
* Set block write protection (SST and ST) and
*/
}
(void) ql_write_flash(qlge,
} else {
(void) ql_write_flash(qlge,
}
return (rtn_val);
}
/*
* ql_write_flash_test
* test write to a flash sector that is not being used
*/
void
{
old_data));
/* enable writing to flash */
(void) ql_unprotect_flash(qlge);
/* erase the sector */
/* write new value to it and read back to confirm */
data = 0x33445566;
if (data != 0x33445566) {
" after writing", data);
}
/* write old value to it and read back to restore */
/* test done, protect the flash to forbid any more flash writting */
(void) ql_protect_flash(qlge);
}
void
{
data = 0x12345678;
if (data != 0x12345678) {
"flash write test failed, get data %x after writing",
data);
}
/* write old value to it and read back to restore */
}
/*
* ql_sem_flash_lock
* Flash memory is a shared resource amoung various PCI Functions, so,
* anyone wants to access flash memory, it needs to lock it first.
*/
int
{
/* Get semaphore to access Flash Address and Flash Data Registers */
rval = DDI_FAILURE;
}
return (rval);
}
void
{
}