tavor.c revision 9e39c5ba00a55fa05777cc94b148296af305e135
/*
* 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 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* IB (InfiniBand) specific functions.
*/
/*
* The reference for the functions in this file is the
*
* Mellanox HCA Flash Programming Application Note
* (Mellanox document number 2205AN)
* rev 1.44, 2007. Chapter 4 in particular.
*
* NOTE: this Mellanox document is labelled Confidential
* explicit approval from Sun Legal.
*/
/*
* IMPORTANT NOTE:
* 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 (bigendian).
* 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.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/sysmacros.h>
#include <fcntl.h>
#include <ctype.h>
#include <string.h>
#include <strings.h>
#include <sys/byteorder.h>
#include <libintl.h> /* for gettext(3c) */
#include "../../hdrs/MELLANOX.h"
#include "../../hdrs/tavor_ib.h"
char *devprefix = "/devices";
char drivername[] = "tavor\0";
char *devsuffix = ":devctl";
extern int errno;
extern struct vrfyplugin *verifier;
extern int fwflash_debug;
/* required functions for this plugin */
int fw_identify(int start);
int fw_devinfo();
/* helper functions */
int
{
int rv = FWFLASH_SUCCESS;
int fd;
struct ib_encap_ident *manuf;
#if defined(_LITTLE_ENDIAN)
#endif
errno = 0;
gettext("tavor: Unable to open specified file "
return (FWFLASH_FAILURE);
}
manuf =
/*
* Now that we've got an open, init'd fd, we can read the
* xFI from the device itself. We've already got the IS
* and xPS stored in manuf.
*/
/* stash some values for later */
/* Invariant Sector comes first */
gettext("tavor: Unable to write HCA Invariant Sector "
"(%d of %d bytes)\n"),
(void) tavor_close(flashdev);
return (FWFLASH_FAILURE);
} else {
}
/* followed by Primary Pointer Sector */
gettext("tavor: Unable to write HCA Primary Pointer "
"Sector (%d of %d bytes)\n)"),
(void) tavor_close(flashdev);
return (FWFLASH_FAILURE);
} else {
}
/* followed by Secondary Pointer Sector */
gettext("tavor: Unable to write HCA Secondary Pointer "
"Sector (%d of %d bytes)\n"),
(void) tavor_close(flashdev);
return (FWFLASH_FAILURE);
} else {
}
/* Now for the xFI sectors */
pchunks++;
/* Get the PFI, then the SFI */
gettext("tavor: Unable to allocate space for "
"device's Primary Firmware Image\n"));
return (FWFLASH_FAILURE);
}
tfi_data.tf_sector_num = j;
if (rv < 0) {
gettext("tavor: Unable to read sector %d of "
"HCA Primary Firmware Image\n"), j);
(void) tavor_close(flashdev);
return (FWFLASH_FAILURE);
}
++j;
}
/*
* It appears that the tavor driver is returning a signed
* -1 (0xffff) in unassigned quadlets if we read a sector
* that isn't full, so for backwards compatibility with
* earlier fwflash versions, we need to zero out what
* remains in the sector.
*/
#if defined(_LITTLE_ENDIAN)
if (j > psz)
break;
}
#endif
gettext("tavor: Unable to write HCA Primary Firmware "
"Image data (%d of %d bytes)\n"),
(void) tavor_close(flashdev);
return (FWFLASH_FAILURE);
} else {
}
pchunks++;
/*
* We allocate wholenum sectors, but only write out what we
* really need (ssz bytes)
*/
gettext("tavor: Unable to allocate space for "
"device's Secondary Firmware Image\n"));
return (FWFLASH_FAILURE);
}
/* get our starting sector number */
tfi_data.tf_sector_num = j;
&tfi_data)) < 0) {
gettext("tavor: Unable to read sector %d of "
"HCA Secondary Firmware Image\n"), j);
(void) tavor_close(flashdev);
return (FWFLASH_FAILURE);
}
++j;
}
/*
* It appears that the tavor driver is returning a signed
* -1 (0xffff) in unassigned quadlets if we read a sector
* that isn't full, so for backwards compatibility with
* earlier fwflash versions, we need to zero out what
* remains in the sector.
*/
#if defined(_LITTLE_ENDIAN)
for (j = 0; j < ssz / 4; j++) {
}
#endif
/* only write out ssz bytes */
gettext("tavor: Unable to write HCA Secondary Firmware "
"Image data (%d of %d bytes)\n"),
j, ssz);
(void) tavor_close(flashdev);
return (FWFLASH_FAILURE);
} else {
}
gettext("Done.\n"));
/*
* this should succeed, but we don't just blindly ignore
* the return code cos that would be obnoxious.
*/
return (tavor_close(flashdev));
}
/*
* If we're invoking fw_writefw, then flashdev is a valid,
* flashable device as determined by fw_identify().
*
* If verifier is null, then we haven't been called following a firmware
* image verification load operation.
*/
int
{
int rv;
struct ib_encap_ident *manuf;
/*
* we've read in to the verifier->fwimage field, and are
* about to do some hand-waving with.
*/
/*
* From the Mellanox HCA Flash programming app note,
* start of ch4, page36:
* ===========================================================
* Failsafe firmware programming ensures that an HCA device
* can boot up in a functional mode even if the burn process
* was interrupted (because of a power failure, reboot, user
* interrupt, etc.). This can be implemented by burning the
* new image to a vacant region on the Flash, and erasing the
* old image only after the new image is successfully burnt.
* This method ensures that there is at least one valid firmware
* image on the Flash at all times. Thus, in case a firmware
* image programming process is aborted for any reason, the HCA
* will still be able to boot up properly using the valid image
* on the Flash.
* ...
*
* 4.1 Notes on Image Programming of HCA Flashes
* Following are some general notes regarding the Flash memory
* in the context of Mellanox HCA devices:
* > The Flash memory is divided into sectors, and each sector
* must be erased prior to its programming.
* > The image to be burnt is byte packed and should be programmed
* into the Flash byte by byte, preserving the byte order, starting
* at offset zero. No amendments are needed for endianess.
* > It is recommended to program the Flash while the device is idle.
* ===========================================================
*
* The comment about endianness is particularly important for us
* since we operate on both big- and litte-endian hosts - it means
* we have to do some byte-swapping gymnastics
*/
/*
* From the Mellanox HCA Flash programming app note,
* section 4.2.5 on page 41/42:
* ===========================================================
* 4.2.5 Failsafe Programming Example
* This section provides an example of a programming utility
* that performs a Failsafe firmware image update. The flow
* ensures that there is at least one valid firmware image on
* the Flash at all times. Thus, in case a firmware image pro-
* gramming process is aborted for any reason, the HCA will
* still be able to boot up properly using the valid image on
* the Flash. Any other flow that ensures the above is also
* considered a Failsafe firmware update.
*
* Update Flow:
* * Check the validity of the PPS and SPS:
* > If both PSs are valid, arbitrarily invalidate one of them
* > If both PSs are invalid, the image on flash is corrupted
* and cannot be updated in a Failsafe way. The user must
* burn a full image in a non-failsafe way.
*
* > If only the PPS is valid:
* i.Burn the secondary image (erase each sector first)
* ii.Burn the SPS with the correct image address (FIA field)
* iii.Invalidate the PPS
*
* > If only the SPS is valid:
* i.Burn the primary image (erase each sector first)
* ii.Burn the PPS with the correct image address (FIA field)
* iii.Invalidate the SPS
* ===========================================================
*/
/*
* Other required tasks called from this function:
*
* * check for CISCO boot extensions in the current xPS, and
* if found, set them in the new xPS
*
* * update the xPS CRC field
*
* _then_ you can setup the outbound transfer to the HCA flash.
*/
/*
* VERY IMPORTANT NOTE:
* The above text from the app note programming guide v1.44 does
* NOT match reality. If you try to do exactly what the above
* text specifies then you'll wind up with a warm, brick-like
* HCA that if you're really lucky has booted up in maintenance
* mode for you to re-flash.
*
* What you need to do is follow the example of the previous
* (v1.2 etc) version from the ON gate - which is what happens
* in this file. Basically - don't erase prior to writing a new
* sector, and _read back_ each sector after writing it. Especially
* the pointer sectors. Otherwise you'll get a warm brick.
*/
manuf =
/*
* If we get here, then the verifier has _already_ checked that
* the part number in the firmware image matches that in the HCA,
* so we only need this check if there's no hardware info available
* already after running through fw_identify().
*/
int resp;
(void) printf("\nUnable to completely verify that this "
"firmware image\n\t(%s)\nis compatible with your "
"HCA\n\t%s\n",
(void) printf("\n\tDo you really want to continue? (Y/N): ");
(void) printf("\nNot proceeding with flash "
"operation of %s on %s\n",
return (FWFLASH_FAILURE);
}
}
/* stash these for later */
/* where does the on-disk image think everything is at? */
"ipfia 0x%0x isfia 0x%0x ipfis 0x%0x isfis 0x%0x\n",
/*
* This is bad - don't flash an image which is larger
* than the size of the HCA's flash
*/
gettext("tavor: on-disk firmware image size (0x%lx bytes) "
"exceeds HCA's flash memory size (0x%lx bytes)!\n"),
gettext("tavor: not flashing this image (%s)\n"),
return (FWFLASH_FAILURE);
}
/*
* The Mellanox HCA Flash app programming note does _not_
* specify that you have to insert the HCA's guid section
* into the flash image before burning it.
*
* HOWEVER it was determined during testing that this is
* actually required (otherwise your HCA's GUIDs revert to
* the manufacturer's defaults, ugh!), so we'll do it too.
*/
/*
* Here we check against our stored, properly-bitwise-munged copy
* of the HCA's GUIDS. If they're not set to default AND the OUI
* is MLX_OUI, then they're ok so we copy the HCA's version into
* our in-memory copy and blat it. If the GUIDs don't match this
* condition, then we use the default GUIDs which are in the on-disk
* firmware image instead.
*/
/* The GUIDs are ok, blat them into the in-memory image */
sizeof (struct mlx_guid_sect));
sizeof (struct mlx_guid_sect));
} else {
/*
* The GUIDs are hosed, we'll have to use
* the vendor defaults in the image instead
*/
gettext("tavor: HCA's GUID section is set to defaults or "
" is invalid, using firmware image manufacturer's "
"default GUID section instead\n"));
}
/* Just in case somebody is booting from this card... */
/* first we write the secondary image and SPS, then the primary */
if (rv != FWFLASH_SUCCESS) {
"tavor: failed to update #2 firmware image\n");
(void) tavor_close(flashdev);
return (FWFLASH_FAILURE);
}
if (rv != FWFLASH_SUCCESS) {
"tavor: failed to update #1 firmware image\n");
(void) tavor_close(flashdev);
return (FWFLASH_FAILURE);
}
/* final update marker to the user */
(void) printf(" +\n");
return (tavor_close(flashdev));
}
/*
* The fw_identify() function walks the device
* tree trying to find devices which this plugin
* can work with.
*
* The parameter "start" gives us the starting index number
* to give the device when we add it to the fw_devices list.
*
* firstdev is allocated by us and we add space as necessary
*
*/
int
fw_identify(int start)
{
int rv = FWFLASH_FAILURE;
struct devicelist *newdev;
char *devpath;
int devlength = 0;
if (thisnode == DI_NODE_NIL) {
return (rv);
}
/* we've found one, at least */
== NULL) {
gettext("%s identification function unable "
"to allocate space for device entry\n"));
return (rv);
}
/* calloc enough for /devices + devpath + ":devctl" + '\0' */
"for a devfs name\n"));
return (FWFLASH_FAILURE);
}
/* CHECK VARIOUS IB THINGS HERE */
gettext("tavor: Unable to allocate space for a "
"device identification record\n"));
return (FWFLASH_FAILURE);
}
if (rv == FWFLASH_FAILURE) {
continue;
}
== NULL) {
"for a driver name\n"));
return (FWFLASH_FAILURE);
}
/* this next bit is backwards compatibility - "IB\0" */
"for a class name\n"));
return (FWFLASH_FAILURE);
}
++idx;
}
if (fwflash_debug != 0) {
struct devicelist *tempdev;
"\t\taccess_devname: %s\n"
"\t\tdrvname: %s\tclassname: %s\n"
"\t\tident->vid: %s\n"
"\t\tident->pid: %s\n"
"\t\tident->revid: %s\n"
"\t\tindex: %d\n"
"\t\tguid0: %s\n"
"\t\tguid1: %s\n"
"\t\tguid2: %s\n"
"\t\tguid3: %s\n"
"\t\tplugin @ 0x%lx\n\n",
&tempdev,
}
}
return (FWFLASH_SUCCESS);
}
int
{
struct ib_encap_ident *encap;
/* Mellanox HCA Flash app note, p40, #4.2.3 table 9 */
gettext("GUID: System Image - %s\n"),
gettext("\t\tNode Image - %s\n"),
gettext("\t\tPort 1\t - %s\n"),
gettext("\t\tPort 2\t - %s\n"),
gettext("\tFirmware revision : %s\n"
"\tProduct\t\t: %s\n"
"\tPSID\t\t: %s\n"),
} else {
gettext("\tFirmware revision : %s\n"
"\tNo hardware information available for this "
}
return (tavor_close(thisdev));
}
/*
* Helper functions lurk beneath this point
*/
/*
* tavor_identify performs the following actions:
*
* allocates and assigns thisdev->vpr
*
* allocates space for the 4 GUIDs which each IB device must have
* queries the tavor driver for this device's GUIDs
*
* determines the hardware vendor, so that thisdev->vpr->vid
* can be set correctly
*/
static int
{
int rv = FWFLASH_SUCCESS;
struct ib_encap_ident *manuf;
char temppsid[17];
char rawpsid[16];
#if defined(_LITTLE_ENDIAN)
#endif
/* open the device */
/* hook thisdev->ident->encap_ident to ib_encap_ident */
/* check that all the bits are sane */
/* return success, if warranted */
errno = 0;
gettext("tavor: Unable to open a %s-attached "
"device node: %s: %s\n"), drivername,
return (FWFLASH_FAILURE);
}
gettext("tavor: Unable to calloc space for a "
"%s-attached handle structure\n"),
return (FWFLASH_FAILURE);
}
/*
* Inform driver that this command supports the Intel Extended
* CFI command set.
*/
errno = 0;
if (ret < 0) {
gettext("ib: TAVOR_IOCTL_FLASH_INIT failed: %s\n"),
return (FWFLASH_FAILURE);
}
/*
* Determine whether the attached driver supports the Intel or
* AMD Extended CFI command sets. If it doesn't support either,
* then we're hosed, so error out.
*/
for (i = 0; i < TAVOR_FLASH_CFI_SIZE_QUADLET; i++) {
}
/* make sure the cmd set is AMD */
gettext("tavor: Unsupported flash device "
"command set\n"));
return (FWFLASH_FAILURE);
}
/* set some defaults */
} else {
gettext("ib: Unknown flash device command set\n"));
return (FWFLASH_FAILURE);
}
/* read from the CFI data */
}
/* set firmware revision */
gettext("ib: Unable to allocate space for a VPR "
"record.\n"));
return (FWFLASH_FAILURE);
}
/*
* We actually want the hwrev field from the ioctl above.
* Until we find out otherwise, add it onto the end of the
* firmware version details.
*/
/*
* For convenience we read in the Invariant Sector as
* well as both the Primary and Secondary Pointer Sectors
*/
gettext("tavor: Unable to allocate space for storing "
"the HCA's Invariant Sector\n"));
return (FWFLASH_FAILURE);
}
info.tf_sector_num = 0;
errno = 0;
< 0) {
gettext("tavor: Unable to read HCA Invariant Sector\n"));
return (FWFLASH_FAILURE);
}
#if defined(_LITTLE_ENDIAN)
}
#endif
gettext("tavor: Unable to allocate space for storing "
"the HCA's Primary Pointer Sector\n"));
return (FWFLASH_FAILURE);
}
errno = 0;
< 0) {
gettext("tavor: Unable to read HCA Primary "
"Pointer Sector\n"));
return (FWFLASH_FAILURE);
}
#if defined(_LITTLE_ENDIAN)
}
#endif
gettext("tavor: Unable to allocate space for storing "
"the HCA's Secondary Pointer Sector\n"));
return (FWFLASH_FAILURE);
}
errno = 0;
< 0) {
gettext("tavor: Unable to read HCA Secondary "
"Pointer Sector\n"));
return (FWFLASH_FAILURE);
}
#if defined(_LITTLE_ENDIAN)
}
#endif
gettext("ib: No guids found for device %s!\n"),
}
/* set hw part number, psid, and name in handle */
for (i = 0; i < 16; i += 4) {
}
"tavor: have raw '%s', want munged '%s'\n",
/* now walk the magic decoder ring table */
for (i = 0; i < MLX_MAX_ID; i++) {
MLX_PSID_SZ)) == 0) {
/* matched */
"tavor: no space available for the "
"HCA PSID record (1)\n");
} else {
}
"tavor: no space available for the "
"HCA PSID record (2)\n");
} else {
}
"tavor: no space available for the "
"HCA PSID record (3)\n");
} else {
}
}
}
"tavor: No hardware part number information available "
"for this HCA\n");
/* Until we deliver the arbel driver, it's all Mellanox */
i = strlen("No hardware information available for this device");
"available for this device");
} else {
} else {
gettext("ib: Unable to allocate space for a "
"hardware identifier\n"));
return (FWFLASH_FAILURE);
}
}
for (i = 0; i < 4; i++) {
gettext("tavor: Unable to allocate space for a "
"human-readable HCA guid\n"));
return (FWFLASH_FAILURE);
}
}
/*
* We do NOT close the fd here, since we can close it
* at the end of the fw_readfw() or fw_writefw() functions
* instead and not get the poor dear confused about whether
* it's been inited already.
*/
return (rv);
}
/*ARGSUSED*/
static int
{
int rv, j;
uint32_t i = 0x00;
struct mlx_guid_sect *p, *s;
#if defined(_LITTLE_ENDIAN)
#endif
/*
* The reference for this function is the
* Mellanox HCA Flash Programming Application Note
* rev 1.44, 2007. Chapter 4 in particular.
*
* NOTE: this Mellanox document is labelled Confidential
* explicit approval from Sun Legal.
*/
/*
* We need to check for both the Primary and Secondary
* Image GUIDs. handle->pps and handle->sps should be
* non-NULL by the time we're called, since we depend
* on them being stashed in handle. Saves on an ioctl().
*/
/* make sure we've got our fallback position organised */
for (i = 0; i < 4; i++) {
}
/* convenience .... */
gettext("tavor: Unable to allocate space for "
"HCA guid record (1)\n"));
return (FWFLASH_FAILURE);
}
gettext("tavor: Unable to allocate space for "
"HCA guid record (2)\n"));
free(p);
return (FWFLASH_FAILURE);
}
errno = 0;
if (rv < 0) {
gettext("tavor: Unable to read Primary Image "
"guid offset\n"));
free(p);
free(s);
return (FWFLASH_FAILURE);
}
/*
* This is because we want the whole of the section
* including the 16 reserved bytes at the front so
* that if we recalculate the CRC we've got the correct
* data to do it with
*/
- FLASH_GUID_PTR - 16;
for (j = 0; j < 13; j++) {
errno = 0;
&info)) < 0) {
gettext("tavor: Unable to read Primary Image "
"guid chunk %d\n"), j);
}
}
/* now grab the secondary guid set */
errno = 0;
&info)) < 0) {
gettext("tavor: Unable to read Secondary Image "
free(p);
free(s);
return (FWFLASH_FAILURE);
}
- FLASH_GUID_PTR - 16;
for (j = 0; j < 13; j++) {
errno = 0;
&info)) < 0) {
gettext("tavor: Unable to read Secondary Image "
return (FWFLASH_FAILURE);
}
}
#if defined(_LITTLE_ENDIAN)
/*
* We don't actually care about p or s later on if we
* write to the HCA - we've already stored the binary
* form in handle->pri_guid_section and handle->sec_guid_section.
* What we're doing here is creating human-readable forms.
*/
for (j = 0; j < 14; j += 2) {
}
for (j = 0; j < 14; j += 2) {
}
#endif
/*
* We don't check and munge the GUIDs to the manufacturer's
* defaults, because if the GUIDs are actually set incorrectly
* at identify time, we really need to know that.
*
* If the GUIDs are bogus, then we'll fix that in fw_writefw()
* by blatting the manufacturer's defaults from the firmware
* image file instead.
*/
"tavor: primary and secondary guids are the same\n");
} else {
/*
* We're going to assume that the guids which are numerically
* larger than the others are correct and copy them to
* handle->ibguids.
*
* For those in the know wrt InfiniBand, if this assumption
* is incorrect, _please_ bug this and fix it, adding a
* comment or two to indicate why
*/
"tavor: primary and secondary guids don't all match\n");
bzero(p, sizeof (struct mlx_guid_sect));
} else {
bzero(s, sizeof (struct mlx_guid_sect));
}
}
free(p);
free(s);
if (fwflash_debug) {
for (i = 0; i < 4; i++) {
}
}
return (FWFLASH_SUCCESS);
}
int
{
struct ib_encap_ident *handle;
errno = 0;
gettext("tavor: Unable to properly close "
"device %s! (%s)\n"),
return (FWFLASH_FAILURE);
}
return (FWFLASH_SUCCESS);
} else
return (FWFLASH_FAILURE);
}
/*
* 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 void
{
uint32_t i;
if (sig1 == FLASH_VSD_CISCO_SIGNATURE &&
"tavor: CISCO signature found in HCA's VSD, copying to "
"new image's VSD\n");
/*
* Set the boot_version field to '2'. This value is
* located in the 2nd byte of the last uint32_t.
* Per the previous version of fwflash, we just or
* the bit in and get on with it.
*/
/*
* Now set some defaults for the SRP boot extension,
* currently the only extension we support. These flags
* are located in the second uint32_t of the VSD.
*/
"to 0x%08x\n",
"to 0x%08x\n",
} else
"tavor: CISCO signature not found in HCA's VSD\n");
}
static int
{
int rv, i;
errno = 0;
"tavor: tavor_write_sector(fd %d, sectnum 0x%x, data 0x%lx)\n",
"tavor:\n"
"\tcmd.tf_type %d\n"
"\tcmd.tf_sector 0x%lx\n"
"\tcmd.tf_sector_num %d\n",
/*
* If we're debugging, dump the first 64 uint32_t that we've
* been passed
*/
if (fwflash_debug > 0) {
i = 0;
while (i < 64) {
"%02x: %08x %08x %08x %08x\n",
i += 4;
}
}
if (rv < 0) {
gettext("tavor: WRITE SECTOR failed for sector "
"%d: %s\n"),
return (FWFLASH_FAILURE);
} else
return (FWFLASH_SUCCESS);
}
/*
* Write zeros to the on-HCA signature and CRC16 fields of sector.
*
* NOTE we do _not_ divide start by 4 because we're talking to the
* HCA, and not finding an offset into verifier->fwimage.
*/
static int
{
int i, rv;
/* signature first, then CRC16 */
"tavor: tavor_zero_sig_crc(fd %d, start 0x%04x)\n",
for (i = 0; i < 4; i++) {
"tavor: invalidating xPS sig (offset from IS 0x%04x) "
"byte %d\n",
errno = 0;
if (rv < 0) {
gettext("tavor: Unable to write 0x00 to "
"offset 0x%04x from IS (sig byte %d): %s\n"),
return (FWFLASH_FAILURE);
}
}
for (i = 0; i < 2; i++) {
"tavor: invalidating xPS CRC16 (offset from IS 0x%04x) "
"byte %d\n",
errno = 0;
if (rv < 0) {
gettext("tavor: Unable to write 0x00 to "
"offset 0x%04x from IS (CRC16 byte %d): %s\n"),
return (FWFLASH_FAILURE);
}
}
return (FWFLASH_SUCCESS);
}
/*
* Write a new FIA for the given xPS. The _caller_ handles
* any required byte-swapping for us.
*
* NOTE we do _not_ divide start by 4 because we're talking to the
* HCA, and not finding an offset into verifier->fwimage.
*/
static int
{
int i, rv;
"tavor: tavor_write_xps_fia(fd %d, offset 0x%04x, "
"start 0x%04x)\n",
for (i = 0; i < 4; i++) {
"tavor: writing xPS' new FIA, byte %d (0x%0x) at "
"offset from IS 0x%04x\n",
errno = 0;
if (rv < 0) {
gettext("tavor: Unable to write byte %d "
"of xPS new FIA (0x%0x, offset from IS "
"0x%04x): %s\n"),
return (FWFLASH_FAILURE);
}
}
return (FWFLASH_SUCCESS);
}
/*
* Write the new CRC16 and Signature to the given xPS. The caller
* has already byte-swapped newcrc if that's necessary.
*
* NOTE we do _not_ divide start by 4 because we're talking to the
* HCA, and not finding an offset into verifier->fwimage.
*/
static int
{
int i, rv;
"tavor: tavor_write_xps_crc_sig(fd %d, offset 0x%04x, "
"newcrc 0x%04x)\n",
for (i = 0; i < 2; i++) {
"tavor: writing new XPS CRC16, byte %d (0x%0x) at "
"offset from IS 0x%04x\n",
errno = 0;
if (rv < 0) {
gettext("tavor: Unable to write byte %d "
"(0x%0x) of xPS' new CRC16 to offset "
"from IS 0x%04x: %s\n"),
return (FWFLASH_FAILURE);
}
}
for (i = 0; i < 4; i++) {
"tavor: writing new xPS Signature, byte %d (0x%0x) at "
"offset from IS 0x%04x\n",
errno = 0;
if (rv < 0) {
gettext("tavor: Unable to write byte %d (0x%0x) "
"of xPS' signature at offset from IS 0x%04x: %s\n"),
return (FWFLASH_FAILURE);
}
}
return (FWFLASH_SUCCESS);
}
/*
* because the reality of what actually _works_ is quite, quite
* different to what is written in the Mellanox HCA Flash Application
* Programming Guide.
*/
static int
{
"tavor: invalid image number requested (%d)\n");
return (FWFLASH_FAILURE);
}
/* Begin documentation departure point */
/* zero the HCA's PPS signature and CRC */
!= FWFLASH_SUCCESS) {
"tavor: Unable zero HCA's %s signature "
"and CRC16 fields\n",
return (FWFLASH_FAILURE);
}
/* End documentation departure point */
/* make sure we don't inadvertently overwrite bits */
"startsectimg %d, num sectors %d\n",
for (i = 0; i < numsect; i++) {
i + startsecthca);
!= FWFLASH_SUCCESS) {
gettext("tavor: Unable to write "
"sector %d to HCA\n"),
i + startsecthca);
return (FWFLASH_FAILURE);
}
(void) printf(" .");
if (rv != FWFLASH_SUCCESS) {
gettext("tavor: Unable to read sector %d "
"back from HCA\n"), i + startsecthca);
return (FWFLASH_FAILURE);
}
(void) printf(" | ");
}
/* Begin documentation departure point */
/* invalidate the xps signature and fia fields */
/* we put the fia back to imgfia later */
/* End documentation departure point */
/* success so far, now burn the new xPS */
!= FWFLASH_SUCCESS) {
gettext("tavor: Unable to write new %s "
"pointer sector to HCA\n"),
return (FWFLASH_FAILURE);
}
(void) printf(" .");
/* Begin documentation departure point */
/* write new fia to the HCA's pps */
gettext("tavor: Unable to update HCA's %s "
"pointer sector FIA record\n"),
return (FWFLASH_FAILURE);
}
/* don't forget the byte-swapping */
"sig 0x%0x and new crc16 0x%0x\n",
/*
* Now we're REALLY hosed. If the card comes up at all,
* expect it to be in "Maintenance Mode".
*/
gettext("tavor: Unable to update HCA's %s CRC "
"and Firmware Image signature fields\n"),
return (FWFLASH_FAILURE);
}
if (rv != FWFLASH_SUCCESS) {
gettext("tavor: Unable to read %s pointer sector "
"from HCA\n"),
return (FWFLASH_FAILURE);
}
(void) printf(" |");
/* End documentation departure point */
return (FWFLASH_SUCCESS);
}
static int
{
int rv;
if (rv < 0) {
"tavor: UNABLE TO READ BACK SECTOR %d from HCA\n",
return (FWFLASH_FAILURE);
}
return (FWFLASH_SUCCESS);
}
/*
* 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);
}