/*
* 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
* http://www.opensource.org/licenses/cddl1.txt.
* 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 (c) 2004-2012 Emulex. All rights reserved.
* Use is subject to license terms.
*/
#include <emlxs.h>
/* Required for EMLXS_CONTEXT in EMLXS_MSGF calls */
EMLXS_MSG_DEF(EMLXS_DOWNLOAD_C);
#define MAX_BOOTID 10
static uint32_t emlxs_erase_fcode_flash(emlxs_hba_t *hba);
static uint32_t emlxs_write_fcode_flash(emlxs_hba_t *hba,
PIMAGE_HDR ImageHdr, caddr_t Buffer);
static int32_t emlxs_build_parms(caddr_t Buffer, PWAKE_UP_PARMS AbsWakeUpParms,
uint32_t BufferSize, PAIF_HDR AifHeader);
static uint32_t emlxs_validate_image(emlxs_hba_t *hba, caddr_t Buffer,
uint32_t Size, emlxs_fw_image_t *fw_image);
static void emlxs_format_dump(emlxs_hba_t *hba, MAILBOXQ *mbq,
uint32_t Type, uint32_t RegionId, uint32_t WordCnt,
uint32_t BaseAddr);
static uint32_t emlxs_start_abs_download(emlxs_hba_t *hba, PAIF_HDR AifHdr,
caddr_t Buffer, uint32_t len,
PWAKE_UP_PARMS WakeUpParms);
static uint32_t emlxs_start_abs_download_2mb(emlxs_hba_t *hba, caddr_t buffer,
uint32_t len, uint32_t offline,
emlxs_fw_image_t *fw_image);
static uint32_t emlxs_proc_abs_2mb(emlxs_hba_t *hba,
caddr_t EntireBuffer, uint32_t FileType,
uint32_t extType);
static void emlxs_format_load_area_cmd(MAILBOXQ *mbq, uint32_t Base,
uint32_t DlByteCount, uint32_t Function,
uint32_t Complete, uint32_t DataOffset, uint32_t AreaId,
uint8_t MbxCmd, uint32_t StepCmd);
static uint32_t emlxs_build_parms_2mb_bwc(emlxs_hba_t *hba, PAIF_HDR AifHdr,
uint32_t extType, PWAKE_UP_PARMS AbsWakeUpParms);
static uint32_t emlxs_update_exp_rom(emlxs_hba_t *hba,
PWAKE_UP_PARMS WakeUpParms);
extern uint32_t emlxs_get_max_sram(emlxs_hba_t *hba, uint32_t *MaxRbusSize,
uint32_t *MaxIbusSize);
static void emlxs_format_prog_flash(MAILBOXQ *mbq, uint32_t Base,
uint32_t DlByteCount, uint32_t Function,
uint32_t Complete, uint32_t BdeAddress,
uint32_t BdeSize, PROG_ID *ProgId, uint32_t keep);
static void emlxs_format_update_parms(MAILBOXQ *mbq,
PWAKE_UP_PARMS WakeUpParms);
static void emlxs_format_update_pci_cfg(emlxs_hba_t *hba, MAILBOXQ *mbq,
uint32_t region_id, uint32_t size);
static uint32_t emlxs_update_wakeup_parms(emlxs_hba_t *hba,
PWAKE_UP_PARMS AbsWakeUpParms,
PWAKE_UP_PARMS WakeUpParms);
static uint32_t emlxs_update_boot_wakeup_parms(emlxs_hba_t *hba,
PWAKE_UP_PARMS WakeUpParms, PROG_ID *id,
uint32_t proc_erom);
static uint32_t emlxs_update_ff_wakeup_parms(emlxs_hba_t *hba,
PWAKE_UP_PARMS WakeUpParms, PROG_ID *id);
static uint32_t emlxs_update_sli1_wakeup_parms(emlxs_hba_t *hba,
PWAKE_UP_PARMS WakeUpParms, PROG_ID *id);
static uint32_t emlxs_update_sli2_wakeup_parms(emlxs_hba_t *hba,
PWAKE_UP_PARMS WakeUpParms, PROG_ID *id);
static uint32_t emlxs_update_sli3_wakeup_parms(emlxs_hba_t *hba,
PWAKE_UP_PARMS WakeUpParms, PROG_ID *id);
static uint32_t emlxs_update_sli4_wakeup_parms(emlxs_hba_t *hba,
PWAKE_UP_PARMS WakeUpParms, PROG_ID *id);
static uint32_t emlxs_start_rel_download(emlxs_hba_t *hba, PIMAGE_HDR ImageHdr,
caddr_t Buffer, PWAKE_UP_PARMS WakeUpParms,
uint32_t dwc_flag);
static uint32_t emlxs_read_load_list(emlxs_hba_t *hba, LOAD_LIST *LoadList);
static uint32_t emlxs_valid_cksum(uint32_t *StartAddr, uint32_t *EndAddr);
static void emlxs_disp_aif_header(emlxs_hba_t *hba, PAIF_HDR AifHdr);
static void emlxs_dump_image_header(emlxs_hba_t *hba, PIMAGE_HDR image);
static uint32_t emlxs_type_check(uint32_t type);
static uint32_t emlxs_kern_check(emlxs_hba_t *hba, uint32_t version);
static uint32_t emlxs_stub_check(emlxs_hba_t *hba, uint32_t version);
static uint32_t emlxs_sli1_check(emlxs_hba_t *hba, uint32_t version);
static uint32_t emlxs_sli2_check(emlxs_hba_t *hba, uint32_t version);
static uint32_t emlxs_sli3_check(emlxs_hba_t *hba, uint32_t version);
static uint32_t emlxs_sli4_check(emlxs_hba_t *hba, uint32_t version);
static uint32_t emlxs_bios_check(emlxs_hba_t *hba, uint32_t version);
static uint32_t emlxs_sbus_fcode_check(emlxs_hba_t *hba, uint32_t version);
static uint32_t emlxs_validate_version(emlxs_hba_t *hba,
emlxs_fw_file_t *file, uint32_t id, uint32_t type,
char *file_type);
static uint32_t emlxs_be2_validate_image(emlxs_hba_t *hba, caddr_t buffer,
uint32_t len, emlxs_be_fw_image_t *fw_image);
static uint32_t emlxs_be3_validate_image(emlxs_hba_t *hba, caddr_t buffer,
uint32_t len, emlxs_be_fw_image_t *fw_image);
static int32_t emlxs_be_verify_phy(emlxs_hba_t *hba, emlxs_be_fw_file_t *file,
MAILBOXQ *mbq, MATCHMAP *mp);
static int32_t emlxs_be_verify_crc(emlxs_hba_t *hba,
emlxs_be_fw_file_t *file,
MAILBOXQ *mbq, MATCHMAP *mp);
static int32_t emlxs_be_flash_image(emlxs_hba_t *hba, caddr_t buffer,
emlxs_be_fw_file_t *file, MAILBOXQ *mbq, MATCHMAP *mp);
static int32_t emlxs_be_fw_download(emlxs_hba_t *hba, caddr_t buffer,
uint32_t len, uint32_t offline);
static int32_t emlxs_obj_fw_download(emlxs_hba_t *hba, caddr_t buffer,
uint32_t len, uint32_t offline);
static int32_t emlxs_obj_flash_image(emlxs_hba_t *hba, caddr_t buffer,
uint32_t size, MAILBOXQ *mbq, MATCHMAP *mp,
uint32_t *change_status);
static uint32_t emlxs_obj_validate_image(emlxs_hba_t *hba, caddr_t buffer,
uint32_t len, emlxs_obj_header_t *obj_hdr);
static uint32_t emlxs_be_version(caddr_t buffer, uint32_t size,
uint32_t *plus_flag);
static uint32_t emlxs_proc_rel_2mb(emlxs_hba_t *hba, caddr_t buffer,
emlxs_fw_image_t *fw_image);
static uint32_t emlxs_delete_load_entry(emlxs_hba_t *hba, PROG_ID *progId);
static void emlxs_verify_image(emlxs_hba_t *hba, emlxs_fw_image_t *image);
static uint32_t emlxs_clean_flash(emlxs_hba_t *hba,
PWAKE_UP_PARMS OldWakeUpParms,
PWAKE_UP_PARMS NewWakeUpParms);
/* ************************************************************************* */
extern int32_t
emlxs_fw_download(emlxs_hba_t *hba, caddr_t buffer, uint32_t len,
uint32_t offline)
{
emlxs_port_t *port = &PPORT;
uint32_t *Uptr;
IMAGE_HDR ImageHdr;
AIF_HDR AifHdr;
uint32_t ImageType;
WAKE_UP_PARMS WakeUpParms;
uint32_t rval = 0;
emlxs_fw_image_t fw_image;
uint32_t i;
#ifdef EMLXS_LITTLE_ENDIAN
caddr_t local_buffer;
uint32_t *bptr1;
uint32_t *bptr2;
#endif /* EMLXS_LITTLE_ENDIAN */
if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
if (hba->model_info.chip & EMLXS_BE_CHIPS) {
rval = emlxs_be_fw_download(hba, buffer, len, offline);
} else {
rval = emlxs_obj_fw_download(hba, buffer, len, offline);
}
return (rval);
}
if (buffer == NULL || len == 0) {
return (EMLXS_IMAGE_BAD);
}
#ifdef EMLXS_LITTLE_ENDIAN
/* We need to swap the image buffer before we start */
/*
* Use KM_SLEEP to allocate a temporary buffer
*/
local_buffer = (caddr_t)kmem_zalloc(len, KM_SLEEP);
/* Perform a 32 bit swap of the image */
bptr1 = (uint32_t *)local_buffer;
bptr2 = (uint32_t *)buffer;
for (i = 0; i < (len / 4); i++) {
*bptr1 = LE_SWAP32(*bptr2);
bptr1++;
bptr2++;
}
/* Replace the original buffer */
buffer = local_buffer;
#endif /* EMLXS_LITTLE_ENDIAN */
bzero(&fw_image, sizeof (emlxs_fw_image_t));
for (i = 0; i < MAX_PROG_TYPES; i++) {
(void) strlcpy(fw_image.prog[i].label, "none",
sizeof (fw_image.prog[i].label));
}
/* Validate image */
if ((rval = emlxs_validate_image(hba, buffer, len, &fw_image))) {
goto done;
}
/* Verify image */
emlxs_verify_image(hba, &fw_image);
/* Get image type */
Uptr = (uint32_t *)buffer;
ImageType = *Uptr;
/*
* Pegasus and beyond FW download is done differently
* for absolute download.
*/
/* Check for absolute image */
if ((ImageType == NOP_IMAGE_TYPE) &&
!(hba->model_info.chip &
(EMLXS_DRAGONFLY_CHIP | EMLXS_CENTAUR_CHIP))) {
/*
* Because 2Mb flash download file format is different from
* 512k, it needs to be handled differently
*/
if (rval = emlxs_start_abs_download_2mb(hba, buffer, len,
offline, &fw_image)) {
goto done;
}
/* Offline already handled */
offline = 0;
goto SLI_DOWNLOAD_EXIT;
}
/* Pre-pegasus adapters only */
/* Initialize headers */
if (ImageType == NOP_IMAGE_TYPE) {
bcopy(buffer, &AifHdr, sizeof (AIF_HDR));
bzero((void *)&ImageHdr, sizeof (IMAGE_HDR));
} else { /* PRG file */
bzero((void *)&AifHdr, sizeof (AIF_HDR));
bcopy(buffer, &ImageHdr, sizeof (IMAGE_HDR));
}
/* Everything checks out, now to just do it */
if (offline) {
if (emlxs_offline(hba, 0) != FC_SUCCESS) {
offline = 0;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to take adapter offline.");
rval = EMLXS_OFFLINE_FAILED;
goto SLI_DOWNLOAD_EXIT;
}
if (EMLXS_SLI_HBA_RESET(hba, 1, 1, 0) != FC_SUCCESS) {
offline = 0;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to restart adapter.");
rval = EMLXS_OFFLINE_FAILED;
goto SLI_DOWNLOAD_EXIT;
}
}
/* Pre-pegasus adapters */
if (ImageHdr.Id.Type == SBUS_FCODE) {
/* Erase Flash */
if (emlxs_erase_fcode_flash(hba)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to erase flash.");
rval = EMLXS_IMAGE_FAILED;
goto SLI_DOWNLOAD_EXIT;
}
/* Write FCODE */
if (emlxs_write_fcode_flash(hba, &ImageHdr, buffer)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to write flash.");
rval = EMLXS_IMAGE_FAILED;
goto SLI_DOWNLOAD_EXIT;
}
goto SLI_DOWNLOAD_EXIT;
}
/* Pre-pegasus PCI adapters */
if (emlxs_read_wakeup_parms(hba, &WakeUpParms, 1)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to get parameters.");
rval = EMLXS_IMAGE_FAILED;
goto SLI_DOWNLOAD_EXIT;
}
if (ImageType == NOP_IMAGE_TYPE) {
if (emlxs_start_abs_download(hba, &AifHdr,
buffer, len, &WakeUpParms)) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_download_failed_msg,
"Failed to program flash.");
rval = EMLXS_IMAGE_FAILED;
goto SLI_DOWNLOAD_EXIT;
}
} else { /* Relative PRG file */
if (emlxs_start_rel_download(hba, &ImageHdr, buffer,
&WakeUpParms, 0)) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_download_failed_msg,
"Failed to program flash.");
rval = EMLXS_IMAGE_FAILED;
goto SLI_DOWNLOAD_EXIT;
}
}
SLI_DOWNLOAD_EXIT:
if (offline) {
(void) emlxs_online(hba);
}
if (rval == 0) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_complete_msg,
"Status good.");
}
done:
#ifdef EMLXS_LITTLE_ENDIAN
/* Free the local buffer */
kmem_free(local_buffer, len);
#endif /* EMLXS_LITTLE_ENDIAN */
return (rval);
} /* emlxs_fw_download */
extern void
emlxs_memset(uint8_t *buffer, uint8_t value, uint32_t size)
{
while (size--) {
*buffer++ = value;
}
} /* emlxs_memset () */
static int32_t
emlxs_be_flash_image(emlxs_hba_t *hba, caddr_t buffer,
emlxs_be_fw_file_t *file, MAILBOXQ *mbq, MATCHMAP *mp)
{
emlxs_port_t *port = &PPORT;
uint8_t *image_ptr;
uint32_t *wptr;
uint8_t *payload;
MAILBOX4 *mb;
IOCTL_COMMON_FLASHROM *flashrom;
mbox_req_hdr_t *hdr_req;
uint32_t image_size;
uint32_t block_size;
uint32_t xfer_size;
uint32_t block_offset;
uint32_t count;
uint32_t rval = 0;
if (file->image_size == 0) {
return (0);
}
image_ptr = (uint8_t *)buffer + file->image_offset;
image_size = file->image_size;
block_size = file->block_size;
block_offset = 0;
mb = (MAILBOX4*)mbq;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"%s: Downloading...", file->label);
while (block_size) {
bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
bzero((void *) mp->virt, mp->size);
xfer_size = min(BE_MAX_XFER_SIZE, block_size);
mb->un.varSLIConfig.be.embedded = 0;
mbq->nonembed = (void *)mp;
mbq->mbox_cmpl = NULL;
mb->mbxCommand = MBX_SLI_CONFIG;
mb->mbxOwner = OWN_HOST;
hdr_req = (mbox_req_hdr_t *)mp->virt;
hdr_req->subsystem = IOCTL_SUBSYSTEM_COMMON;
hdr_req->opcode = COMMON_OPCODE_WRITE_FLASHROM;
hdr_req->timeout = 0;
hdr_req->req_length = sizeof (IOCTL_COMMON_FLASHROM) +
xfer_size;
flashrom = (IOCTL_COMMON_FLASHROM *)(hdr_req + 1);
if (file->type == MGMT_FLASHROM_OPTYPE_PHY_FIRMWARE) {
flashrom->params.opcode = ((block_size == xfer_size)?
MGMT_PHY_FLASHROM_OPCODE_FLASH:
MGMT_PHY_FLASHROM_OPCODE_SAVE);
flashrom->params.optype = 0; /* ignored */
} else {
flashrom->params.opcode = ((block_size == xfer_size)?
MGMT_FLASHROM_OPCODE_FLASH:
MGMT_FLASHROM_OPCODE_SAVE);
flashrom->params.optype = file->type;
}
flashrom->params.data_buffer_size = xfer_size;
flashrom->params.offset = block_offset;
/* Build data buffer payload */
payload = (uint8_t *)(&flashrom->params.data_buffer);
emlxs_memset(payload, 0xff, xfer_size);
/* Copy remaining image into payload */
if (image_size) {
count = min(image_size, xfer_size);
BE_SWAP32_BCOPY(image_ptr, payload, count);
image_size -= count;
image_ptr += count;
}
if ((flashrom->params.opcode == MGMT_FLASHROM_OPCODE_FLASH) ||
(flashrom->params.opcode ==
MGMT_PHY_FLASHROM_OPCODE_FLASH)) {
wptr = (uint32_t *)&payload[(xfer_size - 12)];
wptr[0] = file->load_address;
wptr[1] = file->image_size;
wptr[2] = file->block_crc;
}
/* Send write request */
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0) !=
MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"%s: Unable to download image. status=%x",
file->label, mb->mbxStatus);
rval = EMLXS_IMAGE_FAILED;
goto done;
}
block_size -= xfer_size;
block_offset += xfer_size;
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"%s: Download complete.", file->label);
done:
return (rval);
} /* emlxs_be_flash_image() */
static int32_t
emlxs_be_verify_crc(emlxs_hba_t *hba,
emlxs_be_fw_file_t *file, MAILBOXQ *mbq, MATCHMAP *mp)
{
emlxs_port_t *port = &PPORT;
uint32_t *wptr;
uint8_t *payload;
MAILBOX4 *mb;
IOCTL_COMMON_FLASHROM *flashrom;
mbox_req_hdr_t *hdr_req;
uint32_t xfer_size;
uint32_t block_offset;
uint32_t rval = 0;
uint32_t value;
if (file->type == MGMT_FLASHROM_OPTYPE_PHY_FIRMWARE) {
/* PHY Firmware can't be verified */
return (1);
}
xfer_size = 8;
block_offset = file->block_size - xfer_size;
mb = (MAILBOX4*)mbq;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"%s: Verifying CRC...", file->label);
bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
bzero((void *) mp->virt, mp->size);
mb->un.varSLIConfig.be.embedded = 0;
mbq->nonembed = (void *)mp;
mbq->mbox_cmpl = NULL;
mb->mbxCommand = MBX_SLI_CONFIG;
mb->mbxOwner = OWN_HOST;
hdr_req = (mbox_req_hdr_t *)mp->virt;
hdr_req->subsystem = IOCTL_SUBSYSTEM_COMMON;
hdr_req->opcode = COMMON_OPCODE_READ_FLASHROM;
hdr_req->timeout = 0;
hdr_req->req_length = sizeof (IOCTL_COMMON_FLASHROM) +
xfer_size;
flashrom = (IOCTL_COMMON_FLASHROM *)(hdr_req + 1);
flashrom->params.opcode = MGMT_FLASHROM_OPCODE_REPORT;
flashrom->params.optype = file->type;
flashrom->params.data_buffer_size = xfer_size;
flashrom->params.offset = block_offset;
/* Send read request */
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0) !=
MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"%s: Unable to read CRC. status=%x",
file->label, mb->mbxStatus);
rval = 2;
goto done;
}
payload = (uint8_t *)(&flashrom->params.data_buffer);
wptr = (uint32_t *)(payload + xfer_size - 8);
/* Verify image size */
value = *wptr++;
if (value != file->image_size) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"%s: Image size mismatch. %08x != %08x",
file->label, value, file->image_size);
rval = 1;
goto done;
}
/* Verify block crc */
value = *wptr;
if (value != file->block_crc) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"%s: CRC mismatch. %08x != %08x",
file->label, value, file->block_crc);
rval = 1;
}
done:
if (rval == 0) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"%s: CRC verified.", file->label);
}
return (rval);
} /* emlxs_be_verify_crc() */
static int32_t
emlxs_be_verify_phy(emlxs_hba_t *hba,
emlxs_be_fw_file_t *file, MAILBOXQ *mbq, MATCHMAP *mp)
{
emlxs_port_t *port = &PPORT;
MAILBOX4 *mb;
IOCTL_COMMON_GET_PHY_DETAILS *phy;
mbox_req_hdr_t *hdr_req;
uint32_t rval = 0;
if (file->type != MGMT_FLASHROM_OPTYPE_PHY_FIRMWARE) {
return (1);
}
mb = (MAILBOX4*)mbq;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"%s: Getting PHY Details...", file->label);
bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
bzero((void *) mp->virt, mp->size);
mb->un.varSLIConfig.be.embedded = 0;
mbq->nonembed = (void *)mp;
mbq->mbox_cmpl = NULL;
mb->mbxCommand = MBX_SLI_CONFIG;
mb->mbxOwner = OWN_HOST;
hdr_req = (mbox_req_hdr_t *)mp->virt;
hdr_req->subsystem = IOCTL_SUBSYSTEM_COMMON;
hdr_req->opcode = COMMON_OPCODE_GET_PHY_DETAILS;
hdr_req->timeout = 0;
hdr_req->req_length = sizeof (IOCTL_COMMON_GET_PHY_DETAILS);
phy = (IOCTL_COMMON_GET_PHY_DETAILS *)(hdr_req + 1);
/* Send read request */
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0) !=
MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"%s: Unable to get PHY details. status=%x",
file->label, mb->mbxStatus);
rval = 2;
goto done;
}
if ((phy->params.response.phy_type != PHY_TN_8022) ||
(phy->params.response.interface_type != BASET_10GB_TYPE)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"%s: PHY not applicable. %08x,%08x",
file->label,
phy->params.response.phy_type,
phy->params.response.interface_type);
rval = 1;
}
done:
if (rval == 0) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"%s: PHY verified. %x,%x",
file->label,
phy->params.response.phy_type,
phy->params.response.interface_type);
}
return (rval);
} /* emlxs_be_verify_phy() */
extern int32_t
emlxs_be_read_fw_version(emlxs_hba_t *hba, emlxs_firmware_t *fw)
{
emlxs_port_t *port = &PPORT;
MAILBOXQ *mbq = NULL;
MATCHMAP *mp = NULL;
MAILBOX4 *mb;
uint32_t *wptr;
uint8_t *payload;
IOCTL_COMMON_FLASHROM *flashrom;
mbox_req_hdr_t *hdr_req;
uint32_t xfer_size;
uint32_t block_offset;
uint32_t rval = 0;
bzero((void *) fw, sizeof (emlxs_firmware_t));
if ((mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_SLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
"read_fw_version: Unable to allocate mailbox buffer.");
rval = 1;
goto done;
}
if ((mp = emlxs_mem_buf_alloc(hba, (sizeof (mbox_req_hdr_t) +
sizeof (IOCTL_COMMON_FLASHROM) + 32))) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
"read_fw_version: Unable to allocate payload buffer.");
rval = EMLXS_IMAGE_FAILED;
goto done;
}
mb = (MAILBOX4*)mbq;
/* Read CRC and size */
xfer_size = 8;
block_offset = 0x140000 - xfer_size;
bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
bzero((void *) mp->virt, mp->size);
mb->un.varSLIConfig.be.embedded = 0;
mbq->nonembed = (void *)mp;
mbq->mbox_cmpl = NULL;
mb->mbxCommand = MBX_SLI_CONFIG;
mb->mbxOwner = OWN_HOST;
hdr_req = (mbox_req_hdr_t *)mp->virt;
hdr_req->subsystem = IOCTL_SUBSYSTEM_COMMON;
hdr_req->opcode = COMMON_OPCODE_READ_FLASHROM;
hdr_req->timeout = 0;
hdr_req->req_length = sizeof (IOCTL_COMMON_FLASHROM) +
xfer_size;
flashrom = (IOCTL_COMMON_FLASHROM *)(hdr_req + 1);
flashrom->params.opcode = MGMT_FLASHROM_OPCODE_REPORT;
flashrom->params.optype = MGMT_FLASHROM_OPTYPE_FCOE_FIRMWARE;
flashrom->params.data_buffer_size = xfer_size;
flashrom->params.offset = block_offset;
/* Send read request */
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0) !=
MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
"read_fw_version: Unable to read CRC. status=%x",
mb->mbxStatus);
rval = 1;
goto done;
}
payload = (uint8_t *)(&flashrom->params.data_buffer);
wptr = (uint32_t *)payload;
fw->size = *wptr++; /* image size */
fw->sli4 = *wptr; /* block crc */
fw->kern = *wptr;
fw->stub = *wptr;
/* Read version label */
xfer_size = 32;
block_offset = 0x30;
bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
bzero((void *) mp->virt, mp->size);
mb->un.varSLIConfig.be.embedded = 0;
mbq->nonembed = (void *)mp;
mbq->mbox_cmpl = NULL;
mb->mbxCommand = MBX_SLI_CONFIG;
mb->mbxOwner = OWN_HOST;
hdr_req = (mbox_req_hdr_t *)mp->virt;
hdr_req->subsystem = IOCTL_SUBSYSTEM_COMMON;
hdr_req->opcode = COMMON_OPCODE_READ_FLASHROM;
hdr_req->timeout = 0;
hdr_req->req_length = sizeof (IOCTL_COMMON_FLASHROM) +
xfer_size;
flashrom = (IOCTL_COMMON_FLASHROM *)(hdr_req + 1);
flashrom->params.opcode = MGMT_FLASHROM_OPCODE_REPORT;
flashrom->params.optype = MGMT_FLASHROM_OPTYPE_FCOE_FIRMWARE;
flashrom->params.data_buffer_size = xfer_size;
flashrom->params.offset = block_offset;
/* Send read request */
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0) !=
MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
"read_fw_version: Unable to read version string. status=%x",
mb->mbxStatus);
rval = 1;
goto done;
}
payload = (uint8_t *)(&flashrom->params.data_buffer);
BE_SWAP32_BCOPY(payload, (uint8_t *)fw->label, 32);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sli_detail_msg,
"FCOE FIRMWARE: size=%x version=%s (0x%08x)",
fw->size, fw->label, fw->sli4);
done:
if (mbq) {
emlxs_mem_put(hba, MEM_MBOX, (void *)mbq);
}
if (mp) {
emlxs_mem_buf_free(hba, mp);
}
return (rval);
} /* emlxs_be_read_fw_version() */
static uint32_t
emlxs_be_version(caddr_t buffer, uint32_t size, uint32_t *plus_flag)
{
emlxs_be2_ufi_header_t *ufi_hdr;
char signature[BE2_SIGNATURE_SIZE];
uint32_t be_version = 0;
if (size < sizeof (emlxs_be2_ufi_header_t)) {
return (0);
}
ufi_hdr = (emlxs_be2_ufi_header_t *)buffer;
(void) snprintf(signature, BE2_SIGNATURE_SIZE, "%s+", BE_SIGNATURE);
/* Check if this is a UFI image */
if (strncmp(signature, (char *)ufi_hdr->signature,
strlen(BE_SIGNATURE)) != 0) {
return (0);
}
/* Check if this is a UFI plus image */
if (plus_flag) {
/* Check if this is a UFI plus image */
if (strncmp(signature, (char *)ufi_hdr->signature,
strlen(BE_SIGNATURE)+1) == 0) {
*plus_flag = 1;
} else {
*plus_flag = 0;
}
}
if ((ufi_hdr->build[0] >= '1') && (ufi_hdr->build[0] <= '9')) {
be_version = ufi_hdr->build[0] - '0';
}
return (be_version);
} /* emlxs_be_version() */
static uint32_t
emlxs_be2_validate_image(emlxs_hba_t *hba, caddr_t buffer,
uint32_t len, emlxs_be_fw_image_t *fw_image)
{
emlxs_port_t *port = &PPORT;
emlxs_be2_ufi_header_t *ufi_hdr;
emlxs_be2_flash_dir_t *flash_dir;
emlxs_be2_flash_entry_t *entry;
uint8_t *bptr;
uint32_t *wptr;
uint32_t i;
uint32_t k;
uint32_t mask;
uint32_t value;
uint32_t image_size;
emlxs_be_fw_file_t *file;
emlxs_be_fw_file_t *file2;
uint32_t ufi_plus = 0;
uint32_t be_version = 0;
uint32_t found;
bzero(fw_image, sizeof (emlxs_be_fw_image_t));
if (hba->model_info.chip != EMLXS_BE2_CHIP) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"Invalid adapter model.");
return (EMLXS_IMAGE_INCOMPATIBLE);
}
if (len < (sizeof (emlxs_be2_ufi_header_t) +
sizeof (emlxs_be2_flash_dir_t))) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Image too small. (%d < %d)",
len, (sizeof (emlxs_be2_ufi_header_t) +
sizeof (emlxs_be2_flash_dir_t)));
return (EMLXS_IMAGE_BAD);
}
be_version = emlxs_be_version(buffer, len, &ufi_plus);
/* Check if this is a standard BE2 image */
if (be_version != 2) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"Invalid image provided.");
return (EMLXS_IMAGE_INCOMPATIBLE);
}
ufi_hdr = (emlxs_be2_ufi_header_t *)buffer;
#ifdef EMLXS_BIG_ENDIAN
/* Big Endian Swapping */
/* Swap ufi header */
ufi_hdr->checksum =
SWAP32(ufi_hdr->checksum);
ufi_hdr->antidote =
SWAP32(ufi_hdr->antidote);
ufi_hdr->controller.vendor_id =
SWAP32(ufi_hdr->controller.vendor_id);
ufi_hdr->controller.device_id =
SWAP32(ufi_hdr->controller.device_id);
ufi_hdr->controller.sub_vendor_id =
SWAP32(ufi_hdr->controller.sub_vendor_id);
ufi_hdr->controller.sub_device_id =
SWAP32(ufi_hdr->controller.sub_device_id);
ufi_hdr->file_length =
SWAP32(ufi_hdr->file_length);
ufi_hdr->chunk_num =
SWAP32(ufi_hdr->chunk_num);
ufi_hdr->chunk_cnt =
SWAP32(ufi_hdr->chunk_cnt);
ufi_hdr->image_cnt =
SWAP32(ufi_hdr->image_cnt);
#endif /* EMLXS_BIG_ENDIAN */
if (len != ufi_hdr->file_length) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Invalid image size (%d != %d)",
len, ufi_hdr->file_length);
return (EMLXS_IMAGE_BAD);
}
/* Scan for flash dir signature */
bptr = (uint8_t *)buffer;
flash_dir = NULL;
for (i = 0; i < len; i++, bptr++) {
if (strncmp((char *)bptr, BE_DIR_SIGNATURE,
sizeof (BE_DIR_SIGNATURE)) == 0) {
flash_dir = (emlxs_be2_flash_dir_t *)bptr;
break;
}
}
if (!flash_dir) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Unable to find flash directory.");
return (EMLXS_IMAGE_BAD);
}
#ifdef EMLXS_BIG_ENDIAN
/* Big Endian Swapping */
/* Swap flash dir */
flash_dir->header.format_rev =
SWAP32(flash_dir->header.format_rev);
flash_dir->header.checksum =
SWAP32(flash_dir->header.checksum);
flash_dir->header.antidote =
SWAP32(flash_dir->header.antidote);
flash_dir->header.build_num =
SWAP32(flash_dir->header.build_num);
flash_dir->header.active_entry_mask =
SWAP32(flash_dir->header.active_entry_mask);
flash_dir->header.valid_entry_mask =
SWAP32(flash_dir->header.valid_entry_mask);
flash_dir->header.orig_content_mask =
SWAP32(flash_dir->header.orig_content_mask);
flash_dir->header.resv0 = SWAP32(flash_dir->header.resv0);
flash_dir->header.resv1 = SWAP32(flash_dir->header.resv1);
flash_dir->header.resv2 = SWAP32(flash_dir->header.resv2);
flash_dir->header.resv3 = SWAP32(flash_dir->header.resv3);
flash_dir->header.resv4 = SWAP32(flash_dir->header.resv4);
for (i = 0; i < BE_CONTROLLER_SIZE; i++) {
flash_dir->header.controller[i].vendor_id =
SWAP32(flash_dir->header.controller[i].vendor_id);
flash_dir->header.controller[i].device_id =
SWAP32(flash_dir->header.controller[i].device_id);
flash_dir->header.controller[i].sub_vendor_id =
SWAP32(flash_dir->header.controller[i].sub_vendor_id);
flash_dir->header.controller[i].sub_device_id =
SWAP32(flash_dir->header.controller[i].sub_device_id);
}
for (i = 0, mask = 1; i < BE_FLASH_ENTRIES; i++, mask <<= 1) {
if (!(flash_dir->header.valid_entry_mask & mask)) {
continue;
}
entry = &flash_dir->entry[i];
if ((entry->type == 0) ||
(entry->type == (uint32_t)-1) ||
(entry->image_size == 0)) {
continue;
}
flash_dir->entry[i].type =
SWAP32(flash_dir->entry[i].type);
flash_dir->entry[i].offset =
SWAP32(flash_dir->entry[i].offset);
flash_dir->entry[i].pad_size =
SWAP32(flash_dir->entry[i].pad_size);
flash_dir->entry[i].image_size =
SWAP32(flash_dir->entry[i].image_size);
flash_dir->entry[i].checksum =
SWAP32(flash_dir->entry[i].checksum);
flash_dir->entry[i].entry_point =
SWAP32(flash_dir->entry[i].entry_point);
flash_dir->entry[i].resv0 =
SWAP32(flash_dir->entry[i].resv0);
flash_dir->entry[i].resv1 =
SWAP32(flash_dir->entry[i].resv1);
}
#endif /* EMLXS_BIG_ENDIAN */
/* Verify adapter model */
found = 0;
for (i = 0; i < BE_CONTROLLER_SIZE; i++) {
if (flash_dir->header.controller[i].device_id ==
hba->model_info.device_id) {
found = 1;
}
}
if (!found) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"Invalid adapter device id=0x%x.",
hba->model_info.device_id);
return (EMLXS_IMAGE_INCOMPATIBLE);
}
/* Build fw_image table */
fw_image->be_version = 2;
fw_image->ufi_plus = ufi_plus;
for (i = 0, mask = 1; i < BE_FLASH_ENTRIES; i++, mask <<= 1) {
if (!(flash_dir->header.valid_entry_mask & mask)) {
continue;
}
entry = &flash_dir->entry[i];
if ((entry->type == 0) ||
(entry->type == (uint32_t)-1) ||
(entry->image_size == 0)) {
continue;
}
switch (entry->type) {
case BE_FLASHTYPE_REDBOOT:
file = &fw_image->file[REDBOOT_FLASHTYPE];
(void) strlcpy(file->label, "REDBOOT",
sizeof (file->label));
file->type = MGMT_FLASHROM_OPTYPE_REDBOOT;
break;
case BE_FLASHTYPE_ISCSI_BIOS:
file = &fw_image->file[ISCSI_BIOS_FLASHTYPE];
(void) strlcpy(file->label, "ISCSI BIOS",
sizeof (file->label));
file->type = MGMT_FLASHROM_OPTYPE_ISCSI_BIOS;
break;
case BE_FLASHTYPE_PXE_BIOS:
file = &fw_image->file[PXE_BIOS_FLASHTYPE];
(void) strlcpy(file->label, "PXE BIOS",
sizeof (file->label));
file->type = MGMT_FLASHROM_OPTYPE_PXE_BIOS;
break;
case BE_FLASHTYPE_FCOE_BIOS:
file = &fw_image->file[FCOE_BIOS_FLASHTYPE];
(void) strlcpy(file->label, "FCOE BIOS",
sizeof (file->label));
file->type = MGMT_FLASHROM_OPTYPE_FCOE_BIOS;
break;
case BE_FLASHTYPE_ISCSI_FIRMWARE:
file = &fw_image->file[ISCSI_FIRMWARE_FLASHTYPE];
(void) strlcpy(file->label, "ISCSI FIRMWARE",
sizeof (file->label));
file->type = MGMT_FLASHROM_OPTYPE_ISCSI_FIRMWARE;
break;
case BE_FLASHTYPE_FCOE_FIRMWARE:
file = &fw_image->file[FCOE_FIRMWARE_FLASHTYPE];
(void) strlcpy(file->label, "FCOE FIRMWARE",
sizeof (file->label));
file->type = MGMT_FLASHROM_OPTYPE_FCOE_FIRMWARE;
break;
case BE_FLASHTYPE_FCOE_BACKUP:
case BE_FLASHTYPE_ISCSI_BACKUP:
continue;
default:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Unknown image type found. type=%x",
entry->type);
continue;
}
file->be_version = fw_image->be_version;
file->ufi_plus = fw_image->ufi_plus;
file->image_size = entry->image_size;
image_size = BE_SWAP32(entry->image_size);
if (ufi_plus) {
file->image_offset = entry->offset;
file->block_size = entry->pad_size;
file->block_crc = entry->checksum;
file->load_address = entry->entry_point;
} else {
file->image_offset = entry->offset +
sizeof (emlxs_be2_ufi_header_t);
/* Get entry block size and crc */
k = file->image_offset + file->image_size;
k &= 0xFFFFFFFC;
wptr = (uint32_t *)(buffer + k);
for (; k < len; k += 4) {
if (*wptr++ == image_size) {
/* Calculate block_size */
file->block_size = (k + 8) -
file->image_offset;
/* Read load_address */
value = *(wptr - 2);
file->load_address = BE_SWAP32(value);
/* Read block_crc */
value = *wptr;
file->block_crc = BE_SWAP32(value);
break;
}
}
if (k >= len) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"%s: End of block not found. offset=%x",
file->label, file->image_offset);
bzero(fw_image, sizeof (emlxs_be_fw_image_t));
return (EMLXS_IMAGE_BAD);
}
}
/* Make sure image will fit in block specified */
if (file->image_size + 12 > file->block_size) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"%s: Image too large for block. image=%x block=%x",
file->label, file->image_size, file->block_size);
bzero(fw_image, sizeof (emlxs_be_fw_image_t));
return (EMLXS_IMAGE_BAD);
}
/* Automatically create a backup file entry for firmware */
if (file->type == MGMT_FLASHROM_OPTYPE_FCOE_FIRMWARE) {
file2 = &fw_image->file[FCOE_BACKUP_FLASHTYPE];
bcopy((uint8_t *)file, (uint8_t *)file2,
sizeof (emlxs_be_fw_file_t));
file2->type = MGMT_FLASHROM_OPTYPE_FCOE_BACKUP;
(void) strlcpy(file2->label, "FCOE BACKUP",
sizeof (file2->label));
/* Save FCOE version info */
bptr = (uint8_t *)buffer + file->image_offset + 0x30;
(void) strncpy(fw_image->fcoe_label, (char *)bptr,
BE_VERSION_SIZE);
fw_image->fcoe_version = file->block_crc;
} else if (file->type ==
MGMT_FLASHROM_OPTYPE_ISCSI_FIRMWARE) {
file2 = &fw_image->file[ISCSI_BACKUP_FLASHTYPE];
bcopy((uint8_t *)file, (uint8_t *)file2,
sizeof (emlxs_be_fw_file_t));
file2->type = MGMT_FLASHROM_OPTYPE_ISCSI_BACKUP;
(void) strlcpy(file2->label, "ISCSI BACKUP",
sizeof (file2->label));
/* Save ISCSI version info */
bptr = (uint8_t *)buffer + file->image_offset + 0x30;
(void) strncpy(fw_image->iscsi_label, (char *)bptr,
BE_VERSION_SIZE);
fw_image->iscsi_version = file->block_crc;
}
}
if (fw_image->fcoe_version == 0) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Unable to find FCOE firmware component.");
bzero(fw_image, sizeof (emlxs_be_fw_image_t));
return (EMLXS_IMAGE_BAD);
}
/* Display contents */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"BE2 UFI Image: %08x, %s", fw_image->fcoe_version,
fw_image->fcoe_label);
for (i = 0; i < BE_MAX_FLASHTYPES; i++) {
file = &fw_image->file[i];
if (file->image_size == 0) {
continue;
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"%s: be=%x%s type=%x block=%x image=%x offset=%x crc=%x "
"load=%x",
file->label, file->be_version, (file->ufi_plus)?"+":"",
file->type, file->block_size, file->image_size,
file->image_offset, file->block_crc, file->load_address);
}
return (0);
} /* emlxs_be2_validate_image() */
static uint32_t
emlxs_be3_validate_image(emlxs_hba_t *hba, caddr_t buffer,
uint32_t len, emlxs_be_fw_image_t *fw_image)
{
emlxs_port_t *port = &PPORT;
emlxs_be3_ufi_header_t *ufi_hdr;
emlxs_be3_flash_dir_t *flash_dir;
emlxs_be3_flash_entry_t *entry;
emlxs_be3_image_header_t *flash_image_hdr;
emlxs_be3_image_header_t *image_hdr;
uint8_t *bptr;
uint32_t *wptr;
uint32_t i;
uint32_t value;
emlxs_be_fw_file_t *file;
emlxs_be_fw_file_t *file2;
uint32_t ufi_plus = 0;
uint32_t be_version = 0;
uint32_t found;
bzero(fw_image, sizeof (emlxs_be_fw_image_t));
if (hba->model_info.chip != EMLXS_BE3_CHIP) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"Invalid adapter model.");
return (EMLXS_IMAGE_INCOMPATIBLE);
}
if (len < (sizeof (emlxs_be3_ufi_header_t) +
sizeof (emlxs_be3_flash_dir_t))) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Image too small. (%d < %d)",
len, (sizeof (emlxs_be3_ufi_header_t) +
sizeof (emlxs_be3_flash_dir_t)));
return (EMLXS_IMAGE_BAD);
}
be_version = emlxs_be_version(buffer, len, &ufi_plus);
/* Check if this is a standard BE3 image */
if (be_version != 3) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"Invalid image provided.");
return (EMLXS_IMAGE_INCOMPATIBLE);
}
ufi_hdr = (emlxs_be3_ufi_header_t *)buffer;
#ifdef EMLXS_BIG_ENDIAN
/* Big Endian Swapping */
/* Swap ufi header */
ufi_hdr->ufi_version =
SWAP32(ufi_hdr->ufi_version);
ufi_hdr->file_length =
SWAP32(ufi_hdr->file_length);
ufi_hdr->checksum =
SWAP32(ufi_hdr->checksum);
ufi_hdr->antidote =
SWAP32(ufi_hdr->antidote);
ufi_hdr->image_cnt =
SWAP32(ufi_hdr->image_cnt);
#endif /* EMLXS_BIG_ENDIAN */
if (len != ufi_hdr->file_length) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Invalid image size (%d != %d)",
len, ufi_hdr->file_length);
return (EMLXS_IMAGE_BAD);
}
flash_image_hdr = NULL;
image_hdr = (emlxs_be3_image_header_t *)(buffer +
sizeof (emlxs_be3_ufi_header_t));
for (i = 0; i < ufi_hdr->image_cnt; i++, image_hdr++) {
#ifdef EMLXS_BIG_ENDIAN
image_hdr->id = SWAP32(image_hdr->id);
image_hdr->offset = SWAP32(image_hdr->offset);
image_hdr->length = SWAP32(image_hdr->length);
image_hdr->checksum = SWAP32(image_hdr->checksum);
#endif /* EMLXS_BIG_ENDIAN */
if (image_hdr->id == UFI_BE3_FLASH_ID) {
flash_image_hdr = image_hdr;
}
}
if (!flash_image_hdr) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"No flash image found.");
return (EMLXS_IMAGE_BAD);
}
/* Scan for flash dir signature */
bptr = (uint8_t *)buffer + flash_image_hdr->offset;
flash_dir = NULL;
for (i = 0; i < flash_image_hdr->length; i++, bptr++) {
if (strncmp((char *)bptr, BE_DIR_SIGNATURE,
sizeof (BE_DIR_SIGNATURE)) == 0) {
flash_dir = (emlxs_be3_flash_dir_t *)bptr;
break;
}
}
if (!flash_dir) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Unable to find flash directory.");
return (EMLXS_IMAGE_BAD);
}
#ifdef EMLXS_BIG_ENDIAN
/* Big Endian Swapping */
/* Swap flash dir */
flash_dir->header.format_rev =
SWAP32(flash_dir->header.format_rev);
flash_dir->header.checksum =
SWAP32(flash_dir->header.checksum);
flash_dir->header.antidote =
SWAP32(flash_dir->header.antidote);
flash_dir->header.entry_count =
SWAP32(flash_dir->header.entry_count);
flash_dir->header.resv0 = SWAP32(flash_dir->header.resv0);
flash_dir->header.resv1 = SWAP32(flash_dir->header.resv1);
flash_dir->header.resv2 = SWAP32(flash_dir->header.resv2);
flash_dir->header.resv3 = SWAP32(flash_dir->header.resv3);
for (i = 0; i < BE_CONTROLLER_SIZE; i++) {
flash_dir->header.controller[i].vendor_id =
SWAP32(flash_dir->header.controller[i].vendor_id);
flash_dir->header.controller[i].device_id =
SWAP32(flash_dir->header.controller[i].device_id);
flash_dir->header.controller[i].sub_vendor_id =
SWAP32(flash_dir->header.controller[i].sub_vendor_id);
flash_dir->header.controller[i].sub_device_id =
SWAP32(flash_dir->header.controller[i].sub_device_id);
}
for (i = 0; i < flash_dir->header.entry_count; i++) {
entry = &flash_dir->entry[i];
if ((entry->type == 0) ||
(entry->type == (uint32_t)-1) ||
(entry->image_size == 0)) {
continue;
}
flash_dir->entry[i].type =
SWAP32(flash_dir->entry[i].type);
flash_dir->entry[i].offset =
SWAP32(flash_dir->entry[i].offset);
flash_dir->entry[i].block_size =
SWAP32(flash_dir->entry[i].block_size);
flash_dir->entry[i].image_size =
SWAP32(flash_dir->entry[i].image_size);
flash_dir->entry[i].checksum =
SWAP32(flash_dir->entry[i].checksum);
flash_dir->entry[i].entry_point =
SWAP32(flash_dir->entry[i].entry_point);
flash_dir->entry[i].resv0 =
SWAP32(flash_dir->entry[i].resv0);
flash_dir->entry[i].resv1 =
SWAP32(flash_dir->entry[i].resv1);
}
#endif /* EMLXS_BIG_ENDIAN */
/* Verify image checksum */
if (flash_dir->header.checksum != flash_image_hdr->checksum) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Invalid flash directory checksum. (%x != %x)\n",
flash_dir->header.checksum, flash_image_hdr->checksum);
return (EMLXS_IMAGE_BAD);
}
/* Verify adapter model */
found = 0;
for (i = 0; i < BE_CONTROLLER_SIZE; i++) {
if (flash_dir->header.controller[i].device_id ==
hba->model_info.device_id) {
found = 1;
}
}
if (!found) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"Invalid adapter device id=0x%x.",
hba->model_info.device_id);
return (EMLXS_IMAGE_INCOMPATIBLE);
}
/* Build fw_image table */
fw_image->be_version = 3;
fw_image->ufi_plus = ufi_plus;
for (i = 0; i < flash_dir->header.entry_count; i++) {
entry = &flash_dir->entry[i];
if ((entry->type == 0) ||
(entry->type == (uint32_t)-1) ||
(entry->image_size == 0)) {
continue;
}
switch (entry->type) {
case BE_FLASHTYPE_REDBOOT:
file = &fw_image->file[REDBOOT_FLASHTYPE];
(void) strlcpy(file->label, "REDBOOT",
sizeof (file->label));
file->type = MGMT_FLASHROM_OPTYPE_REDBOOT;
break;
case BE_FLASHTYPE_ISCSI_BIOS:
file = &fw_image->file[ISCSI_BIOS_FLASHTYPE];
(void) strlcpy(file->label, "ISCSI BIOS",
sizeof (file->label));
file->type = MGMT_FLASHROM_OPTYPE_ISCSI_BIOS;
break;
case BE_FLASHTYPE_PXE_BIOS:
file = &fw_image->file[PXE_BIOS_FLASHTYPE];
(void) strlcpy(file->label, "PXE BIOS",
sizeof (file->label));
file->type = MGMT_FLASHROM_OPTYPE_PXE_BIOS;
break;
case BE_FLASHTYPE_FCOE_BIOS:
file = &fw_image->file[FCOE_BIOS_FLASHTYPE];
(void) strlcpy(file->label, "FCOE BIOS",
sizeof (file->label));
file->type = MGMT_FLASHROM_OPTYPE_FCOE_BIOS;
break;
case BE_FLASHTYPE_ISCSI_FIRMWARE:
file = &fw_image->file[ISCSI_FIRMWARE_FLASHTYPE];
(void) strlcpy(file->label, "ISCSI FIRMWARE",
sizeof (file->label));
file->type = MGMT_FLASHROM_OPTYPE_ISCSI_FIRMWARE;
break;
case BE_FLASHTYPE_FCOE_FIRMWARE:
file = &fw_image->file[FCOE_FIRMWARE_FLASHTYPE];
(void) strlcpy(file->label, "FCOE FIRMWARE",
sizeof (file->label));
file->type = MGMT_FLASHROM_OPTYPE_FCOE_FIRMWARE;
break;
case BE_FLASHTYPE_NCSI_FIRMWARE:
file = &fw_image->file[NCSI_FIRMWARE_FLASHTYPE];
(void) strlcpy(file->label, "NCSI FIRMWARE",
sizeof (file->label));
file->type = MGMT_FLASHROM_OPTYPE_NCSI_FIRMWARE;
break;
case BE_FLASHTYPE_FLASH_ISM:
case BE_FLASHTYPE_FCOE_BACKUP:
case BE_FLASHTYPE_ISCSI_BACKUP:
continue;
case BE_FLASHTYPE_PHY_FIRMWARE:
file = &fw_image->file[PHY_FIRMWARE_FLASHTYPE];
(void) strlcpy(file->label, "PHY FIRMWARE",
sizeof (file->label));
file->type = MGMT_FLASHROM_OPTYPE_PHY_FIRMWARE;
break;
default:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Unknown image type found. type=%x",
entry->type);
continue;
}
file->be_version = fw_image->be_version;
file->ufi_plus = fw_image->ufi_plus;
file->image_size = entry->image_size;
if (ufi_plus) {
file->image_offset = entry->offset;
file->block_size = entry->block_size;
file->block_crc = entry->checksum;
file->load_address = entry->entry_point;
} else {
file->image_offset = entry->offset +
flash_image_hdr->offset;
file->block_size = entry->block_size;
wptr = (uint32_t *)(buffer + file->image_offset +
file->block_size);
/* Read load address */
value = *(wptr - 3);
file->load_address = BE_SWAP32(value);
/* Read block_crc */
value = *(wptr - 1);
file->block_crc = BE_SWAP32(value);
}
/* Make sure image will fit in block specified */
if (file->image_size + 12 > file->block_size) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"%s: Image too large for block. image=%x block=%x",
file->label, file->image_size, file->block_size);
bzero(fw_image, sizeof (emlxs_be_fw_image_t));
return (EMLXS_IMAGE_BAD);
}
/* Automatically create a backup file entry for firmware */
if (file->type == MGMT_FLASHROM_OPTYPE_FCOE_FIRMWARE) {
file2 = &fw_image->file[FCOE_BACKUP_FLASHTYPE];
bcopy((uint8_t *)file, (uint8_t *)file2,
sizeof (emlxs_be_fw_file_t));
file2->type = MGMT_FLASHROM_OPTYPE_FCOE_BACKUP;
(void) strlcpy(file2->label, "FCOE BACKUP",
sizeof (file2->label));
/* Save FCOE version info */
bptr = (uint8_t *)buffer + file->image_offset + 0x30;
(void) strncpy(fw_image->fcoe_label, (char *)bptr,
BE_VERSION_SIZE);
fw_image->fcoe_version = file->block_crc;
} else if (file->type ==
MGMT_FLASHROM_OPTYPE_ISCSI_FIRMWARE) {
file2 = &fw_image->file[ISCSI_BACKUP_FLASHTYPE];
bcopy((uint8_t *)file, (uint8_t *)file2,
sizeof (emlxs_be_fw_file_t));
file2->type = MGMT_FLASHROM_OPTYPE_ISCSI_BACKUP;
(void) strlcpy(file2->label, "ISCSI BACKUP",
sizeof (file->label));
/* Save ISCSI version info */
bptr = (uint8_t *)buffer + file->image_offset + 0x30;
(void) strncpy(fw_image->iscsi_label, (char *)bptr,
BE_VERSION_SIZE);
fw_image->iscsi_version = file->block_crc;
}
}
if (fw_image->fcoe_version == 0) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Unable to find FCOE firmware component.");
bzero(fw_image, sizeof (emlxs_be_fw_image_t));
return (EMLXS_IMAGE_BAD);
}
/* Display contents */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"BE3 UFI Image: %08x, %s", fw_image->fcoe_version,
fw_image->fcoe_label);
for (i = 0; i < BE_MAX_FLASHTYPES; i++) {
file = &fw_image->file[i];
if (file->image_size == 0) {
continue;
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"%s: be=%x%s type=%x block=%x image=%x offset=%x crc=%x "
"load=%x",
file->label, file->be_version, (file->ufi_plus)? "+":"",
file->type, file->block_size, file->image_size,
file->image_offset, file->block_crc, file->load_address);
}
return (0);
} /* emlxs_be3_validate_image() */
static int32_t
emlxs_be_fw_download(emlxs_hba_t *hba, caddr_t buffer, uint32_t len,
uint32_t offline)
{
emlxs_port_t *port = &PPORT;
uint32_t i;
uint32_t update = 0;
uint32_t rval = 0;
MAILBOXQ *mbq = NULL;
MATCHMAP *mp = NULL;
emlxs_be_fw_image_t fw_image;
emlxs_be_fw_file_t *file;
uint32_t be_version;
/* For now we will not take the driver offline during a download */
offline = 0;
if (hba->sli_mode != EMLXS_HBA_SLI4_MODE) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"Invalid sli_mode. mode=%d", hba->sli_mode);
return (EMLXS_IMAGE_INCOMPATIBLE);
}
if (!(hba->model_info.chip & EMLXS_BE_CHIPS)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"Invalid adapter model. chip=%x", hba->model_info.chip);
return (EMLXS_IMAGE_INCOMPATIBLE);
}
if (buffer == NULL || len == 0) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Empty buffer provided. buf=%p size=%d", buffer, len);
return (EMLXS_IMAGE_BAD);
}
be_version = emlxs_be_version(buffer, len, 0);
switch (be_version) {
case 0:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"Invalid image provided. Non-UFI format.");
return (EMLXS_IMAGE_INCOMPATIBLE);
case 2:
rval = emlxs_be2_validate_image(hba, buffer, len, &fw_image);
if (rval) {
return (rval);
}
break;
case 3:
rval = emlxs_be3_validate_image(hba, buffer, len, &fw_image);
if (rval) {
return (rval);
}
break;
default:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"Invalid image provided. Unknown BE version. (%x)",
be_version);
return (EMLXS_IMAGE_INCOMPATIBLE);
}
/* Allocate resources */
if ((mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_SLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to allocate mailbox buffer.");
offline = 0;
rval = EMLXS_IMAGE_FAILED;
goto done;
}
if ((mp = emlxs_mem_buf_alloc(hba, (sizeof (mbox_req_hdr_t) +
sizeof (IOCTL_COMMON_FLASHROM) + BE_MAX_XFER_SIZE))) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to allocate flash buffer.");
offline = 0;
rval = EMLXS_IMAGE_FAILED;
goto done;
}
/* Check if update is required */
for (i = 0; i < BE_MAX_FLASHTYPES; i++) {
file = &fw_image.file[i];
if (file->image_size == 0) {
continue;
}
if (file->type == MGMT_FLASHROM_OPTYPE_PHY_FIRMWARE) {
rval = emlxs_be_verify_phy(hba, file, mbq, mp);
if (rval != 0) {
/* Do not update */
file->image_size = 0;
continue;
}
} else {
rval = emlxs_be_verify_crc(hba, file, mbq, mp);
if (rval == 0) {
/* Do not update */
file->image_size = 0;
continue;
}
}
update++;
}
if (!update) {
offline = 0;
rval = 0;
goto done;
}
/*
* Everything checks out, now to just do it
*/
if (offline) {
if (emlxs_offline(hba, 0) != FC_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to take adapter offline.");
offline = 0;
rval = EMLXS_OFFLINE_FAILED;
goto done;
}
}
/* Download entries which require update */
for (i = 0; i < BE_MAX_FLASHTYPES; i++) {
file = &fw_image.file[i];
if (file->image_size == 0) {
continue;
}
rval = emlxs_be_flash_image(hba, buffer, file, mbq, mp);
if (rval != 0) {
goto done;
}
}
done:
if (mbq) {
emlxs_mem_put(hba, MEM_MBOX, (void *)mbq);
}
if (mp) {
emlxs_mem_buf_free(hba, mp);
}
if (offline) {
(void) emlxs_online(hba);
}
if (rval == 0) {
if (update) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_complete_msg,
"Status good.");
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fw_updated_msg,
"The new firmware will not be activated until "
"the adapter is power cycled: %s",
fw_image.fcoe_label);
} else {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"No firmware update required.");
}
}
return (rval);
} /* emlxs_be_fw_download() */
static int32_t
emlxs_obj_flash_image(emlxs_hba_t *hba, caddr_t buffer, uint32_t size,
MAILBOXQ *mbq, MATCHMAP *mp, uint32_t *change_status)
{
emlxs_port_t *port = &PPORT;
uint8_t *image_ptr;
MAILBOX4 *mb;
mbox_req_hdr_t *hdr_req;
mbox_rsp_hdr_t *hdr_rsp;
uint32_t image_size;
uint32_t xfer_size;
uint32_t image_offset;
uint32_t rval = 0;
IOCTL_COMMON_WRITE_OBJECT *write_obj;
uint32_t cstatus = 0;
if (!buffer || size == 0) {
return (0);
}
image_ptr = (uint8_t *)buffer;
image_size = size;
image_offset = 0;
mb = (MAILBOX4*)mbq;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"OBJ File: Downloading...");
while (image_size) {
bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
bzero((void *) mp->virt, mp->size);
xfer_size = min(OBJ_MAX_XFER_SIZE, image_size);
mb->un.varSLIConfig.be.embedded = 1;
mbq->nonembed = NULL;
mbq->mbox_cmpl = NULL;
mb->mbxCommand = MBX_SLI_CONFIG;
mb->mbxOwner = OWN_HOST;
hdr_req = (mbox_req_hdr_t *)
&mb->un.varSLIConfig.be.un_hdr.hdr_req;
hdr_req->subsystem = IOCTL_SUBSYSTEM_COMMON;
hdr_req->opcode = COMMON_OPCODE_WRITE_OBJ;
hdr_req->timeout = 0;
write_obj = (IOCTL_COMMON_WRITE_OBJECT *)(hdr_req + 1);
write_obj->params.request.EOF =
((xfer_size == image_size)? 1:0);
write_obj->params.request.desired_write_length = xfer_size;
write_obj->params.request.write_offset = image_offset;
(void) strlcpy((char *)write_obj->params.request.object_name,
"/prg", sizeof (write_obj->params.request.object_name));
BE_SWAP32_BUFFER((uint8_t *)
write_obj->params.request.object_name,
sizeof (write_obj->params.request.object_name));
write_obj->params.request.buffer_desc_count = 1;
write_obj->params.request.buffer_length = xfer_size;
write_obj->params.request.buffer_addrlo = PADDR_LO(mp->phys);
write_obj->params.request.buffer_addrhi = PADDR_HI(mp->phys);
hdr_req->req_length = 116 +
(write_obj->params.request.buffer_desc_count * 12);
bcopy(image_ptr, mp->virt, xfer_size);
hdr_rsp = (mbox_rsp_hdr_t *)
&mb->un.varSLIConfig.be.un_hdr.hdr_rsp;
write_obj = (IOCTL_COMMON_WRITE_OBJECT *)(hdr_rsp + 1);
/* Send write request */
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0) !=
MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"OBJ File: Unable to download image. status=%x "
"(%x,%x)",
mb->mbxStatus, hdr_rsp->status,
hdr_rsp->extra_status);
return (EMLXS_IMAGE_FAILED);
}
/* Check header status */
if (hdr_rsp->status) {
if ((hdr_rsp->status == MBX_RSP_STATUS_FAILED) &&
(hdr_rsp->extra_status ==
MGMT_ADDI_STATUS_INCOMPATIBLE)) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_download_failed_msg,
"OBJ File: Image file incompatible with "
"adapter hardware.");
return (EMLXS_IMAGE_INCOMPATIBLE);
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"OBJ File: Unable to download image. "
"hdr_status=%x,%x size=%d,%d",
hdr_rsp->status, hdr_rsp->extra_status,
write_obj->params.response.actual_write_length,
xfer_size);
return (EMLXS_IMAGE_FAILED);
}
/* Check response length */
if (write_obj->params.response.actual_write_length == 0) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"OBJ File: No data actually written.");
return (EMLXS_IMAGE_FAILED);
}
if (write_obj->params.response.actual_write_length >
xfer_size) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"OBJ File: Mismatch in data xfer size. "
"size=%d,%d offset=%d",
write_obj->params.response.actual_write_length,
xfer_size, image_offset);
return (EMLXS_IMAGE_FAILED);
}
/* Set xfer_size to actual write length */
xfer_size = write_obj->params.response.actual_write_length;
image_ptr += xfer_size;
image_offset += xfer_size;
image_size -= xfer_size;
if (image_size == 0) {
cstatus = write_obj->params.response.change_status;
}
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"OBJ File: Download complete. (cstatus=%d)",
cstatus);
if (change_status) {
*change_status = cstatus;
}
return (rval);
} /* emlxs_obj_flash_image() */
static uint32_t
emlxs_obj_validate_image(emlxs_hba_t *hba, caddr_t buffer, uint32_t len,
emlxs_obj_header_t *obj_hdr_in)
{
emlxs_port_t *port = &PPORT;
emlxs_obj_header_t obj_hdr;
if (obj_hdr_in) {
bzero(obj_hdr_in, sizeof (emlxs_obj_header_t));
}
if (hba->sli_mode != EMLXS_HBA_SLI4_MODE) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"Invalid sli_mode. mode=%d", hba->sli_mode);
return (EMLXS_IMAGE_INCOMPATIBLE);
}
if (hba->model_info.chip & EMLXS_BE_CHIPS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"Invalid adapter model. chip=%x", hba->model_info.chip);
return (EMLXS_IMAGE_INCOMPATIBLE);
}
if (len < sizeof (emlxs_obj_header_t)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Image too small. (%d < %d)",
len, sizeof (emlxs_obj_header_t));
return (EMLXS_IMAGE_BAD);
}
bcopy(buffer, (uint8_t *)&obj_hdr, sizeof (emlxs_obj_header_t));
/* Swap first 3 words */
LE_SWAP32_BUFFER((uint8_t *)&obj_hdr, 12);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Object Header: size=%d magic=%04x,%04x type=%02x id=%02x",
obj_hdr.FileSize,
obj_hdr.MagicNumHi, obj_hdr.MagicNumLo,
obj_hdr.FileType,
obj_hdr.Id);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Object Header: Date=%s Rev=%s",
obj_hdr.Date,
obj_hdr.Revision);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Object Header: Name=%s",
obj_hdr.RevName);
if ((obj_hdr.MagicNumHi != OBJ_MAGIC_NUM_HI) ||
(obj_hdr.MagicNumLo != OBJ_MAGIC_NUM_LO)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"Wrong Magic Number: %x,%x",
obj_hdr.MagicNumHi, obj_hdr.MagicNumLo);
return (EMLXS_IMAGE_INCOMPATIBLE);
}
if (obj_hdr.FileSize != len) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Image too small. (%d < %d)",
len, obj_hdr.FileSize);
return (EMLXS_IMAGE_BAD);
}
if ((hba->model_info.chip & EMLXS_LANCER_CHIP) &&
(obj_hdr.Id != OBJ_LANCER_ID)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"Invalid adapter model. chip=%x fwid=%x",
hba->model_info.chip,
obj_hdr.Id);
return (EMLXS_IMAGE_INCOMPATIBLE);
}
if (obj_hdr_in) {
bcopy(&obj_hdr, obj_hdr_in, sizeof (emlxs_obj_header_t));
}
return (0);
} /* emlxs_obj_validate_image() */
static int32_t
emlxs_obj_fw_download(emlxs_hba_t *hba, caddr_t buffer, uint32_t len,
uint32_t offline)
{
emlxs_port_t *port = &PPORT;
uint32_t rval = 0;
MAILBOXQ *mbq = NULL;
MATCHMAP *mp = NULL;
uint32_t change_status = 0;
/* For now we will not take the driver offline during a download */
offline = 0;
if (hba->sli_mode != EMLXS_HBA_SLI4_MODE) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"Invalid sli_mode. mode=%d", hba->sli_mode);
return (EMLXS_IMAGE_INCOMPATIBLE);
}
if (hba->model_info.chip & EMLXS_BE_CHIPS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"Invalid adapter model. chip=%x", hba->model_info.chip);
return (EMLXS_IMAGE_INCOMPATIBLE);
}
if (buffer == NULL || len == 0) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Empty buffer provided. buf=%p size=%d", buffer, len);
return (EMLXS_IMAGE_BAD);
}
rval = emlxs_obj_validate_image(hba, buffer, len, 0);
if (rval) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"Invalid image provided.");
return (EMLXS_IMAGE_INCOMPATIBLE);
}
/* Allocate resources */
if ((mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_SLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to allocate mailbox buffer.");
offline = 0;
rval = EMLXS_IMAGE_FAILED;
goto done;
}
if ((mp = emlxs_mem_buf_alloc(hba, OBJ_MAX_XFER_SIZE)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to allocate flash buffer.");
offline = 0;
rval = EMLXS_IMAGE_FAILED;
goto done;
}
/*
* Everything checks out, now to just do it
*/
if (offline) {
if (emlxs_offline(hba, 0) != FC_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to take adapter offline.");
offline = 0;
rval = EMLXS_OFFLINE_FAILED;
goto done;
}
}
rval = emlxs_obj_flash_image(hba, buffer, len, mbq, mp, &change_status);
done:
if (mbq) {
emlxs_mem_put(hba, MEM_MBOX, (void *)mbq);
}
if (mp) {
emlxs_mem_buf_free(hba, mp);
}
if (offline) {
(void) emlxs_online(hba);
}
if (rval == 0) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_complete_msg,
"Status good.");
switch (change_status) {
case CS_NO_RESET:
break;
case CS_REBOOT_RQD:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fw_updated_msg,
"The new firmware will not be activated until "
"the adapter is power cycled.");
rval = EMLXS_REBOOT_REQUIRED;
break;
case CS_FW_RESET_RQD:
case CS_PROTO_RESET_RQD:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_fw_updated_msg,
"Resetting all ports to activate new firmware.");
emlxs_sli4_hba_reset_all(hba, 0);
}
}
return (rval);
} /* emlxs_obj_fw_download() */
extern int32_t
emlxs_cfl_download(emlxs_hba_t *hba, uint32_t region, caddr_t buffer,
uint32_t len)
{
emlxs_port_t *port = &PPORT;
MAILBOXQ *mbox = NULL;
MAILBOX *mb;
uint32_t rval = 0;
uint32_t region_id;
uint32_t id;
#ifdef EMLXS_BIG_ENDIAN
caddr_t local_buffer;
uint32_t *bptr1;
uint32_t *bptr2;
uint32_t i;
#endif /* EMLXS_BIG_ENDIAN */
if (buffer == NULL || len == 0) {
return (EMLXS_IMAGE_BAD);
}
#ifdef EMLXS_BIG_ENDIAN
/* We need to swap the image buffer before we start */
/*
* Use KM_SLEEP to allocate a temporary buffer
*/
local_buffer = (caddr_t)kmem_zalloc(len, KM_SLEEP);
/* Perform a 32 bit swap of the image */
bptr1 = (uint32_t *)local_buffer;
bptr2 = (uint32_t *)buffer;
for (i = 0; i < (len / 4); i++) {
*bptr1 = SWAP32(*bptr2);
bptr1++;
bptr2++;
}
/* Replace the original buffer */
buffer = local_buffer;
#endif /* EMLXS_BIG_ENDIAN */
if (len > 128) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Invalid image length: 0x%x > 128", len);
return (EMLXS_IMAGE_BAD);
}
/* Check the region number */
if ((region > 2) && (region != 0xff)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Invalid region id: 0x%x", region);
return (EMLXS_IMAGE_BAD);
}
/* Check the image vendor id */
id = *(int32_t *)buffer;
if ((id & 0xffff) != 0x10df) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Invalid image id: 0x%x", id);
return (EMLXS_IMAGE_BAD);
}
if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to allocate mailbox buffer.");
rval = 1;
goto done;
}
mb = (MAILBOX *)mbox;
/*
* Everything checks out, now to just do it
*/
if (emlxs_offline(hba, 0) != FC_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to take HBA offline.");
rval = EMLXS_OFFLINE_FAILED;
goto done;
}
if (EMLXS_SLI_HBA_RESET(hba, 1, 1, 0) != FC_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to restart adapter.");
rval = EMLXS_OFFLINE_FAILED;
goto done;
}
/* Check if default region is requested */
if (region == 0xff) {
/*
* Sun-branded Helios and Zypher have different
* default PCI region
*/
if ((hba->model_info.flags & EMLXS_ORACLE_BRANDED) &&
(hba->model_info.chip &
(EMLXS_HELIOS_CHIP | EMLXS_ZEPHYR_CHIP))) {
region = 2;
} else {
region = 0;
}
}
/* Set region id based on PCI region requested */
region_id = DEF_PCI_CFG_REGION_ID + region;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"PCI configuration: PCI%d region=%d id=0x%x size=%d", region,
region_id, id, len);
/* Copy the data buffer to SLIM */
WRITE_SLIM_COPY(hba, (uint32_t *)buffer,
(volatile uint32_t *)((volatile char *)hba->sli.sli3.slim_addr +
sizeof (MAILBOX)), (len / sizeof (uint32_t)));
#ifdef FMA_SUPPORT
if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.slim_acc_handle)
!= DDI_FM_OK) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_invalid_access_handle_msg, NULL);
rval = 1;
}
#endif /* FMA_SUPPORT */
emlxs_format_update_pci_cfg(hba, mbox, region_id, len);
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) != MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to update PCI configuration: Mailbox cmd=%x "
"status=%x info=%d", mb->mbxCommand, mb->mbxStatus,
mb->un.varUpdateCfg.rsp_info);
rval = 1;
}
(void) emlxs_online(hba);
if (rval == 0) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_complete_msg,
"Status good.");
}
done:
if (mbox) {
kmem_free(mbox, sizeof (MAILBOXQ));
}
#ifdef EMLXS_BIG_ENDIAN
/* Free the local buffer */
kmem_free(local_buffer, len);
#endif /* EMLXS_BIG_ENDIAN */
return (rval);
} /* emlxs_cfl_download */
static uint32_t
emlxs_valid_cksum(uint32_t *StartAddr, uint32_t *EndAddr)
{
uint32_t Temp;
uint32_t CkSum;
EndAddr++;
CkSum = SLI_CKSUM_SEED;
CkSum = (CkSum >> 1) | (CkSum << 31);
while (StartAddr != EndAddr) {
CkSum = (CkSum << 1) | (CkSum >> 31);
Temp = *StartAddr;
CkSum ^= Temp;
StartAddr++;
}
return (CkSum << 1) | (CkSum >> 31);
} /* emlxs_valid_cksum() */
static void
emlxs_disp_aif_header(emlxs_hba_t *hba, PAIF_HDR AifHdr)
{
emlxs_port_t *port = &PPORT;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg, "AIF Header: ");
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"AIF Header: compress_br = 0x%x", AifHdr->CompressBr);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"AIF Header: reloc_br = 0x%x", AifHdr->RelocBr);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"AIF Header: zinit_br = 0x%x", AifHdr->ZinitBr);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"AIF Header: entry_br = 0x%x", AifHdr->EntryBr);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"AIF Header: area_id = 0x%x", AifHdr->Area_ID);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"AIF Header: rosize = 0x%x", AifHdr->RoSize);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"AIF Header: dbgsize = 0x%x", AifHdr->DbgSize);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"AIF Header: zinitsize = 0x%x", AifHdr->ZinitSize);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"AIF Header: dbgtype = 0x%x", AifHdr->DbgType);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"AIF Header: imagebase = 0x%x", AifHdr->ImageBase);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"AIF Header: area_size = 0x%x", AifHdr->Area_Size);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"AIF Header: address_mode = 0x%x", AifHdr->AddressMode);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"AIF Header: database = 0x%x", AifHdr->DataBase);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"AIF Header: aversion = 0x%x", AifHdr->AVersion);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"AIF Header: spare2 = 0x%x", AifHdr->Spare2);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"AIF Header: debug_swi = 0x%x", AifHdr->DebugSwi);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"AIF Header: zinitcode[0] = 0x%x", AifHdr->ZinitCode[0]);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"AIF Header: zinitcode[1] = 0x%x", AifHdr->ZinitCode[1]);
} /* emlxs_disp_aif_header() */
static void
emlxs_dump_image_header(emlxs_hba_t *hba, PIMAGE_HDR image)
{
emlxs_port_t *port = &PPORT;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg, "Img Header: ");
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Img Header: BlockSize = 0x%x", image->BlockSize);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Img Header: PROG_ID Type = 0x%x", image->Id.Type);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Img Header: PROG_ID Id = 0x%x", image->Id.Id);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Img Header: PROG_ID Ver = 0x%x", image->Id.Ver);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Img Header: PROG_ID Rev = 0x%x", image->Id.Rev);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Img Header: PROG_ID revcomp = 0x%x", image->Id.un.revcomp);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Img Header: Flags = 0x%x", image->Flags);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Img Header: EntryAdr = 0x%x", image->EntryAdr);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Img Header: InitAdr = 0x%x", image->InitAdr);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Img Header: ExitAdr = 0x%x", image->ExitAdr);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Img Header: ImageBase = 0x%x", image->ImageBase);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Img Header: ImageSize = 0x%x", image->ImageSize);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Img Header: ZinitSize = 0x%x", image->ZinitSize);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Img Header: RelocSize = 0x%x", image->RelocSize);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Img Header: HdrCks = 0x%x", image->HdrCks);
} /* emlxs_dump_image_header() */
static void
emlxs_format_dump(emlxs_hba_t *hba, MAILBOXQ *mbq, uint32_t Type,
uint32_t RegionId, uint32_t WordCount, uint32_t BaseAddr)
{
if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
MAILBOX4 *mb = (MAILBOX4 *)mbq;
/* Clear the local dump_region */
bzero(hba->sli.sli4.dump_region.virt,
hba->sli.sli4.dump_region.size);
bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
mb->mbxCommand = MBX_DUMP_MEMORY;
mb->un.varDmp4.type = Type;
mb->un.varDmp4.entry_index = BaseAddr;
mb->un.varDmp4.region_id = RegionId;
mb->un.varDmp4.available_cnt = min((WordCount*4),
hba->sli.sli4.dump_region.size);
mb->un.varDmp4.addrHigh =
PADDR_HI(hba->sli.sli4.dump_region.phys);
mb->un.varDmp4.addrLow =
PADDR_LO(hba->sli.sli4.dump_region.phys);
mb->un.varDmp4.rsp_cnt = 0;
mb->mbxOwner = OWN_HOST;
} else {
MAILBOX *mb = (MAILBOX *)mbq;
bzero((void *)mb, MAILBOX_CMD_BSIZE);
mb->mbxCommand = MBX_DUMP_MEMORY;
mb->un.varDmp.type = Type;
mb->un.varDmp.region_id = RegionId;
mb->un.varDmp.word_cnt = WordCount;
mb->un.varDmp.base_adr = BaseAddr;
mb->mbxOwner = OWN_HOST;
}
mbq->mbox_cmpl = NULL; /* no cmpl needed */
return;
} /* emlxs_format_dump() */
/* ARGSUSED */
static uint32_t
emlxs_start_abs_download(emlxs_hba_t *hba,
PAIF_HDR AifHdr,
caddr_t Buffer,
uint32_t len,
PWAKE_UP_PARMS WakeUpParms)
{
emlxs_port_t *port = &PPORT;
uint32_t DlByteCount = AifHdr->RoSize + AifHdr->RwSize;
uint32_t *Src;
uint32_t *Dst;
caddr_t DataBuffer = NULL;
MAILBOXQ *mbox;
MAILBOX *mb;
uint32_t rval = 1;
uint32_t SegSize = DL_SLIM_SEG_BYTE_COUNT;
uint32_t DlToAddr = AifHdr->ImageBase;
uint32_t DlCount;
uint32_t i;
WAKE_UP_PARMS AbsWakeUpParms;
int32_t AbsChangeParams;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Performing absolute download...");
if ((DataBuffer = (caddr_t)kmem_zalloc(DL_SLIM_SEG_BYTE_COUNT,
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to allocate data buffer.");
return (rval);
}
if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to allocate mailbox buffer.");
kmem_free(DataBuffer, DL_SLIM_SEG_BYTE_COUNT);
return (rval);
}
mb = (MAILBOX *)mbox;
AbsChangeParams = emlxs_build_parms(Buffer,
&AbsWakeUpParms, len, AifHdr);
Buffer += sizeof (AIF_HDR);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg, "Erasing flash...");
if (AifHdr->ImageBase == 0x20000) {
/* DWC File */
emlxs_format_prog_flash(mbox, 0x20000, 0x50000, ERASE_FLASH, 0,
0, 0, NULL, 0);
} else {
emlxs_format_prog_flash(mbox, DlToAddr, DlByteCount,
ERASE_FLASH, 0, 0, 0, NULL, 0);
}
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) != MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to erase Flash: Mailbox cmd=%x status=%x",
mb->mbxCommand, mb->mbxStatus);
rval = 1;
goto EXIT_ABS_DOWNLOAD;
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Programming flash...");
while (DlByteCount) {
if (DlByteCount > SegSize) {
DlCount = SegSize;
} else {
DlCount = DlByteCount;
}
DlByteCount -= DlCount;
Dst = (uint32_t *)DataBuffer;
Src = (uint32_t *)Buffer;
for (i = 0; i < (DlCount / 4); i++) {
*Dst = *Src;
Dst++;
Src++;
}
WRITE_SLIM_COPY(hba, (uint32_t *)DataBuffer,
(volatile uint32_t *)
((volatile char *)hba->sli.sli3.slim_addr +
sizeof (MAILBOX)), (DlCount / sizeof (uint32_t)));
emlxs_format_prog_flash(mbox, DlToAddr, DlCount,
PROGRAM_FLASH, (DlByteCount) ? 0 : 1, 0, DlCount, NULL, 0);
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) !=
MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to program Flash: Mailbox cmd=%x status=%x",
mb->mbxCommand, mb->mbxStatus);
rval = 1;
goto EXIT_ABS_DOWNLOAD;
}
Buffer += DlCount;
DlToAddr += DlCount;
}
#ifdef FMA_SUPPORT
if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.slim_acc_handle)
!= DDI_FM_OK) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_invalid_access_handle_msg, NULL);
rval = 1;
goto EXIT_ABS_DOWNLOAD;
}
#endif /* FMA_SUPPORT */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg, "Updating params...");
if (AbsChangeParams) {
rval =
emlxs_update_wakeup_parms(hba, &AbsWakeUpParms,
WakeUpParms);
}
EXIT_ABS_DOWNLOAD:
if (DataBuffer) {
kmem_free(DataBuffer, DL_SLIM_SEG_BYTE_COUNT);
}
if (mbox) {
kmem_free(mbox, sizeof (MAILBOXQ));
}
return (rval);
} /* emlxs_start_abs_download() */
/* ARGSUSED */
static void
emlxs_format_prog_flash(MAILBOXQ *mbq,
uint32_t Base,
uint32_t DlByteCount,
uint32_t Function,
uint32_t Complete,
uint32_t BdeAddress,
uint32_t BdeSize,
PROG_ID *ProgId,
uint32_t keep)
{
MAILBOX *mb = (MAILBOX *)mbq;
bzero((void *)mb, MAILBOX_CMD_BSIZE);
if (ProgId) {
mb->mbxCommand = MBX_DOWN_LOAD;
} else {
mb->mbxCommand = MBX_LOAD_SM;
}
mb->un.varLdSM.load_cmplt = Complete;
mb->un.varLdSM.method = DL_FROM_SLIM;
mb->un.varLdSM.update_flash = 1;
mb->un.varLdSM.erase_or_prog = Function;
mb->un.varLdSM.dl_to_adr = Base;
mb->un.varLdSM.dl_len = DlByteCount;
mb->un.varLdSM.keep = keep;
if (BdeSize) {
mb->un.varLdSM.un.dl_from_slim_offset = DL_FROM_SLIM_OFFSET;
} else if (ProgId) {
mb->un.varLdSM.un.prog_id = *ProgId;
} else {
mb->un.varLdSM.un.dl_from_slim_offset = 0;
}
mb->mbxOwner = OWN_HOST;
mbq->mbox_cmpl = NULL;
} /* emlxs_format_prog_flash() */
static void
emlxs_format_update_parms(MAILBOXQ *mbq, PWAKE_UP_PARMS WakeUpParms)
{
MAILBOX *mb = (MAILBOX *)mbq;
bzero((void *)mb, MAILBOX_CMD_BSIZE);
mb->mbxCommand = MBX_UPDATE_CFG;
mb->un.varUpdateCfg.req_type = UPDATE_DATA;
mb->un.varUpdateCfg.region_id = WAKE_UP_PARMS_REGION_ID;
mb->un.varUpdateCfg.entry_len = sizeof (WAKE_UP_PARMS);
mb->un.varUpdateCfg.byte_len = sizeof (WAKE_UP_PARMS);
bcopy((caddr_t)WakeUpParms,
(caddr_t)&(mb->un.varUpdateCfg.cfg_data),
sizeof (WAKE_UP_PARMS));
mbq->mbox_cmpl = NULL;
} /* emlxs_format_update_parms () */
/* ARGSUSED */
static void
emlxs_format_update_pci_cfg(emlxs_hba_t *hba, MAILBOXQ *mbq,
uint32_t region_id, uint32_t size)
{
MAILBOX *mb = (MAILBOX *)mbq;
bzero((void *)mb, MAILBOX_CMD_BSIZE);
mb->mbxCommand = MBX_UPDATE_CFG;
mb->un.varUpdateCfg.Vbit = 1;
mb->un.varUpdateCfg.Obit = 1;
mb->un.varUpdateCfg.cfg_data = DL_FROM_SLIM_OFFSET;
mb->un.varUpdateCfg.req_type = UPDATE_DATA;
mb->un.varUpdateCfg.region_id = region_id;
mb->un.varUpdateCfg.entry_len = size;
mb->un.varUpdateCfg.byte_len = size;
mbq->mbox_cmpl = NULL;
} /* emlxs_format_update_pci_cfg() */
static uint32_t
emlxs_update_boot_wakeup_parms(emlxs_hba_t *hba, PWAKE_UP_PARMS WakeUpParms,
PROG_ID * prog_id, uint32_t proc_erom)
{
emlxs_port_t *port = &PPORT;
MAILBOX *mb;
MAILBOXQ *mbox;
uint32_t rval = 0;
PROG_ID old_prog_id;
if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to allocate mailbox buffer.");
return (1);
}
mb = (MAILBOX *)mbox;
if (proc_erom && !(hba->model_info.chip &
(EMLXS_DRAGONFLY_CHIP | EMLXS_CENTAUR_CHIP))) {
WakeUpParms->u1.EROM_prog_id = *prog_id;
(void) emlxs_update_exp_rom(hba, WakeUpParms);
}
old_prog_id = WakeUpParms->u0.boot_bios_id;
WakeUpParms->u0.boot_bios_id = *prog_id;
emlxs_format_update_parms(mbox, WakeUpParms);
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) != MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to update boot wakeup parms: Mailbox cmd=%x "
"status=%x", mb->mbxCommand, mb->mbxStatus);
WakeUpParms->u0.boot_bios_id = old_prog_id;
rval = 1;
}
if (mbox) {
kmem_free(mbox, sizeof (MAILBOXQ));
}
return (rval);
} /* emlxs_update_boot_wakeup_parms() */
static uint32_t
emlxs_update_ff_wakeup_parms(emlxs_hba_t *hba, PWAKE_UP_PARMS WakeUpParms,
PROG_ID *prog_id)
{
emlxs_port_t *port = &PPORT;
uint32_t rval = 0;
MAILBOXQ *mbox;
MAILBOX *mb;
PROG_ID old_prog_id;
if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to allocate mailbox buffer.");
return (1);
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"FF: Updating parms...");
mb = (MAILBOX *)mbox;
old_prog_id = WakeUpParms->prog_id;
WakeUpParms->prog_id = *prog_id;
emlxs_format_update_parms(mbox, WakeUpParms);
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) != MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to update wakeup parameters: Mailbox cmd=%x "
"status=%x", mb->mbxCommand, mb->mbxStatus);
WakeUpParms->prog_id = old_prog_id;
rval = 1;
}
if (mbox) {
kmem_free(mbox, sizeof (MAILBOXQ));
}
return (rval);
} /* emlxs_update_ff_wakeup_parms() */
static uint32_t
emlxs_update_sli1_wakeup_parms(emlxs_hba_t *hba, PWAKE_UP_PARMS WakeUpParms,
PROG_ID * prog_id)
{
emlxs_port_t *port = &PPORT;
uint32_t rval = 0;
MAILBOXQ *mbox;
MAILBOX *mb;
PROG_ID old_prog_id;
if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to allocate mailbox buffer.");
return (1);
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"SLI1: Updating parms...");
mb = (MAILBOX *)mbox;
old_prog_id = WakeUpParms->sli1_prog_id;
WakeUpParms->sli1_prog_id = *prog_id;
emlxs_format_update_parms(mbox, WakeUpParms);
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) != MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to update wakeup parameters. Mailbox cmd=%x "
"status=%x", mb->mbxCommand, mb->mbxStatus);
WakeUpParms->sli1_prog_id = old_prog_id;
rval = 1;
}
if (mbox) {
kmem_free(mbox, sizeof (MAILBOXQ));
}
return (rval);
} /* emlxs_update_sli1_wakeup_parms() */
static uint32_t
emlxs_update_sli2_wakeup_parms(emlxs_hba_t *hba, PWAKE_UP_PARMS WakeUpParms,
PROG_ID * prog_id)
{
emlxs_port_t *port = &PPORT;
uint32_t rval = 0;
MAILBOXQ *mbox;
MAILBOX *mb;
PROG_ID old_prog_id;
if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to allocate mailbox buffer.");
return (1);
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"SLI2: Updating parms...");
mb = (MAILBOX *)mbox;
old_prog_id = WakeUpParms->sli2_prog_id;
WakeUpParms->sli2_prog_id = *prog_id;
emlxs_format_update_parms(mbox, WakeUpParms);
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) != MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to update wakeup parameters. Mailbox cmd=%x "
"status=%x", mb->mbxCommand, mb->mbxStatus);
WakeUpParms->sli2_prog_id = old_prog_id;
rval = 1;
}
if (mbox) {
kmem_free(mbox, sizeof (MAILBOXQ));
}
return (rval);
} /* emlxs_update_sli2_wakeup_parms() */
static uint32_t
emlxs_update_sli3_wakeup_parms(emlxs_hba_t *hba, PWAKE_UP_PARMS WakeUpParms,
PROG_ID *prog_id)
{
emlxs_port_t *port = &PPORT;
uint32_t rval = 0;
MAILBOXQ *mbox;
MAILBOX *mb;
PROG_ID old_prog_id;
if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to allocate mailbox buffer.");
return (1);
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"SLI3: Updating parms...");
mb = (MAILBOX *)mbox;
old_prog_id = WakeUpParms->sli3_prog_id;
WakeUpParms->sli3_prog_id = *prog_id;
emlxs_format_update_parms(mbox, WakeUpParms);
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) != MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to update wakeup parameters. Mailbox cmd=%x "
"status=%x", mb->mbxCommand, mb->mbxStatus);
WakeUpParms->sli3_prog_id = old_prog_id;
rval = 1;
}
if (mbox) {
kmem_free(mbox, sizeof (MAILBOXQ));
}
return (rval);
} /* emlxs_update_sli3_wakeup_parms() */
static uint32_t
emlxs_update_sli4_wakeup_parms(emlxs_hba_t *hba, PWAKE_UP_PARMS WakeUpParms,
PROG_ID *prog_id)
{
emlxs_port_t *port = &PPORT;
uint32_t rval = 0;
MAILBOXQ *mbox;
MAILBOX *mb;
PROG_ID old_prog_id;
if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to allocate mailbox buffer.");
return (1);
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"SLI4: Updating parms...");
mb = (MAILBOX *)mbox;
old_prog_id = WakeUpParms->sli4_prog_id;
WakeUpParms->sli4_prog_id = *prog_id;
emlxs_format_update_parms(mbox, WakeUpParms);
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) != MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to update wakeup parameters. Mailbox cmd=%x "
"status=%x", mb->mbxCommand, mb->mbxStatus);
WakeUpParms->sli4_prog_id = old_prog_id;
rval = 1;
}
if (mbox) {
kmem_free(mbox, sizeof (MAILBOXQ));
}
return (rval);
} /* emlxs_update_sli4_wakeup_parms() */
static uint32_t
emlxs_clean_flash(emlxs_hba_t *hba,
PWAKE_UP_PARMS OldWakeUpParms, PWAKE_UP_PARMS NewWakeUpParms)
{
emlxs_port_t *port = &PPORT;
PROG_ID load_list[MAX_LOAD_ENTRY];
PROG_ID *wakeup_list[MAX_LOAD_ENTRY];
uint32_t count;
uint32_t i;
uint32_t j;
uint32_t k = 0;
uint32_t *wptr;
if (!NewWakeUpParms) {
return (1);
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"Cleaning flash...");
/* If old wakeup parameter list is available, */
/* then cleanup old entries */
if (OldWakeUpParms) {
if (bcmp(&OldWakeUpParms->prog_id, &NewWakeUpParms->prog_id,
sizeof (PROG_ID))) {
wptr = (uint32_t *)&OldWakeUpParms->prog_id;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"OLD: prog_id: 0x%08x 0x%08x Removing.",
wptr[0], wptr[1]);
(void) emlxs_delete_load_entry(hba,
&OldWakeUpParms->prog_id);
}
if (bcmp(&OldWakeUpParms->u0.boot_bios_id,
&NewWakeUpParms->u0.boot_bios_id, sizeof (PROG_ID))) {
wptr = (uint32_t *)&OldWakeUpParms->u0.boot_bios_id;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"OLD: boot_bios_id: 0x%08x 0x%08x Removing.",
wptr[0], wptr[1]);
(void) emlxs_delete_load_entry(hba,
&OldWakeUpParms->u0.boot_bios_id);
}
if (bcmp(&OldWakeUpParms->sli1_prog_id,
&NewWakeUpParms->sli1_prog_id, sizeof (PROG_ID))) {
wptr = (uint32_t *)&OldWakeUpParms->sli1_prog_id;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"OLD: sli1_prog_id: 0x%08x 0x%08x Removing.",
wptr[0], wptr[1]);
(void) emlxs_delete_load_entry(hba,
&OldWakeUpParms->sli1_prog_id);
}
if (bcmp(&OldWakeUpParms->sli2_prog_id,
&NewWakeUpParms->sli2_prog_id, sizeof (PROG_ID))) {
wptr = (uint32_t *)&OldWakeUpParms->sli2_prog_id;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"OLD: sli2_prog_id: 0x%08x 0x%08x Removing.",
wptr[0], wptr[1]);
(void) emlxs_delete_load_entry(hba,
&OldWakeUpParms->sli2_prog_id);
}
if (bcmp(&OldWakeUpParms->sli3_prog_id,
&NewWakeUpParms->sli3_prog_id, sizeof (PROG_ID))) {
wptr = (uint32_t *)&OldWakeUpParms->sli3_prog_id;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"OLD: sli3_prog_id: 0x%08x 0x%08x Removing.",
wptr[0], wptr[1]);
(void) emlxs_delete_load_entry(hba,
&OldWakeUpParms->sli3_prog_id);
}
if (bcmp(&OldWakeUpParms->sli4_prog_id,
&NewWakeUpParms->sli4_prog_id, sizeof (PROG_ID))) {
wptr = (uint32_t *)&OldWakeUpParms->sli4_prog_id;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"OLD: sli4_prog_id: 0x%08x 0x%08x Removing.",
wptr[0], wptr[1]);
(void) emlxs_delete_load_entry(hba,
&OldWakeUpParms->sli4_prog_id);
}
return (0);
}
/* Otherwise use the current load list */
count = emlxs_get_load_list(hba, load_list);
if (!count) {
return (1);
}
/* Init the wakeup list */
wptr = (uint32_t *)&NewWakeUpParms->prog_id;
if (*wptr) {
wakeup_list[k++] = &NewWakeUpParms->prog_id;
}
wptr = (uint32_t *)&NewWakeUpParms->u0.boot_bios_id;
if (*wptr) {
wakeup_list[k++] = &NewWakeUpParms->u0.boot_bios_id;
}
wptr = (uint32_t *)&NewWakeUpParms->sli1_prog_id;
if (*wptr) {
wakeup_list[k++] = &NewWakeUpParms->sli1_prog_id;
}
wptr = (uint32_t *)&NewWakeUpParms->sli2_prog_id;
if (*wptr) {
wakeup_list[k++] = &NewWakeUpParms->sli2_prog_id;
}
wptr = (uint32_t *)&NewWakeUpParms->sli3_prog_id;
if (*wptr) {
wakeup_list[k++] = &NewWakeUpParms->sli3_prog_id;
}
wptr = (uint32_t *)&NewWakeUpParms->sli4_prog_id;
if (*wptr) {
wakeup_list[k++] = &NewWakeUpParms->sli4_prog_id;
}
if (k == 0) {
return (0);
}
/* Match load list to wakeup list */
for (i = 0; i < count; i++) {
wptr = (uint32_t *)&load_list[i];
for (j = 0; j < k; j++) {
if (bcmp((uint8_t *)wakeup_list[j],
(uint8_t *)&load_list[i], sizeof (PROG_ID)) == 0) {
break;
}
}
/* No match */
if (j == k) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"Load List[%d]: %08x %08x Removing.",
i, wptr[0], wptr[1]);
(void) emlxs_delete_load_entry(hba, &load_list[i]);
} else {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"Load List[%d]: %08x %08x Preserving.",
i, wptr[0], wptr[1]);
}
}
return (0);
} /* emlxs_clean_flash() */
/* ARGSUSED */
static uint32_t
emlxs_start_rel_download(emlxs_hba_t *hba,
PIMAGE_HDR ImageHdr,
caddr_t Buffer,
PWAKE_UP_PARMS WakeUpParms,
uint32_t dwc_flag)
{
emlxs_port_t *port = &PPORT;
MAILBOXQ *mbox;
MAILBOX *mb;
uint32_t *Src;
uint32_t *Dst;
caddr_t DataBuffer = NULL;
uint32_t rval = 0;
uint32_t DlByteCount;
uint32_t SegSize = DL_SLIM_SEG_BYTE_COUNT;
uint32_t DlCount;
uint32_t i;
uint32_t *wptr;
wptr = (uint32_t *)&ImageHdr->Id;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Relative download: %08x %08x", wptr[0], wptr[1]);
if ((DataBuffer = (caddr_t)kmem_zalloc(DL_SLIM_SEG_BYTE_COUNT,
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to allocate data buffer.");
return (1);
}
if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to allocate mailbox buffer.");
kmem_free(DataBuffer, DL_SLIM_SEG_BYTE_COUNT);
return (1);
}
mb = (MAILBOX *)mbox;
DlByteCount = ImageHdr->BlockSize;
emlxs_format_prog_flash(mbox, 0, DlByteCount, ERASE_FLASH, 0, 0, 0,
&ImageHdr->Id, 0);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
" Erasing flash...");
rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0);
if (rval) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to erase flash. Mailbox cmd=%x status=%x",
mb->mbxCommand, mb->mbxStatus);
goto EXIT_REL_DOWNLOAD;
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
" Programming flash...");
while (DlByteCount) {
if (DlByteCount > SegSize) {
DlCount = SegSize;
} else {
DlCount = DlByteCount;
}
DlByteCount -= DlCount;
Dst = (uint32_t *)DataBuffer;
Src = (uint32_t *)Buffer;
for (i = 0; i < (DlCount / 4); i++) {
*Dst = *Src;
Dst++;
Src++;
}
WRITE_SLIM_COPY(hba, (uint32_t *)DataBuffer,
(volatile uint32_t *)
((volatile char *)hba->sli.sli3.slim_addr +
sizeof (MAILBOX)), (DlCount / sizeof (uint32_t)));
emlxs_format_prog_flash(mbox,
0,
DlCount,
PROGRAM_FLASH,
(DlByteCount) ? 0 : 1,
0, DlCount, &ImageHdr->Id, dwc_flag);
rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0);
if (rval) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to program flash. Mailbox cmd=%x status=%x",
mb->mbxCommand, mb->mbxStatus);
goto EXIT_REL_DOWNLOAD;
}
Buffer += DlCount;
}
#ifdef FMA_SUPPORT
if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.slim_acc_handle)
!= DDI_FM_OK) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_invalid_access_handle_msg, NULL);
rval = 1;
goto EXIT_REL_DOWNLOAD;
}
#endif /* FMA_SUPPORT */
/* Update wakeup parameters */
switch (ImageHdr->Id.Type) {
case TEST_PROGRAM:
break;
case FUNC_FIRMWARE:
if (!dwc_flag) {
rval = emlxs_update_ff_wakeup_parms(hba, WakeUpParms,
&ImageHdr->Id);
} else {
WakeUpParms->prog_id = ImageHdr->Id;
}
break;
case BOOT_BIOS:
if (!dwc_flag) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"BOOT: Updating parms...");
rval = emlxs_update_boot_wakeup_parms(hba, WakeUpParms,
&ImageHdr->Id, 1);
} else {
if (hba->wakeup_parms.u0.boot_bios_wd[0]) {
WakeUpParms->u0.boot_bios_id = ImageHdr->Id;
}
if (!(hba->model_info.chip &
(EMLXS_DRAGONFLY_CHIP | EMLXS_CENTAUR_CHIP))) {
WakeUpParms->u1.EROM_prog_id = ImageHdr->Id;
}
}
break;
case SLI1_OVERLAY:
if (!dwc_flag) {
rval = emlxs_update_sli1_wakeup_parms(hba, WakeUpParms,
&ImageHdr->Id);
} else {
WakeUpParms->sli1_prog_id = ImageHdr->Id;
}
break;
case SLI2_OVERLAY:
if (!dwc_flag) {
rval = emlxs_update_sli2_wakeup_parms(hba, WakeUpParms,
&ImageHdr->Id);
} else {
WakeUpParms->sli2_prog_id = ImageHdr->Id;
}
break;
case SLI3_OVERLAY:
if (!dwc_flag) {
rval = emlxs_update_sli3_wakeup_parms(hba, WakeUpParms,
&ImageHdr->Id);
} else {
WakeUpParms->sli3_prog_id = ImageHdr->Id;
}
break;
case SLI4_OVERLAY:
if (!dwc_flag) {
rval = emlxs_update_sli4_wakeup_parms(hba, WakeUpParms,
&ImageHdr->Id);
} else {
WakeUpParms->sli4_prog_id = ImageHdr->Id;
}
break;
default:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"Image type not supported. Type=%x", ImageHdr->Id.Type);
break;
}
EXIT_REL_DOWNLOAD:
if (DataBuffer) {
kmem_free(DataBuffer, DL_SLIM_SEG_BYTE_COUNT);
}
if (mbox) {
kmem_free(mbox, sizeof (MAILBOXQ));
}
return (rval);
} /* emlxs_start_rel_download() */
static uint32_t
emlxs_proc_rel_2mb(emlxs_hba_t *hba, caddr_t buffer, emlxs_fw_image_t *fw_image)
{
emlxs_port_t *port = &PPORT;
uint32_t rval = 0;
WAKE_UP_PARMS RelWakeUpParms;
WAKE_UP_PARMS WakeUpParms;
uint32_t i;
IMAGE_HDR ImageHdr;
caddr_t bptr;
uint32_t flash_cleaned = 0;
if (emlxs_read_wakeup_parms(hba, &WakeUpParms, 0)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to get wakeup parameters.");
return (EMLXS_IMAGE_FAILED);
}
download:
bcopy(&WakeUpParms, &RelWakeUpParms, sizeof (WAKE_UP_PARMS));
for (i = 0; i < MAX_PROG_TYPES; i++) {
if (!fw_image->prog[i].version) {
continue;
}
bptr = buffer + fw_image->prog[i].offset;
bcopy(bptr, &ImageHdr, sizeof (IMAGE_HDR));
rval = emlxs_start_rel_download(hba, &ImageHdr, bptr,
&RelWakeUpParms, 1);
if (rval) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_download_failed_msg,
"Failed to program flash.");
if ((rval == NO_FLASH_MEM_AVAIL) && !flash_cleaned) {
/* Cleanup using current load list */
(void) emlxs_clean_flash(hba, 0, &WakeUpParms);
flash_cleaned = 1;
goto download;
}
return (EMLXS_IMAGE_FAILED);
}
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_detail_msg,
"Updating wakeup parameters.");
if (emlxs_update_wakeup_parms(hba, &RelWakeUpParms,
&RelWakeUpParms)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to update parameters.");
return (EMLXS_IMAGE_FAILED);
}
/* Cleanup using old wakeup paramters */
(void) emlxs_clean_flash(hba, &WakeUpParms, &RelWakeUpParms);
return (0);
} /* emlxs_proc_rel_2mb() */
#define FLASH_POLLING_BIT 0x80
#define FLASH_ERROR_BIT 0x20
typedef struct _flash_t
{
uint32_t offset;
uint8_t val;
} flash_t;
static uint32_t
emlxs_write_fcode_flash(emlxs_hba_t *hba,
PIMAGE_HDR ImageHdr, caddr_t Buffer)
{
emlxs_port_t *port = &PPORT;
uint8_t bb;
uint8_t cc;
uint8_t *src;
uint32_t DlByteCount = ImageHdr->BlockSize;
uint32_t i;
uint32_t j;
uint32_t k;
flash_t wr[3] = {
{0x555, 0xaa},
{0x2aa, 0x55},
{0x555, 0xa0}
};
/* Load Fcode */
src = (uint8_t *)Buffer + sizeof (IMAGE_HDR);
for (i = 0; i < DlByteCount; i++) {
for (k = 0; k < 3; k++) {
SBUS_WRITE_FLASH_COPY(hba, wr[k].offset, wr[k].val);
}
/* Reverse Endian word alignment */
j = (i & 3) ^ 3;
bb = src[j];
if (j == 0) {
src += 4;
}
SBUS_WRITE_FLASH_COPY(hba, i, bb);
/* check for complete */
for (;;) {
BUSYWAIT_US(20);
cc = SBUS_READ_FLASH_COPY(hba, i);
/* If data matches then continue */
if (cc == bb) {
break;
}
/* Polling bit will be inverse final value */
/* while active */
if ((cc ^ bb) & FLASH_POLLING_BIT) {
/* Still busy */
/* Check for error bit */
if (cc & FLASH_ERROR_BIT) {
/* Read data one more time */
cc = SBUS_READ_FLASH_COPY(hba, i);
/* Check if data matches */
if (cc == bb) {
break;
}
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_download_failed_msg,
"FCode write error: offset:%x "
"wrote:%x read:%x\n", i, bb, cc);
return (1);
}
}
}
}
/* Load Header */
src = (uint8_t *)ImageHdr;
for (i = (0xFFFF - sizeof (IMAGE_HDR)); i < 0xFFFF; i++) {
for (k = 0; k < 3; k++) {
SBUS_WRITE_FLASH_COPY(hba, wr[k].offset, wr[k].val);
}
/* Reverse Endian word alignment */
j = (i & 3) ^ 3;
bb = src[j];
if (j == 0) {
src += 4;
}
SBUS_WRITE_FLASH_COPY(hba, i, bb);
/* check for complete */
for (;;) {
BUSYWAIT_US(20);
cc = SBUS_READ_FLASH_COPY(hba, i);
/* If data matches then continue */
if (cc == bb) {
break;
}
/* Polling bit will be inverse final value */
/* while active */
if ((cc ^ bb) & FLASH_POLLING_BIT) {
/* Still busy */
/* Check for error bit */
if (cc & FLASH_ERROR_BIT) {
/* Read data one more time */
cc = SBUS_READ_FLASH_COPY(hba, i);
/* Check if data matches */
if (cc == bb) {
break;
}
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_download_failed_msg,
"FCode write error: offset:%x "
"wrote:%x read:%x\n", i, bb, cc);
return (1);
}
}
}
}
#ifdef FMA_SUPPORT
if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.sbus_flash_acc_handle)
!= DDI_FM_OK) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_invalid_access_handle_msg, NULL);
return (1);
}
#endif /* FMA_SUPPORT */
return (0);
} /* emlxs_write_fcode_flash() */
static uint32_t
emlxs_erase_fcode_flash(emlxs_hba_t *hba)
{
emlxs_port_t *port = &PPORT;
int32_t i, j;
uint8_t cc;
uint32_t offset;
flash_t ef[6] = {
{0x555, 0xaa},
{0x2aa, 0x55},
{0x555, 0x80},
{0x555, 0xaa},
{0x2aa, 0x55},
{0x555, 0x10}
};
/* Auto select */
flash_t as[3] = {
{0x555, 0xaa},
{0x2aa, 0x55},
{0x555, 0x90}
};
/* Check Manufacturers Code */
for (i = 0; i < 3; i++) {
SBUS_WRITE_FLASH_COPY(hba, as[i].offset, as[i].val);
}
cc = SBUS_READ_FLASH_COPY(hba, 0);
/* Check Device Code */
for (i = 0; i < 3; i++) {
SBUS_WRITE_FLASH_COPY(hba, as[i].offset, as[i].val);
}
cc = SBUS_READ_FLASH_COPY(hba, 1);
/* Check block protections (up to 4 16K blocks = 64K) */
for (j = 0; j < 4; j++) {
for (i = 0; i < 3; i++) {
SBUS_WRITE_FLASH_COPY(hba, as[i].offset, as[i].val);
}
offset = (j << 14) | 0x2;
cc = SBUS_READ_FLASH_COPY(hba, offset);
if (cc == 0x01) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Block %d is protected and can't be erased.", j);
}
}
/* Write erase flash sequence */
for (i = 0; i < 6; i++) {
SBUS_WRITE_FLASH_COPY(hba, ef[i].offset, ef[i].val);
}
/* check for complete */
for (;;) {
/* Delay 3 seconds */
BUSYWAIT_MS(3000);
cc = SBUS_READ_FLASH_COPY(hba, 0);
/* If data matches then continue; */
if (cc == 0xff) {
break;
}
/* Polling bit will be inverse final value while active */
if ((cc ^ 0xff) & FLASH_POLLING_BIT) {
/* Still busy */
/* Check for error bit */
if (cc & FLASH_ERROR_BIT) {
/* Read data one more time */
cc = SBUS_READ_FLASH_COPY(hba, 0);
/* Check if data matches */
if (cc == 0xff) {
break;
}
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_download_failed_msg,
"FCode write error: offset:%x wrote:%x "
"read:%x\n", i, 0xff, cc);
return (1);
}
}
}
#ifdef FMA_SUPPORT
if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.sbus_flash_acc_handle)
!= DDI_FM_OK) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_invalid_access_handle_msg, NULL);
return (1);
}
#endif /* FMA_SUPPORT */
return (0);
} /* emlxs_erase_fcode_flash() */
static uint32_t
emlxs_delete_load_entry(emlxs_hba_t *hba, PROG_ID *progId)
{
emlxs_port_t *port = &PPORT;
MAILBOXQ *mbox = NULL;
MAILBOX *mb;
uint32_t rval = 0;
if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"Unable to allocate mailbox buffer.");
return (1);
}
mb = (MAILBOX *)mbox;
mb->mbxCommand = MBX_DEL_LD_ENTRY;
mb->un.varDelLdEntry.list_req = FLASH_LOAD_LIST;
mb->un.varDelLdEntry.prog_id = *progId;
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) != MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"Unable to delete load entry: Mailbox cmd=%x status=%x",
mb->mbxCommand, mb->mbxStatus);
rval = 1;
}
done:
if (mbox) {
kmem_free(mbox, sizeof (MAILBOXQ));
}
return (rval);
} /* emlxs_delete_load_entry() */
extern uint32_t
emlxs_get_load_list(emlxs_hba_t *hba, PROG_ID *load_list)
{
emlxs_port_t *port = &PPORT;
LOAD_ENTRY *LoadEntry;
LOAD_LIST *LoadList = NULL;
uint32_t i;
uint32_t count = 0;
bzero(load_list, (sizeof (PROG_ID) * MAX_LOAD_ENTRY));
if ((LoadList = (LOAD_LIST *)kmem_zalloc(sizeof (LOAD_LIST),
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"Unable to allocate LOADLIST buffer.");
goto done;
}
if (emlxs_read_load_list(hba, LoadList)) {
goto done;
}
for (i = 0; i < LoadList->entry_cnt; i++) {
LoadEntry = &LoadList->load_entry[i];
if ((LoadEntry->un.wd[0] != 0) &&
(LoadEntry->un.wd[0] != 0xffffffff)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
"Load List[%d]: %08x %08x", count,
LoadEntry->un.wd[0], LoadEntry->un.wd[1]);
load_list[count++] = LoadEntry->un.id;
}
}
done:
if (LoadList) {
kmem_free(LoadList, sizeof (LOAD_LIST));
}
return (count);
} /* emlxs_get_load_list() */
extern uint32_t
emlxs_read_wakeup_parms(emlxs_hba_t *hba, PWAKE_UP_PARMS WakeUpParms,
uint32_t verbose)
{
emlxs_port_t *port = &PPORT;
MAILBOXQ *mbox;
MAILBOX *mb;
uint32_t rval = 0;
uint32_t *wd;
bzero(WakeUpParms, sizeof (WAKE_UP_PARMS));
if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"Unable to allocate mailbox buffer.");
return (1);
}
mb = (MAILBOX *)mbox;
emlxs_format_dump(hba, mbox,
DMP_NV_PARAMS,
WAKE_UP_PARMS_REGION_ID,
sizeof (WAKE_UP_PARMS) / sizeof (uint32_t), 0);
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) != MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"Unable to get parameters: Mailbox cmd=%x status=%x",
mb->mbxCommand, mb->mbxStatus);
if (mb->un.varDmp.word_cnt == (uint32_t)CFG_DATA_NO_REGION) {
rval = (uint32_t)CFG_DATA_NO_REGION;
} else {
rval = 1;
}
} else {
if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
EMLXS_MPDATA_SYNC(hba->sli.sli4.dump_region.dma_handle,
0, hba->sli.sli4.dump_region.size,
DDI_DMA_SYNC_FORKERNEL);
bcopy((caddr_t)hba->sli.sli4.dump_region.virt,
(caddr_t)WakeUpParms, sizeof (WAKE_UP_PARMS));
} else {
bcopy((caddr_t)&mb->un.varDmp.resp_offset,
(caddr_t)WakeUpParms, sizeof (WAKE_UP_PARMS));
}
if (verbose) {
wd = (uint32_t *)&WakeUpParms->prog_id;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
"Wakeup: prog_id=%08x %08x", wd[0], wd[1]);
wd = (uint32_t *)&WakeUpParms->u0.boot_bios_id;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
"Wakeup: boot_bios_id=%08x %08x", wd[0], wd[1]);
wd = (uint32_t *)&WakeUpParms->sli1_prog_id;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
"Wakeup: sli1_prog_id=%08x %08x", wd[0], wd[1]);
wd = (uint32_t *)&WakeUpParms->sli2_prog_id;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
"Wakeup: sli2_prog_id=%08x %08x", wd[0], wd[1]);
wd = (uint32_t *)&WakeUpParms->sli3_prog_id;
if (wd[0] || wd[1]) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_init_debug_msg,
"Wakeup: sli3_prog_id=%08x %08x", wd[0],
wd[1]);
}
wd = (uint32_t *)&WakeUpParms->sli4_prog_id;
if (wd[0] || wd[1]) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_init_debug_msg,
"Wakeup: sli4_prog_id=%08x %08x", wd[0],
wd[1]);
}
wd = (uint32_t *)&WakeUpParms->u1.EROM_prog_id;
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
"Wakeup: EROM_prog_id=%08x %08x", wd[0], wd[1]);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
"Wakeup: pci_cfg_rsvd=%x",
WakeUpParms->pci_cfg_rsvd);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
"Wakeup: use_hdw_def=%x",
WakeUpParms->use_hdw_def);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
"Wakeup: pci_cfg_sel=%x",
WakeUpParms->pci_cfg_sel);
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_init_debug_msg,
"Wakeup: cfg_lookup=%x",
WakeUpParms->pci_cfg_lookup_sel);
}
}
done:
if (mbox) {
kmem_free(mbox, sizeof (MAILBOXQ));
}
#ifdef FMA_SUPPORT
if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
if (emlxs_fm_check_dma_handle(hba,
hba->sli.sli4.dump_region.dma_handle) != DDI_FM_OK) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_invalid_dma_handle_msg,
"read_wakeup_parms: hdl=%p",
hba->sli.sli4.dump_region.dma_handle);
rval = 1;
}
}
#endif /* FMA_SUPPORT */
return (rval);
} /* emlxs_read_wakeup_parms() */
static uint32_t
emlxs_read_load_list(emlxs_hba_t *hba, LOAD_LIST *LoadList)
{
emlxs_port_t *port = &PPORT;
LOAD_ENTRY *LoadEntry;
uint32_t *Uptr;
uint32_t CurEntryAddr;
MAILBOXQ *mbox = NULL;
MAILBOX *mb;
bzero((caddr_t)LoadList, sizeof (LOAD_LIST));
if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"Unable to allocate mailbox buffer.");
return (1);
}
mb = (MAILBOX *)mbox;
emlxs_format_dump(hba, mbox, DMP_MEM_REG, 0, 2, FLASH_LOAD_LIST_ADR);
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) != MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"Unable to get load list: Mailbox cmd=%x status=%x",
mb->mbxCommand, mb->mbxStatus);
goto done;
}
if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
EMLXS_MPDATA_SYNC(hba->sli.sli4.dump_region.dma_handle, 0,
hba->sli.sli4.dump_region.size, DDI_DMA_SYNC_FORKERNEL);
Uptr = (uint32_t *)hba->sli.sli4.dump_region.virt;
} else {
Uptr = (uint32_t *)&mb->un.varDmp.resp_offset;
}
LoadList->head = Uptr[0];
LoadList->tail = Uptr[1];
CurEntryAddr = LoadList->head;
while ((CurEntryAddr != FLASH_LOAD_LIST_ADR) &&
(LoadList->entry_cnt < MAX_LOAD_ENTRY)) {
LoadEntry = &LoadList->load_entry[LoadList->entry_cnt];
LoadList->entry_cnt++;
emlxs_format_dump(hba, mbox,
DMP_MEM_REG, 0, FLASH_LOAD_ENTRY_SIZE, CurEntryAddr);
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) !=
MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"Unable to get load list (%d): Mailbox cmd=%x "
"status=%x", LoadList->entry_cnt, mb->mbxCommand,
mb->mbxStatus);
goto done;
}
if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
EMLXS_MPDATA_SYNC(hba->sli.sli4.dump_region.dma_handle,
0, hba->sli.sli4.dump_region.size,
DDI_DMA_SYNC_FORKERNEL);
Uptr = (uint32_t *)hba->sli.sli4.dump_region.virt;
} else {
Uptr = (uint32_t *)&mb->un.varDmp.resp_offset;
}
LoadEntry->next = Uptr[0];
LoadEntry->prev = Uptr[1];
LoadEntry->start_adr = Uptr[2];
LoadEntry->len = Uptr[3];
LoadEntry->un.wd[0] = Uptr[4];
LoadEntry->un.wd[1] = Uptr[5];
/* update next current load entry address */
CurEntryAddr = LoadEntry->next;
} /* end of while (not end of list) */
done:
if (mbox) {
kmem_free(mbox, sizeof (MAILBOXQ));
}
#ifdef FMA_SUPPORT
if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
if (emlxs_fm_check_dma_handle(hba,
hba->sli.sli4.dump_region.dma_handle) != DDI_FM_OK) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_invalid_dma_handle_msg,
"read_load_list: hdl=%p",
hba->sli.sli4.dump_region.dma_handle);
return (1);
}
}
#endif /* FMA_SUPPORT */
return (0);
} /* emlxs_read_load_list() */
extern uint32_t
emlxs_get_boot_config(emlxs_hba_t *hba, uint8_t *boot_state)
{
emlxs_port_t *port = &PPORT;
MAILBOXQ *mbq;
MAILBOX4 *mb;
mbox_req_hdr_t *hdr_req;
IOCTL_COMMON_BOOT_CFG *boot_cfg;
if (hba->sli_mode != EMLXS_HBA_SLI4_MODE) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
"Invalid sli_mode. mode=%d", hba->sli_mode);
return (1);
}
if ((mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
"Unable to allocate mailbox buffer.");
return (1);
}
mb = (MAILBOX4 *)mbq;
bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
mb->un.varSLIConfig.be.embedded = 1;
mbq->nonembed = NULL;
mbq->mbox_cmpl = NULL;
mb->mbxCommand = MBX_SLI_CONFIG;
mb->mbxOwner = OWN_HOST;
hdr_req = (mbox_req_hdr_t *)
&mb->un.varSLIConfig.be.un_hdr.hdr_req;
hdr_req->subsystem = IOCTL_SUBSYSTEM_COMMON;
hdr_req->opcode = COMMON_OPCODE_GET_BOOT_CFG;
boot_cfg = (IOCTL_COMMON_BOOT_CFG *)(hdr_req + 1);
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
"Unable to read boot config: Mailbox cmd=%x "
"status=%x", mb->mbxCommand, mb->mbxStatus);
kmem_free(mbq, sizeof (MAILBOXQ));
return (1);
}
*boot_state = boot_cfg->params.response.boot_status;
kmem_free(mbq, sizeof (MAILBOXQ));
return (0);
}
extern uint32_t
emlxs_set_boot_config(emlxs_hba_t *hba, uint8_t boot_state)
{
emlxs_port_t *port = &PPORT;
MAILBOXQ *mbq;
MAILBOX4 *mb;
mbox_req_hdr_t *hdr_req;
IOCTL_COMMON_BOOT_CFG *boot_cfg;
if (hba->sli_mode != EMLXS_HBA_SLI4_MODE) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
"Invalid sli_mode. mode=%d", hba->sli_mode);
return (1);
}
if ((mbq = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
"Unable to allocate mailbox buffer.");
return (1);
}
mb = (MAILBOX4 *)mbq;
bzero((void *) mb, MAILBOX_CMD_SLI4_BSIZE);
mb->un.varSLIConfig.be.embedded = 1;
mbq->nonembed = NULL;
mbq->mbox_cmpl = NULL;
mb->mbxCommand = MBX_SLI_CONFIG;
mb->mbxOwner = OWN_HOST;
hdr_req = (mbox_req_hdr_t *)
&mb->un.varSLIConfig.be.un_hdr.hdr_req;
hdr_req->subsystem = IOCTL_SUBSYSTEM_COMMON;
hdr_req->opcode = COMMON_OPCODE_SET_BOOT_CFG;
boot_cfg = (IOCTL_COMMON_BOOT_CFG *)(hdr_req + 1);
boot_cfg->params.request.boot_status = boot_state;
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbq, MBX_WAIT, 0) != MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
"Unable to read boot config: Mailbox cmd=%x "
"status=%x", mb->mbxCommand, mb->mbxStatus);
kmem_free(mbq, sizeof (MAILBOXQ));
return (1);
}
kmem_free(mbq, sizeof (MAILBOXQ));
return (0);
}
static int
emlxs_build_parms(caddr_t Buffer,
PWAKE_UP_PARMS AbsWakeUpParms,
uint32_t BufferSize, PAIF_HDR AifHeader)
{
IMAGE_HDR ImageHdr;
uint32_t NextImage;
uint32_t i;
int32_t ChangeParams = FALSE;
caddr_t Sptr;
caddr_t Dptr;
bzero((caddr_t)AbsWakeUpParms, sizeof (WAKE_UP_PARMS));
if ((AifHeader->ImageBase != 0x20000) &&
((AifHeader->RoSize + AifHeader->RwSize) <= 0x20000)) {
return (FALSE);
}
NextImage = SLI_IMAGE_START - AifHeader->ImageBase;
while (BufferSize > NextImage) {
Sptr = &Buffer[NextImage];
Dptr = (caddr_t)&ImageHdr;
for (i = 0; i < sizeof (IMAGE_HDR); i++) {
Dptr[i] = Sptr[i];
}
if (ImageHdr.BlockSize == 0xffffffff)
break;
switch (ImageHdr.Id.Type) {
case TEST_PROGRAM:
break;
case FUNC_FIRMWARE:
AbsWakeUpParms->prog_id = ImageHdr.Id;
ChangeParams = TRUE;
break;
case BOOT_BIOS:
AbsWakeUpParms->u0.boot_bios_id = ImageHdr.Id;
ChangeParams = TRUE;
break;
case SLI1_OVERLAY:
AbsWakeUpParms->sli1_prog_id = ImageHdr.Id;
ChangeParams = TRUE;
break;
case SLI2_OVERLAY:
AbsWakeUpParms->sli2_prog_id = ImageHdr.Id;
ChangeParams = TRUE;
break;
case SLI3_OVERLAY:
AbsWakeUpParms->sli3_prog_id = ImageHdr.Id;
ChangeParams = TRUE;
break;
case SLI4_OVERLAY:
AbsWakeUpParms->sli4_prog_id = ImageHdr.Id;
ChangeParams = TRUE;
break;
default:
break;
}
NextImage += ImageHdr.BlockSize;
}
return (ChangeParams);
} /* emlxs_build_parms() */
static uint32_t
emlxs_update_wakeup_parms(emlxs_hba_t *hba,
PWAKE_UP_PARMS AbsWakeUpParms, PWAKE_UP_PARMS WakeUpParms)
{
emlxs_port_t *port = &PPORT;
MAILBOX *mb;
MAILBOXQ *mbox;
uint32_t rval = 0;
if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to allocate mailbox buffer.");
return (1);
}
mb = (MAILBOX *)mbox;
WakeUpParms->prog_id = AbsWakeUpParms->prog_id;
WakeUpParms->u0.boot_bios_id = AbsWakeUpParms->u0.boot_bios_id;
WakeUpParms->sli1_prog_id = AbsWakeUpParms->sli1_prog_id;
WakeUpParms->sli2_prog_id = AbsWakeUpParms->sli2_prog_id;
WakeUpParms->sli3_prog_id = AbsWakeUpParms->sli3_prog_id;
WakeUpParms->sli4_prog_id = AbsWakeUpParms->sli4_prog_id;
emlxs_format_update_parms(mbox, WakeUpParms);
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) != MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to update wakeup parameters: Mailbox cmd=%x "
"status=%x", mb->mbxCommand, mb->mbxStatus);
rval = 1;
}
if (mbox) {
kmem_free(mbox, sizeof (MAILBOXQ));
}
return (rval);
} /* emlxs_update_wakeup_parms() */
static uint32_t
emlxs_validate_version(emlxs_hba_t *hba, emlxs_fw_file_t *file, uint32_t id,
uint32_t type, char *file_type)
{
emlxs_port_t *port = &PPORT;
/* Create the version label */
emlxs_decode_version(file->version, file->label, sizeof (file->label));
/* Process the DWC type */
switch (type) {
case TEST_PROGRAM:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"%s: TEST: offset=%08x version=%08x, %s", file_type,
file->offset, file->version, file->label);
break;
case BOOT_BIOS:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"%s: BOOT: offset=%08x version=%08x, %s", file_type,
file->offset, file->version, file->label);
if (!emlxs_bios_check(hba, id)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"BOOT Check: Image not compatible with %s. id=%02x",
hba->model_info.model, id);
return (EMLXS_IMAGE_INCOMPATIBLE);
}
break;
case FUNC_FIRMWARE: /* Stub */
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"%s: STUB: offset=%08x version=%08x, %s", file_type,
file->offset, file->version, file->label);
if (!emlxs_stub_check(hba, id)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"STUB Check: Image not compatible with %s. id=%02x",
hba->model_info.model, id);
return (EMLXS_IMAGE_INCOMPATIBLE);
}
break;
case SLI1_OVERLAY:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"%s: SLI1: offset=%08x version=%08x, %s", file_type,
file->offset, file->version, file->label);
if (!emlxs_sli1_check(hba, id)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"SLI1 Check: Image not compatible with %s. id=%02x",
hba->model_info.model, id);
return (EMLXS_IMAGE_INCOMPATIBLE);
}
break;
case SLI2_OVERLAY:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"%s: SLI2: offset=%08x version=%08x, %s", file_type,
file->offset, file->version, file->label);
if (!emlxs_sli2_check(hba, id)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"SLI2 Check: Image not compatible with %s. id=%02x",
hba->model_info.model, id);
return (EMLXS_IMAGE_INCOMPATIBLE);
}
break;
case SLI3_OVERLAY:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"%s: SLI3: offset=%08x version=%08x, %s", file_type,
file->offset, file->version, file->label);
if (!emlxs_sli3_check(hba, id)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"SLI3 Check: Image not compatible with %s. id=%02x",
hba->model_info.model, id);
return (EMLXS_IMAGE_INCOMPATIBLE);
}
break;
case SLI4_OVERLAY:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"%s: SLI4: offset=%08x version=%08x, %s", file_type,
file->offset, file->version, file->label);
if (!emlxs_sli4_check(hba, id)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"SLI4 Check: Image not compatible with %s. id=%02x",
hba->model_info.model, id);
return (EMLXS_IMAGE_INCOMPATIBLE);
}
break;
case SBUS_FCODE:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"%s: SBUS FCODE: offset=%08x version=%08x, %s",
file_type, file->offset, file->version, file->label);
if (!emlxs_sbus_fcode_check(hba, id)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"SBUS FCODE Check: Image not compatible with %s. "
"id=%02x", hba->model_info.model, id);
return (EMLXS_IMAGE_INCOMPATIBLE);
}
break;
case KERNEL_CODE:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_msg,
"%s: KERN: offset=%08x version=%08x, %s", file_type,
file->offset, file->version, file->label);
if (!emlxs_kern_check(hba, id)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_incompat_msg,
"KERN Check: Image not compatible with %s. id=%02x",
hba->model_info.model, id);
return (EMLXS_IMAGE_INCOMPATIBLE);
}
break;
default:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"%s: Image type not supported. type=%x", file_type, type);
return (EMLXS_IMAGE_BAD);
}
return (0);
} /* emlxs_validate_version() */
static void
emlxs_verify_image(emlxs_hba_t *hba, emlxs_fw_image_t *fw_image)
{
emlxs_port_t *port = &PPORT;
emlxs_vpd_t *vpd = &VPD;
uint32_t i;
uint32_t count;
/* Check for AWC file */
if (fw_image->awc.version) {
if (fw_image->awc.version == vpd->postKernRev) {
fw_image->awc.version = 0;
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"AWC file: KERN: old=%s new=%s %s.",
vpd->postKernName,
fw_image->awc.label,
(fw_image->awc.version)? "Update":"Skip");
}
/* Check for BWC file */
if (fw_image->bwc.version) {
if (strcmp(vpd->fcode_version, fw_image->bwc.label) == 0) {
fw_image->bwc.version = 0;
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"BWC file: BOOT: old=%s new=%s %s.",
vpd->fcode_version,
fw_image->bwc.label,
(fw_image->bwc.version)? "Update":"Skip");
}
/* Check for DWC file */
if (fw_image->dwc.version) {
/* Check for program files */
count = 0;
for (i = 0; i < MAX_PROG_TYPES; i++) {
if (!fw_image->prog[i].version) {
continue;
}
/* Skip components that don't need updating */
switch (i) {
case TEST_PROGRAM:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"DWC file: TEST: new=%s "
"Update.",
fw_image->prog[i].label);
break;
case BOOT_BIOS:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"DWC file: BOOT: new=%s "
"Update.",
fw_image->prog[i].label);
break;
case FUNC_FIRMWARE:
if (vpd->opFwRev &&
(fw_image->prog[i].version ==
vpd->opFwRev)) {
fw_image->prog[i].version = 0;
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"DWC file: STUB: old=%s new=%s %s.",
vpd->opFwName,
fw_image->prog[i].label,
(fw_image->prog[i].version)?
"Update":"Skip");
break;
case SLI1_OVERLAY:
if (vpd->sli1FwRev &&
(fw_image->prog[i].version ==
vpd->sli1FwRev)) {
fw_image->prog[i].version = 0;
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"DWC file: SLI1: old=%s new=%s %s.",
vpd->sli1FwName,
fw_image->prog[i].label,
(fw_image->prog[i].version)?
"Update":"Skip");
break;
case SLI2_OVERLAY:
if (vpd->sli2FwRev &&
(fw_image->prog[i].version ==
vpd->sli2FwRev)) {
fw_image->prog[i].version = 0;
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"DWC file: SLI2: old=%s new=%s %s.",
vpd->sli2FwName,
fw_image->prog[i].label,
(fw_image->prog[i].version)?
"Update":"Skip");
break;
case SLI3_OVERLAY:
if (vpd->sli3FwRev &&
(fw_image->prog[i].version ==
vpd->sli3FwRev)) {
fw_image->prog[i].version = 0;
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"DWC file: SLI3: old=%s new=%s %s.",
vpd->sli3FwName,
fw_image->prog[i].label,
(fw_image->prog[i].version)?
"Update":"Skip");
break;
case SLI4_OVERLAY:
if (vpd->sli4FwRev &&
(fw_image->prog[i].version ==
vpd->sli4FwRev)) {
fw_image->prog[i].version = 0;
}
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"DWC file: SLI4: old=%s new=%s %s.",
vpd->sli4FwRev,
fw_image->prog[i].label,
(fw_image->prog[i].version)?
"Update":"Skip");
break;
default:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"DWC file: type=%x version=%x label=%s "
"Update.",
i,
fw_image->prog[i].version,
fw_image->prog[i].label);
}
if (fw_image->prog[i].version) {
count++;
}
}
if (!count) {
fw_image->dwc.version = 0;
}
}
return;
} /* emlxs_verify_image() */
static uint32_t
emlxs_validate_image(emlxs_hba_t *hba, caddr_t Buffer, uint32_t Size,
emlxs_fw_image_t *image)
{
emlxs_port_t *port = &PPORT;
uint32_t ImageType;
AIF_HDR AifHdr;
IMAGE_HDR ImageHdr;
uint32_t NextImage;
uint32_t count;
uint32_t FileType;
uint32_t FileLen = 0;
uint32_t TotalLen = 0;
uint32_t *CkSumEnd;
uint32_t id;
uint32_t type;
uint32_t ver;
uint32_t ImageLength;
uint32_t BufferSize;
uint32_t rval = 0;
caddr_t bptr;
emlxs_vpd_t *vpd;
vpd = &VPD;
/* Get image type */
ImageType = *((uint32_t *)Buffer);
/* Pegasus and beyond adapters */
if ((ImageType == NOP_IMAGE_TYPE) &&
!(hba->model_info.chip &
(EMLXS_DRAGONFLY_CHIP | EMLXS_CENTAUR_CHIP))) {
bptr = Buffer;
TotalLen = sizeof (uint32_t);
while (TotalLen < Size) {
if (Size < sizeof (AIF_HDR)) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_image_bad_msg,
"Invalid image header length: 0x%x < 0x%x",
Size, sizeof (AIF_HDR));
return (EMLXS_IMAGE_BAD);
}
bcopy(bptr, &AifHdr, sizeof (AIF_HDR));
emlxs_disp_aif_header(hba, &AifHdr);
ImageLength = AifHdr.RoSize;
/* Validate checksum */
CkSumEnd =
(uint32_t *)(bptr + ImageLength +
sizeof (AIF_HDR));
if (emlxs_valid_cksum((uint32_t *)bptr, CkSumEnd)) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_image_bad_msg,
"Invalid checksum found.");
return (EMLXS_IMAGE_BAD);
}
FileType = AifHdr.ZinitBr;
switch (FileType) {
case FILE_TYPE_AWC:
image->awc.offset =
(uint32_t)((uintptr_t)bptr -
(uintptr_t)Buffer);
image->awc.version = AifHdr.AVersion;
image->awc.revcomp = 0;
id = (AifHdr.AVersion & 0x00ff0000) >> 16;
type = emlxs_type_check(
(AifHdr.AVersion & 0xff000000) >> 24);
/* Validate the file version */
if ((rval = emlxs_validate_version(hba,
&image->awc, id, type, "AWC file"))) {
return (rval);
}
break;
case FILE_TYPE_BWC:
image->bwc.offset =
(uint32_t)((uintptr_t)bptr -
(uintptr_t)Buffer);
image->bwc.version = AifHdr.AVersion;
image->bwc.revcomp = 0;
id = (AifHdr.AVersion & 0x00ff0000) >> 16;
type = emlxs_type_check(
(AifHdr.AVersion & 0xff000000) >> 24);
/* Validate the file version */
if ((rval = emlxs_validate_version(hba,
&image->bwc, id, type, "BWC file"))) {
return (rval);
}
break;
case FILE_TYPE_DWC:
image->dwc.offset =
(uint32_t)((uintptr_t)bptr -
(uintptr_t)Buffer);
image->dwc.version = AifHdr.AVersion;
image->dwc.revcomp = 0;
id = (AifHdr.AVersion & 0x00ff0000) >> 16;
type = emlxs_type_check(
(AifHdr.AVersion & 0xff000000) >> 24);
/* Validate the file version */
if ((rval = emlxs_validate_version(hba,
&image->dwc, id, type, "DWC file"))) {
return (rval);
}
/* Scan for program types */
NextImage = sizeof (AIF_HDR) + 4;
BufferSize = AifHdr.RoSize + AifHdr.RwSize;
count = 0;
while (BufferSize > NextImage) {
bcopy(&bptr[NextImage], &ImageHdr,
sizeof (IMAGE_HDR));
emlxs_dump_image_header(hba,
&ImageHdr);
/* Validate block size */
if (ImageHdr.BlockSize == 0xffffffff) {
break;
}
type = emlxs_type_check(
ImageHdr.Id.Type);
/* Calculate the program offset */
image->prog[type].offset =
(uint32_t)((uintptr_t)
&bptr[NextImage] -
(uintptr_t)Buffer);
/* Acquire the versions */
image->prog[type].version =
(ImageHdr.Id.Type << 24) |
(ImageHdr.Id.Id << 16) |
(ImageHdr.Id.Ver << 8) |
ImageHdr.Id.Rev;
image->prog[type].revcomp =
ImageHdr.Id.un.revcomp;
/* Validate the file version */
if ((rval = emlxs_validate_version(hba,
&image->prog[type], ImageHdr.Id.Id,
type, "DWC prog"))) {
return (rval);
}
count++;
NextImage += ImageHdr.BlockSize;
} /* while () */
if (count == 0) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_image_bad_msg,
"DWC file has no PRG images.");
return (EMLXS_IMAGE_BAD);
}
break;
}
FileLen =
sizeof (AIF_HDR) + ImageLength +
sizeof (uint32_t);
TotalLen += FileLen;
bptr += FileLen;
}
}
/* Pre-pegasus adapters */
else if (ImageType == NOP_IMAGE_TYPE) {
if (Size < sizeof (AIF_HDR)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Invalid image header length: 0x%x < 0x%x", Size,
sizeof (AIF_HDR));
return (EMLXS_IMAGE_BAD);
}
bcopy(Buffer, &AifHdr, sizeof (AIF_HDR));
emlxs_disp_aif_header(hba, &AifHdr);
ImageLength = AifHdr.RoSize + AifHdr.RwSize;
if (Size != (sizeof (AIF_HDR) + ImageLength + sizeof (int))) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Image length incorrect: 0x%x != 0x%x", Size,
sizeof (AIF_HDR) + ImageLength +
sizeof (uint32_t));
return (EMLXS_IMAGE_BAD);
}
if (AifHdr.ImageBase && AifHdr.ImageBase != 0x20000) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Invalid imageBase value %x != 0x20000",
AifHdr.ImageBase);
return (EMLXS_IMAGE_BAD);
}
CkSumEnd =
(uint32_t *)(Buffer + ImageLength + sizeof (AIF_HDR));
if (emlxs_valid_cksum((uint32_t *)Buffer, CkSumEnd)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Invalid checksum found.");
return (EMLXS_IMAGE_BAD);
}
image->dwc.offset = 0;
image->dwc.version = AifHdr.AVersion;
image->dwc.revcomp = 0;
id = (AifHdr.AVersion & 0x00ff0000) >> 16;
type = emlxs_type_check((AifHdr.AVersion & 0xff000000) >> 24);
/* Validate the file version */
if ((rval = emlxs_validate_version(hba, &image->dwc, id, type,
"DWC file"))) {
return (rval);
}
NextImage = SLI_IMAGE_START - AifHdr.ImageBase;
while (Size > NextImage) {
bcopy(&Buffer[NextImage], &ImageHdr,
sizeof (IMAGE_HDR));
emlxs_dump_image_header(hba, &ImageHdr);
/* Validate block size */
if (ImageHdr.BlockSize == 0xffffffff) {
break;
}
type = emlxs_type_check(ImageHdr.Id.Type);
/* Calculate the program offset */
image->prog[type].offset = NextImage;
/* Acquire the versions */
image->prog[type].version =
(ImageHdr.Id.Type << 24) |
(ImageHdr.Id.Id << 16) |
(ImageHdr.Id.Ver << 8) |
ImageHdr.Id.Rev;
image->prog[type].revcomp = ImageHdr.Id.un.revcomp;
/* Validate the file version */
if ((rval = emlxs_validate_version(hba,
&image->prog[type], ImageHdr.Id.Id, type,
"DWC prog"))) {
return (rval);
}
NextImage += ImageHdr.BlockSize;
}
} else { /* PRG File */
/* Precheck image size */
if (Size < sizeof (IMAGE_HDR)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Invalid image header length: 0x%x < 0x%x", Size,
sizeof (IMAGE_HDR));
return (EMLXS_IMAGE_BAD);
}
bcopy(Buffer, &ImageHdr, sizeof (IMAGE_HDR));
emlxs_dump_image_header(hba, &ImageHdr);
/* Validate block size */
if (ImageHdr.BlockSize == 0xffffffff) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Invalid block size.");
return (EMLXS_IMAGE_BAD);
}
ImageLength = ImageHdr.BlockSize;
/* Validate image length */
if (Size != ImageLength) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Invalid image length: 0x%x != 0x%x", Size,
ImageLength);
return (EMLXS_IMAGE_BAD);
}
/* Validate Checksum */
CkSumEnd =
(uint32_t *)Buffer + (ImageLength / sizeof (uint32_t)) -
1;
if (emlxs_valid_cksum((uint32_t *)Buffer, CkSumEnd)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Invalid checksum found.");
return (EMLXS_IMAGE_BAD);
}
type = emlxs_type_check(ImageHdr.Id.Type);
/* Calculate the program offset */
image->prog[type].offset = 0;
/* Acquire the versions */
image->prog[type].version =
(ImageHdr.Id.Type << 24) |
(ImageHdr.Id.Id << 16) |
(ImageHdr.Id.Ver << 8) |
ImageHdr.Id.Rev;
image->prog[type].revcomp = ImageHdr.Id.un.revcomp;
/* Validate the file version */
if ((rval = emlxs_validate_version(hba, &image->prog[type],
ImageHdr.Id.Id, type, "DWC file"))) {
return (rval);
}
}
/*
* This checks if a DragonFly (pre-V2 ASIC) SLI2
* image file is < version 3.8
*/
if (FC_JEDEC_ID(vpd->biuRev) == DRAGONFLY_JEDEC_ID) {
ver = (image->prog[SLI2_OVERLAY].version &
0x0000ff00) >> 8;
if (ver >= 0x38) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_image_incompat_msg,
"ASIC Check: Image requires DragonFly "
"V2 ASIC");
return (EMLXS_IMAGE_INCOMPATIBLE);
}
}
return (0);
} /* emlxs_validate_image() */
static uint32_t
emlxs_update_exp_rom(emlxs_hba_t *hba, PWAKE_UP_PARMS WakeUpParms)
{
emlxs_port_t *port = &PPORT;
MAILBOXQ *mbox;
MAILBOX *mb;
uint32_t next_address;
uint32_t rval = 0;
if (WakeUpParms->u1.EROM_prog_wd[0] == 0) {
return (1);
}
if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to allocate mailbox buffer.");
return (1);
}
bzero(mbox, sizeof (MAILBOXQ));
mb = (MAILBOX *)mbox;
mb->mbxCommand = MBX_LOAD_EXP_ROM;
mb->un.varLdExpRom.step = EROM_CMD_FIND_IMAGE;
mb->un.varLdExpRom.progress = 0;
mb->un.varLdExpRom.un.prog_id = WakeUpParms->u1.EROM_prog_id;
mbox->mbox_cmpl = NULL;
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) != MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to load exp ROM. Mailbox cmd=%x status=%x",
mb->mbxCommand, mb->mbxStatus);
rval = 1;
goto SLI_DOWNLOAD_EXIT;
}
if (mb->un.varLdExpRom.progress == EROM_RSP_COPY_DONE) {
(void) emlxs_update_wakeup_parms(hba, WakeUpParms, WakeUpParms);
rval = 1;
goto SLI_DOWNLOAD_EXIT;
}
if (mb->un.varLdExpRom.progress != EROM_RSP_ERASE_STARTED) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Invalid exp ROM progress. progress=%x",
mb->un.varLdExpRom.progress);
rval = 1;
goto SLI_DOWNLOAD_EXIT;
}
/*
* continue Erase
*/
while (mb->un.varLdExpRom.progress != EROM_RSP_ERASE_COMPLETE) {
next_address = mb->un.varLdExpRom.dl_to_adr;
bzero((void *)mb, MAILBOX_CMD_BSIZE);
mb->mbxCommand = MBX_LOAD_EXP_ROM;
mb->un.varLdExpRom.step = EROM_CMD_CONTINUE_ERASE;
mb->un.varLdExpRom.dl_to_adr = next_address;
mb->un.varLdExpRom.progress = 0;
mb->un.varLdExpRom.un.prog_id = WakeUpParms->u1.EROM_prog_id;
mbox->mbox_cmpl = NULL;
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) !=
MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to load exp ROM. Mailbox cmd=%x status=%x",
mb->mbxCommand, mb->mbxStatus);
rval = 1;
goto SLI_DOWNLOAD_EXIT;
}
}
while (mb->un.varLdExpRom.progress != EROM_RSP_COPY_DONE) {
next_address = mb->un.varLdExpRom.dl_to_adr;
bzero((void *)mb, MAILBOX_CMD_BSIZE);
mb->mbxCommand = MBX_LOAD_EXP_ROM;
mb->un.varLdExpRom.step = EROM_CMD_COPY;
mb->un.varLdExpRom.dl_to_adr = next_address;
mb->un.varLdExpRom.progress = 0;
mb->un.varLdExpRom.un.prog_id = WakeUpParms->u1.EROM_prog_id;
mbox->mbox_cmpl = NULL;
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) !=
MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to load exp ROM. Mailbox cmd=%x status=%x",
mb->mbxCommand, mb->mbxStatus);
rval = 1;
goto SLI_DOWNLOAD_EXIT;
}
}
rval = emlxs_update_wakeup_parms(hba, WakeUpParms, WakeUpParms);
SLI_DOWNLOAD_EXIT:
if (mbox) {
kmem_free(mbox, sizeof (MAILBOXQ));
}
return (rval);
} /* emlxs_update_exp_rom() */
/*
*
* FUNCTION NAME: emlxs_start_abs_download_2mb
*
* DESCRIPTION: Perform absolute download for 2 MB flash. A incoming
* buffer may consist of more than 1 file. This function
* will parse the buffer to find all the files.
*
*
* PARAMETERS:
*
*
* RETURNS:
*
*/
/* ARGSUSED */
static uint32_t
emlxs_start_abs_download_2mb(emlxs_hba_t *hba, caddr_t buffer, uint32_t len,
uint32_t offline, emlxs_fw_image_t *fw_image)
{
emlxs_port_t *port = &PPORT;
uint32_t rval = 0;
/* If nothing to download then quit now */
if (!fw_image->awc.version &&
!fw_image->dwc.version &&
!fw_image->bwc.version) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_msg,
"Nothing new to update. Exiting.");
return (0);
}
/*
* Everything checks out, now to just do it
*/
if (offline) {
if (emlxs_offline(hba, 0) != FC_SUCCESS) {
return (EMLXS_OFFLINE_FAILED);
}
if (EMLXS_SLI_HBA_RESET(hba, 1, 1, 0) != FC_SUCCESS) {
return (EMLXS_OFFLINE_FAILED);
}
}
if (fw_image->awc.version) {
rval = emlxs_proc_abs_2mb(hba,
(buffer + fw_image->awc.offset),
FILE_TYPE_AWC, 0);
if (rval) {
goto SLI_DOWNLOAD_2MB_EXIT;
}
}
if (fw_image->bwc.version) {
rval = emlxs_proc_abs_2mb(hba,
(buffer + fw_image->bwc.offset),
FILE_TYPE_BWC,
(fw_image->dwc.version)? ALLext:BWCext);
if (rval) {
goto SLI_DOWNLOAD_2MB_EXIT;
}
}
if (fw_image->dwc.version) {
rval = emlxs_proc_rel_2mb(hba, buffer, fw_image);
if (rval) {
goto SLI_DOWNLOAD_2MB_EXIT;
}
}
SLI_DOWNLOAD_2MB_EXIT:
if (offline) {
(void) emlxs_online(hba);
}
return (rval);
} /* emlxs_start_abs_download_2mb() */
/*
*
* FUNCTION NAME: emlxs_proc_abs_2mb
*
* DESCRIPTION: Given one of the 3 file types(awc/bwc/dwc), it will reset
* the port and download the file with sliIssueMbCommand()
*
*
* PARAMETERS:
*
*
* RETURNS:
*
*/
static uint32_t
emlxs_proc_abs_2mb(emlxs_hba_t *hba, caddr_t EntireBuffer,
uint32_t FileType, uint32_t extType)
{
emlxs_port_t *port = &PPORT;
PAIF_HDR AifHdr;
caddr_t Buffer = NULL;
caddr_t DataBuffer = NULL;
uint32_t *Src;
uint32_t *Dst;
MAILBOXQ *mbox;
MAILBOX *mb;
uint32_t DlByteCount;
uint32_t rval = 0;
uint32_t SegSize = DL_SLIM_SEG_BYTE_COUNT;
uint32_t DlToAddr;
uint32_t DlCount;
WAKE_UP_PARMS AbsWakeUpParms;
uint32_t i;
uint32_t NextAddr;
uint32_t EraseByteCount;
uint32_t AreaId;
uint32_t RspProgress = 0;
uint32_t ParamsChg;
AifHdr = (PAIF_HDR)EntireBuffer;
DlByteCount = AifHdr->RoSize + AifHdr->RwSize;
DlToAddr = AifHdr->ImageBase;
if ((DataBuffer = (caddr_t)kmem_zalloc(DL_SLIM_SEG_BYTE_COUNT,
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"%x: Unable to allocate data buffer.", FileType);
return (EMLXS_IMAGE_FAILED);
}
if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"%x: Unable to allocate mailbox buffer.", FileType);
kmem_free(DataBuffer, DL_SLIM_SEG_BYTE_COUNT);
return (EMLXS_IMAGE_FAILED);
}
mb = (MAILBOX *)mbox;
Buffer = EntireBuffer + sizeof (AIF_HDR);
switch (FileType) {
case FILE_TYPE_AWC:
ParamsChg = 0;
break;
case FILE_TYPE_BWC:
rval = emlxs_build_parms_2mb_bwc(hba,
AifHdr, extType, &AbsWakeUpParms);
if (rval == FALSE) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"BWC build parms failed.");
rval = EMLXS_IMAGE_FAILED;
goto EXIT_ABS_DOWNLOAD;
}
ParamsChg = 1;
break;
default:
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_image_bad_msg,
"Invalid file type: %x", FileType);
rval = EMLXS_IMAGE_BAD;
goto EXIT_ABS_DOWNLOAD;
}
EraseByteCount = AifHdr->Area_Size;
AreaId = AifHdr->Area_ID;
emlxs_format_load_area_cmd(mbox,
DlToAddr,
EraseByteCount,
ERASE_FLASH,
0, DL_FROM_SLIM_OFFSET, AreaId, MBX_LOAD_AREA, CMD_START_ERASE);
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) != MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"%x: Could not erase 2MB Flash: Mailbox cmd=%x status=%x",
FileType, mb->mbxCommand, mb->mbxStatus);
rval = EMLXS_IMAGE_FAILED;
goto EXIT_ABS_DOWNLOAD;
}
while (mb->un.varLdArea.progress != RSP_ERASE_COMPLETE) {
NextAddr = mb->un.varLdArea.dl_to_adr;
emlxs_format_load_area_cmd(mbox,
NextAddr,
EraseByteCount,
ERASE_FLASH,
0,
DL_FROM_SLIM_OFFSET,
AreaId, MBX_LOAD_AREA, CMD_CONTINUE_ERASE);
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) !=
MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"%x: Could not erase 2MB Flash2: Mailbox cmd=%x "
"status=%x", FileType, mb->mbxCommand,
mb->mbxStatus);
rval = EMLXS_IMAGE_FAILED;
goto EXIT_ABS_DOWNLOAD;
}
}
while (DlByteCount) {
if (DlByteCount >= SegSize)
DlCount = SegSize;
else
DlCount = DlByteCount;
DlByteCount -= DlCount;
Dst = (uint32_t *)DataBuffer;
Src = (uint32_t *)Buffer;
for (i = 0; i < (DlCount / 4); i++) {
*Dst = *Src;
Dst++;
Src++;
}
WRITE_SLIM_COPY(hba, (uint32_t *)DataBuffer,
(volatile uint32_t *)((volatile char *)
hba->sli.sli3.slim_addr + sizeof (MAILBOX)),
(DlCount / sizeof (uint32_t)));
if ((RspProgress == RSP_DOWNLOAD_MORE) || (RspProgress == 0)) {
emlxs_format_load_area_cmd(mbox,
DlToAddr,
DlCount,
PROGRAM_FLASH,
(DlByteCount) ? 0 : 1,
DL_FROM_SLIM_OFFSET,
AreaId,
MBX_LOAD_AREA,
(DlByteCount) ? CMD_DOWNLOAD : CMD_END_DOWNLOAD);
if (EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0) !=
MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_download_failed_msg,
"%x: Could not program 2MB Flash: Mailbox "
"cmd=%x status=%x", FileType,
mb->mbxCommand, mb->mbxStatus);
rval = EMLXS_IMAGE_FAILED;
goto EXIT_ABS_DOWNLOAD;
}
}
RspProgress = mb->un.varLdArea.progress;
Buffer += DlCount;
DlToAddr += DlCount;
}
#ifdef FMA_SUPPORT
if (emlxs_fm_check_acc_handle(hba, hba->sli.sli3.slim_acc_handle)
!= DDI_FM_OK) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_invalid_access_handle_msg, NULL);
rval = EMLXS_IMAGE_FAILED;
goto EXIT_ABS_DOWNLOAD;
}
#endif /* FMA_SUPPORT */
if (RspProgress != RSP_DOWNLOAD_DONE) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"%x: Failed download response received. %x", FileType,
RspProgress);
rval = EMLXS_IMAGE_FAILED;
goto EXIT_ABS_DOWNLOAD;
}
if (ParamsChg) {
if (emlxs_update_wakeup_parms(hba, &AbsWakeUpParms,
&AbsWakeUpParms)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"%x: Unable to update parms.", FileType);
rval = EMLXS_IMAGE_FAILED;
}
}
EXIT_ABS_DOWNLOAD:
if (DataBuffer) {
kmem_free(DataBuffer, DL_SLIM_SEG_BYTE_COUNT);
}
if (mbox) {
kmem_free(mbox, sizeof (MAILBOXQ));
}
return (rval);
} /* emlxs_proc_abs_2mb() */
static void
emlxs_format_load_area_cmd(MAILBOXQ * mbq,
uint32_t Base,
uint32_t DlByteCount,
uint32_t Function,
uint32_t Complete,
uint32_t DataOffset, uint32_t AreaId, uint8_t MbxCmd, uint32_t StepCmd)
{
MAILBOX *mb = (MAILBOX *)mbq;
bzero((void *)mb, MAILBOX_CMD_BSIZE);
mb->mbxCommand = MbxCmd;
mb->mbxOwner = OWN_HOST;
mb->un.varLdArea.update_flash = 1;
mb->un.varLdArea.erase_or_prog = Function;
mb->un.varLdArea.dl_to_adr = Base;
mb->un.varLdArea.dl_len = DlByteCount;
mb->un.varLdArea.load_cmplt = Complete;
mb->un.varLdArea.method = DL_FROM_SLIM;
mb->un.varLdArea.area_id = AreaId;
mb->un.varLdArea.step = StepCmd;
mb->un.varLdArea.un.dl_from_slim_offset = DataOffset;
mbq->mbox_cmpl = NULL;
} /* emlxs_format_load_area_cmd() */
/* ARGSUSED */
static uint32_t
emlxs_build_parms_2mb_bwc(emlxs_hba_t *hba,
PAIF_HDR AifHdr, uint32_t extType, PWAKE_UP_PARMS AbsWakeUpParms)
{
emlxs_port_t *port = &PPORT;
uint32_t pId[2];
uint32_t returnStat;
/* Read wakeup paramters */
if (emlxs_read_wakeup_parms(hba, AbsWakeUpParms, 0) ==
(uint32_t)CFG_DATA_NO_REGION) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to get BWC parameters.");
return (FALSE);
}
pId[0] = AifHdr->AVersion;
pId[1] = 0;
if (extType == BWCext) {
AbsWakeUpParms->u0.boot_bios_wd[0] = pId[0];
AbsWakeUpParms->u0.boot_bios_wd[1] = pId[1];
AbsWakeUpParms->u1.EROM_prog_wd[0] = pId[0];
AbsWakeUpParms->u1.EROM_prog_wd[1] = pId[1];
}
else if (extType == ALLext) {
if (!AbsWakeUpParms->u0.boot_bios_wd[0]) {
/* case of EROM inactive */
AbsWakeUpParms->u1.EROM_prog_wd[1] = pId[1];
AbsWakeUpParms->u1.EROM_prog_wd[0] = pId[0];
} else {
/* case of EROM active */
if (AbsWakeUpParms->u0.boot_bios_wd[0] == pId[0]) {
/* same ID */
AbsWakeUpParms->u0.boot_bios_wd[0] = pId[0];
AbsWakeUpParms->u0.boot_bios_wd[1] = pId[1];
AbsWakeUpParms->u1.EROM_prog_wd[0] = pId[0];
AbsWakeUpParms->u1.EROM_prog_wd[1] = pId[1];
} else {
/* different ID */
AbsWakeUpParms->u1.EROM_prog_wd[0] = pId[0];
AbsWakeUpParms->u1.EROM_prog_wd[1] = pId[1];
returnStat =
emlxs_update_exp_rom(hba, AbsWakeUpParms);
if (returnStat) {
AbsWakeUpParms->u0.boot_bios_wd[0] =
pId[0];
AbsWakeUpParms->u0.boot_bios_wd[1] =
pId[1];
}
}
}
}
return (TRUE);
} /* emlxs_build_parms_2mb_bwc() */
extern uint32_t
emlxs_get_max_sram(emlxs_hba_t *hba, uint32_t *MaxRbusSize,
uint32_t *MaxIbusSize)
{
emlxs_port_t *port = &PPORT;
MAILBOXQ *mbox;
MAILBOX *mb;
uint32_t *Uptr;
uint32_t rval = 0;
if (MaxRbusSize) {
*MaxRbusSize = 0;
}
if (MaxIbusSize) {
*MaxIbusSize = 0;
}
if ((mbox = (MAILBOXQ *)kmem_zalloc(sizeof (MAILBOXQ),
KM_NOSLEEP)) == NULL) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to allocate mailbox buffer.");
return (1);
}
mb = (MAILBOX *)mbox;
emlxs_format_dump(hba, mbox, DMP_MEM_REG, 0, 2, MAX_RBUS_SRAM_SIZE_ADR);
if ((rval = EMLXS_SLI_ISSUE_MBOX_CMD(hba, mbox, MBX_WAIT, 0)) !=
MBX_SUCCESS) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_download_failed_msg,
"Unable to get SRAM size: Mailbox cmd=%x status=%x",
mb->mbxCommand, mb->mbxStatus);
rval = 1;
goto Exit_Function;
}
if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
EMLXS_MPDATA_SYNC(hba->sli.sli4.dump_region.dma_handle, 0,
hba->sli.sli4.dump_region.size, DDI_DMA_SYNC_FORKERNEL);
Uptr = (uint32_t *)hba->sli.sli4.dump_region.virt;
} else {
Uptr = (uint32_t *)&mb->un.varDmp.resp_offset;
}
if (MaxRbusSize) {
*MaxRbusSize = Uptr[0];
}
if (MaxIbusSize) {
*MaxIbusSize = Uptr[1];
}
Exit_Function:
if (mbox) {
kmem_free(mbox, sizeof (MAILBOXQ));
}
#ifdef FMA_SUPPORT
if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
if (emlxs_fm_check_dma_handle(hba,
hba->sli.sli4.dump_region.dma_handle) != DDI_FM_OK) {
EMLXS_MSGF(EMLXS_CONTEXT,
&emlxs_invalid_dma_handle_msg,
"get_max_sram: hdl=%p",
hba->sli.sli4.dump_region.dma_handle);
rval = 1;
}
}
#endif /* FMA_SUPPORT */
return (rval);
} /* emlxs_get_max_sram() */
static uint32_t
emlxs_kern_check(emlxs_hba_t *hba, uint32_t version)
{
uint8_t *ptr;
uint8_t ver;
ver = version & 0xff;
ptr = hba->model_info.pt_FF;
while (*ptr) {
if (*ptr++ == ver) {
return (1);
}
}
return (0);
} /* emlxs_kern_check() */
static uint32_t
emlxs_stub_check(emlxs_hba_t *hba, uint32_t version)
{
uint8_t *ptr;
uint8_t ver;
ver = version & 0xff;
ptr = hba->model_info.pt_2;
while (*ptr) {
if (*ptr++ == ver) {
return (1);
}
}
return (0);
} /* emlxs_stub_check() */
static uint32_t
emlxs_bios_check(emlxs_hba_t *hba, uint32_t version)
{
uint8_t *ptr;
uint8_t ver;
ver = version & 0xff;
ptr = hba->model_info.pt_3;
while (*ptr) {
if (*ptr++ == ver) {
return (1);
}
}
return (0);
} /* emlxs_bios_check() */
static uint32_t
emlxs_sli1_check(emlxs_hba_t *hba, uint32_t version)
{
uint8_t *ptr;
uint8_t ver;
ver = version & 0xff;
ptr = hba->model_info.pt_6;
while (*ptr) {
if (*ptr++ == ver) {
return (1);
}
}
return (0);
} /* emlxs_sli1_check() */
static uint32_t
emlxs_sli2_check(emlxs_hba_t *hba, uint32_t version)
{
uint8_t *ptr;
uint8_t ver;
ver = version & 0xff;
ptr = hba->model_info.pt_7;
while (*ptr) {
if (*ptr++ == ver) {
return (1);
}
}
return (0);
} /* emlxs_sli2_check() */
static uint32_t
emlxs_sli3_check(emlxs_hba_t *hba, uint32_t version)
{
uint8_t *ptr;
uint8_t ver;
ver = version & 0xff;
ptr = hba->model_info.pt_B;
while (*ptr) {
if (*ptr++ == ver) {
return (1);
}
}
return (0);
} /* emlxs_sli3_check() */
static uint32_t
emlxs_sli4_check(emlxs_hba_t *hba, uint32_t version)
{
uint8_t *ptr;
uint8_t ver;
ver = version & 0xff;
ptr = hba->model_info.pt_E;
while (*ptr) {
if (*ptr++ == ver) {
return (1);
}
}
return (0);
} /* emlxs_sli4_check() */
static uint32_t
emlxs_sbus_fcode_check(emlxs_hba_t *hba, uint32_t version)
{
uint8_t *ptr;
uint8_t ver;
ver = version & 0xff;
ptr = hba->model_info.pt_A;
while (*ptr) {
if (*ptr++ == ver) {
return (1);
}
}
return (0);
} /* emlxs_sbus_fcode_check() */
static uint32_t
emlxs_type_check(uint32_t type)
{
if (type == 0xff) {
return (KERNEL_CODE);
}
if (type >= MAX_PROG_TYPES) {
return (RESERVED_D);
}
return (type);
} /* emlxs_type_check() */
extern int32_t
emlxs_boot_code_disable(emlxs_hba_t *hba)
{
emlxs_port_t *port = &PPORT;
PROG_ID Id;
emlxs_vpd_t *vpd;
uint8_t boot_state = 0;
vpd = &VPD;
if (hba->model_info.chip & EMLXS_BE_CHIPS) {
return (EMLXS_OP_NOT_SUP);
}
if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
/* Read Boot Config */
if (emlxs_get_boot_config(hba, &boot_state)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
"boot_code_enable: Unable to get boot config.");
return (FC_FAILURE);
}
/* Check if boot code is already disabled */
if (! boot_state) {
return (FC_SUCCESS);
}
/* Disable boot code */
boot_state = 0;
if (emlxs_set_boot_config(hba, boot_state)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
"boot_code_enable: Unable to set boot config.");
return (FC_FAILURE);
}
/* Now read the boot config again to verify */
if (emlxs_get_boot_config(hba, &boot_state)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
"boot_code_enable: Unable to get boot config.");
return (FC_FAILURE);
}
/* return the result */
return ((boot_state == 0) ? FC_SUCCESS : FC_FAILURE);
} else {
if (emlxs_read_wakeup_parms(hba, &hba->wakeup_parms, 0)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
"boot_code_disable: Unable to read wake up parms.");
return (FC_FAILURE);
}
/* Check if boot code is already disabled */
if (hba->wakeup_parms.u0.boot_bios_wd[0] == 0) {
return (FC_SUCCESS);
}
/* Make sure EROM entry has copy of boot bios entry */
if (!(hba->model_info.chip &
(EMLXS_DRAGONFLY_CHIP | EMLXS_CENTAUR_CHIP)) &&
(hba->wakeup_parms.u0.boot_bios_wd[0] !=
hba->wakeup_parms.u1.EROM_prog_wd[0]) &&
(hba->wakeup_parms.u0.boot_bios_wd[1] !=
hba->wakeup_parms.u1.EROM_prog_wd[1])) {
(void) emlxs_update_boot_wakeup_parms(hba,
&hba->wakeup_parms,
&hba->wakeup_parms.u0.boot_bios_id, 1);
}
/* Update the bios id with a zero id */
/* Don't load the EROM this time */
bzero(&Id, sizeof (PROG_ID));
(void) emlxs_update_boot_wakeup_parms(hba,
&hba->wakeup_parms, &Id, 0);
/* Now read the parms again to verify */
(void) emlxs_read_wakeup_parms(hba, &hba->wakeup_parms, 1);
emlxs_decode_version(hba->wakeup_parms.u0.boot_bios_wd[0],
vpd->boot_version, sizeof (vpd->boot_version));
/* (void) strcpy(vpd->fcode_version, vpd->boot_version); */
/* Return the result */
return ((hba->wakeup_parms.u0.boot_bios_wd[0] == 0) ?
FC_SUCCESS : FC_FAILURE);
}
} /* emlxs_boot_code_disable() */
extern int32_t
emlxs_boot_code_enable(emlxs_hba_t *hba)
{
emlxs_port_t *port = &PPORT;
emlxs_vpd_t *vpd;
PROG_ID load_list[MAX_LOAD_ENTRY];
uint32_t i;
uint32_t count;
uint8_t boot_state = 0;
vpd = &VPD;
if (hba->model_info.chip & EMLXS_BE_CHIPS) {
return (FC_SUCCESS);
}
if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
/* Read Boot Config */
if (emlxs_get_boot_config(hba, &boot_state)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
"boot_code_enable: Unable to get boot config.");
return (FC_FAILURE);
}
/* Check if boot code is already enabled */
if (boot_state) {
return (FC_SUCCESS);
}
/* Enable boot code */
boot_state = 1;
if (emlxs_set_boot_config(hba, boot_state)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
"boot_code_enable: Unable to set boot config.");
return (FC_FAILURE);
}
/* Now read the boot config again to verify */
if (emlxs_get_boot_config(hba, &boot_state)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
"boot_code_enable: Unable to get boot config.");
return (FC_FAILURE);
}
/* return the result */
return ((boot_state != 0) ? FC_SUCCESS : FC_FAILURE);
} else {
/* Read the wakeup parms */
if (emlxs_read_wakeup_parms(hba, &hba->wakeup_parms, 0)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
"boot_code_enable: Unable to read wake up parms.");
return (FC_FAILURE);
}
/* Check if boot code is already enabled */
if (hba->wakeup_parms.u0.boot_bios_id.Type == BOOT_BIOS) {
return (FC_SUCCESS);
}
if (!(hba->model_info.chip &
(EMLXS_DRAGONFLY_CHIP | EMLXS_CENTAUR_CHIP))) {
if (hba->wakeup_parms.u1.EROM_prog_id.Type
!= BOOT_BIOS) {
return (EMLXS_NO_BOOT_CODE);
}
/* Update the parms with the boot image id */
/* Don't load the EROM this time */
(void) emlxs_update_boot_wakeup_parms(hba,
&hba->wakeup_parms,
&hba->wakeup_parms.u1.EROM_prog_id, 0);
} else { /* (EMLXS_DRAGONFLY_CHIP | EMLXS_CENTAUR_CHIP) */
count = emlxs_get_load_list(hba, load_list);
if (!count) {
return (FC_FAILURE);
}
/* Scan load list for a boot image */
for (i = 0; i < count; i++) {
if (load_list[i].Type == BOOT_BIOS) {
/*
* Update the parms with boot image id
* Don't load the EROM this time
*/
(void) emlxs_update_boot_wakeup_parms(
hba, &hba->wakeup_parms,
&load_list[i], 0);
break;
}
}
if (i == count) {
return (EMLXS_NO_BOOT_CODE);
}
}
/* Now read the parms again to verify */
(void) emlxs_read_wakeup_parms(hba, &hba->wakeup_parms, 1);
emlxs_decode_version(hba->wakeup_parms.u0.boot_bios_wd[0],
vpd->boot_version, sizeof (vpd->boot_version));
/* (void) strcpy(vpd->fcode_version, vpd->boot_version); */
/* return the result */
return ((hba->wakeup_parms.u0.boot_bios_wd[0] != 0) ?
FC_SUCCESS : FC_FAILURE);
}
} /* emlxs_boot_code_enable() */
extern int32_t
emlxs_boot_code_state(emlxs_hba_t *hba)
{
emlxs_port_t *port = &PPORT;
uint8_t boot_state = 0;
if (hba->model_info.chip & EMLXS_BE_CHIPS) {
return (FC_SUCCESS);
}
if (hba->sli_mode == EMLXS_HBA_SLI4_MODE) {
/* Read Boot Config */
if (emlxs_get_boot_config(hba, &boot_state)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
"boot_code_state: Unable to read boot config.");
return (FC_FAILURE);
}
return ((boot_state != 0) ? FC_SUCCESS : FC_FAILURE);
} else {
/* Read the wakeup parms */
if (emlxs_read_wakeup_parms(hba, &hba->wakeup_parms, 1)) {
EMLXS_MSGF(EMLXS_CONTEXT, &emlxs_sfs_debug_msg,
"boot_code_state: Unable to read wake up parms.");
return (FC_FAILURE);
}
/* return the result */
return ((hba->wakeup_parms.u0.boot_bios_wd[0] != 0) ?
FC_SUCCESS : FC_FAILURE);
}
} /* emlxs_boot_code_state() */