fwflash_ib.c revision 3b136daba8fa33f4c5101eb6f6146fc10b8984e4
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <locale.h>
#include <unistd.h>
#include <fcntl.h>
#include <ctype.h>
#include <errno.h>
#include <libdevinfo.h>
#include <inttypes.h>
#include "fwflash.h"
#include "fwflash_ib.h"
#include "fwflash_ib_impl.h"
#include "fwflash_mlx.h"
/*
* Internal IB Flash update routines
*/
int offset);
int type);
/* global arg list */
extern int fwflash_arg_list;
/*
* Generate list of devices.
*/
char **
fwflash_ib_device_list(int *count)
{
char *phys_path;
int phys_path_len;
char **device_list = NULL;
int i;
goto out;
}
if (root_node == DI_NODE_NIL) {
goto out;
}
*count = 0;
while (node != DI_NODE_NIL) {
++(*count);
}
if (*count <= 0) {
goto out;
}
/* Allocate device_list for number of devices */
if (device_list == NULL) {
errno));
goto out;
}
i = 0;
while (node != DI_NODE_NIL) {
}
/*
* Set path length, plus enough spaces to add
*/
device_list[i] = (char *)malloc(sizeof (char) *
(phys_path_len + 2));
if (device_list[i] == NULL) {
FWFLASH_IB_DRIVER_NAME, i, errno));
device_list = (char **)NULL;
goto out;
}
"/devices%s:devctl", phys_path);
i++;
}
out:
return (device_list);
}
fwflash_ib_open(char *dev_path)
{
int fd = 0;
int id_size = 0;
int ret;
int i, j;
goto bad;
}
if (fd == -1) {
perror("fwflash_ib_open");
goto bad;
}
goto bad;
}
/*
* Inform driver: this cmd supports the Intel Extended CFI
* command set.
*/
/* call flash init ioctl */
if (ret != 0) {
"(0x%x)\n", errno));
goto bad;
}
/*
* Determine if the attached driver doesn't support
* the Intel Extended CFI command set. And if not,
* verify it's the AMD command set. If not error out
* as the Intel cmd set can't be used without support
* in the driver.
*/
for (i = 0; i < TAVOR_FLASH_CFI_SIZE_QUADLET; i++) {
}
/* make sure the cmd set is AMD */
gettext("Unsupported flash device command set"));
goto bad;
}
/* set some defaults */
} else {
gettext("Uknown flash device command set"));
goto bad;
}
/* read from the CFI data */
}
goto bad;
}
/* set firmware revision */
/* set hw part number, psid, and name in handle */
if (init_ioctl.tf_pn_len != 0) {
/* part number length */
for (i = 0; i < init_ioctl.tf_pn_len; i++) {
break;
}
}
if (i == init_ioctl.tf_pn_len) {
}
} else {
}
errno));
goto bad;
}
/* Find part number, set the rest */
for (i = 0; i < FWFLASH_MAX_ID; i++) {
/* Set PSID */
("\nPSID malloc failed (%d)\n",
errno));
goto bad;
}
/* determine name length */
for (j = 0; j < FWFLASH_MAX_ID_SZ; j++) {
id_size = j + 1;
break;
}
}
if (j == FWFLASH_MAX_ID_SZ) {
}
/* Set string ID */
("\nID malloc failed (%d)\n",
errno));
goto bad;
}
break;
}
}
if (i == FWFLASH_MAX_ID) {
}
}
return (handle);
bad:
/* cleanup */
}
}
}
}
return (NULL);
}
/*
* Close device by calling _FINI.
*/
void
{
int ret;
if (ret != 0) {
return;
}
if (ret != 0) {
perror("fwflash_ib_close");
return;
}
}
/* cleanup */
}
}
}
}
}
/*
*/
int
{
int ret;
if (ret != 0) {
errno));
}
return (ret);
}
int
{
int ret;
if (ret != 0) {
errno));
}
return (ret);
}
/*
* Notes:
* 1. flash read is done in 32 bit quantities, and the driver returns
* data in host byteorder form.
* 2. flash write is done in 8 bit quantities by the driver.
* 3. data in the flash should be in network byteorder.
* 4. data in image files is in network byteorder form.
* 5. data in image structures in memory is kept in network byteorder.
* 6. the functions in this file deal with data in host byteorder form.
*/
int
{
int start_sector;
int ps_offset;
#ifdef _LITTLE_ENDIAN
int j;
#endif
/* Get Sector Size */
/* Verify flash info */
if (ret != 0) {
goto out;
}
/* Read IS Sector */
ioctl_info.tf_sector_num = 0;
if (ret != 0) {
goto out;
}
#ifdef _LITTLE_ENDIAN
/* swap sector contents into network byte order form */
}
#endif
/* offset is the start of the xPS sector */
/* 'type' is the sector number input as PPS or SPS */
/* Read in PS */
if (ret != 0) {
goto out;
}
#ifdef _LITTLE_ENDIAN
/* swap sector contents into network byte order form */
}
#endif
/* Verify Valid signature */
if (ret != 0) {
goto out;
}
/* Verify Valid CRC */
if (ret != 0) {
goto out;
}
/* Read Firmware Image Size */
if (ret != 0) {
goto out;
}
/* Based on firmware size, see how many sectors it takes up */
/* Get Firmware Start Address */
if (ret != 0) {
goto out;
}
/* Translate fw addr to sector offset */
/* Read one sector at a time */
ioctl_info.tf_sector_num = i;
if (ret != 0) {
goto out;
}
#ifdef _LITTLE_ENDIAN
/* swap sector contents into network byte order form */
}
#endif
}
out:
return (ret);
}
/*
* type is PRIMARY or SECONDARY
*/
int
{
int ps_offset;
int sector_size;
int start_sector_local;
int start_sector_flash;
int local_addr, flash_addr;
int save_addr;
if (ret != 0) {
goto out;
}
ret = -1;
goto out;
}
/* Check Hardware Rev */
if (ver != 0) {
ret = -1;
goto out;
}
if (ret != 0) {
if (ret != 0) {
("\nFailed to write Invariant Sector\n"));
goto out;
}
}
/* Get Sector Size */
/* Verify local PS */
if (ret != 0) {
goto out;
}
/* Invalidate FW Signature */
if (ret != 0) {
goto out;
}
/* Invalidate FW CRC */
/* Read Image Size */
/* Based on size, calculate how many sectors we need */
/* Get Firmware Start Address on local */
/* Get Firmware Start Address on flash */
if (local_addr < flash_addr) {
addr = flash_addr;
} else {
addr = local_addr;
}
/* Translate fw addr to sector offset */
/* Write one sector of fw image at a time */
for (i = 0; i < len; i++) {
start_sector_local + i, sector_size);
/* give the user some progress output */
(void) printf(" .");
if (ret != 0) {
goto out;
}
}
/* Invalidate local SIG and CRC */
/* Invalidate Firmware Image Address but save it to put back locally */
/* Write fw PS */
if (ret != 0) {
goto out;
}
/* Make sure fw addr pointer is updated to be correct */
if (ret != 0) {
goto out;
}
/* Restore previous firmware address in local image */
/* Set local SIG */
/* calc local CRC */
/* Set CRC */
if (ret != 0) {
goto out;
}
/* Set Signature */
if (ret != 0) {
goto out;
}
if (ret != 0) {
}
out:
return (ret);
}
int
{
int sector_size;
int start_sector_local;
int start_sector_flash;
int local_addr, flash_addr;
int ret, i;
#ifdef _LITTLE_ENDIAN
int j;
#endif
if (ret != 0) {
goto out;
}
ret = -1;
goto out;
}
ret = -1;
goto out;
}
/* Get Sector Size */
/* Get offset to pointer sector based on type */
/* Get FW Size */
/* Based on size, determine number of sectors needed */
/* First read IS sector */
ioctl_info.tf_sector_num = 0;
if (ret != 0) {
goto out;
}
#ifdef _LITTLE_ENDIAN
/* swap sector contents into network byte order form */
}
#endif
/* Compare IS */
i));
ret = -1;
goto out;
}
}
/* First read pointer sector */
if (ret != 0) {
goto out;
}
#ifdef _LITTLE_ENDIAN
/* swap sector contents into network byte order form */
}
#endif
/* Get Firmware Start Address */
/* Get Firmware Start Address on flash */
/* Compare PS */
/* Skip error, if firmware image addr is correct */
if (i == (ps_offset / 4) &&
continue;
}
i));
ret = -1;
goto out;
}
}
/* Setup addr pointer based on firmware size differences */
if (local_addr < flash_addr) {
addr = flash_addr;
} else {
addr = local_addr;
}
/* Translate fw addr to sector offset */
/* Read FW image */
for (i = 0; i < len; i++) {
start_sector_local + i, sector_size);
if (ret != 0) {
goto out;
}
#ifdef _LITTLE_ENDIAN
/* swap sector contents into network byte order form */
}
#endif
}
/* Compare FW Image */
end_addr));
for (i = start_addr / 4;
i < end_addr / 4; i++) {
i));
ret = -1;
break;
}
}
out:
}
return (ret);
}
int
{
int sector_size;
int ret;
return (-1);
}
/* Get sector size */
/* Write one sector of IS */
ioctl_info.tf_sector_num = 0;
if (ret != 0) {
return (-1);
}
return (0);
}
int
{
char ans;
int sector_size;
int ps_okay[2];
int ps_offset;
int ret, i;
ret = -1;
goto out;
}
if (ret != 0) {
goto out;
}
/* Get sector size */
/* Verify flash info */
if (ret != 0) {
goto out;
}
handle->hwfw_match = 0;
for (i = 1; i < 3; i++) {
/* set array pointer */
ps = i - 1;
/* Read PS */
ps_offset = i << sector_size;
/* set state field correctly */
}
/* verify fw matches the hardware */
}
if (handle->hwfw_match == 0) {
/* HW VPD exist and a mismatch was found */
"Please verify that the firmware image"
"\n\tis intended for use with this hardware"));
} else {
"Unable to verify firmware is appropriate"
"\n\tfor the hardware"));
}
ret = -1;
} else {
ret = 0;
}
}
out:
}
return (ret);
}
int
{
int ps_offset;
int sector;
int sector_size;
int sector_size_val;
int ps_okay[2];
int addr;
int len;
int ret;
int ps;
int i;
if (ret != 0) {
goto out;
}
return (-1);
}
ret = -1;
goto out;
}
/* Get Sector Size */
for (i = 1; i < 3; i++) {
/* set array pointer */
ps = i - 1;
/* Read PS */
ps_offset = i << sector_size;
continue;
}
/* Get FW addr */
/* Get length */
}
gettext("ERROR: no valid Pointer Sector found"));
return (-1);
}
/* Build image to write out */
/* Copy IS */
/* Setup PS */
if (ps_okay[0] == 0) {
fw_new_addr[0] = addr;
/* Copy in PS */
/* Set new FW addr */
htonl(fw_new_addr[0]);
/* Set new Crc16 */
/* Copy FW Image */
fw_size[0]);
fw_size[0]) << sector_size);
}
}
if (ps_okay[1] == 0) {
/* Copy in PS */
/* Set new FW addr */
/* Set new Crc16 */
/* Copy FW Image if needed */
fw_size[1]);
}
}
if (ret == 0) {
perror("fwrite");
return (-1);
}
out:
return (ret);
}
int
{
int sector_size;
int ps_offset;
int ret = 0;
ret = -1;
goto out;
}
goto out;
}
if (ret != 0) {
goto out;
}
}
if (ret != 0) {
goto out;
}
}
/* Read Sector Size */
/* ps_offset is the start of the xPS sector */
/* 'type' is the sector number input as PPS or SPS */
/*
* guids are supplied by callers as 64 bit values in host byteorder.
* Storage is in network byteorder.
*/
#ifdef _BIG_ENDIAN
}
}
}
}
#else
}
}
}
}
#endif
out:
return (ret);
}
int
{
int ret;
#ifdef _LITTLE_ENDIAN
#endif
if (ret != 0) {
goto out;
}
ret = -1;
goto out;
}
if (ret != 0) {
goto out;
}
#ifdef _LITTLE_ENDIAN
/*
* guids are read as pairs of 32 bit host byteorder values and treated
* by callers as 64 bit values. So swap each pair of 32 bit values
* to make them correct
*/
}
#endif
if (ret != 0) {
}
out:
return (ret);
}
/*
* Notes:
* 1. flash read is done in 32 bit quantities, and the driver returns
* data in host byteorder form.
* 2. flash write is done in 8 bit quantities by the driver.
* 3. data in the flash should be in network byteorder.
* 4. data in image files is in network byteorder form.
* 5. data in image structures in memory is kept in network byteorder.
* 6. the functions in this file only deal with 32 bit and smaller data
* in host byteorder form.
*/
static int
{
return (-1);
}
return (0);
}
static int
{
int num_sectors;
int mod;
if (mod > 0) {
num_sectors++;
}
return (num_sectors);
}
static int
{
int ret;
int i;
for (i = 0; i < len / 4; i++) {
if (ret == 0) {
break;
} else {
}
}
}
return (0);
}
static int
{
int ret;
if (ret != 0) {
return (ret);
}
if (ret != 0) {
return (ret);
}
return (ret);
}
static int
{
int ret;
if (ret != 0) {
goto out;
}
ret = -1;
}
out:
return (ret);
}
/*
* We would not need this if it were not for Cisco's image using the
* VSD to store boot options and flags for their PXE boot extension,
* but not setting the proper default values for the extension in
* their image. As it turns out, some of the data for the extension
* is stored in the VSD in the firmware file, and the rest is set by
* their firmware utility. That's not very nice for us, since it could
* change at any time without our knowledge. Well, for the time being,
* we can use this to examine and fix up anything in the VSD that we might
* need to handle, for any vendor specific settings.
*/
static int
{
int i;
/* read the VSD into local storage */
for (i = 0; i < FLASH_PS_VSD_LENGTH / 4; i++) {
}
/* check for the Cisco signature at the first and last 16b */
if (vsd_sig1 == FLASH_VSD_CISCO_SIGNATURE &&
/*
* Fix up this VSD so that it contains the proper
* default values for the Cisco, nee Topspin, boot
* extension(s)
*/
/*
* Set the Cisco VSD's "boot_version" to '2'. This value is
* located in the 2nd byte of the last dword. Just or the bit
* in and move on.
*/
0x00020000);
/*
* Set some defaults for the SRP boot extension. This is
* currently the only extension we support. The boot options
* flags are located in the second dword of the VSD.
*/
/* Set updated PS CRC */
}
return (0);
}
static int
{
return (-1);
}
return (0);
}
static int
{
int ret, i;
for (i = 0; i < 4; i++) {
ioctl_info.tf_byte = 0;
if (ret != 0) {
return (ret);
}
}
return (0);
}
/*
* Due to calling convention, handle->fw is in network byte order.
* CRC must be calculated on bytes in network byte order.
*
* Yet when compared, they are compared in host byteorder. Since the crc16
* function returns host byteorder.
*/
static int
{
FLASH_PS_CRC16_OFFSET) /4]));
return (-1);
}
return (0);
}
static void
{
}
static int
{
int ret, i;
for (i = 0; i < 2; i++) {
if (ret != 0) {
return (ret);
}
}
return (0);
}
static uint32_t
{
int ret;
if (ret != 0) {
return (ret);
}
if (ret != 0) {
return (ret);
}
#ifdef DEBUG
{
int i;
for (i = 0; i < 4; i++)
}
#endif /* DEBUG */
}
static uint32_t
{
int offset;
return (0);
}
return (size & FLASH_IS_SECTOR_SIZE_MASK);
}
static int
{
int sector_size;
int ps_offset;
int ret, i;
#ifdef _LITTLE_ENDIAN
#endif
ret = -1;
goto out;
}
/* Get Sector Size */
/* Get offset to pointer sector based on type */
ret = -1;
goto out;
}
/* Read IS sector */
ioctl_info.tf_sector_num = 0;
if (ret != 0) {
goto out;
}
#ifdef _LITTLE_ENDIAN
/* swap sector contents into network byte order form */
}
#endif
/* Compare IS */
for (i = 0; i < (ps_offset / 4); i++) {
i));
ret = -1;
break;
}
}
out:
}
return (ret);
}
static int
{
"Expected: 0x%08x, actual: 0x%08x.\n",
return (1);
}
return (0);
}
static uchar_t *
{
int i;
#ifndef _LITTLE_ENDIAN
#endif /* _LITTLE_ENDIAN */
union {
} psid;
for (i = 0; i < FWFLASH_PSID_SZ/4; i++) {
FLASH_PS_PSID_OFFSET) / 4 + i]);
#ifndef _LITTLE_ENDIAN
#endif /* _LITTLE_ENDIAN */
}
goto out;
}
out:
return (psid_str);
}
static void
int type)
{
/* get PSID of firmware file */
handle->hwfw_match = 0;
return;
}
/*
* Check the part number of the hardware against the part number
* of the firmware file. If the hardware information is not
* available, check the currently loaded firmware against the
* firmware file to be uploaded.
*/
} else {
}
}
static void
{
int i;
int no_match = 0;
/* verify fw matches the hardware */
/* already been verified */
return;
}
/* find the PSID from FW in the mlx table */
for (i = 0; i < FWFLASH_MAX_ID; i++) {
/*
* Need this check here and the 'continue's below
* becasue there are some cards that have a
* 'new' part number but the same PSID value.
*/
break;
}
/* match PSID */
psid_size) == 0) {
/* match part numbers */
continue;
} else {
handle->hwfw_match = 0;
no_match = i;
continue;
}
}
}
if (i == FWFLASH_MAX_ID && no_match == 0) {
/* no match found */
handle->hwfw_match = 0;
} else {
if (handle->hwfw_match == 0) {
"firmware image is meant for"));
}
}
}
static void
{
int ps_offset;
int ret, i;
#ifdef _LITTLE_ENDIAN
int j;
#endif
/* Get Sector Size */
/* get device size */
/* allocate some space */
/* Look for PSID in PPS first, then SPS if no match */
for (i = 1; i < 3; i++) {
ps_offset = i << sector_size;
/* Read in xPS */
ioctl_info.tf_sector_num = i;
if (ret != 0) {
handle->hwfw_match = 0;
return;
}
#ifdef _LITTLE_ENDIAN
/* swap sector contents into network byte order form */
}
#endif
/* grab PSID from xPS */
handle->hwfw_match = 0;
return;
}
i == 1 ? "Primary" : "Secondary",
/* compare PSIDs */
psid_size) == 0) {
break;
} else {
handle->hwfw_match = 0;
}
}
}
static uint16_t
{
return (1);
}
/* Read Flash HW Version */
FLASH_IS_HWVER_MASK) >> 24;
local_hwver == 0x20)) {
} else {
}
return (0);
}
static void
{
}
static int
{
int ret, i;
for (i = 0; i < 2; i++) {
ioctl_info.tf_byte = 0;
if (ret != 0) {
return (ret);
}
}
return (0);
}
static uint32_t
{
return (size);
}
static uint32_t
{
return (addr);
}
static uint32_t
{
int ret;
if (ret != 0) {
return (ret);
}
return (ioctl_info.tf_quadlet);
}
static int
{
int ret, i;
for (i = 0; i < 4; i++) {
if (ret != 0) {
return (ret);
}
}
return (0);
}
static int
{
int ret, i;
for (i = 0; i < 4; i++) {
if (ret != 0) {
return (ret);
}
}
return (0);
}
static int
{
int start_addr;
int sector_size;
int ps_offset;
int ret, i;
/* Read Sector Size */
/* offset is the start of the xPS sector */
/* 'type' is the sector number input as PPS or SPS */
if (ret != 0) {
return (ret);
}
if (ret != 0) {
return (ret);
}
for (i = 0; i < 8; i++) {
if (ret != 0) {
return (ret);
}
}
return (0);
}
static void
{
}
/*
* crc16 - computes 16 bit crc of supplied buffer.
* image should be in network byteorder
* result is returned in host byteorder form
*/
static uint16_t
{
uint32_t i, j;
for (i = 0; i < size / 4; i++) {
for (j = 0; j < 32; j++) {
if (crc & 0x8000) {
} else {
}
}
}
for (i = 0; i < 16; i++) {
if (crc & 0x8000) {
} else {
}
}
return (crc & 0xFFFF);
}