summaryrefslogtreecommitdiff
path: root/usr/src/cmd
diff options
context:
space:
mode:
authorBill Taylor <Bill.Taylor@Sun.COM>2009-04-30 13:42:05 -0700
committerBill Taylor <Bill.Taylor@Sun.COM>2009-04-30 13:42:05 -0700
commit9e39c5ba00a55fa05777cc94b148296af305e135 (patch)
treec461af0758c1502672201c88b4032ea0df9ea42c /usr/src/cmd
parentb31d69afd0b141cad8082cc344f651651108c210 (diff)
downloadillumos-gate-9e39c5ba00a55fa05777cc94b148296af305e135.tar.gz
6808773 code for Mellanox devices (hermon, tavor, udapl, fwflash) can become open source
Diffstat (limited to 'usr/src/cmd')
-rw-r--r--usr/src/cmd/fwflash/plugins/Makefile6
-rw-r--r--usr/src/cmd/fwflash/plugins/hdrs/MELLANOX.h199
-rw-r--r--usr/src/cmd/fwflash/plugins/hdrs/hermon_ib.h282
-rw-r--r--usr/src/cmd/fwflash/plugins/hdrs/tavor_ib.h226
-rw-r--r--usr/src/cmd/fwflash/plugins/i386/Makefile94
-rw-r--r--usr/src/cmd/fwflash/plugins/sparc/Makefile94
-rw-r--r--usr/src/cmd/fwflash/plugins/transport/common/hermon.c1885
-rw-r--r--usr/src/cmd/fwflash/plugins/transport/common/tavor.c1921
-rw-r--r--usr/src/cmd/fwflash/plugins/transport/i386/Makefile31
-rw-r--r--usr/src/cmd/fwflash/plugins/transport/sparc/Makefile28
-rw-r--r--usr/src/cmd/fwflash/plugins/vendor/hermon-MELLANOX.c383
-rw-r--r--usr/src/cmd/fwflash/plugins/vendor/tavor-MELLANOX.c337
12 files changed, 5452 insertions, 34 deletions
diff --git a/usr/src/cmd/fwflash/plugins/Makefile b/usr/src/cmd/fwflash/plugins/Makefile
index 53b9d8ccf3..3a28e5a923 100644
--- a/usr/src/cmd/fwflash/plugins/Makefile
+++ b/usr/src/cmd/fwflash/plugins/Makefile
@@ -19,9 +19,7 @@
# CDDL HEADER END
#
#
-#ident "%Z%%M% %I% %E% SMI"
-#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# cmd/fwflash/plugins
@@ -29,7 +27,7 @@
include $(SRC)/cmd/Makefile.cmd
-COMMON_SUBDIRS= transport
+COMMON_SUBDIRS= $(MACH) transport
CLOSED_SUBDIRS= $(CLOSED)/cmd/fwflash/plugins
SUBDIRS= $(COMMON_SUBDIRS) $(CLOSED_SUBDIRS)
diff --git a/usr/src/cmd/fwflash/plugins/hdrs/MELLANOX.h b/usr/src/cmd/fwflash/plugins/hdrs/MELLANOX.h
new file mode 100644
index 0000000000..ec214d62af
--- /dev/null
+++ b/usr/src/cmd/fwflash/plugins/hdrs/MELLANOX.h
@@ -0,0 +1,199 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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.
+ */
+
+#ifndef _HDRS_MELLANOX_H
+#define _HDRS_MELLANOX_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * MELLANOX.h
+ *
+ * This file contain common information related to Mellanox technologies
+ * HCA cards.
+ */
+#define SUNW_OUI 0x0003baULL
+#define MLX_OUI 0x0002c9ULL
+#define MLX_DEFAULT_NODE_GUID 0x2c9000100d050ULL
+#define MLX_DEFAULT_P1_GUID 0x2c9000100d051ULL
+#define MLX_DEFAULT_P2_GUID 0x2c9000100d052ULL
+#define MLX_DEFAULT_SYSIMG_GUID 0x2c9000100d053ULL
+
+/* How many bits to shift and leave just the OUI */
+#define OUISHIFT 40
+
+#define MLX_VPR_VIDLEN 9 /* "MELLANOX" + '\0' */
+#define MLX_VPR_REVLEN 21 /* "%04x.%04x.%04x: %04x" + '\0' */
+
+#define FWFLASH_IB_MAGIC_NUMBER 0xF00B0021
+
+/* Numerically largest OUI that's presently assigned */
+#define TAVOR_MAX_OUI 0xacde48
+
+#define FWFLASH_IB_STATE_NONE 0x00
+#define FWFLASH_IB_STATE_IMAGE_PRI 0x01
+#define FWFLASH_IB_STATE_IMAGE_SEC 0x02
+#define FWFLASH_IB_STATE_MMAP 0x04
+#define FWFLASH_IB_STATE_GUIDN 0x10
+#define FWFLASH_IB_STATE_GUID1 0x20
+#define FWFLASH_IB_STATE_GUID2 0x40
+#define FWFLASH_IB_STATE_GUIDS 0x80
+
+#define FWFLASH_IB_STATE_IMAGE FWFLASH_IB_STATE_IMAGE_PRI
+
+#define FWFLASH_IB_STATE_PFI_IMAGE FWFLASH_IB_STATE_IMAGE_PRI
+#define FWFLASH_IB_STATE_SFI_IMAGE FWFLASH_IB_STATE_IMAGE_SEC
+
+/*
+ * Structure to hold the part number, PSID, and string ID
+ * for an HCA card.
+ */
+typedef struct mlx_mdr_s {
+ char *mlx_pn;
+ char *mlx_psid;
+ char *mlx_id;
+} mlx_mdr_t;
+
+/*
+ * Magic decoder ring for matching HCA hardware/firmware.
+ * Part Number / PSID / String ID
+ */
+mlx_mdr_t mlx_mdr[] = {
+ /* Part No PSID Card ID */
+ { "MHEA28-XS", "MT_0250000001", "Lion mini" },
+ { "MHEA28-XSC", "MT_0390110001", "Lion mini" },
+ { "MHEA28-XT", "MT_0150000001", "Lion mini" },
+ { "MHEA28-XTC", "MT_0370110001", "Lion mini" },
+ { "MHGA28-XT", "MT_0150000002", "Lion mini" },
+ { "MHGA28-XTC", "MT_0370110002", "Lion mini" },
+ { "MHGA28-XTC", "MT_0370130002", "Lion mini" },
+ { "MHGA28-XS", "MT_0250000002", "Lion mini" },
+ { "MHGA28-XSC", "MT_0390110002", "Lion mini" },
+ { "MHGA28-XSC", "MT_0390130002", "Lion mini" },
+ { "MHEL-CF128", "MT_0190000001", "Lion cub" },
+ { "MHEL-CF128-T", "MT_00A0000001", "Lion cub" },
+ { "MTLP25208-CF128T", "MT_00A0000001", "Lion cub" },
+ { "MHEL-CF128-TC", "MT_00A0010001", "Lion cub" },
+ { "MHEL-CF128-TC", "MT_0140010001", "Lion cub" },
+ { "MHEL-CF128-SC", "MT_0190010001", "Lion cub" },
+ { "MHEA28-1TC", "MT_02F0110001", "Lion cub" },
+ { "MHEA28-1SC", "MT_0330110001", "Lion cub" },
+ { "MHGA28-1T", "MT_0200000001", "Lion cub" },
+ { "MHGA28-1TC", "MT_02F0110002", "Lion cub" },
+ { "MHGA28-1SC", "MT_0330110002", "Lion cub" },
+ { "MHGA28-1S", "MT_0430000001", "Lion cub" },
+ { "MHEL-CF256-T", "MT_00B0000001", "Lion cub" },
+ { "MTLP25208-CF256T", "MT_00B0000001", "Lion cub" },
+ { "MHEL-CF256-TC", "MT_00B0010001", "Lion cub" },
+ { "MHEA28-2TC", "MT_0300110001", "Lion cub" },
+ { "MHEA28-2SC", "MT_0340110001", "Lion cub" },
+ { "MHGA28-2T", "MT_0210000001", "Lion cub" },
+ { "MHGA28-2TC", "MT_0300110002", "Lion cub" },
+ { "MHGA28-2SC", "MT_0340110002", "Lion cub" },
+ { "MHEL-CF512-T", "MT_00C0000001", "Lion cub" },
+ { "MTLP25208-CF512T", "MT_00C0000001", "Lion cub" },
+ { "MHGA28-5T", "MT_0220000001", "Lion cub" },
+ { "375-3382-01", "SUN0030000001", "Sun Lion cub DDR" },
+ { "MHES14-XSC", "MT_0410110001", "Tiger" },
+ { "MHES14-XT", "MT_01F0000001", "Tiger" },
+ { "MHES14-XTC", "MT_03F0110001", "Tiger" },
+ { "MHES18-XS", "MT_0260000001", "Cheetah" },
+ { "MHES18-XS", "MT_0260010001", "Cheetah" },
+ { "MHES18-XSC", "MT_03D0110001", "Cheetah" },
+ { "MHES18-XSC", "MT_03D0120001", "Cheetah" },
+ { "MHES18-XSC", "MT_03D0130001", "Cheetah" },
+ { "MHES18-XT", "MT_0230000002", "Cheetah" },
+ { "MHES18-XT", "MT_0230010002", "Cheetah" },
+ { "MHES18-XTC", "MT_03B0110001", "Cheetah" },
+ { "MHES18-XTC", "MT_03B0120001", "Cheetah" },
+ { "MHES18-XTC", "MT_03B0140001", "Cheetah" },
+ { "MHGS18-XS", "MT_0260000002", "Cheetah" },
+ { "MHGS18-XSC", "MT_03D0110002", "Cheetah" },
+ { "MHGS18-XSC", "MT_03D0120002", "Cheetah" },
+ { "MHGS18-XSC", "MT_03D0130002", "Cheetah" },
+ { "MHGS18-XT", "MT_0230000001", "Cheetah" },
+ { "MHGS18-XTC", "MT_03B0110002", "Cheetah" },
+ { "MHGS18-XTC", "MT_03B0120002", "Cheetah" },
+ { "MHGS18-XTC", "MT_03B0140002", "Cheetah" },
+ { "MHXL-CF128", "MT_0180000001", "Cougar Cub 128" },
+ { "MHXL-CF128-T", "MT_0030000001", "Cougar Cub 128" },
+ { "MTLP23108-CF128T", "MT_0030000001", "Cougar Cub 128" },
+ { "MHET2X-1SC", "MT_0280110001", "Cougar Cub 128" },
+ { "MHET2X-1SC", "MT_0280120001", "Cougar Cub 128" },
+ { "MHET2X-1TC", "MT_0270110001", "Cougar Cub 128" },
+ { "MHET2X-1TC", "MT_0270120001", "Cougar Cub 128" },
+ { "MHXL-CF256-T", "MT_0040000001", "Cougar Cub 256" },
+ { "MHET2X-2SC", "MT_02D0110001", "Cougar Cub 256" },
+ { "MHET2X-2SC", "MT_02D0120001", "Cougar Cub 256" },
+ { "MHET2X-2TC", "MT_02B0110001", "Cougar Cub 256" },
+ { "MHET2X-2TC", "MT_02B0120001", "Cougar Cub 256" },
+ { "375-3481-01", "SUN0040000001", "Sun Cougar Cub SDR" },
+ { "MHX-CE128-T", "MT_0000000001", "Cougar 128" },
+ { "MTPB23108-CE128", "MT_0000000001", "Cougar 128" },
+ { "MHX-CE256-T", "MT_0010000001", "Cougar 256" },
+ { "MTPB23108-CE256", "MT_0010000001", "Cougar 256" },
+ { "MHX-CE512-T", "MT_0050000001", "Cougar 512" },
+ { "MTPB23108-CE512", "MT_0050000001", "Cougar 512" },
+ { "MHEH28-XSC", "MT_04C0110001", "Eagle SDR" },
+ { "MHEH28-XSC", "MT_04C0130005", "Eagle SDR" },
+ { "MHEH28-XTC", "MT_04A0110001", "Eagle SDR" },
+ { "MHEH28-XTC", "MT_04A0130005", "Eagle SDR" },
+ { "MHGH28-XSC", "MT_04C0110002", "Eagle DDR" },
+ { "MHGH28-XSC", "MT_04C0120002", "Eagle DDR" },
+ { "MHGH28-XSC", "MT_04C0140005", "Eagle DDR" },
+ { "MHGH28-XTC", "MT_04A0110002", "Eagle DDR" },
+ { "MHGH28-XTC", "MT_04A0120002", "Eagle DDR" },
+ { "MHGH28-XTC", "MT_04A0140005", "Eagle DDR" },
+ { "X1289A-Z", "SUN0010010001", "Sun IB NEM DDR" },
+ { "375-3548-01", "SUN0060000001", "Sun IB EM DDR X4216A-Z" },
+ { "375-3549-01", "SUN0070000001", "Sun PCIe DDR X4217A" },
+ { "375-3481-01", "SUN0050000001", "Sun PCIe EM SDR" },
+ { "MHGH29-XSC", "MT_0A60110002", "Eagle DDR PCIe Gen 2.0" },
+ { "MHGH29-XSC", "MT_0A60120005", "Eagle DDR PCIe Gen 2.0" },
+ { "MHGH29-XTC", "MT_0A50110002", "Eagle DDR PCIe Gen 2.0" },
+ { "MHGH29-XTC", "MT_0A50120005", "Eagle DDR PCIe Gen 2.0" },
+ { "375-3605-01", "SUN0160000001", "Sun Mirage QDR" },
+ { "375-3606-01", "SUN0150000001", "Sun Falcon QDR" },
+ { "MHJH29-XTC", "MT_04E0110003", "Eagle QDR" },
+ { "375-3551-05", "SUN0080000001", "Sun C48-IB-NEM" }
+};
+
+/* Get mlx_mdr[] array size */
+#define MLX_SZ_MLX_MDR sizeof (mlx_mdr)
+#define MLX_SZ_MLX_MDR_STRUCT sizeof (mlx_mdr[0])
+
+#define MLX_MAX_ID MLX_SZ_MLX_MDR/MLX_SZ_MLX_MDR_STRUCT
+#define MLX_PSID_SZ 16
+#define MLX_STR_ID_SZ 64
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _HDRS_MELLANOX_H */
diff --git a/usr/src/cmd/fwflash/plugins/hdrs/hermon_ib.h b/usr/src/cmd/fwflash/plugins/hdrs/hermon_ib.h
new file mode 100644
index 0000000000..1de41aa8fd
--- /dev/null
+++ b/usr/src/cmd/fwflash/plugins/hdrs/hermon_ib.h
@@ -0,0 +1,282 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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.
+ */
+
+#ifndef _HDRS_HERMON_IB_H
+#define _HDRS_HERMON_IB_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * ConnectX (hermon) specific definitions.
+ */
+
+/*
+ * The reference for the definitions in this file is the
+ *
+ * Mellanox HCA Flash Programming Application Note
+ * (Mellanox document number 2205AN)
+ * rev 1.45, 2007. Chapter 4 in particular.
+ */
+
+#include <sys/types.h>
+#include <sys/ib/adapters/hermon/hermon_ioctl.h>
+#include "MELLANOX.h"
+
+#define FWFLASH_IB_HERMON_DRIVER "hermon"
+
+/*
+ * Image Info section: Refer Mellanox App note 1.45, Section 4.4
+ *
+ * The Image Info section contains management information about the
+ * firmware image. It consists of a series of consecutive data tags.
+ * Each tag contains a 32-bit header, providing a TagID which indicates
+ * the data type, and the size of the data in the tag.
+ */
+#define MLX_MASK_TAGID 0xff000000
+#define MLX_MASK_TAGSIZE 0x00ffffff
+
+enum tag_ids {
+ CNX_IMAGE_INFO_REV = 0, /* IMAGE_INFO format revision */
+ CNX_FW_VER = 1, /* Firmware Version */
+ CNX_FW_BUILD_TIME = 2, /* Firmware Build Time */
+ CNX_DEV_TYPE = 3, /* Device Type */
+ CNX_PSID = 4, /* Parameter Set IDentification */
+ CNX_VSD = 5, /* Vendor Specific Data */
+ CNX_RES1 = 6, /* reserved */
+ CNX_RES2 = 7, /* reserved */
+ CNX_VSD_VENDOR_ID = 8, /* PCISIG vendor ID */
+ /* 0x9 - 0xFE are reserved */
+ CNX_END_TAG = 0xff /* END tag */
+};
+
+enum tag_sizes {
+ CNX_IMAGE_INFO_REV_SZ = 4,
+ CNX_FW_VER_SZ = 8,
+ CNX_FW_BUILD_TIME_SZ = 8,
+ CNX_DEV_TYPE_SZ = 4,
+ CNX_PSID_SZ = 16,
+ CNX_VSD_SZ = 208,
+ CNX_VSD_VENDOR_ID_SZ = 4,
+ CNX_END_TAG_SZ = 0
+};
+
+/*
+ * Image Info Format revision (TagID - CNX_IMAGE_INFO_REV).
+ * Provides the format revision of the Image Info section. Currently it is 0x1
+ */
+#define CNX_IMAGE_INFO_VER 1
+
+/*
+ * Firmware Version (TagID - CNX_FW_VER)
+ * Provides the major, minor and sub-minor versions of the firmware image.
+ */
+#define CNX_MASK_FW_VER_MAJ 0xffff0000
+#define CNX_MASK_FW_VER_MIN CNX_MASK_FW_VER_MAJ
+#define CNX_MASK_FW_VER_SUBMIN 0x0000ffff
+
+typedef struct cnx_fw_rev_s {
+ uint16_t major;
+ uint16_t reserved;
+ uint16_t minor;
+ uint16_t subminor;
+} cnx_fw_rev_t;
+
+
+/*
+ * Firmware Build Time (TagID - CNX_FW_BUILD_TIME)
+ * Provides the data and time of the firmware image build.
+ */
+#define CNX_MASK_FW_BUILD_HOUR 0x00ff0000
+#define CNX_MASK_FW_BUILD_MIN 0x0000ff00
+#define CNX_MASK_FW_BUILD_SEC 0x000000ff
+#define CNX_MASK_FW_BUILD_YEAR 0xffff0000
+#define CNX_MASK_FW_BUILD_MON 0x0000ff00
+#define CNX_MASK_FW_BUILD_DAY 0x000000ff
+
+typedef struct cnx_fw_build_time_tag {
+ uint8_t reserved;
+ uint8_t hour;
+ uint8_t minute;
+ uint8_t second;
+ uint16_t year;
+ uint8_t month;
+ uint8_t day;
+} cnx_fw_build_time_t;
+
+/*
+ * Device Type (TagID - CNX_DEV_TYPE)
+ * The device type tag is only 4 bytes long, so we don't bother to
+ * declare a separate struct for it.
+ *
+ * The CNX_MASK_DEV_TYPE_REV provides the mask to extract the hardware
+ * device's PCI Revision ID.
+ * The CNX_MASK_DEV_TYPE_ID provides the mask to extract the hardware
+ * device's PCI Device ID.
+ */
+#define CNX_MASK_DEV_TYPE_REV 0x00ff0000
+#define CNX_MASK_DEV_TYPE_ID 0x0000ffff
+
+/*
+ * The PSID (TagID - CNX_PSID) and VSD (TagID - CNX_VSD) tag contents are
+ * just bytes without any specific structure, so we'll declare their sizes
+ * but nothing else.
+ */
+#define CNX_TAG_PSID_SIZE 0x10
+#define CNX_TAG_VSD_SIZE 0xD0
+
+/*
+ * VSD Vendor ID (TagID - CNX_VSD_VENDOR_ID)
+ * The VSD Vendor ID tag holds the PCISIG vendor ID of the vendor that
+ * fills the VSD tag.
+ */
+#define CNX_MASK_VSD_VENDORID 0x00ff
+
+typedef struct cnx_img_info_s {
+ cnx_fw_rev_t fw_rev;
+ cnx_fw_build_time_t fw_buildtime;
+ uint16_t dev_id;
+ uint16_t vsd_vendor_id;
+ uint8_t psid[CNX_PSID_SZ];
+ uint8_t vsd[CNX_VSD_SZ];
+} cnx_img_info_t;
+
+/*
+ * ConnectX Devices Firmware Image Format
+ */
+typedef struct mlx_cnx_xfi { /* Byte Offset */
+ uint32_t magic_pattern[4]; /* 0x00 - 0x0F */
+ uint8_t xfiresv1[24]; /* 0x10 - 0x27 */
+ uint32_t failsafechunkinfo; /* 0x28 - 0x2B */
+ uint32_t imageinfoptr; /* 0x2C - 0x2F */
+ uint32_t fwimagesz; /* 0x30 - 0x33 */
+ uint32_t nguidptr; /* 0x34 - 0x37 */
+ uint8_t *xfiremainder;
+} mlx_cnx_xfi_t;
+
+uint32_t cnx_magic_pattern[4] = {
+ 0x4D544657,
+ 0x8CDFD000,
+ 0xDEAD9270,
+ 0x4154BEEF };
+
+#define CNX_XFI_IMGINFO_CKSUM_MASK 0xFF000000
+#define CNX_XFI_IMGINFO_PTR_MASK 0x00FFFFFF
+
+#define CNX_HWVER_OFFSET 0x20
+#define CNX_HWVER_MASK 0xFF000000
+
+#define CNX_CHUNK_SIZE_OFFSET 0x28
+#define CNX_IMG_INF_PTR_OFFSET 0x2C
+#define CNX_IMG_INF_SZ_OFFSET -0x0C
+#define CNX_IMG_SIZE_OFFSET 0x30
+#define CNX_NGUIDPTR_OFFSET 0x34
+
+/*
+ * ConnectX Devices GUID Section Structure.
+ *
+ * Of all the structures we poke around with, we're packing
+ * these because we frequently have to operate on them as
+ * plain old byte arrays. If we don't pack it then the compiler
+ * will "properly" align it for us - which results in a
+ * structure that's a l l s p r e a d o u t.
+ */
+#pragma pack(1)
+typedef struct mlx_cnx_guid_sect { /* Byte Offset */
+ uint8_t guidresv[16]; /* 0x00 - 0x0F */
+ uint64_t nodeguid; /* 0x10 - 0x17 */
+ uint64_t port1guid; /* 0x18 - 0x1F */
+ uint64_t port2guid; /* 0x20 - 0x27 */
+ uint64_t sysimguid; /* 0x28 - 0x2F */
+ uint64_t port1_mac; /* 0x30 - 0x31 - rsvd - must be zero */
+ /* 0x32 - 0x37 - Port1 MAC [47:0] */
+ uint64_t port2_mac; /* 0x38 - 0x39 - rsvd - must be zero */
+ /* 0x3A - 0x3F - Port2 MAC [47:0] */
+ uint16_t guidresv2; /* 0x40 - 0x41 */
+ uint16_t guidcrc; /* 0x42 - 0x43 */
+} mlx_cnx_guid_sect_t;
+#pragma pack()
+
+#define CNX_NGUID_OFFSET 0x10
+#define CNX_P1GUID_OFFSET 0x18
+#define CNX_P2GUID_OFFSET 0x20
+#define CNX_SYSIMGUID_OFFSET 0x28
+#define CNX_P1MAC_OFFSET 0x32
+#define CNX_P2MAC_OFFSET 0x3A
+#define CNX_GUID_CRC16_SIZE 0x40 /* 00-3F */
+#define CNX_GUID_CRC16_OFFSET 0x42
+
+
+/* we hook this struct into vpr->encap_ident */
+typedef struct ib_cnx_encap_ident_s {
+ uint_t magic; /* FWFLASH_IB_MAGIC_NUMBER */
+ int fd; /* fd of hermon device */
+ int cmd_set; /* COMMAND SET */
+ int pn_len; /* Part# Length */
+ int hwfw_match; /* 1 = match, 0 - nomatch */
+ /* Used during write for validation */
+ cnx_img_info_t hwfw_img_info; /* HW Image Info Section */
+ cnx_img_info_t file_img_info; /* Image File's Image Info Section */
+ mlx_mdr_t info; /* Details of HW part#, name, */
+ uint32_t *fw; /* this where image is read to */
+ uint32_t hwrev; /* H/W revision. ex: A0, A1 */
+ uint32_t fw_sz; /* FW image size */
+ uint32_t sector_sz; /* FW sector size */
+ uint32_t device_sz; /* FW device size */
+ uint32_t state;
+ uint64_t ibguids[4]; /* HW's GUIDs backup info */
+ uint64_t ib_mac[2]; /* HW's MAC backup info */
+ uint32_t log2_chunk_sz; /* FW chunk size */
+ uint32_t img2_start_addr; /* Boot Address, 0 - Pri */
+} ib_cnx_encap_ident_t;
+
+/*
+ * Common Flash Interface data.
+ */
+typedef union cfi_u {
+ uchar_t cfi_char[HERMON_CFI_INFO_SIZE];
+ uint32_t cfi_int[HERMON_CFI_INFO_QSIZE];
+} cfi_t;
+
+/* used by both identify and verifier plugin */
+uint16_t cnx_crc16(uint8_t *image, uint32_t size, int is_image);
+int cnx_is_magic_pattern_present(int *data, int hwim_or_fwim);
+int cnx_parse_img_info(int *buf, uint32_t byte_size, cnx_img_info_t *img_info,
+ int is_image);
+
+#define CNX_FILE_IMG 1 /* Processing File Image */
+#define CNX_HW_IMG 2 /* Processing Hardware Image */
+
+/* Validate the handle */
+#define CNX_I_CHECK_HANDLE(s) \
+ ((s == NULL) || ((s)->magic != FWFLASH_IB_MAGIC_NUMBER))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _HDRS_HERMON_IB_H */
diff --git a/usr/src/cmd/fwflash/plugins/hdrs/tavor_ib.h b/usr/src/cmd/fwflash/plugins/hdrs/tavor_ib.h
new file mode 100644
index 0000000000..e2445163c9
--- /dev/null
+++ b/usr/src/cmd/fwflash/plugins/hdrs/tavor_ib.h
@@ -0,0 +1,226 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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.
+ */
+
+#ifndef _TAVOR_IB_H
+#define _TAVOR_IB_H
+
+/*
+ * tavor_ib.h
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include <sys/ib/adapters/tavor/tavor_ioctl.h>
+
+#define FWFLASH_IB_DRIVER_NAME "tavor"
+
+#define NODE_GUID_OFFSET 0x0
+#define PORT1_GUID_OFFSET 0x08
+#define PORT2_GUID_OFFSET 0x10
+#define FLASH_SIZE_OFFSET 0x20
+#define FLASH_GUID_PTR 0x24
+
+typedef struct fw_rev_s {
+ uint32_t major;
+ uint32_t minor;
+ uint32_t subminor;
+ uint32_t holder;
+} fw_rev_t;
+
+
+typedef struct mlx_is {
+ uint8_t isresv1[16];
+ uint8_t hwrev; /* hardware version */
+ uint8_t isver; /* Invariant Sector version */
+ uint32_t isresv2;
+ /* offset from 0x32 to get log2sectsz */
+ uint16_t log2sectszp;
+ /*
+ * 3rd lot of reserved bytes CAN BE variable length,
+ * but defaults to 0x18 bytes
+ */
+ uint8_t isresv3[0x18];
+ uint16_t log2sectsz; /* log_2 of flash sector size */
+ uint8_t *isresv4; /* remainder of IS */
+} mlx_is_t;
+
+typedef struct mlx_xps {
+ uint32_t fia; /* fw image addr */
+ uint32_t fis; /* fw image size */
+ uint32_t signature; /* firmware signature */
+ uint8_t xpsresv1[20];
+ uint8_t vsdpsid[224]; /* VSD and PSID */
+ uint32_t xpsresv2;
+ uint16_t xpsresv3; /* MUST be zero */
+ uint16_t crc16;
+ uint8_t *xpsresv4; /* from 0x108 to END OF SECTOR */
+} mlx_xps_t;
+
+
+#define XFI_IMGINFO_OFFSET 28
+#define XFI_IMGINFO_CKSUM_MASK 0xFF000000
+#define XFI_IMGINFO_PTR_MASK 0x00FFFFFF
+
+typedef struct mlx_xfi {
+ uint8_t xfiresv1[28];
+ uint32_t imageinfoptr;
+ uint32_t xfiresv2;
+ uint32_t nguidptr;
+ uint8_t *xfiremainder;
+} mlx_xfi_t;
+
+/*
+ * Of all the structures we poke around with, we're packing
+ * these because we frequently have to operate on them as
+ * plain old byte arrays. If we don't pack it then the compiler
+ * will "properly" align it for us - which results in a
+ * structure that's a l l s p r e a d o u t.
+ */
+#pragma pack(1)
+typedef struct mlx_guid_sect
+{
+ uint8_t guidresv[16];
+ uint64_t nodeguid;
+ uint64_t port1guid;
+ uint64_t port2guid;
+ uint64_t sysimguid;
+ uint16_t guidresv2;
+ uint16_t guidcrc;
+} mlx_guid_sect_t;
+#pragma pack()
+
+/* this is 13x 32bit words */
+#define GUIDSECTION_SZ sizeof (struct mlx_guid_sect)
+
+/* we hook this struct into vpr->encap_ident */
+typedef struct ib_encap_ident {
+ uint_t magic;
+ int fd;
+ fw_rev_t fw_rev;
+ uint32_t hwrev;
+ uint32_t sector_sz;
+ uint32_t device_sz;
+ uint32_t state;
+ int cmd_set;
+ mlx_mdr_t info;
+ int pn_len;
+ int hwfw_match;
+ uint32_t pfi_guid_addr; /* addr of the offset */
+ uint32_t sfi_guid_addr;
+ uint32_t pri_guid_section[GUIDSECTION_SZ];
+ uint32_t sec_guid_section[GUIDSECTION_SZ];
+ uint64_t ibguids[4];
+ uint8_t *inv; /* Invariant Sector */
+ uint8_t *pps; /* Primary Pointer Sector */
+ uint8_t *sps; /* Secondary Pointer Sector */
+ uint8_t *pfi; /* Primary Firmware Image */
+ uint8_t *sfi; /* Secondary Firmware Image */
+ uint8_t mlx_psid[16];
+ uint8_t mlx_vsd[208];
+} ib_encap_ident_t;
+
+#define FLASH_PS_SIGNATURE 0x5a445a44
+
+#define FLASH_IS_SECTOR_SIZE_OFFSET 0x32
+#define FLASH_IS_SECTOR_SIZE_MASK 0x0000FFFF
+#define FLASH_IS_HWVER_OFFSET 0x10
+#define FLASH_IS_HWVER_MASK 0xFF000000
+#define FLASH_IS_ISVER_MASK 0x00FF0000
+
+#define FLASH_IS_SECT_SIZE_PTR 0x16
+#define FLASH_IS_SECT_SIZE_PTR_MASK 0x0000FFFF
+
+#define FLASH_PS_FI_ADDR_OFFSET 0x00
+#define FLASH_PS_FW_SIZE_OFFSET 0x04
+#define FLASH_PS_SIGNATURE_OFFSET 0x08
+/* Vendor Specific Data (VSD) */
+#define FLASH_PS_VSD_OFFSET 0x20
+/* VSD length in bytes */
+#define FLASH_PS_VSD_LENGTH 0xE0
+#define FLASH_PS_VSD_LENGTH_4 0x38
+/* PSID is the last 16B of VSD */
+#define FLASH_PS_PSID_OFFSET 0xF0
+
+/* For use with Cisco's VSD */
+#define FLASH_VSD_CISCO_SIGNATURE 0x05ad
+#define FLASH_VSD_CISCO_BOOT_OPTIONS 0x00000004
+#define FLASH_VSD_CISCO_FLAG_AUTOUPGRADE 0x01000000
+#define FLASH_VSD_CISCO_FLAG_BOOT_ENABLE_PORT_1 0x00010000
+#define FLASH_VSD_CISCO_FLAG_BOOT_ENABLE_PORT_2 0x00020000
+#define FLASH_VSD_CISCO_FLAG_BOOT_ENABLE_SCAN 0x00040000
+#define FLASH_VSD_CISCO_FLAG_BOOT_TYPE_WELL_KNOWN 0x00000000
+#define FLASH_VSD_CISCO_FLAG_BOOT_TRY_FOREVER 0x00001000
+#define FLASH_VSD_CISCO_BOOT_VERSION 2
+/* For use with Cisco's VSD */
+
+#define MLX_CISCO_CHECK 1
+#define MLX_CISCO_SET 2
+
+#define FLASH_PS_CRC16_SIZE 0x104
+#define FLASH_PS_CRC16_OFFSET 0x106
+
+#define FLASH_FI_NGUID_OFFSET 0x0
+#define FLASH_FI_P1GUID_OFFSET 0x08
+#define FLASH_FI_P2GUID_OFFSET 0x10
+#define FLASH_FI_SYSIMGUID_OFFSET 0x18
+#define FLASH_GUID_CRC16_SIZE 0x30
+#define FLASH_GUID_CRC16_OFFSET 0x32
+#define FLASH_GUID_SIZE 0x34
+
+#define FLASH_GUID_CRC_LEN 0x2F
+/*
+ * Used during read/write ioctl calls to setup the offset into the firmware
+ * image memory for that particular sector.
+ */
+#define FLASH_SECTOR_OFFSET(fw, sect, sz) \
+ (caddr_t)((uintptr_t)fw + (sect << sz))
+
+/*
+ * Vital System Data from PCI config space.
+ */
+uint32_t vsd_int[FLASH_PS_VSD_LENGTH_4];
+
+
+/*
+ * Common Flash Interface data.
+ */
+typedef union cfi_u {
+ uchar_t cfi_char[TAVOR_CFI_INFO_SIZE];
+ uint32_t cfi_int[TAVOR_CFI_INFO_QSIZE];
+} cfi_t;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+
+
+
+#endif /* _TAVOR_IB_H */
diff --git a/usr/src/cmd/fwflash/plugins/i386/Makefile b/usr/src/cmd/fwflash/plugins/i386/Makefile
new file mode 100644
index 0000000000..068a041c0d
--- /dev/null
+++ b/usr/src/cmd/fwflash/plugins/i386/Makefile
@@ -0,0 +1,94 @@
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/fwflash/plugins/i386
+#
+
+SRCS= tavor-MELLANOX.c hermon-MELLANOX.c
+OBJECTS= $(SRCS:%.c=%.o)
+PLUGINS= $(SRCS:%.c=%.so)
+POFILES= $(SRCS:%.c=%.po)
+LINTFILE= $(SRCS:%.c=%.ln)
+
+VERIFYPOFILE= fwflash_verify_msg.po
+
+CLOBBERFILES= $(PLUGINS) $(OBJECTS) $(LINTFILE) \
+ $(POFILES) $(VERIFYPOFILE)
+TEXT_DOMAIN= SUNW_OST_OSCMD
+
+all: $(PLUGINS)
+
+
+include $(SRC)/Makefile.master
+include $(SRC)/cmd/fwflash/Makefile.com
+
+
+CFLAGS += -g -D_POSIX_PTHREAD_SEMANTICS -I$(ROOT)/usr/include
+MANUFACTURING_MODE=0
+CFLAGS += -DMANUFACTURING_MODE=$(MANUFACTURING_MODE)
+LDLIBS += -ldevinfo -lumem -lc
+DYNFLAGS += -Bdynamic
+LIBS= $(DYNLIB)
+
+BUILD.SO= $(LD) -o $@ -G $(DYNFLAGS)
+
+%.o: ../vendor/%.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
+%.so: %.o
+ $(BUILD.SO) $<
+ $(POST_PROCESS)
+
+%.ln: ../vendor/%.c
+ $(LINT.c) $(LINTFLAGS) -c $<
+
+%.po: ../vendor/%.c
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) \
+ `($(GREP) -l gettext $< || echo /dev/null)`
+ $(SED) "/^domain/d" messages.po > $@
+ $(RM) messages.po
+
+#
+# Message catalog
+#
+
+$(VERIFYPOFILE): $(POFILES)
+ $(RM) $@
+ cat $(POFILES) > $@
+
+install: $(ROOTLIBFWFLASHVERIFY) \
+ $(ROOTLIBFWFLASHVERIFY)/tavor-MELLANOX.so \
+ $(ROOTLIBFWFLASHVERIFY)/hermon-MELLANOX.so
+
+clean:
+ $(RM) $(OBJECTS)
+
+clobber: clean
+ $(RM) $(CLOBBERFILES)
+
+lint: lint_SRCS
+lint_SRCS: $(LINTFILE)
+
+_msg msg: $(VERIFYPOFILE)
diff --git a/usr/src/cmd/fwflash/plugins/sparc/Makefile b/usr/src/cmd/fwflash/plugins/sparc/Makefile
new file mode 100644
index 0000000000..d5ca244954
--- /dev/null
+++ b/usr/src/cmd/fwflash/plugins/sparc/Makefile
@@ -0,0 +1,94 @@
+#
+# 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
+# or http://www.opensolaris.org/os/licensing.
+# 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 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# cmd/fwflash/plugins/sparc
+#
+
+SRCS= tavor-MELLANOX.c hermon-MELLANOX.c
+OBJECTS= $(SRCS:%.c=%.o)
+PLUGINS= $(SRCS:%.c=%.so)
+POFILES= $(SRCS:%.c=%.po)
+LINTFILE= $(SRCS:%.c=%.ln)
+
+VERIFYPOFILE= fwflash_verify_msg.po
+
+CLOBBERFILES= $(PLUGINS) $(OBJECTS) $(LINTFILE) \
+ $(POFILES) $(VERIFYPOFILE)
+TEXT_DOMAIN= SUNW_OST_OSCMD
+
+all: $(PLUGINS)
+
+
+include $(SRC)/Makefile.master
+include $(SRC)/cmd/fwflash/Makefile.com
+
+
+CFLAGS += -g -D_POSIX_PTHREAD_SEMANTICS -I$(ROOT)/usr/include
+MANUFACTURING_MODE=0
+CFLAGS += -DMANUFACTURING_MODE=$(MANUFACTURING_MODE)
+LDLIBS += -ldevinfo -lumem -lc
+DYNFLAGS += -Bdynamic
+LIBS= $(DYNLIB)
+
+BUILD.SO= $(LD) -o $@ -G $(DYNFLAGS)
+
+%.o: ../vendor/%.c
+ $(COMPILE.c) $<
+ $(POST_PROCESS_O)
+
+%.so: %.o
+ $(BUILD.SO) $<
+ $(POST_PROCESS)
+
+%.ln: ../vendor/%.c
+ $(LINT.c) $(LINTFLAGS) -c $<
+
+%.po: ../vendor/%.c
+ $(RM) messages.po
+ $(XGETTEXT) $(XGETFLAGS) \
+ `($(GREP) -l gettext $< || echo /dev/null)`
+ $(SED) "/^domain/d" messages.po > $@
+ $(RM) messages.po
+
+#
+# Message catalog
+#
+
+$(VERIFYPOFILE): $(POFILES)
+ $(RM) $@
+ cat $(POFILES) > $@
+
+install: $(ROOTLIBFWFLASHVERIFY) \
+ $(ROOTLIBFWFLASHVERIFY)/tavor-MELLANOX.so \
+ $(ROOTLIBFWFLASHVERIFY)/hermon-MELLANOX.so
+
+clean:
+ $(RM) $(OBJECTS)
+
+clobber: clean
+ $(RM) $(CLOBBERFILES)
+
+lint: lint_SRCS
+lint_SRCS: $(LINTFILE)
+
+_msg msg: $(VERIFYPOFILE)
diff --git a/usr/src/cmd/fwflash/plugins/transport/common/hermon.c b/usr/src/cmd/fwflash/plugins/transport/common/hermon.c
new file mode 100644
index 0000000000..d9394640be
--- /dev/null
+++ b/usr/src/cmd/fwflash/plugins/transport/common/hermon.c
@@ -0,0 +1,1885 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * The reference for the functions in this file is the
+ *
+ * Mellanox HCA Flash Programming Application Note
+ * (Mellanox document number 2205AN) rev 1.45, 2007.
+ * Chapter 4 in particular.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <sys/queue.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+
+#include <sys/byteorder.h>
+
+#include <libintl.h> /* for gettext(3c) */
+
+#include <fwflash/fwflash.h>
+#include "../../hdrs/hermon_ib.h"
+
+char *devprefix = "/devices";
+char drivername[] = "hermon\0";
+char *devsuffix = ":devctl";
+
+extern di_node_t rootnode;
+extern int errno;
+extern struct fw_plugin *self;
+extern struct vrfyplugin *verifier;
+extern int fwflash_debug;
+
+/* required functions for this plugin */
+int fw_readfw(struct devicelist *device, char *filename);
+int fw_writefw(struct devicelist *device);
+int fw_identify(int start);
+int fw_devinfo();
+
+
+/* helper functions */
+static int cnx_identify(struct devicelist *thisdev);
+static int cnx_get_guids(ib_cnx_encap_ident_t *handle);
+static int cnx_close(struct devicelist *flashdev);
+static int cnx_check_for_magic_pattern(ib_cnx_encap_ident_t *hdl, uint32_t adr);
+static uint32_t cnx_get_log2_chunk_size_f_hdl(ib_cnx_encap_ident_t *handle,
+ int type);
+static uint32_t cnx_get_log2_chunk_size(uint32_t chunk_size_word);
+static uint32_t cnx_cont2phys(uint32_t log2_chunk_sz, uint32_t cont_addr,
+ int type);
+static uint32_t cnx_get_image_size_f_hdl(ib_cnx_encap_ident_t *hdl, int type);
+static void cnx_local_set_guid_crc_img(uint32_t offset, uint32_t guid_crc_size,
+ uint32_t guid_crc_offset);
+static int cnx_read_image(ib_cnx_encap_ident_t *handle);
+static int cnx_write_file(ib_cnx_encap_ident_t *handle, const char *filename);
+static int cnx_verify_image(ib_cnx_encap_ident_t *handle, int type);
+static int cnx_read_guids(ib_cnx_encap_ident_t *handle, int type);
+static int cnx_set_guids(ib_cnx_encap_ident_t *handle, void *arg);
+static int cnx_write_image(ib_cnx_encap_ident_t *handle, int type);
+static int cnx_read_ioctl(ib_cnx_encap_ident_t *hdl,
+ hermon_flash_ioctl_t *info);
+static int cnx_write_ioctl(ib_cnx_encap_ident_t *hdl,
+ hermon_flash_ioctl_t *info);
+static int cnx_erase_sector_ioctl(ib_cnx_encap_ident_t *hdl,
+ hermon_flash_ioctl_t *info);
+static int cnx_find_magic_n_chnk_sz(ib_cnx_encap_ident_t *handle, int type);
+static int cnx_get_image_info(ib_cnx_encap_ident_t *handle);
+
+
+int
+fw_readfw(struct devicelist *flashdev, char *filename)
+{
+ ib_cnx_encap_ident_t *manuf;
+ int rv = FWFLASH_SUCCESS;
+
+ logmsg(MSG_INFO, "hermon: fw_readfw: filename %s\n", filename);
+
+ manuf = (ib_cnx_encap_ident_t *)flashdev->ident->encap_ident;
+ if (CNX_I_CHECK_HANDLE(manuf)) {
+ logmsg(MSG_ERROR, gettext("hermon: Invalid Handle for "
+ "device %s! \n"), flashdev->access_devname);
+ return (FWFLASH_FAILURE);
+ }
+
+ logmsg(MSG_INFO, "hermon: fw_identify should have read the image. "
+ "state 0x%x\n", manuf->state);
+
+ rv = cnx_read_image(manuf);
+ if (rv != FWFLASH_SUCCESS) {
+ logmsg(MSG_ERROR, gettext("hermon: Failed to read any valid "
+ "image on device (%s)\n"), flashdev->access_devname);
+ logmsg(MSG_ERROR, gettext("Aborting read.\n"));
+ } else {
+ rv = cnx_write_file(manuf, filename);
+ }
+
+ cnx_close(flashdev);
+ return (rv);
+}
+
+
+/*
+ * 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
+fw_writefw(struct devicelist *flashdev)
+{
+ ib_cnx_encap_ident_t *manuf;
+ int i, j, k;
+
+ logmsg(MSG_INFO, "hermon: fw_writefw\n");
+
+ manuf = (ib_cnx_encap_ident_t *)flashdev->ident->encap_ident;
+
+ if (CNX_I_CHECK_HANDLE(manuf)) {
+ logmsg(MSG_ERROR, gettext("hermon: Invalid Handle for "
+ "device %s! \n"), flashdev->access_devname);
+ return (FWFLASH_FAILURE);
+ }
+
+ /*
+ * Try the primary first, then the secondary.
+ * 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().
+ */
+ if (manuf->pn_len == 0) {
+ int resp;
+
+ (void) fprintf(stderr, gettext("Unable to completely verify "
+ "that this firmware image (%s) is compatible with your "
+ "HCA %s"), verifier->imgfile, flashdev->access_devname);
+ (void) fprintf(stderr, gettext("Do you really want to "
+ "continue? (Y/N): "));
+ (void) fflush(stdin);
+ resp = getchar();
+ if (resp != 'Y' && resp != 'y') {
+ (void) fprintf(stderr, gettext("Not proceeding with "
+ "flash operation of %s on %s"),
+ verifier->imgfile, flashdev->access_devname);
+ return (FWFLASH_FAILURE);
+ }
+ }
+
+ logmsg(MSG_INFO, "hermon: fw_writefw: Using Existing GUIDs.\n");
+ manuf->state |=
+ FWFLASH_IB_STATE_GUIDN |
+ FWFLASH_IB_STATE_GUID1 |
+ FWFLASH_IB_STATE_GUID2 |
+ FWFLASH_IB_STATE_GUIDS;
+ if (cnx_set_guids(manuf, manuf->ibguids) != FWFLASH_SUCCESS) {
+ logmsg(MSG_WARN, gettext("hermon: Failed to set GUIDs"));
+ }
+
+ /*
+ * Update both Primary and Secondary images
+ *
+ * For Failsafe firmware image update, if the current image (i.e.
+ * containing a magic pattern) on the Flash is stored on the Primary
+ * location, burn the new image to the Secondary location first,
+ * or vice versa.
+ */
+
+ /* Note Current Image location. */
+ j = manuf->state &
+ (FWFLASH_IB_STATE_IMAGE_PRI | FWFLASH_IB_STATE_IMAGE_SEC);
+
+ /*
+ * If we find that current image location is not found, no worries
+ * we shall default to PRIMARY, and proceed with burning anyway.
+ */
+ if (j == 0)
+ j = FWFLASH_IB_STATE_IMAGE_PRI;
+
+ for (i = FWFLASH_FLASH_IMAGES; i > 0; i--) {
+ char *type;
+
+ if (i == 2) {
+ if (j == 2)
+ k = 1; /* Burn PRI First */
+ else
+ k = 2; /* Burn SEC First */
+ } else {
+ if (k == 2)
+ k = 1; /* Burn PRI next */
+ else
+ k = 2; /* Burn SEC next */
+ }
+ type = ((k == 1) ? "Primary" : "Secondary");
+
+ logmsg(MSG_INFO, "hermon: fw_write: UPDATING %s image\n", type);
+
+ if (cnx_write_image(manuf, k) != FWFLASH_SUCCESS) {
+ (void) fprintf(stderr,
+ gettext("Failed to update %s image on device %s"),
+ type, flashdev->access_devname);
+ goto out;
+ }
+
+ logmsg(MSG_INFO, "hermon: fw_write: Verify %s image..\n", type);
+ if (cnx_verify_image(manuf, k) != FWFLASH_SUCCESS) {
+ (void) fprintf(stderr,
+ gettext("Failed to verify %s image for device %s"),
+ type, flashdev->access_devname);
+ goto out;
+ }
+ }
+out:
+ /* final update marker to the user */
+ (void) printf(" +\n");
+ return (cnx_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;
+ di_node_t thisnode;
+ struct devicelist *newdev;
+ char *devpath;
+ int idx = start;
+ int devlength = 0;
+
+ logmsg(MSG_INFO, "hermon: fw_identify\n");
+ thisnode = di_drv_first_node(drivername, rootnode);
+
+ if (thisnode == DI_NODE_NIL) {
+ logmsg(MSG_INFO, gettext("No %s nodes in this system\n"),
+ drivername);
+ return (rv);
+ }
+
+ /* we've found one, at least */
+ for (; thisnode != DI_NODE_NIL; thisnode = di_drv_next_node(thisnode)) {
+
+ devpath = di_devfs_path(thisnode);
+
+ if ((newdev = calloc(1, sizeof (struct devicelist))) == NULL) {
+ logmsg(MSG_ERROR, gettext("hermon: Unable to allocate "
+ "space for device entry\n"));
+ di_devfs_path_free(devpath);
+ return (FWFLASH_FAILURE);
+ }
+
+ /* calloc enough for /devices + devpath + ":devctl" + '\0' */
+ devlength = strlen(devpath) + strlen(devprefix) +
+ strlen(devsuffix) + 2;
+
+ if ((newdev->access_devname = calloc(1, devlength)) == NULL) {
+ logmsg(MSG_ERROR, gettext("hermon: Unable to allocate "
+ "space for a devfs name\n"));
+ (void) free(newdev);
+ di_devfs_path_free(devpath);
+ return (FWFLASH_FAILURE);
+ }
+ snprintf(newdev->access_devname, devlength,
+ "%s%s%s", devprefix, devpath, devsuffix);
+
+ if ((newdev->ident = calloc(1, sizeof (struct vpr))) == NULL) {
+ logmsg(MSG_ERROR, gettext("hermon: Unable to allocate "
+ "space for a device identification record\n"));
+ (void) free(newdev->access_devname);
+ (void) free(newdev);
+ di_devfs_path_free(devpath);
+ return (FWFLASH_FAILURE);
+ }
+
+ /* CHECK VARIOUS IB THINGS HERE */
+ rv = cnx_identify(newdev);
+ if (rv == FWFLASH_FAILURE) {
+ (void) free(newdev->ident);
+ (void) free(newdev->access_devname);
+ (void) free(newdev);
+ di_devfs_path_free(devpath);
+ continue;
+ }
+
+ if ((newdev->drvname = calloc(1, strlen(drivername) + 1))
+ == NULL) {
+ logmsg(MSG_ERROR, gettext("hermon: Unable to allocate"
+ " space for a driver name\n"));
+ (void) free(newdev->ident);
+ (void) free(newdev->access_devname);
+ (void) free(newdev);
+ di_devfs_path_free(devpath);
+ return (FWFLASH_FAILURE);
+ }
+
+ (void) strlcpy(newdev->drvname, drivername,
+ strlen(drivername) + 1);
+
+ /* this next bit is backwards compatibility - "IB\0" */
+ if ((newdev->classname = calloc(1, 3)) == NULL) {
+ logmsg(MSG_ERROR, gettext("hermon: Unable to allocate "
+ "space for a class name\n"));
+ (void) free(newdev->drvname);
+ (void) free(newdev->ident);
+ (void) free(newdev->access_devname);
+ (void) free(newdev);
+ di_devfs_path_free(devpath);
+ return (FWFLASH_FAILURE);
+ }
+ (void) strlcpy(newdev->classname, "IB", 3);
+
+ newdev->index = idx;
+ ++idx;
+ newdev->plugin = self;
+
+ di_devfs_path_free(devpath);
+
+ TAILQ_INSERT_TAIL(fw_devices, newdev, nextdev);
+ }
+
+ if (fwflash_debug != 0) {
+ struct devicelist *tempdev;
+
+ TAILQ_FOREACH(tempdev, fw_devices, nextdev) {
+ logmsg(MSG_INFO, "fw_identify: hermon:\n");
+ logmsg(MSG_INFO, "\ttempdev @ 0x%lx\n"
+ "\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,
+ tempdev->access_devname,
+ tempdev->drvname, newdev->classname,
+ tempdev->ident->vid,
+ tempdev->ident->pid,
+ tempdev->ident->revid,
+ tempdev->index,
+ tempdev->addresses[0],
+ tempdev->addresses[1],
+ tempdev->addresses[2],
+ tempdev->addresses[3],
+ tempdev->plugin);
+ }
+ }
+
+ return (FWFLASH_SUCCESS);
+}
+
+
+int
+fw_devinfo(struct devicelist *thisdev)
+{
+ ib_cnx_encap_ident_t *encap;
+
+ logmsg(MSG_INFO, "hermon: fw_devinfo\n");
+
+ encap = (ib_cnx_encap_ident_t *)thisdev->ident->encap_ident;
+ if (CNX_I_CHECK_HANDLE(encap)) {
+ logmsg(MSG_ERROR, gettext("hermon: fw_devinfo: Invalid handle "
+ "for device %s! \n"), thisdev->access_devname);
+ return (FWFLASH_FAILURE);
+ }
+
+ /* Try the primary first, then the secondary */
+ fprintf(stdout, gettext("Device[%d] %s\n"),
+ thisdev->index, thisdev->access_devname);
+ fprintf(stdout, gettext("Class [%s]\n"), thisdev->classname);
+
+ fprintf(stdout, "\t");
+
+ /* Mellanox HCA Flash app note, p40, #4.2.3 table 9 */
+ fprintf(stdout, gettext("GUID: System Image - %s\n"),
+ thisdev->addresses[3]);
+ fprintf(stdout, gettext("\t\tNode Image - %s\n"),
+ thisdev->addresses[0]);
+ fprintf(stdout, gettext("\t\tPort 1\t - %s\n"),
+ thisdev->addresses[1]);
+ fprintf(stdout, gettext("\t\tPort 2\t - %s\n"),
+ thisdev->addresses[2]);
+
+ fprintf(stdout, gettext("\tFirmware revision : %s\n"),
+ thisdev->ident->revid);
+
+ if (encap->pn_len != 0) {
+ if (strlen(encap->info.mlx_id))
+ fprintf(stdout, gettext("\tProduct\t\t : %s (%s)\n"),
+ encap->info.mlx_pn, encap->info.mlx_id);
+ else
+ fprintf(stdout, gettext("\tProduct\t\t : %s \n"),
+ encap->info.mlx_pn);
+
+ if (strlen(encap->info.mlx_psid))
+ fprintf(stdout, gettext("\tPSID\t\t : %s\n"),
+ encap->info.mlx_psid);
+ else if (strlen(thisdev->ident->pid))
+ fprintf(stdout, gettext("\t%s\n"), thisdev->ident->pid);
+ } else {
+ fprintf(stdout, gettext("\t%s\n"), thisdev->ident->pid);
+ }
+ fprintf(stdout, "\n\n");
+
+ return (cnx_close(thisdev));
+}
+
+
+/*
+ * Helper functions lurk beneath this point
+ */
+
+
+/*
+ * 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.
+ */
+
+static int
+cnx_read_image(ib_cnx_encap_ident_t *handle)
+{
+ hermon_flash_ioctl_t ioctl_info;
+ uint32_t phys_addr;
+ int ret, i;
+ int image_size;
+ int type;
+
+ type = handle->state &
+ (FWFLASH_IB_STATE_IMAGE_PRI | FWFLASH_IB_STATE_IMAGE_SEC);
+ logmsg(MSG_INFO, "cnx_read_image: type %lx\n", type);
+
+ if (type == 0) {
+ logmsg(MSG_ERROR, gettext("cnx_read_image: Must read in "
+ "image first\n"));
+ return (FWFLASH_FAILURE);
+ }
+
+ image_size = handle->fw_sz;
+ if (image_size <= 0) {
+ logmsg(MSG_ERROR, gettext("cnx_read_image: Invalid image size "
+ "0x%x for %s image\n"),
+ image_size, (type == 0x1 ? "Primary" : "Secondary"));
+ return (FWFLASH_FAILURE);
+ }
+
+ logmsg(MSG_INFO, "hermon: fw_size: 0x%x\n", image_size);
+
+ handle->fw = (uint32_t *)calloc(1, image_size);
+ if (handle->fw == NULL) {
+ logmsg(MSG_ERROR, gettext("cnx_read_image: Unable to allocate "
+ "memory for fw_img : (%s)\n"), strerror(errno));
+ return (FWFLASH_FAILURE);
+ }
+
+ ioctl_info.af_type = HERMON_FLASH_READ_QUADLET;
+ for (i = 0; i < image_size; i += 4) {
+ phys_addr = cnx_cont2phys(handle->log2_chunk_sz, i, type);
+ ioctl_info.af_addr = phys_addr;
+
+ ret = cnx_read_ioctl(handle, &ioctl_info);
+ if (ret != 0) {
+ logmsg(MSG_ERROR, gettext("cnx_read_image: Failed to "
+ "read sector %d\n"), i);
+ free(handle->fw);
+ return (FWFLASH_FAILURE);
+ }
+ handle->fw[i / 4] = htonl(ioctl_info.af_quadlet);
+ }
+
+ for (i = 0; i < image_size; i += 4) {
+ logmsg(MSG_INFO, "cnx_read_image: addr[0x%x] = 0x%08x\n", i,
+ ntohl(handle->fw[i / 4]));
+ }
+
+ return (FWFLASH_SUCCESS);
+}
+
+static int
+cnx_write_file(ib_cnx_encap_ident_t *handle, const char *filename)
+{
+ FILE *fp;
+ int fd;
+ mode_t mode = S_IRUSR | S_IWUSR;
+ int len;
+
+ logmsg(MSG_INFO, "cnx_write_file\n");
+
+ errno = 0;
+ if ((fd = open(filename, O_RDWR|O_CREAT|O_DSYNC, mode)) < 0) {
+ logmsg(MSG_ERROR, gettext("hermon: Unable to open specified "
+ "file (%s) for writing: %s\n"), filename, strerror(errno));
+ return (FWFLASH_FAILURE);
+ }
+
+ errno = 0;
+ fp = fdopen(fd, "w");
+ if (fp == NULL) {
+ (void) fprintf(stderr, gettext("hermon: Unknown filename %s : "
+ "%s\n"), filename, strerror(errno));
+ return (FWFLASH_FAILURE);
+ }
+
+ len = ntohl(handle->fw[CNX_IMG_SIZE_OFFSET / 4]);
+ logmsg(MSG_INFO, "cnx_write_file: Writing to file. Length 0x%x\n", len);
+
+ if (fwrite(&handle->fw[0], len, 1, fp) == 0) {
+ (void) fprintf(stderr, gettext("hermon: fwrite failed"));
+ perror("fwrite");
+ (void) fclose(fp);
+ return (FWFLASH_FAILURE);
+ }
+ (void) fclose(fp);
+ return (FWFLASH_SUCCESS);
+}
+
+static int
+cnx_verify_image(ib_cnx_encap_ident_t *handle, int type)
+{
+ uint32_t new_start_addr;
+
+ logmsg(MSG_INFO, "hermon: cnx_verify_image\n");
+
+ new_start_addr = cnx_cont2phys(handle->log2_chunk_sz, 0, type);
+
+ return (cnx_check_for_magic_pattern(handle, new_start_addr));
+}
+
+static int
+cnx_set_guids(ib_cnx_encap_ident_t *handle, void *arg)
+{
+ uint32_t addr;
+ uint32_t *guids;
+
+ logmsg(MSG_INFO, "hermon: cnx_set_guids\n");
+
+ guids = (uint32_t *)arg;
+ addr = ntohl(verifier->fwimage[CNX_NGUIDPTR_OFFSET / 4]) / 4;
+ logmsg(MSG_INFO, "cnx_set_guids: guid_start_addr: 0x%x\n", addr * 4);
+
+ /*
+ * guids are supplied by callers as 64 bit values in host byteorder.
+ * Storage is in network byteorder.
+ */
+#ifdef _BIG_ENDIAN
+ if (handle->state & FWFLASH_IB_STATE_GUIDN) {
+ verifier->fwimage[addr] = guids[0];
+ verifier->fwimage[addr + 1] = guids[1];
+ }
+
+ if (handle->state & FWFLASH_IB_STATE_GUID1) {
+ verifier->fwimage[addr + 2] = guids[2];
+ verifier->fwimage[addr + 3] = guids[3];
+ }
+
+ if (handle->state & FWFLASH_IB_STATE_GUID2) {
+ verifier->fwimage[addr + 4] = guids[4];
+ verifier->fwimage[addr + 5] = guids[5];
+ }
+
+ if (handle->state & FWFLASH_IB_STATE_GUIDS) {
+ verifier->fwimage[addr + 6] = guids[6];
+ verifier->fwimage[addr + 7] = guids[7];
+ }
+#else
+ if (handle->state & FWFLASH_IB_STATE_GUIDN) {
+ verifier->fwimage[addr] = htonl(guids[1]);
+ verifier->fwimage[addr + 1] = htonl(guids[0]);
+ }
+
+ if (handle->state & FWFLASH_IB_STATE_GUID1) {
+ verifier->fwimage[addr + 2] = htonl(guids[3]);
+ verifier->fwimage[addr + 3] = htonl(guids[2]);
+ }
+
+ if (handle->state & FWFLASH_IB_STATE_GUID2) {
+ verifier->fwimage[addr + 4] = htonl(guids[5]);
+ verifier->fwimage[addr + 5] = htonl(guids[4]);
+ }
+
+ if (handle->state & FWFLASH_IB_STATE_GUIDS) {
+ verifier->fwimage[addr + 6] = htonl(guids[7]);
+ verifier->fwimage[addr + 7] = htonl(guids[6]);
+ }
+#endif
+
+ cnx_local_set_guid_crc_img((addr * 4) - 0x10, CNX_GUID_CRC16_SIZE,
+ CNX_GUID_CRC16_OFFSET);
+
+ return (FWFLASH_SUCCESS);
+}
+
+/*
+ * Notes: Burn the image
+ *
+ * 1. Erase the entire sector where the new image is to be burned.
+ * 2. Burn the image WITHOUT the magic pattern. This marks the new image
+ * as invalid during the burn process. If the current image (i.e
+ * containing a magic pattern) on the Flash is stored on the even
+ * chunks (PRIMARY), burn the new image to the odd chunks (SECONDARY),
+ * or vice versa.
+ * 3. Burn the magic pattern at the beginning of the new image on the Flash.
+ * This will validate the new image.
+ * 4. Set the BootAddress register to its new location.
+ */
+static int
+cnx_write_image(ib_cnx_encap_ident_t *handle, int type)
+{
+ hermon_flash_ioctl_t ioctl_info;
+ int sector_size;
+ int size;
+ int i;
+ uint32_t new_start_addr;
+ uint32_t log2_chunk_sz;
+ uint8_t *fw;
+
+ logmsg(MSG_INFO, "hermon: cnx_write_image\n");
+
+ if (type == 0) {
+ logmsg(MSG_ERROR, gettext("cnx_write_image: Must inform us "
+ " where to write.\n"));
+ return (FWFLASH_FAILURE);
+ }
+
+ log2_chunk_sz = cnx_get_log2_chunk_size(
+ ntohl(verifier->fwimage[CNX_CHUNK_SIZE_OFFSET / 4]));
+
+ sector_size = handle->sector_sz;
+ new_start_addr = ((type - 1) << handle->log2_chunk_sz);
+
+ /* Read Image Size */
+ size = ntohl(verifier->fwimage[CNX_IMG_SIZE_OFFSET / 4]);
+ logmsg(MSG_INFO, "cnx_write_image: fw image size: 0x%x\n", size);
+
+ /* Sectors must be erased before they can be written to. */
+ ioctl_info.af_type = HERMON_FLASH_ERASE_SECTOR;
+ for (i = 0; i < size; i += sector_size) {
+ ioctl_info.af_sector_num =
+ cnx_cont2phys(log2_chunk_sz, i, type) / sector_size;
+ if (cnx_erase_sector_ioctl(handle, &ioctl_info) != 0) {
+ logmsg(MSG_ERROR, gettext("cnx_write_image: Failed to "
+ "erase sector 0x%x\n"), ioctl_info.af_sector_num);
+ return (FWFLASH_FAILURE);
+ }
+ }
+
+ fw = (uint8_t *)verifier->fwimage;
+ ioctl_info.af_type = HERMON_FLASH_WRITE_BYTE;
+
+ /* Write the new image without the magic pattern */
+ for (i = 16; i < size; i++) {
+ ioctl_info.af_byte = fw[i];
+ ioctl_info.af_addr = cnx_cont2phys(log2_chunk_sz, i, type);
+ if (cnx_write_ioctl(handle, &ioctl_info) != 0) {
+ logmsg(MSG_ERROR, gettext("cnx_write_image: Failed to "
+ "write byte 0x%x\n"), ioctl_info.af_byte);
+ return (FWFLASH_FAILURE);
+ }
+
+ if (i && !(i % handle->sector_sz)) {
+ (void) printf(" .");
+ (void) fflush((void *)NULL);
+ }
+ }
+
+ /* Validate the new image -- Write the magic pattern. */
+ for (i = 0; i < 16; i++) {
+ ioctl_info.af_byte = fw[i];
+ ioctl_info.af_addr = cnx_cont2phys(log2_chunk_sz, i, type);
+ if (cnx_write_ioctl(handle, &ioctl_info) != 0) {
+ logmsg(MSG_ERROR, gettext("cnx_write_image: Failed to "
+ "write magic pattern byte 0x%x\n"),
+ ioctl_info.af_byte);
+ return (FWFLASH_FAILURE);
+ }
+ }
+
+ /* Write new image start address to CR space */
+ errno = 0;
+ ioctl_info.af_addr = new_start_addr;
+ if (ioctl(handle->fd, HERMON_IOCTL_WRITE_BOOT_ADDR, &ioctl_info) != 0) {
+ logmsg(MSG_WARN, gettext("cnx_write_image: Failed to "
+ "update boot address register: %s\n"), strerror(errno));
+ }
+
+ return (FWFLASH_SUCCESS);
+}
+
+
+/*
+ * cnx_identify performs the following actions:
+ *
+ * allocates and assigns thisdev->vpr
+ *
+ * allocates space for the 4 GUIDs which each IB device must have
+ * queries the hermon driver for this device's GUIDs
+ *
+ * determines the hardware vendor, so that thisdev->vpr->vid
+ * can be set correctly
+ */
+static int
+cnx_identify(struct devicelist *thisdev)
+{
+ int fd, ret, i;
+ hermon_flash_init_ioctl_t init_ioctl;
+ ib_cnx_encap_ident_t *manuf;
+ cfi_t cfi;
+ int hw_psid_found = 0;
+
+ logmsg(MSG_INFO, "hermon: cnx_identify\n");
+ /* open the device */
+ /* hook thisdev->ident->encap_ident to ib_cnx_encap_ident_t */
+ /* check that all the bits are sane */
+ /* return success, if warranted */
+
+ errno = 0;
+ if ((fd = open(thisdev->access_devname, O_RDONLY)) < 0) {
+ logmsg(MSG_ERROR, gettext("hermon: Unable to open a %s-"
+ "attached device node: %s: %s\n"), drivername,
+ thisdev->access_devname, strerror(errno));
+ return (FWFLASH_FAILURE);
+ }
+
+ if ((manuf = calloc(1, sizeof (ib_cnx_encap_ident_t))) == NULL) {
+ logmsg(MSG_ERROR, gettext("hermon: Unable to allocate space "
+ "for a %s-attached handle structure\n"), drivername);
+ close(fd);
+ return (FWFLASH_FAILURE);
+ }
+ manuf->magic = FWFLASH_IB_MAGIC_NUMBER;
+ manuf->state = FWFLASH_IB_STATE_NONE;
+ manuf->fd = fd;
+ manuf->log2_chunk_sz = 0;
+
+ thisdev->ident->encap_ident = manuf;
+
+ /*
+ * Inform driver that this command supports the Intel Extended
+ * CFI command set.
+ */
+ cfi.cfi_char[0x10] = 'M';
+ cfi.cfi_char[0x11] = 'X';
+ cfi.cfi_char[0x12] = '2';
+ init_ioctl.af_cfi_info[0x4] = ntohl(cfi.cfi_int[0x4]);
+
+ errno = 0;
+ ret = ioctl(fd, HERMON_IOCTL_FLASH_INIT, &init_ioctl);
+ if (ret < 0) {
+ logmsg(MSG_ERROR, gettext("hermon: HERMON_IOCTL_FLASH_INIT "
+ "failed: %s\n"), strerror(errno));
+ close(fd);
+ free(manuf);
+ return (FWFLASH_FAILURE);
+ }
+
+ manuf->hwrev = init_ioctl.af_hwrev;
+ logmsg(MSG_INFO, "hermon: init_ioctl: hwrev: %x, fwver: %d.%d.%04d, "
+ "PN# Len %d\n", init_ioctl.af_hwrev, init_ioctl.af_fwrev.afi_maj,
+ init_ioctl.af_fwrev.afi_min, init_ioctl.af_fwrev.afi_sub,
+ init_ioctl.af_pn_len);
+
+ /*
+ * 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 < HERMON_FLASH_CFI_SIZE_QUADLET; i++) {
+ cfi.cfi_int[i] = ntohl(init_ioctl.af_cfi_info[i]);
+ }
+ manuf->cmd_set = cfi.cfi_char[0x13];
+
+ if (cfi.cfi_char[0x10] == 'Q' &&
+ cfi.cfi_char[0x11] == 'R' &&
+ cfi.cfi_char[0x12] == 'Y') {
+ /* make sure the cmd set is SPI */
+ if (manuf->cmd_set != HERMON_FLASH_SPI_CMDSET) {
+ logmsg(MSG_ERROR, gettext("hermon: Unsupported flash "
+ "device command set\n"));
+ goto identify_end;
+ }
+ /* set some defaults */
+ manuf->sector_sz = HERMON_FLASH_SECTOR_SZ_DEFAULT;
+ manuf->device_sz = HERMON_FLASH_DEVICE_SZ_DEFAULT;
+ } else if (manuf->cmd_set == HERMON_FLASH_SPI_CMDSET) {
+ manuf->sector_sz = HERMON_FLASH_SPI_SECTOR_SIZE;
+ manuf->device_sz = HERMON_FLASH_SPI_DEVICE_SIZE;
+ } else {
+ if (manuf->cmd_set != HERMON_FLASH_AMD_CMDSET &&
+ manuf->cmd_set != HERMON_FLASH_INTEL_CMDSET) {
+ logmsg(MSG_ERROR, gettext("hermon: Unknown flash "
+ "device command set %lx\n"), manuf->cmd_set);
+ goto identify_end;
+ }
+ /* read from the CFI data */
+ manuf->sector_sz = ((cfi.cfi_char[0x30] << 8) |
+ cfi.cfi_char[0x2F]) << 8;
+ manuf->device_sz = 0x1 << cfi.cfi_char[0x27];
+ }
+
+ logmsg(MSG_INFO, "hermon: sector_sz: 0x%08x device_sz: 0x%08x\n",
+ manuf->sector_sz, manuf->device_sz);
+
+ /* set firmware revision */
+ manuf->hwfw_img_info.fw_rev.major = init_ioctl.af_fwrev.afi_maj;
+ manuf->hwfw_img_info.fw_rev.minor = init_ioctl.af_fwrev.afi_min;
+ manuf->hwfw_img_info.fw_rev.subminor = init_ioctl.af_fwrev.afi_sub;
+
+ if (((thisdev->ident->vid = calloc(1, MLX_VPR_VIDLEN + 1)) == NULL) ||
+ ((thisdev->ident->revid = calloc(1, MLX_VPR_REVLEN + 1)) == NULL)) {
+ logmsg(MSG_ERROR, gettext("hermon: Unable to allocate space "
+ "for a VPR record.\n"));
+ goto identify_end;
+ }
+ (void) strlcpy(thisdev->ident->vid, "MELLANOX", MLX_VPR_VIDLEN);
+
+ /*
+ * 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.
+ */
+ snprintf(thisdev->ident->revid, MLX_VPR_REVLEN, "%d.%d.%04d",
+ manuf->hwfw_img_info.fw_rev.major,
+ manuf->hwfw_img_info.fw_rev.minor,
+ manuf->hwfw_img_info.fw_rev.subminor);
+
+ if ((ret = cnx_get_guids(manuf)) != FWFLASH_SUCCESS) {
+ logmsg(MSG_WARN, gettext("hermon: No GUIDs found for "
+ "device %s!\n"), thisdev->access_devname);
+ }
+
+ /* set hw part number, psid, and name in handle */
+ /* now walk the magic decoder ring table */
+ manuf->info.mlx_pn = NULL;
+ manuf->info.mlx_psid = NULL;
+ manuf->info.mlx_id = NULL;
+
+ if (cnx_get_image_info(manuf) != FWFLASH_SUCCESS) {
+ logmsg(MSG_WARN, gettext("hermon: Failed to read Image Info "
+ "for PSID\n"));
+ hw_psid_found = 0;
+ } else {
+ hw_psid_found = 1;
+ }
+
+ if (init_ioctl.af_pn_len != 0) {
+ /* part number length */
+ for (i = 0; i < init_ioctl.af_pn_len; i++) {
+ if (init_ioctl.af_hwpn[i] == ' ') {
+ manuf->pn_len = i;
+ break;
+ }
+ }
+ if (i == init_ioctl.af_pn_len) {
+ manuf->pn_len = init_ioctl.af_pn_len;
+ }
+ } else {
+ logmsg(MSG_INFO, "hermon: Failed to get Part# from hermon "
+ "driver \n");
+ manuf->pn_len = 0;
+ }
+
+ if (manuf->pn_len != 0) {
+ errno = 0;
+ manuf->info.mlx_pn = calloc(1, manuf->pn_len);
+ if (manuf->info.mlx_pn == NULL) {
+ logmsg(MSG_ERROR, gettext("hermon: no space available "
+ "for the HCA PN record (%s)\n"), strerror(errno));
+ goto identify_end;
+ }
+ (void) memcpy(manuf->info.mlx_pn, init_ioctl.af_hwpn,
+ manuf->pn_len);
+ manuf->info.mlx_pn[manuf->pn_len] = 0;
+
+ logmsg(MSG_INFO, "hermon: HCA PN (%s) PN-Len %d\n",
+ manuf->info.mlx_pn, manuf->pn_len);
+
+ errno = 0;
+ manuf->info.mlx_psid = calloc(1, MLX_PSID_SZ);
+ if (manuf->info.mlx_psid == NULL) {
+ logmsg(MSG_ERROR, gettext("hermon: PSID calloc "
+ "failed :%s\n"), strerror(errno));
+ goto identify_end;
+ }
+
+ errno = 0;
+ if ((manuf->info.mlx_id = calloc(1, MLX_STR_ID_SZ)) == NULL) {
+ logmsg(MSG_ERROR, gettext("hermon: "
+ "ID calloc failed (%s)\n"),
+ strerror(errno));
+ goto identify_end;
+ }
+
+ /* Find part number, set the rest */
+ for (i = 0; i < MLX_MAX_ID; i++) {
+ if (strncmp((const char *)init_ioctl.af_hwpn,
+ mlx_mdr[i].mlx_pn, manuf->pn_len) == 0) {
+
+ if (hw_psid_found) {
+ logmsg(MSG_INFO, "HW-PSID: %s "
+ "MLX_MDR[%d]: %s\n",
+ manuf->hwfw_img_info.psid, i,
+ mlx_mdr[i].mlx_psid);
+ if (strncmp((const char *)
+ manuf->hwfw_img_info.psid,
+ mlx_mdr[i].mlx_psid,
+ MLX_PSID_SZ) != 0)
+ continue;
+ }
+ /* Set PSID */
+ (void) memcpy(manuf->info.mlx_psid,
+ mlx_mdr[i].mlx_psid, MLX_PSID_SZ);
+ manuf->info.mlx_psid[MLX_PSID_SZ - 1] = 0;
+
+ logmsg(MSG_INFO, "hermon: HCA PSID (%s)\n",
+ manuf->info.mlx_psid);
+
+ (void) strlcpy(manuf->info.mlx_id,
+ mlx_mdr[i].mlx_id,
+ strlen(mlx_mdr[i].mlx_id) + 1);
+
+ logmsg(MSG_INFO, "hermon: HCA Name (%s)\n",
+ manuf->info.mlx_id);
+
+ break;
+ }
+ }
+ }
+
+ if ((manuf->pn_len == 0) || (i == MLX_MAX_ID)) {
+ logmsg(MSG_INFO, "hermon: No hardware part number "
+ "information available for this HCA\n");
+
+ i = strlen("No hardware information available for this device");
+
+ thisdev->ident->pid = calloc(1, i + 2);
+ sprintf(thisdev->ident->pid, "No additional hardware info "
+ "available for this device");
+ } else {
+ errno = 0;
+ if ((thisdev->ident->pid = calloc(1,
+ strlen(manuf->info.mlx_psid) + 1)) != NULL) {
+ (void) strlcpy(thisdev->ident->pid,
+ manuf->info.mlx_psid,
+ strlen(manuf->info.mlx_psid) + 1);
+ } else {
+ logmsg(MSG_ERROR,
+ gettext("hermon: Unable to allocate space for a "
+ "hardware identifier: %s\n"), strerror(errno));
+ goto identify_end;
+ }
+ }
+
+ for (i = 0; i < 4; i++) {
+ errno = 0;
+ if ((thisdev->addresses[i] = calloc(1,
+ (2 * sizeof (uint64_t)) + 1)) == NULL) {
+ logmsg(MSG_ERROR,
+ gettext("hermon: Unable to allocate space for a "
+ "human-readable HCA guid: %s\n"), strerror(errno));
+ goto identify_end;
+ }
+ (void) sprintf(thisdev->addresses[i], "%016llx",
+ manuf->ibguids[i]);
+ }
+
+ /*
+ * 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 (FWFLASH_SUCCESS);
+
+ /* cleanup */
+identify_end:
+ cnx_close(thisdev);
+ return (FWFLASH_FAILURE);
+}
+
+static int
+cnx_get_guids(ib_cnx_encap_ident_t *handle)
+{
+ int i, rv;
+
+ logmsg(MSG_INFO, "cnx_get_guids\n");
+
+ /* make sure we've got our fallback position organised */
+ for (i = 0; i < 4; i++) {
+ handle->ibguids[i] = 0x00000000;
+ }
+
+ rv = cnx_find_magic_n_chnk_sz(handle, FWFLASH_IB_STATE_IMAGE_PRI);
+ if (rv != FWFLASH_SUCCESS) {
+ logmsg(MSG_INFO, "hermon: Failed to get Primary magic number. "
+ "Trying Secondary... \n");
+ rv = cnx_find_magic_n_chnk_sz(handle,
+ FWFLASH_IB_STATE_IMAGE_SEC);
+ if (rv != FWFLASH_SUCCESS) {
+ logmsg(MSG_ERROR, gettext("hermon: Failed to get "
+ "Secondary magic number.\n"));
+ logmsg(MSG_ERROR,
+ gettext("Warning: HCA Firmware corrupt.\n"));
+ return (FWFLASH_FAILURE);
+ }
+ rv = cnx_read_guids(handle, FWFLASH_IB_STATE_IMAGE_SEC);
+ if (rv != FWFLASH_SUCCESS) {
+ logmsg(MSG_ERROR, gettext("hermon: Failed to read "
+ "secondary guids.\n"));
+ return (FWFLASH_FAILURE);
+ }
+ } else {
+ rv = cnx_read_guids(handle, FWFLASH_IB_STATE_IMAGE_PRI);
+ if (rv != FWFLASH_SUCCESS) {
+ logmsg(MSG_ERROR, gettext("hermon: Failed to read "
+ "primary guids.\n"));
+ return (FWFLASH_FAILURE);
+ }
+ }
+ for (i = 0; i < 4; i++) {
+ logmsg(MSG_INFO, "hermon: ibguids[%d] 0x%016llx\n", i,
+ handle->ibguids[i]);
+ }
+ for (i = 0; i < 2; i++) {
+ logmsg(MSG_INFO, "hermon: ib_portmac[%d] 0x%016llx\n", i,
+ handle->ib_mac[i]);
+ }
+
+ return (FWFLASH_SUCCESS);
+}
+
+static int
+cnx_close(struct devicelist *flashdev)
+{
+ ib_cnx_encap_ident_t *handle;
+
+ logmsg(MSG_INFO, "cnx_close\n");
+
+ handle = (ib_cnx_encap_ident_t *)flashdev->ident->encap_ident;
+
+ if (CNX_I_CHECK_HANDLE(handle)) {
+ logmsg(MSG_ERROR, gettext("hermon: Invalid Handle to close "
+ "device %s! \n"), flashdev->access_devname);
+ return (FWFLASH_FAILURE);
+ }
+
+ if (handle->fd > 0) {
+ errno = 0;
+ (void) ioctl(handle->fd, HERMON_IOCTL_FLASH_FINI);
+ if (close(handle->fd) != 0) {
+ logmsg(MSG_ERROR, gettext("hermon: Unable to properly "
+ "close device %s! (%s)\n"),
+ flashdev->access_devname, strerror(errno));
+ return (FWFLASH_FAILURE);
+ }
+ }
+
+ if (handle != NULL) {
+ if (handle->info.mlx_id != NULL)
+ free(handle->info.mlx_id);
+
+ if (handle->info.mlx_psid != NULL)
+ free(handle->info.mlx_psid);
+
+ if (handle->fw != NULL)
+ free(handle->fw);
+ free(handle);
+ }
+
+ if (flashdev->ident->vid != NULL)
+ free(flashdev->ident->vid);
+
+ if (flashdev->ident->revid != NULL)
+ free(flashdev->ident->revid);
+
+ return (FWFLASH_SUCCESS);
+}
+
+
+/*
+ * Driver read/write ioctl calls.
+ */
+static int
+cnx_read_ioctl(ib_cnx_encap_ident_t *hdl, hermon_flash_ioctl_t *info)
+{
+ int ret;
+
+#ifdef CNX_DEBUG
+ logmsg(MSG_INFO, "cnx_read_ioctl: fd %d af_type 0x%x af_addr 0x%x "
+ "af_sector_num(0x%x)\n", hdl->fd, info->af_type,
+ info->af_addr, info->af_sector_num);
+#endif
+
+ errno = 0;
+ ret = ioctl(hdl->fd, HERMON_IOCTL_FLASH_READ, info);
+ if (ret != 0) {
+ logmsg(MSG_ERROR, gettext("HERMON_IOCTL_FLASH_READ failed "
+ "(%s)\n"), strerror(errno));
+ }
+ return (ret);
+}
+
+static int
+cnx_write_ioctl(ib_cnx_encap_ident_t *hdl, hermon_flash_ioctl_t *info)
+{
+ int ret;
+
+#ifdef CNX_DEBUG
+ logmsg(MSG_INFO, "cnx_write_ioctl: fd(%d) af_type(0x%x) "
+ "af_addr(0x%x) af_sector_num(0x%x) af_byte(0x%x)\n",
+ hdl->fd, info->af_type, info->af_addr, info->af_sector_num,
+ info->af_byte);
+#endif
+ errno = 0;
+ ret = ioctl(hdl->fd, HERMON_IOCTL_FLASH_WRITE, info);
+ if (ret != 0) {
+ logmsg(MSG_ERROR, gettext("HERMON_IOCTL_FLASH_WRITE "
+ "failed (%s)\n"), strerror(errno));
+ }
+ return (ret);
+}
+
+static int
+cnx_erase_sector_ioctl(ib_cnx_encap_ident_t *hdl, hermon_flash_ioctl_t *info)
+{
+ int ret;
+
+#ifdef CNX_DEBUG
+ logmsg(MSG_INFO, "cnx_erase_sector_ioctl: fd(%d) af_type(0x%x) "
+ "af_sector_num(0x%x)\n", hdl->fd, info->af_type,
+ info->af_sector_num);
+#endif
+ errno = 0;
+ ret = ioctl(hdl->fd, HERMON_IOCTL_FLASH_ERASE, info);
+ if (ret != 0) {
+ logmsg(MSG_ERROR, gettext("HERMON_IOCTL_FLASH_ERASE "
+ "failed (%s)\n"), strerror(errno));
+ }
+ return (ret);
+}
+
+/*
+ * cnx_crc16 - computes 16 bit crc of supplied buffer.
+ * image should be in network byteorder
+ * result is returned in host byteorder form
+ */
+uint16_t
+cnx_crc16(uint8_t *image, uint32_t size, int is_image)
+{
+ const uint16_t poly = 0x100b;
+ uint32_t crc = 0xFFFF;
+ uint32_t word;
+ uint32_t i, j;
+
+ logmsg(MSG_INFO, "hermon: cnx_crc16\n");
+
+ for (i = 0; i < size / 4; i++) {
+ word = (image[4 * i] << 24) |
+ (image[4 * i + 1] << 16) |
+ (image[4 * i + 2] << 8) |
+ (image[4 * i + 3]);
+
+ if (is_image == CNX_HW_IMG)
+ word = MLXSWAPBITS32(word);
+
+ for (j = 0; j < 32; j++) {
+ if (crc & 0x8000) {
+ crc = (((crc << 1) |
+ (word >> 31)) ^ poly) & 0xFFFF;
+ } else {
+ crc = ((crc << 1) | (word >> 31)) & 0xFFFF;
+ }
+ word = (word << 1) & 0xFFFFFFFF;
+ }
+ }
+
+ for (i = 0; i < 16; i++) {
+ if (crc & 0x8000) {
+ crc = ((crc << 1) ^ poly) & 0xFFFF;
+ } else {
+ crc = (crc << 1) & 0xFFFF;
+ }
+ }
+
+ crc = crc ^ 0xFFFF;
+ return (crc & 0xFFFF);
+}
+
+static void
+cnx_local_set_guid_crc_img(uint32_t offset, uint32_t guid_crc_size,
+ uint32_t guid_crc_offset)
+{
+ uint16_t crc;
+ uint8_t *fw_p = (uint8_t *)&verifier->fwimage[0];
+
+ crc = htons(cnx_crc16((uint8_t *)&verifier->fwimage[offset / 4],
+ guid_crc_size, CNX_FILE_IMG));
+
+ logmsg(MSG_INFO, "cnx_local_set_guid_crc_img: new guid_sect crc: %x\n",
+ ntohs(crc));
+ (void) memcpy(&fw_p[offset + guid_crc_offset], &crc, 2);
+}
+
+/*
+ * Address translation functions for ConnectX
+ * Variable definitions:
+ * - log2_chunk_size: log2 of a Flash chunk size
+ * - cont_addr: a contiguous image address to be translated
+ * - is_image_in_odd_chunk: When this bit is 1, it indicates the new image is
+ * stored in odd chunks of the Flash.
+ */
+static uint32_t
+cnx_cont2phys(uint32_t log2_chunk_size, uint32_t cont_addr, int type)
+{
+ uint32_t result;
+ int is_image_in_odd_chunks;
+
+ is_image_in_odd_chunks = type - 1;
+
+ if (log2_chunk_size) {
+ result = cont_addr & (0xffffffff >> (32 - log2_chunk_size)) |
+ (is_image_in_odd_chunks << log2_chunk_size) |
+ (cont_addr << 1) & (0xffffffff << (log2_chunk_size + 1));
+ } else {
+ result = cont_addr;
+ }
+
+ return (result);
+}
+
+static int
+cnx_read_guids(ib_cnx_encap_ident_t *handle, int type)
+{
+#ifdef _LITTLE_ENDIAN
+ uint32_t *ptr, tmp;
+#endif
+ hermon_flash_ioctl_t ioctl_info;
+ uint32_t *guids;
+ uint32_t *ibmac;
+ int ret, i;
+ uint32_t nguidptr_addr;
+ union {
+ uint8_t bytes[4];
+ uint32_t dword;
+ } crc16_u;
+ uint32_t *guid_structure;
+ uint16_t crc;
+
+ logmsg(MSG_INFO, "cnx_read_guids\n");
+
+ errno = 0;
+ guid_structure = (uint32_t *)calloc(1,
+ CNX_GUID_CRC16_SIZE / 4 * sizeof (uint32_t));
+ if (guid_structure == NULL) {
+ logmsg(MSG_WARN, gettext("hermon: Can't calloc guid_structure "
+ ": (%s)\n"), strerror(errno));
+ return (FWFLASH_FAILURE);
+ }
+
+ ioctl_info.af_type = HERMON_FLASH_READ_QUADLET;
+ ioctl_info.af_addr = cnx_cont2phys(handle->log2_chunk_sz,
+ CNX_NGUIDPTR_OFFSET, type);
+
+ ret = cnx_read_ioctl(handle, &ioctl_info);
+ if (ret != 0) {
+ logmsg(MSG_WARN, gettext("hermon: Failed to read GUID Pointer "
+ "Address\n"));
+ goto out;
+ }
+
+ guids = (uint32_t *)&handle->ibguids[0];
+ ibmac = (uint32_t *)&handle->ib_mac[0];
+ nguidptr_addr = cnx_cont2phys(handle->log2_chunk_sz,
+ ioctl_info.af_quadlet, type);
+
+ logmsg(MSG_INFO, "NGUIDPTR: 0x%08x \n", nguidptr_addr);
+ /* Read in the entire guid section in order to calculate the CRC */
+ ioctl_info.af_addr = nguidptr_addr - 0x10;
+ ioctl_info.af_type = HERMON_FLASH_READ_QUADLET;
+
+ for (i = 0; i < CNX_GUID_CRC16_SIZE / 4; i++) {
+ ret = cnx_read_ioctl(handle, &ioctl_info);
+ if (ret != 0) {
+ logmsg(MSG_INFO, "Failed to read guid_structure "
+ "(0x%x)\n", i);
+ goto out;
+ }
+
+ if (i >= 4 && i < 12) {
+ guids[i - 4] = ioctl_info.af_quadlet;
+ }
+ if (i >= 12 && i < 16) {
+ ibmac[i - 12] = ioctl_info.af_quadlet;
+ }
+
+ guid_structure[i] = ioctl_info.af_quadlet;
+ ioctl_info.af_addr += 4;
+ }
+
+ for (i = 0; i < CNX_GUID_CRC16_SIZE / 4; i++) {
+ logmsg(MSG_INFO, "guid_structure[%x] = 0x%08x\n", i,
+ guid_structure[i]);
+ }
+
+ /*
+ * Check the CRC--make sure it computes.
+ */
+
+ /* 0x12 subtracted: 0x2 for alignment, 0x10 to reach structure start */
+ ioctl_info.af_addr = nguidptr_addr + CNX_GUID_CRC16_OFFSET - 0x12;
+ ioctl_info.af_type = HERMON_FLASH_READ_QUADLET;
+
+ ret = cnx_read_ioctl(handle, &ioctl_info);
+ if (ret != 0) {
+ logmsg(MSG_WARN, gettext("hermon: Failed to read guid crc "
+ "at 0x%x\n"), ioctl_info.af_addr);
+ goto out;
+ }
+
+ crc16_u.dword = ioctl_info.af_quadlet;
+ crc = cnx_crc16((uint8_t *)guid_structure, CNX_GUID_CRC16_SIZE,
+ CNX_HW_IMG);
+
+ if (crc != crc16_u.dword) {
+ logmsg(MSG_WARN, gettext("hermon: calculated crc16: 0x%x "
+ "differs from GUID section 0x%x\n"), crc, crc16_u.dword);
+ } else {
+ logmsg(MSG_INFO, "hermon: calculated crc16: 0x%x MATCHES with "
+ "GUID section 0x%x\n", crc, crc16_u.dword);
+ }
+
+#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
+ */
+ ptr = (uint32_t *)guids;
+ for (ret = 0; ret < 8; ret += 2) {
+ tmp = ptr[ret];
+ ptr[ret] = ptr[ret+1];
+ ptr[ret+1] = tmp;
+ }
+ ptr = (uint32_t *)&handle->ib_mac[0];
+ for (ret = 0; ret < 4; ret += 2) {
+ tmp = ptr[ret];
+ ptr[ret] = ptr[ret+1];
+ ptr[ret+1] = tmp;
+ }
+#endif
+ ret = FWFLASH_SUCCESS;
+
+out:
+ free(guid_structure);
+ return (ret);
+}
+
+static int
+cnx_find_magic_n_chnk_sz(ib_cnx_encap_ident_t *handle, int type)
+{
+ int i, found = 0;
+ uint32_t addr;
+ uint32_t boot_addresses[] =
+ {0, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000};
+
+ logmsg(MSG_INFO, "cnx_find_magic_n_chnk_sz\n");
+
+ switch (type) {
+ case FWFLASH_IB_STATE_IMAGE_PRI:
+ addr = 0;
+ if (cnx_check_for_magic_pattern(handle, addr) !=
+ FWFLASH_SUCCESS) {
+ goto err;
+ }
+ break;
+
+ case FWFLASH_IB_STATE_IMAGE_SEC:
+ for (i = 1; i < 6; i++) {
+ addr = boot_addresses[i];
+ if (cnx_check_for_magic_pattern(handle, addr) ==
+ FWFLASH_SUCCESS) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ goto err;
+ }
+ break;
+
+ default:
+ logmsg(MSG_INFO, "cnx_find_magic_pattern: unknown type\n");
+ goto err;
+ }
+
+ logmsg(MSG_INFO, "magic_pattern found at addr %x\n", addr);
+ handle->img2_start_addr = addr;
+
+ handle->log2_chunk_sz = cnx_get_log2_chunk_size_f_hdl(handle, type);
+ if (handle->log2_chunk_sz == 0) {
+ logmsg(MSG_INFO, "no chunk size found for type %x. "
+ "Assuming non-failsafe burn\n", type);
+ }
+
+ handle->fw_sz = cnx_get_image_size_f_hdl(handle, type);
+ if (handle->fw_sz == 0) {
+ logmsg(MSG_INFO, "no fw size found for type %x. \n", type);
+ }
+ handle->state |= type;
+
+ return (FWFLASH_SUCCESS);
+err:
+ logmsg(MSG_INFO, "no magic_pattern found for type %x\n", type);
+ return (FWFLASH_FAILURE);
+}
+
+static int
+cnx_check_for_magic_pattern(ib_cnx_encap_ident_t *handle, uint32_t addr)
+{
+ int i;
+ hermon_flash_ioctl_t ioctl_info;
+ int magic_pattern_buf[4];
+
+ logmsg(MSG_INFO, "cnx_check_for_magic_pattern\n");
+
+ ioctl_info.af_type = HERMON_FLASH_READ_QUADLET;
+
+ for (i = 0; i < 4; i++) {
+ ioctl_info.af_addr = addr + (i * sizeof (uint32_t));
+ if (cnx_read_ioctl(handle, &ioctl_info) != 0) {
+ logmsg(MSG_INFO, "\nFailed to read magic pattern\n");
+ return (FWFLASH_FAILURE);
+ }
+
+ magic_pattern_buf[i] = ioctl_info.af_quadlet;
+ }
+
+ return (cnx_is_magic_pattern_present(magic_pattern_buf, CNX_HW_IMG));
+
+}
+
+int
+cnx_is_magic_pattern_present(int *data, int is_image)
+{
+ int i;
+ int dword;
+
+ logmsg(MSG_INFO, "cnx_is_magic_pattern_present\n");
+
+ for (i = 0; i < 4; i++) {
+ if (is_image == CNX_FILE_IMG)
+ dword = MLXSWAPBITS32(data[i]);
+ else
+ dword = data[i];
+ logmsg(MSG_INFO, "local_quadlet: %08x, magic pattern: %08x\n",
+ dword, cnx_magic_pattern[i]);
+ if (dword != cnx_magic_pattern[i]) {
+ return (FWFLASH_FAILURE);
+ }
+ }
+
+ return (FWFLASH_SUCCESS);
+}
+
+static uint32_t
+cnx_get_log2_chunk_size_f_hdl(ib_cnx_encap_ident_t *handle, int type)
+{
+ hermon_flash_ioctl_t ioctl_info;
+ int ret;
+
+ logmsg(MSG_INFO, "cnx_get_log2_chunk_size_f_hdl\n");
+
+ /* If chunk size is already set, just return it. */
+ if (handle->log2_chunk_sz) {
+ return (handle->log2_chunk_sz);
+ }
+
+ switch (type) {
+ case FWFLASH_IB_STATE_IMAGE_PRI:
+ ioctl_info.af_addr = CNX_CHUNK_SIZE_OFFSET;
+ break;
+ case FWFLASH_IB_STATE_IMAGE_SEC:
+ ioctl_info.af_addr =
+ handle->img2_start_addr + CNX_CHUNK_SIZE_OFFSET;
+ break;
+ default:
+ logmsg(MSG_INFO,
+ "cnx_get_log2_chunk_size_f_hdl: unknown type\n");
+ return (0);
+ }
+
+ ioctl_info.af_type = HERMON_FLASH_READ_QUADLET;
+
+ ret = cnx_read_ioctl(handle, &ioctl_info);
+ if (ret != 0) {
+ logmsg(MSG_INFO, "\nFailed to read chunk size\n");
+ return (0);
+ }
+
+ return (cnx_get_log2_chunk_size(ioctl_info.af_quadlet));
+}
+
+
+static uint32_t
+cnx_get_log2_chunk_size(uint32_t chunk_size_word)
+{
+ uint8_t checksum;
+ uint32_t log2_chunk_size;
+
+ logmsg(MSG_INFO, "cnx_get_log2_chunk_size: chunk_size_word:"
+ " 0x%x\n", chunk_size_word);
+
+ checksum =
+ (chunk_size_word & 0xff) +
+ ((chunk_size_word >> 8) & 0xff) +
+ ((chunk_size_word >> 16) & 0xff) +
+ ((chunk_size_word >> 24) & 0xff);
+
+ if (checksum != 0) {
+ logmsg(MSG_INFO, "Corrupted chunk size checksum\n");
+ return (0);
+ }
+
+ if (chunk_size_word & 0x8) {
+ log2_chunk_size = (chunk_size_word & 0x7) + 16;
+ logmsg(MSG_INFO, "log2 chunk size: 0x%x\n", log2_chunk_size);
+ return (log2_chunk_size);
+ } else {
+ return (0);
+ }
+}
+
+static uint32_t
+cnx_get_image_size_f_hdl(ib_cnx_encap_ident_t *handle, int type)
+{
+ hermon_flash_ioctl_t ioctl_info;
+ int ret;
+
+ logmsg(MSG_INFO, "cnx_get_image_size_f_hdl\n");
+
+ ioctl_info.af_addr = cnx_cont2phys(handle->log2_chunk_sz,
+ CNX_IMG_SIZE_OFFSET, type);
+ ioctl_info.af_type = HERMON_FLASH_READ_QUADLET;
+
+ ret = cnx_read_ioctl(handle, &ioctl_info);
+ if (ret != 0) {
+ logmsg(MSG_INFO, "Failed to read image size\n");
+ return (0);
+ }
+
+ logmsg(MSG_INFO, "Image Size: 0x%x\n", ioctl_info.af_quadlet);
+
+ return (ioctl_info.af_quadlet);
+}
+
+static int
+cnx_get_image_info(ib_cnx_encap_ident_t *handle)
+{
+ uint32_t ii_ptr_addr;
+ uint32_t ii_size;
+ int *buf;
+ int i, type;
+ hermon_flash_ioctl_t ioctl_info;
+
+ logmsg(MSG_INFO, "cnx_get_image_info: state %x\n", handle->state);
+
+ type = handle->state &
+ (FWFLASH_IB_STATE_IMAGE_PRI | FWFLASH_IB_STATE_IMAGE_SEC);
+
+ /* Get the image info pointer */
+ ioctl_info.af_addr = cnx_cont2phys(handle->log2_chunk_sz,
+ CNX_IMG_INF_PTR_OFFSET, type);
+ ioctl_info.af_type = HERMON_FLASH_READ_QUADLET;
+
+ if (cnx_read_ioctl(handle, &ioctl_info) != FWFLASH_SUCCESS) {
+ logmsg(MSG_WARN, gettext("hermon: Failed to read image info "
+ "Address\n"));
+ return (FWFLASH_FAILURE);
+ }
+ ii_ptr_addr = ioctl_info.af_quadlet & 0xffffff;
+
+ /* Get the image info size, a negative offset from the image info ptr */
+ ioctl_info.af_addr = cnx_cont2phys(handle->log2_chunk_sz,
+ ii_ptr_addr + CNX_IMG_INF_SZ_OFFSET, type);
+ ioctl_info.af_type = HERMON_FLASH_READ_QUADLET;
+
+ if (cnx_read_ioctl(handle, &ioctl_info) != FWFLASH_SUCCESS) {
+ logmsg(MSG_WARN, gettext("hermon: Failed to read image info "
+ "size\n"));
+ return (FWFLASH_FAILURE);
+ }
+ logmsg(MSG_INFO, "hermon: ImageInfo Sz: 0x%x\n", ioctl_info.af_quadlet);
+
+ ii_size = ioctl_info.af_quadlet;
+ /* size is in dwords--convert it to bytes */
+ ii_size *= 4;
+
+ logmsg(MSG_INFO, "hermon: ii_ptr_addr: 0x%x ii_size: 0x%x\n",
+ ii_ptr_addr, ii_size);
+
+ buf = (int *)calloc(1, ii_size);
+
+ ioctl_info.af_addr = cnx_cont2phys(handle->log2_chunk_sz,
+ ii_ptr_addr, type);
+ ioctl_info.af_type = HERMON_FLASH_READ_QUADLET;
+
+ for (i = 0; i < ii_size/4; i++) {
+ if (cnx_read_ioctl(handle, &ioctl_info) != FWFLASH_SUCCESS) {
+ logmsg(MSG_WARN, gettext("hermon: Failed to read "
+ "image info (0x%x)\n"), i);
+ free(buf);
+ return (FWFLASH_FAILURE);
+ }
+
+ buf[i] = ioctl_info.af_quadlet;
+ ioctl_info.af_addr += 4;
+ }
+
+ /* Parse the image info section */
+ if (cnx_parse_img_info(buf, ii_size, &handle->hwfw_img_info,
+ CNX_HW_IMG) != FWFLASH_SUCCESS) {
+ logmsg(MSG_WARN, gettext("hermon: Failed to parse Image Info "
+ "section\n"));
+ free(buf);
+ return (FWFLASH_FAILURE);
+ }
+
+ free(buf);
+ return (FWFLASH_SUCCESS);
+}
+
+int
+cnx_parse_img_info(int *buf, uint32_t byte_size, cnx_img_info_t *img_info,
+ int is_image)
+{
+ uint32_t *p;
+ uint32_t offs = 0;
+ uint32_t tag_num = 0;
+ int end_found = 0;
+ uint32_t tag_size, tag_id;
+ uint32_t tmp;
+ const char *str;
+ int i;
+
+ p = (uint32_t *)buf;
+
+ logmsg(MSG_INFO, "hermon: cnx_parse_img_info\n");
+
+ while (!end_found && (offs < byte_size)) {
+ if (is_image == CNX_FILE_IMG) {
+ tag_size = ntohl(*p) & 0xffffff;
+ tag_id = ntohl(*p) >> 24;
+ tmp = ntohl(*(p + 1));
+ } else {
+ tag_size = ((*p) & 0xffffff);
+ tag_id = ((*p) >> 24);
+ tmp = (*(p + 1));
+ }
+
+ logmsg(MSG_INFO, "tag_id: %d tag_size: %d\n", tag_id, tag_size);
+
+ if ((offs + tag_size) > byte_size) {
+ logmsg(MSG_WARN, gettext("hermon: Image Info section "
+ "corrupted: Tag# %d - tag_id %d, size %d exceeds "
+ "info section size (%d bytes)"), tag_num, tag_id,
+ tag_size, byte_size);
+ return (FWFLASH_FAILURE);
+ }
+
+ switch (tag_id) {
+ case CNX_FW_VER:
+ if (tag_size != CNX_FW_VER_SZ) {
+ logmsg(MSG_INFO, "ERROR: tag_id: %d tag_size: "
+ "%d expected sz %d\n", tag_id, tag_size,
+ CNX_FW_VER_SZ);
+ }
+ tmp = (tmp & CNX_MASK_FW_VER_MAJ) >> 16;
+ img_info->fw_rev.major = tmp;
+ if (is_image == CNX_FILE_IMG)
+ tmp = ntohl(*(p + 2));
+ else
+ tmp = (*(p + 2));
+ img_info->fw_rev.minor =
+ (tmp & CNX_MASK_FW_VER_MIN)>> 16;
+ img_info->fw_rev.subminor =
+ tmp & CNX_MASK_FW_VER_SUBMIN;
+
+ logmsg(MSG_INFO, "FW_VER: %d.%d.%d\n",
+ img_info->fw_rev.major, img_info->fw_rev.minor,
+ img_info->fw_rev.subminor);
+ break;
+
+ case CNX_FW_BUILD_TIME:
+ if (tag_size != CNX_FW_BUILD_TIME_SZ) {
+ logmsg(MSG_INFO, "ERROR: tag_id: %d tag_size: "
+ "%d expected sz %d\n", tag_id, tag_size,
+ CNX_FW_BUILD_TIME_SZ);
+ }
+ img_info->fw_buildtime.hour =
+ (tmp & CNX_MASK_FW_BUILD_HOUR) >> 16;
+ img_info->fw_buildtime.minute =
+ (tmp & CNX_MASK_FW_BUILD_MIN) >> 8;
+ img_info->fw_buildtime.second =
+ (tmp & CNX_MASK_FW_BUILD_SEC);
+
+ if (is_image == CNX_FILE_IMG)
+ tmp = ntohl(*(p + 2));
+ else
+ tmp = (*(p + 2));
+
+ img_info->fw_buildtime.year =
+ (tmp & CNX_MASK_FW_BUILD_YEAR) >> 16;
+ img_info->fw_buildtime.month =
+ (tmp & CNX_MASK_FW_BUILD_MON) >> 8;
+ img_info->fw_buildtime.day =
+ (tmp & CNX_MASK_FW_BUILD_DAY);
+
+ logmsg(MSG_INFO, "Build TIME: %d:%d:%d %d:%d:%d\n",
+ img_info->fw_buildtime.year,
+ img_info->fw_buildtime.month,
+ img_info->fw_buildtime.day,
+ img_info->fw_buildtime.hour,
+ img_info->fw_buildtime.minute,
+ img_info->fw_buildtime.second);
+ break;
+
+ case CNX_DEV_TYPE:
+ if (tag_size != CNX_DEV_TYPE_SZ) {
+ logmsg(MSG_INFO, "ERROR: tag_id: %d tag_size: "
+ "%d expected sz %d\n", tag_id, tag_size,
+ CNX_DEV_TYPE_SZ);
+ }
+ img_info->dev_id = tmp & CNX_MASK_DEV_TYPE_ID;
+ logmsg(MSG_INFO, "DEV_TYPE: %d\n", img_info->dev_id);
+ break;
+
+ case CNX_VSD_VENDOR_ID:
+ if (tag_size != CNX_VSD_VENDOR_ID_SZ) {
+ logmsg(MSG_INFO, "ERROR: tag_id: %d tag_size: "
+ "%d expected sz %d\n", tag_id, tag_size,
+ CNX_VSD_VENDOR_ID_SZ);
+ }
+ img_info->vsd_vendor_id = tmp & CNX_MASK_VSD_VENDORID;
+ logmsg(MSG_INFO, "VSD Vendor ID: 0x%lX\n",
+ img_info->vsd_vendor_id);
+ break;
+
+ case CNX_PSID:
+ if (tag_size != CNX_PSID_SZ) {
+ logmsg(MSG_INFO, "ERROR: tag_id: %d tag_size: "
+ "%d expected sz %d\n", tag_id, tag_size,
+ CNX_PSID_SZ);
+ }
+ str = (const char *)p;
+ str += 4;
+
+ for (i = 0; i < CNX_PSID_SZ; i++)
+ img_info->psid[i] = str[i];
+
+#ifdef _LITTLE_ENDIAN
+ if (is_image == CNX_HW_IMG) {
+ for (i = 0; i < CNX_PSID_SZ; i += 4) {
+ img_info->psid[i+3] = str[i];
+ img_info->psid[i+2] = str[i+1];
+ img_info->psid[i+1] = str[i+2];
+ img_info->psid[i] = str[i+3];
+ }
+ }
+#endif
+
+ logmsg(MSG_INFO, "PSID: %s\n", img_info->psid);
+ break;
+
+ case CNX_VSD:
+ if (tag_size != CNX_VSD_SZ) {
+ logmsg(MSG_INFO, "ERROR: tag_id: %d tag_size: "
+ "%d expected sz %d\n", tag_id, tag_size,
+ CNX_VSD_SZ);
+ }
+ str = (const char *)p;
+ str += 4;
+
+ for (i = 0; i < CNX_VSD_SZ; i++)
+ img_info->vsd[i] = str[i];
+
+#ifdef _LITTLE_ENDIAN
+ if (is_image == CNX_HW_IMG) {
+ for (i = 0; i < CNX_VSD_SZ; i += 4) {
+ img_info->vsd[i+3] = str[i];
+ img_info->vsd[i+2] = str[i+1];
+ img_info->vsd[i+1] = str[i+2];
+ img_info->vsd[i] = str[i+3];
+ }
+ }
+#endif
+ logmsg(MSG_INFO, "VSD: %s\n", img_info->vsd);
+ break;
+
+ case CNX_END_TAG:
+ if (tag_size != CNX_END_TAG_SZ) {
+ logmsg(MSG_INFO, "ERROR: tag_id: %d tag_size: "
+ "%d expected sz %d\n", tag_id, tag_size,
+ CNX_END_TAG_SZ);
+ }
+ end_found = 1;
+ break;
+
+ default:
+ if (tag_id > CNX_END_TAG) {
+ logmsg(MSG_WARN, gettext("Invalid img_info "
+ "tag ID %d of size %d\n"), tag_id,
+ tag_size);
+ }
+ break;
+ }
+
+ p += (tag_size / 4) + 1;
+ offs += tag_size + 4;
+ tag_num++;
+ }
+
+ if (offs != byte_size) {
+ logmsg(MSG_WARN, gettext("hermon: Corrupt Image Info section "
+ "in firmware image\n"));
+ if (end_found) {
+ logmsg(MSG_WARN, gettext("Info section corrupted: "
+ "Section data size is %x bytes, but end tag found "
+ "after %x bytes.\n"), byte_size, offs);
+ } else {
+ logmsg(MSG_WARN, gettext("Info section corrupted: "
+ "Section data size is %x bytes, but end tag not "
+ "found at section end.\n"), byte_size);
+ }
+ return (FWFLASH_FAILURE);
+ }
+
+ return (FWFLASH_SUCCESS);
+}
diff --git a/usr/src/cmd/fwflash/plugins/transport/common/tavor.c b/usr/src/cmd/fwflash/plugins/transport/common/tavor.c
new file mode 100644
index 0000000000..2df9209760
--- /dev/null
+++ b/usr/src/cmd/fwflash/plugins/transport/common/tavor.c
@@ -0,0 +1,1921 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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
+ * so DO NOT move this file out of usr/closed without
+ * 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/types.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <sys/queue.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+
+#include <sys/byteorder.h>
+
+#include <libintl.h> /* for gettext(3c) */
+
+#include <fwflash/fwflash.h>
+#include "../../hdrs/MELLANOX.h"
+#include "../../hdrs/tavor_ib.h"
+
+
+
+char *devprefix = "/devices";
+char drivername[] = "tavor\0";
+char *devsuffix = ":devctl";
+
+
+extern di_node_t rootnode;
+extern int errno;
+extern struct fw_plugin *self;
+extern struct vrfyplugin *verifier;
+extern int fwflash_debug;
+
+
+/* required functions for this plugin */
+int fw_readfw(struct devicelist *device, char *filename);
+int fw_writefw(struct devicelist *device);
+int fw_identify(int start);
+int fw_devinfo();
+
+
+/* helper functions */
+
+static int tavor_identify(struct devicelist *thisdev);
+static int tavor_get_guids(struct ib_encap_ident *handle);
+static int tavor_close(struct devicelist *flashdev);
+static void tavor_cisco_extensions(mlx_xps_t *hcaxps, mlx_xps_t *diskxps);
+static uint16_t crc16(uint8_t *image, uint32_t size);
+static int tavor_write_sector(int fd, int sectnum, int32_t *data);
+static int tavor_zero_sig_crc(int fd, uint32_t start);
+static int tavor_write_xps_fia(int fd, uint32_t offset, uint32_t start);
+static int tavor_write_xps_crc_sig(int fd, uint32_t offset, uint16_t newcrc);
+static int tavor_blast_image(int fd, int prisec, uint32_t hcafia,
+ uint32_t sectsz, struct mlx_xps *newxps);
+static int tavor_readback(int infd, int whichsect, int sectsz);
+
+
+
+int
+fw_readfw(struct devicelist *flashdev, char *filename)
+{
+
+ int rv = FWFLASH_SUCCESS;
+ int fd;
+ mode_t mode = S_IRUSR | S_IWUSR;
+ uint8_t pchunks;
+ uint8_t *raw_pfi;
+ uint8_t *raw_sfi;
+ uint32_t j, offset;
+ uint32_t pfia, sfia, psz, ssz;
+ tavor_flash_ioctl_t tfi_data;
+ struct ib_encap_ident *manuf;
+ struct mlx_xps *lpps;
+ struct mlx_xps *lsps;
+#if defined(_LITTLE_ENDIAN)
+ uint32_t *ptr;
+#endif
+
+ errno = 0;
+ if ((fd = open(filename, O_RDWR|O_CREAT|O_DSYNC, mode)) < 0) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to open specified file "
+ "(%s) for writing: %s\n"), filename, strerror(errno));
+ return (FWFLASH_FAILURE);
+ }
+
+ manuf =
+ (struct ib_encap_ident *)(uintptr_t)flashdev->ident->encap_ident;
+ lpps = (struct mlx_xps *)(uintptr_t)manuf->pps;
+ lsps = (struct mlx_xps *)(uintptr_t)manuf->sps;
+
+ /*
+ * 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 */
+ pfia = MLXSWAPBITS32(lpps->fia);
+ sfia = MLXSWAPBITS32(lsps->fia);
+ psz = MLXSWAPBITS32(lpps->fis);
+ ssz = MLXSWAPBITS32(lsps->fis);
+
+ /* Invariant Sector comes first */
+ if ((j = write(fd, manuf->inv, manuf->sector_sz)) !=
+ manuf->sector_sz) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to write HCA Invariant Sector "
+ "(%d of %d bytes)\n"),
+ j, manuf->sector_sz);
+ (void) tavor_close(flashdev);
+ return (FWFLASH_FAILURE);
+ } else {
+ fprintf(stdout, gettext("Writing ."));
+ }
+
+ /* followed by Primary Pointer Sector */
+ if ((j = write(fd, manuf->pps, manuf->sector_sz)) !=
+ manuf->sector_sz) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to write HCA Primary Pointer "
+ "Sector (%d of %d bytes)\n)"),
+ j, manuf->sector_sz);
+ (void) tavor_close(flashdev);
+ return (FWFLASH_FAILURE);
+ } else {
+ fprintf(stdout, " .");
+ }
+
+ /* followed by Secondary Pointer Sector */
+ if ((j = write(fd, manuf->sps, manuf->sector_sz)) !=
+ manuf->sector_sz) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to write HCA Secondary Pointer "
+ "Sector (%d of %d bytes)\n"),
+ j, manuf->sector_sz);
+ (void) tavor_close(flashdev);
+ return (FWFLASH_FAILURE);
+ } else {
+ fprintf(stdout, " .");
+ }
+
+ /* Now for the xFI sectors */
+ pchunks = psz / manuf->sector_sz;
+
+ if ((psz % manuf->sector_sz) != 0)
+ pchunks++;
+
+ /* Get the PFI, then the SFI */
+ if ((raw_pfi = calloc(1, pchunks * manuf->sector_sz)) == NULL) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to allocate space for "
+ "device's Primary Firmware Image\n"));
+ return (FWFLASH_FAILURE);
+ }
+ bzero(&tfi_data, sizeof (tavor_flash_ioctl_t));
+ tfi_data.tf_type = TAVOR_FLASH_READ_SECTOR;
+ j = pfia / manuf->sector_sz;
+
+ for (offset = 0; offset < psz; offset += manuf->sector_sz) {
+ tfi_data.tf_sector_num = j;
+ tfi_data.tf_sector = (caddr_t)&raw_pfi[offset];
+ rv = ioctl(manuf->fd, TAVOR_IOCTL_FLASH_READ, &tfi_data);
+ if (rv < 0) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to read sector %d of "
+ "HCA Primary Firmware Image\n"), j);
+ free(raw_pfi);
+ (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.
+ */
+ bzero(&raw_pfi[psz], (pchunks * manuf->sector_sz) - psz);
+
+#if defined(_LITTLE_ENDIAN)
+ ptr = (uint32_t *)(uintptr_t)raw_pfi;
+ for (j = 0; j < (pchunks * manuf->sector_sz / 4); j++) {
+ ptr[j] = htonl(ptr[j]);
+ if (j > psz)
+ break;
+ }
+#endif
+
+ if ((j = write(fd, raw_pfi, pchunks * manuf->sector_sz))
+ != pchunks * manuf->sector_sz) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to write HCA Primary Firmware "
+ "Image data (%d of %d bytes)\n"),
+ j, pchunks * manuf->sector_sz);
+ free(raw_pfi);
+ (void) tavor_close(flashdev);
+ return (FWFLASH_FAILURE);
+ } else {
+ fprintf(stdout, " .");
+ }
+
+ pchunks = ssz / manuf->sector_sz;
+
+ if ((ssz % manuf->sector_sz) != 0)
+ pchunks++;
+
+ /*
+ * We allocate wholenum sectors, but only write out what we
+ * really need (ssz bytes)
+ */
+ if ((raw_sfi = calloc(1, pchunks * manuf->sector_sz)) == NULL) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to allocate space for "
+ "device's Secondary Firmware Image\n"));
+ free(raw_pfi);
+ return (FWFLASH_FAILURE);
+ }
+ bzero(&tfi_data, sizeof (tavor_flash_ioctl_t));
+ tfi_data.tf_type = TAVOR_FLASH_READ_SECTOR;
+
+ /* get our starting sector number */
+ j = sfia / manuf->sector_sz;
+
+ for (offset = 0; offset < ssz; offset += manuf->sector_sz) {
+ tfi_data.tf_sector_num = j;
+ tfi_data.tf_sector = (caddr_t)&raw_sfi[offset];
+ if ((rv = ioctl(manuf->fd, TAVOR_IOCTL_FLASH_READ,
+ &tfi_data)) < 0) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to read sector %d of "
+ "HCA Secondary Firmware Image\n"), j);
+ (void) tavor_close(flashdev);
+ free(raw_pfi);
+ free(raw_sfi);
+ 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.
+ */
+ bzero(&raw_sfi[ssz], (pchunks * manuf->sector_sz) - ssz);
+
+#if defined(_LITTLE_ENDIAN)
+ ptr = (uint32_t *)(uintptr_t)raw_sfi;
+ for (j = 0; j < ssz / 4; j++) {
+ ptr[j] = htonl(ptr[j]);
+ }
+#endif
+
+ /* only write out ssz bytes */
+ if ((j = write(fd, raw_sfi, ssz)) != ssz) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to write HCA Secondary Firmware "
+ "Image data (%d of %d bytes)\n"),
+ j, ssz);
+ (void) tavor_close(flashdev);
+ free(raw_pfi);
+ free(raw_sfi);
+ return (FWFLASH_FAILURE);
+ } else {
+ fprintf(stdout, " .\n");
+ }
+
+ fprintf(stdout,
+ gettext("Done.\n"));
+
+ free(raw_pfi);
+ free(raw_sfi);
+ /*
+ * 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
+fw_writefw(struct devicelist *flashdev)
+{
+
+ int rv;
+ uint32_t j, sectsz, hpfia, hsfia;
+ uint32_t ipfia, isfia, ipfis, isfis;
+ struct ib_encap_ident *manuf;
+ struct mlx_is *iinv;
+ struct mlx_xps *ipps, *lpps;
+ struct mlx_xps *isps, *lsps;
+ struct mlx_xfi *ipfi, *isfi;
+
+ /*
+ * linv, lpps/lsps are from the HCA whereas
+ * iinv/ipps/isps are in the on-disk firmware image that
+ * 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 =
+ (struct ib_encap_ident *)(uintptr_t)flashdev->ident->encap_ident;
+ lpps = (struct mlx_xps *)(uintptr_t)manuf->pps;
+ lsps = (struct mlx_xps *)(uintptr_t)manuf->sps;
+ iinv = (struct mlx_is *)&verifier->fwimage[0];
+ sectsz = 1 << MLXSWAPBITS16(iinv->log2sectsz + iinv->log2sectszp);
+ ipps = (struct mlx_xps *)&verifier->fwimage[sectsz/4];
+ isps = (struct mlx_xps *)&verifier->fwimage[sectsz/2];
+
+ /*
+ * 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().
+ */
+ if (manuf->pn_len == 0) {
+ int resp;
+
+ (void) printf("\nUnable to completely verify that this "
+ "firmware image\n\t(%s)\nis compatible with your "
+ "HCA\n\t%s\n",
+ verifier->imgfile, flashdev->access_devname);
+ (void) printf("\n\tDo you really want to continue? (Y/N): ");
+
+ (void) fflush(stdin);
+ resp = getchar();
+ if (resp != 'Y' && resp != 'y') {
+ (void) printf("\nNot proceeding with flash "
+ "operation of %s on %s\n",
+ verifier->imgfile, flashdev->access_devname);
+ return (FWFLASH_FAILURE);
+ }
+ }
+
+ /* stash these for later */
+ hpfia = MLXSWAPBITS32(lpps->fia);
+ hsfia = MLXSWAPBITS32(lsps->fia);
+
+ /* where does the on-disk image think everything is at? */
+ ipfia = MLXSWAPBITS32(ipps->fia);
+ isfia = MLXSWAPBITS32(isps->fia);
+ ipfis = MLXSWAPBITS32(ipps->fis);
+ isfis = MLXSWAPBITS32(isps->fis);
+
+ logmsg(MSG_INFO, "tavor: hpfia 0x%0x hsfia 0x%0x "
+ "ipfia 0x%0x isfia 0x%0x ipfis 0x%0x isfis 0x%0x\n",
+ hpfia, hsfia, ipfia, isfia, ipfis, isfis);
+
+ if ((ipfis + isfis) > manuf->device_sz) {
+ /*
+ * This is bad - don't flash an image which is larger
+ * than the size of the HCA's flash
+ */
+ logmsg(MSG_ERROR,
+ gettext("tavor: on-disk firmware image size (0x%lx bytes) "
+ "exceeds HCA's flash memory size (0x%lx bytes)!\n"),
+ ipfis + isfis, manuf->device_sz);
+ logmsg(MSG_ERROR,
+ gettext("tavor: not flashing this image (%s)\n"),
+ verifier->imgfile);
+ 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.
+ */
+
+ ipfi = (struct mlx_xfi *)&verifier->fwimage[ipfia/4];
+ isfi = (struct mlx_xfi *)&verifier->fwimage[isfia/4];
+
+ /*
+ * 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.
+ */
+ if (((manuf->ibguids[0] != MLX_DEFAULT_NODE_GUID) &&
+ (manuf->ibguids[1] != MLX_DEFAULT_P1_GUID) &&
+ (manuf->ibguids[2] != MLX_DEFAULT_P2_GUID) &&
+ (manuf->ibguids[3] != MLX_DEFAULT_SYSIMG_GUID)) &&
+ ((((manuf->ibguids[0] & HIGHBITS64) >> OUISHIFT) == MLX_OUI) ||
+ (((manuf->ibguids[1] & HIGHBITS64) >> OUISHIFT) == MLX_OUI) ||
+ (((manuf->ibguids[2] & HIGHBITS64) >> OUISHIFT) == MLX_OUI) ||
+ (((manuf->ibguids[3] & HIGHBITS64) >> OUISHIFT) == MLX_OUI))) {
+ /* The GUIDs are ok, blat them into the in-memory image */
+ j = ((ipfia + MLXSWAPBITS32(ipfi->nguidptr)) / 4) - 4;
+ bcopy(manuf->pri_guid_section, &verifier->fwimage[j],
+ sizeof (struct mlx_guid_sect));
+ j = ((isfia + MLXSWAPBITS32(isfi->nguidptr)) / 4) - 4;
+ bcopy(manuf->sec_guid_section, &verifier->fwimage[j],
+ sizeof (struct mlx_guid_sect));
+ } else {
+ /*
+ * The GUIDs are hosed, we'll have to use
+ * the vendor defaults in the image instead
+ */
+ logmsg(MSG_ERROR,
+ 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... */
+ tavor_cisco_extensions(lpps, ipps);
+ tavor_cisco_extensions(lsps, isps);
+
+ /* first we write the secondary image and SPS, then the primary */
+ rv = tavor_blast_image(manuf->fd, 2, hsfia, manuf->sector_sz, isps);
+ if (rv != FWFLASH_SUCCESS) {
+ logmsg(MSG_INFO,
+ "tavor: failed to update #2 firmware image\n");
+ (void) tavor_close(flashdev);
+ return (FWFLASH_FAILURE);
+ }
+
+ rv = tavor_blast_image(manuf->fd, 1, hpfia, manuf->sector_sz, ipps);
+ if (rv != FWFLASH_SUCCESS) {
+ logmsg(MSG_INFO,
+ "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;
+ di_node_t thisnode;
+ struct devicelist *newdev;
+ char *devpath;
+ int idx = start;
+ int devlength = 0;
+
+ thisnode = di_drv_first_node(drivername, rootnode);
+
+ if (thisnode == DI_NODE_NIL) {
+ logmsg(MSG_INFO, gettext("No %s nodes in this system\n"),
+ drivername);
+ return (rv);
+ }
+
+ /* we've found one, at least */
+ for (; thisnode != DI_NODE_NIL; thisnode = di_drv_next_node(thisnode)) {
+
+ devpath = di_devfs_path(thisnode);
+
+ if ((newdev = calloc(1, sizeof (struct devicelist)))
+ == NULL) {
+ logmsg(MSG_ERROR,
+ gettext("%s identification function unable "
+ "to allocate space for device entry\n"));
+ di_devfs_path_free(devpath);
+ return (rv);
+ }
+
+ /* calloc enough for /devices + devpath + ":devctl" + '\0' */
+ devlength = strlen(devpath) + strlen(devprefix) +
+ strlen(devsuffix) + 2;
+
+ if ((newdev->access_devname = calloc(1, devlength)) == NULL) {
+ logmsg(MSG_ERROR, gettext("Unable to calloc space "
+ "for a devfs name\n"));
+ di_devfs_path_free(devpath);
+ (void) free(newdev);
+ return (FWFLASH_FAILURE);
+ }
+ snprintf(newdev->access_devname, devlength,
+ "%s%s%s", devprefix, devpath, devsuffix);
+
+ /* CHECK VARIOUS IB THINGS HERE */
+
+ if ((newdev->ident = calloc(1, sizeof (struct vpr))) == NULL) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to allocate space for a "
+ "device identification record\n"));
+ (void) free(newdev->access_devname);
+ (void) free(newdev);
+ di_devfs_path_free(devpath);
+ return (FWFLASH_FAILURE);
+ }
+
+ rv = tavor_identify(newdev);
+ if (rv == FWFLASH_FAILURE) {
+ (void) free(newdev->ident);
+ (void) free(newdev->access_devname);
+ (void) free(newdev);
+ di_devfs_path_free(devpath);
+ continue;
+ }
+
+ if ((newdev->drvname = calloc(1, strlen(drivername) + 1))
+ == NULL) {
+ logmsg(MSG_ERROR, gettext("Unable to allocate space "
+ "for a driver name\n"));
+ (void) free(newdev->ident);
+ (void) free(newdev->access_devname);
+ (void) free(newdev);
+ di_devfs_path_free(devpath);
+ return (FWFLASH_FAILURE);
+ }
+
+ (void) strlcpy(newdev->drvname, drivername,
+ strlen(drivername) + 1);
+
+ /* this next bit is backwards compatibility - "IB\0" */
+ if ((newdev->classname = calloc(1, 3)) == NULL) {
+ logmsg(MSG_ERROR, gettext("Unable to allocate space "
+ "for a class name\n"));
+ (void) free(newdev->drvname);
+ (void) free(newdev->ident);
+ (void) free(newdev->access_devname);
+ (void) free(newdev);
+ di_devfs_path_free(devpath);
+ return (FWFLASH_FAILURE);
+ }
+ (void) strlcpy(newdev->classname, "IB", 3);
+
+ newdev->index = idx;
+ ++idx;
+ newdev->plugin = self;
+
+ di_devfs_path_free(devpath);
+ TAILQ_INSERT_TAIL(fw_devices, newdev, nextdev);
+ }
+
+ if (fwflash_debug != 0) {
+ struct devicelist *tempdev;
+
+ TAILQ_FOREACH(tempdev, fw_devices, nextdev) {
+ logmsg(MSG_INFO, "ib:fw_identify:\n");
+ logmsg(MSG_INFO, "\ttempdev @ 0x%lx\n"
+ "\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,
+ tempdev->access_devname,
+ tempdev->drvname, newdev->classname,
+ tempdev->ident->vid,
+ tempdev->ident->pid,
+ tempdev->ident->revid,
+ tempdev->index,
+ tempdev->addresses[0],
+ tempdev->addresses[1],
+ tempdev->addresses[2],
+ tempdev->addresses[3],
+ tempdev->plugin);
+ }
+ }
+
+ return (FWFLASH_SUCCESS);
+}
+
+
+
+int
+fw_devinfo(struct devicelist *thisdev)
+{
+
+ struct ib_encap_ident *encap;
+
+
+ encap = (struct ib_encap_ident *)thisdev->ident->encap_ident;
+
+ fprintf(stdout, gettext("Device[%d] %s\n Class [%s]\n"),
+ thisdev->index, thisdev->access_devname, thisdev->classname);
+
+ fprintf(stdout, "\t");
+
+ /* Mellanox HCA Flash app note, p40, #4.2.3 table 9 */
+ fprintf(stdout,
+ gettext("GUID: System Image - %s\n"),
+ thisdev->addresses[3]);
+ fprintf(stdout,
+ gettext("\t\tNode Image - %s\n"),
+ thisdev->addresses[0]);
+ fprintf(stdout,
+ gettext("\t\tPort 1\t - %s\n"),
+ thisdev->addresses[1]);
+ fprintf(stdout,
+ gettext("\t\tPort 2\t - %s\n"),
+ thisdev->addresses[2]);
+
+ if (encap->pn_len != 0) {
+ fprintf(stdout,
+ gettext("\tFirmware revision : %s\n"
+ "\tProduct\t\t: %s\n"
+ "\tPSID\t\t: %s\n"),
+ thisdev->ident->revid,
+ encap->info.mlx_pn,
+ encap->info.mlx_psid);
+ } else {
+ fprintf(stdout,
+ gettext("\tFirmware revision : %s\n"
+ "\tNo hardware information available for this "
+ "device\n"), thisdev->ident->revid);
+ }
+ fprintf(stdout, "\n\n");
+
+ 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
+tavor_identify(struct devicelist *thisdev)
+{
+ int rv = FWFLASH_SUCCESS;
+ int fd, ret, i;
+
+ tavor_flash_init_ioctl_t init_ioctl;
+ tavor_flash_ioctl_t info;
+ struct ib_encap_ident *manuf;
+ cfi_t cfi;
+ char temppsid[17];
+ char rawpsid[16];
+
+#if defined(_LITTLE_ENDIAN)
+ uint32_t *ptr;
+#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;
+ if ((fd = open(thisdev->access_devname, O_RDONLY)) < 0) {
+ logmsg(MSG_INFO,
+ gettext("tavor: Unable to open a %s-attached "
+ "device node: %s: %s\n"), drivername,
+ thisdev->access_devname, strerror(errno));
+ return (FWFLASH_FAILURE);
+ }
+
+ if ((manuf = calloc(1, sizeof (ib_encap_ident_t))) == NULL) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to calloc space for a "
+ "%s-attached handle structure\n"),
+ drivername);
+ return (FWFLASH_FAILURE);
+ }
+ manuf->magic = FWFLASH_IB_MAGIC_NUMBER;
+ manuf->state = FWFLASH_IB_STATE_NONE;
+ manuf->fd = fd;
+
+ thisdev->ident->encap_ident = manuf;
+
+ /*
+ * Inform driver that this command supports the Intel Extended
+ * CFI command set.
+ */
+ cfi.cfi_char[0x10] = 'M';
+ cfi.cfi_char[0x11] = 'X';
+ cfi.cfi_char[0x12] = '2';
+ init_ioctl.tf_cfi_info[0x4] = MLXSWAPBITS32(cfi.cfi_int[0x4]);
+
+ errno = 0;
+ ret = ioctl(fd, TAVOR_IOCTL_FLASH_INIT, &init_ioctl);
+ if (ret < 0) {
+ logmsg(MSG_ERROR,
+ gettext("ib: TAVOR_IOCTL_FLASH_INIT failed: %s\n"),
+ strerror(errno));
+ free(manuf);
+ close(fd);
+ return (FWFLASH_FAILURE);
+ }
+
+ manuf->hwrev = init_ioctl.tf_hwrev;
+
+ /*
+ * 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++) {
+ cfi.cfi_int[i] = MLXSWAPBITS32(init_ioctl.tf_cfi_info[i]);
+ }
+ manuf->cmd_set = cfi.cfi_char[0x13];
+
+ if (cfi.cfi_char[0x10] == 'Q' &&
+ cfi.cfi_char[0x11] == 'R' &&
+ cfi.cfi_char[0x12] == 'Y') {
+ /* make sure the cmd set is AMD */
+ if (manuf->cmd_set != TAVOR_FLASH_AMD_CMDSET) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unsupported flash device "
+ "command set\n"));
+ free(manuf);
+ close(fd);
+ return (FWFLASH_FAILURE);
+ }
+ /* set some defaults */
+ manuf->device_sz = TAVOR_FLASH_DEVICE_SZ_DEFAULT;
+ } else {
+ if (manuf->cmd_set != TAVOR_FLASH_AMD_CMDSET &&
+ manuf->cmd_set != TAVOR_FLASH_INTEL_CMDSET) {
+ logmsg(MSG_ERROR,
+ gettext("ib: Unknown flash device command set\n"));
+ free(manuf);
+ close(fd);
+ return (FWFLASH_FAILURE);
+ }
+ /* read from the CFI data */
+ manuf->sector_sz = ((cfi.cfi_char[0x30] << 8) |
+ cfi.cfi_char[0x2F]) << 8;
+ manuf->device_sz = 0x1 << cfi.cfi_char[0x27];
+ }
+
+ logmsg(MSG_INFO, "sector_sz: 0x%08x\ndevice_sz: 0x%08x\n",
+ manuf->sector_sz, manuf->device_sz);
+
+ manuf->state |= FWFLASH_IB_STATE_MMAP;
+
+ /* set firmware revision */
+ manuf->fw_rev.major = init_ioctl.tf_fwrev.tfi_maj;
+ manuf->fw_rev.minor = init_ioctl.tf_fwrev.tfi_min;
+ manuf->fw_rev.subminor = init_ioctl.tf_fwrev.tfi_sub;
+
+ if (((thisdev->ident->vid = calloc(1, MLX_VPR_VIDLEN + 1)) == NULL) ||
+ ((thisdev->ident->revid = calloc(1, MLX_VPR_REVLEN + 1)) == NULL)) {
+
+ logmsg(MSG_ERROR,
+ gettext("ib: Unable to allocate space for a VPR "
+ "record.\n"));
+ free(thisdev->ident);
+ free(manuf->info.mlx_pn);
+ free(manuf->info.mlx_psid);
+ free(manuf->info.mlx_id);
+ free(manuf);
+ close(fd);
+ return (FWFLASH_FAILURE);
+ }
+ (void) strlcpy(thisdev->ident->vid, "MELLANOX", MLX_VPR_VIDLEN);
+ /*
+ * 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.
+ */
+
+ snprintf(thisdev->ident->revid, MLX_VPR_REVLEN, "%d.%d.%04d",
+ manuf->fw_rev.major, manuf->fw_rev.minor,
+ manuf->fw_rev.subminor);
+
+ bzero(manuf->ibguids, sizeof (manuf->ibguids));
+
+ /*
+ * For convenience we read in the Invariant Sector as
+ * well as both the Primary and Secondary Pointer Sectors
+ */
+
+ if ((manuf->inv = calloc(1, manuf->sector_sz)) == NULL) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to allocate space for storing "
+ "the HCA's Invariant Sector\n"));
+ return (FWFLASH_FAILURE);
+ }
+ bzero(&info, sizeof (tavor_flash_ioctl_t));
+
+ info.tf_type = TAVOR_FLASH_READ_SECTOR;
+ info.tf_sector = (caddr_t)manuf->inv;
+ info.tf_sector_num = 0;
+
+ errno = 0;
+
+ if ((rv = ioctl(manuf->fd, TAVOR_IOCTL_FLASH_READ, &info))
+ < 0) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to read HCA Invariant Sector\n"));
+ return (FWFLASH_FAILURE);
+ }
+
+#if defined(_LITTLE_ENDIAN)
+ ptr = (uint32_t *)(uintptr_t)manuf->inv;
+ for (i = 0; i < (manuf->sector_sz / 4); i++) {
+ ptr[i] = htonl(ptr[i]);
+ }
+#endif
+
+ if ((manuf->pps = calloc(1, manuf->sector_sz)) == NULL) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to allocate space for storing "
+ "the HCA's Primary Pointer Sector\n"));
+ return (FWFLASH_FAILURE);
+ }
+ bzero(&info, sizeof (tavor_flash_ioctl_t));
+
+ info.tf_type = TAVOR_FLASH_READ_SECTOR;
+ info.tf_sector = (caddr_t)manuf->pps;
+ info.tf_sector_num = 1;
+
+ errno = 0;
+
+ if ((rv = ioctl(manuf->fd, TAVOR_IOCTL_FLASH_READ, &info))
+ < 0) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to read HCA Primary "
+ "Pointer Sector\n"));
+ return (FWFLASH_FAILURE);
+ }
+
+#if defined(_LITTLE_ENDIAN)
+ ptr = (uint32_t *)(uintptr_t)manuf->pps;
+ for (i = 0; i < (manuf->sector_sz / 4); i++) {
+ ptr[i] = htonl(ptr[i]);
+ }
+#endif
+
+ if ((manuf->sps = calloc(1, manuf->sector_sz)) == NULL) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to allocate space for storing "
+ "the HCA's Secondary Pointer Sector\n"));
+ return (FWFLASH_FAILURE);
+ }
+ bzero(&info, sizeof (tavor_flash_ioctl_t));
+
+ info.tf_type = TAVOR_FLASH_READ_SECTOR;
+ info.tf_sector = (caddr_t)manuf->sps;
+ info.tf_sector_num = 2;
+
+ errno = 0;
+
+ if ((rv = ioctl(manuf->fd, TAVOR_IOCTL_FLASH_READ, &info))
+ < 0) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to read HCA Secondary "
+ "Pointer Sector\n"));
+ return (FWFLASH_FAILURE);
+ }
+
+#if defined(_LITTLE_ENDIAN)
+ ptr = (uint32_t *)(uintptr_t)manuf->sps;
+ for (i = 0; i < (manuf->sector_sz / 4); i++) {
+ ptr[i] = htonl(ptr[i]);
+ }
+#endif
+
+ if ((ret = tavor_get_guids(manuf)) != FWFLASH_SUCCESS) {
+ logmsg(MSG_INFO,
+ gettext("ib: No guids found for device %s!\n"),
+ thisdev->access_devname);
+ }
+
+ /* set hw part number, psid, and name in handle */
+ bzero(temppsid, 17);
+ bcopy(manuf->pps+FLASH_PS_PSID_OFFSET, &rawpsid, 16);
+
+ for (i = 0; i < 16; i += 4) {
+ temppsid[i] = rawpsid[i+3];
+ temppsid[i+1] = rawpsid[i+2];
+ temppsid[i+2] = rawpsid[i+1];
+ temppsid[i+3] = rawpsid[i];
+ }
+ logmsg(MSG_INFO,
+ "tavor: have raw '%s', want munged '%s'\n",
+ rawpsid, temppsid);
+
+ /* now walk the magic decoder ring table */
+ manuf->info.mlx_pn = NULL;
+ manuf->info.mlx_psid = NULL;
+ manuf->info.mlx_id = NULL;
+ manuf->pn_len = 0;
+
+ for (i = 0; i < MLX_MAX_ID; i++) {
+ if ((strncmp(temppsid, mlx_mdr[i].mlx_psid,
+ MLX_PSID_SZ)) == 0) {
+ /* matched */
+ if ((manuf->info.mlx_pn = calloc(1,
+ strlen(mlx_mdr[i].mlx_pn) + 1)) == NULL) {
+ logmsg(MSG_INFO,
+ "tavor: no space available for the "
+ "HCA PSID record (1)\n");
+ } else {
+ (void) strlcpy(manuf->info.mlx_pn,
+ mlx_mdr[i].mlx_pn,
+ strlen(mlx_mdr[i].mlx_pn) + 1);
+ manuf->pn_len = strlen(mlx_mdr[i].mlx_pn);
+ }
+
+ if ((manuf->info.mlx_psid = calloc(1,
+ strlen(mlx_mdr[i].mlx_psid) + 1)) == NULL) {
+ logmsg(MSG_INFO,
+ "tavor: no space available for the "
+ "HCA PSID record (2)\n");
+ } else {
+ (void) strlcpy(manuf->info.mlx_psid,
+ mlx_mdr[i].mlx_psid,
+ strlen(mlx_mdr[i].mlx_psid) + 1);
+ }
+ if ((manuf->info.mlx_id = calloc(1,
+ strlen(mlx_mdr[i].mlx_id) + 1)) == NULL) {
+ logmsg(MSG_INFO,
+ "tavor: no space available for the "
+ "HCA PSID record (3)\n");
+ } else {
+ (void) strlcpy(manuf->info.mlx_id,
+ mlx_mdr[i].mlx_id,
+ strlen(mlx_mdr[i].mlx_id) + 1);
+ }
+ }
+ }
+ if ((manuf->pn_len == 0) || (i == MLX_MAX_ID)) {
+ logmsg(MSG_INFO,
+ "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");
+
+ thisdev->ident->pid = calloc(1, i + 2);
+ sprintf(thisdev->ident->pid, "No hardware information "
+ "available for this device");
+ } else {
+ if ((thisdev->ident->pid = calloc(1,
+ strlen(manuf->info.mlx_psid) + 1)) != NULL) {
+ (void) strlcpy(thisdev->ident->pid,
+ manuf->info.mlx_psid,
+ strlen(manuf->info.mlx_psid) + 1);
+ } else {
+ logmsg(MSG_ERROR,
+ gettext("ib: Unable to allocate space for a "
+ "hardware identifier\n"));
+ free(thisdev->ident);
+ free(manuf->info.mlx_pn);
+ free(manuf->info.mlx_psid);
+ free(manuf->info.mlx_id);
+ free(manuf);
+ close(fd);
+ return (FWFLASH_FAILURE);
+ }
+ }
+
+ for (i = 0; i < 4; i++) {
+ if ((thisdev->addresses[i] = calloc(1,
+ (2 * sizeof (uint64_t)) + 1)) == NULL) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to allocate space for a "
+ "human-readable HCA guid\n"));
+ return (FWFLASH_FAILURE);
+ }
+ (void) sprintf(thisdev->addresses[i], "%016llx",
+ manuf->ibguids[i]);
+ }
+
+ /*
+ * 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
+tavor_get_guids(struct ib_encap_ident *handle)
+{
+ int rv, j;
+ uint32_t i = 0x00;
+ tavor_flash_ioctl_t info;
+ struct mlx_guid_sect *p, *s;
+
+#if defined(_LITTLE_ENDIAN)
+ uint32_t *ptr, tmp;
+#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
+ * so DO NOT move this file out of usr/closed without
+ * 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++) {
+ handle->ibguids[i] = 0x00000000;
+ }
+
+ /* convenience .... */
+
+ if ((p = calloc(1, sizeof (mlx_guid_sect_t))) == NULL) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to allocate space for "
+ "HCA guid record (1)\n"));
+ return (FWFLASH_FAILURE);
+ }
+ if ((s = calloc(1, sizeof (mlx_guid_sect_t))) == NULL) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to allocate space for "
+ "HCA guid record (2)\n"));
+ free(p);
+ return (FWFLASH_FAILURE);
+ }
+
+ bcopy(&handle->pps[0], &i, 4);
+ handle->pfi_guid_addr = MLXSWAPBITS32(i) + FLASH_GUID_PTR;
+ bcopy(&handle->sps[0], &i, 4);
+ handle->sfi_guid_addr = MLXSWAPBITS32(i) + FLASH_GUID_PTR;
+
+ bzero(&info, sizeof (tavor_flash_ioctl_t));
+ info.tf_type = TAVOR_FLASH_READ_QUADLET;
+ info.tf_addr = handle->pfi_guid_addr;
+
+ errno = 0;
+
+ rv = ioctl(handle->fd, TAVOR_IOCTL_FLASH_READ, &info);
+ if (rv < 0) {
+ logmsg(MSG_ERROR,
+ 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
+ */
+ info.tf_addr = handle->pfi_guid_addr + info.tf_quadlet
+ - FLASH_GUID_PTR - 16;
+
+ bzero(handle->pri_guid_section, sizeof (mlx_guid_sect_t));
+
+ for (j = 0; j < 13; j++) {
+ errno = 0;
+ if ((rv = ioctl(handle->fd, TAVOR_IOCTL_FLASH_READ,
+ &info)) < 0) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to read Primary Image "
+ "guid chunk %d\n"), j);
+ }
+ handle->pri_guid_section[j] = info.tf_quadlet;
+ info.tf_addr += 4;
+ }
+ bcopy(&handle->pri_guid_section, p, sizeof (struct mlx_guid_sect));
+
+ /* now grab the secondary guid set */
+ bzero(&info, sizeof (tavor_flash_ioctl_t));
+ info.tf_type = TAVOR_FLASH_READ_QUADLET;
+ info.tf_addr = handle->sfi_guid_addr;
+
+ errno = 0;
+
+ if ((rv = ioctl(handle->fd, TAVOR_IOCTL_FLASH_READ,
+ &info)) < 0) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to read Secondary Image "
+ "guid offset (%s)\n"), strerror(errno));
+ free(p);
+ free(s);
+ return (FWFLASH_FAILURE);
+ }
+
+ info.tf_addr = handle->sfi_guid_addr + info.tf_quadlet
+ - FLASH_GUID_PTR - 16;
+
+ bzero(handle->sec_guid_section, sizeof (mlx_guid_sect_t));
+
+ for (j = 0; j < 13; j++) {
+ errno = 0;
+ if ((rv = ioctl(handle->fd, TAVOR_IOCTL_FLASH_READ,
+ &info)) < 0) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to read Secondary Image "
+ "guid chunk %d (%s)\n"), j, strerror(errno));
+ return (FWFLASH_FAILURE);
+ }
+ handle->sec_guid_section[j] = info.tf_quadlet;
+ info.tf_addr += 4;
+ }
+
+ bcopy(&handle->sec_guid_section, s, sizeof (struct mlx_guid_sect));
+
+#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.
+ */
+
+ ptr = (uint32_t *)(uintptr_t)p;
+ for (j = 0; j < 14; j += 2) {
+ tmp = ptr[j];
+ ptr[j] = ptr[j+1];
+ ptr[j+1] = tmp;
+ }
+
+ ptr = (uint32_t *)(uintptr_t)s;
+ for (j = 0; j < 14; j += 2) {
+ tmp = ptr[j];
+ ptr[j] = ptr[j+1];
+ ptr[j+1] = tmp;
+ }
+#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.
+ */
+ if ((p->nodeguid == s->nodeguid) &&
+ (p->port1guid == s->port1guid) &&
+ (p->port2guid == s->port2guid) &&
+ (p->sysimguid == s->sysimguid)) {
+ logmsg(MSG_INFO,
+ "tavor: primary and secondary guids are the same\n");
+ handle->ibguids[0] = p->nodeguid;
+ handle->ibguids[1] = p->port1guid;
+ handle->ibguids[2] = p->port2guid;
+ handle->ibguids[3] = p->sysimguid;
+ } 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
+ */
+ logmsg(MSG_INFO,
+ "tavor: primary and secondary guids don't all match\n");
+
+ if (s->nodeguid > p->nodeguid) {
+ handle->ibguids[0] = s->nodeguid;
+ handle->ibguids[1] = s->port1guid;
+ handle->ibguids[2] = s->port2guid;
+ handle->ibguids[3] = s->sysimguid;
+ bzero(p, sizeof (struct mlx_guid_sect));
+ } else {
+ handle->ibguids[0] = p->nodeguid;
+ handle->ibguids[1] = p->port1guid;
+ handle->ibguids[2] = p->port2guid;
+ handle->ibguids[3] = p->sysimguid;
+ bzero(s, sizeof (struct mlx_guid_sect));
+ }
+ }
+
+ free(p);
+ free(s);
+
+ if (fwflash_debug) {
+ for (i = 0; i < 4; i++) {
+ logmsg(MSG_INFO, "ibguids[%d] %0llx\n", i,
+ handle->ibguids[i]);
+ }
+ }
+
+ return (FWFLASH_SUCCESS);
+}
+
+
+int
+tavor_close(struct devicelist *flashdev)
+{
+
+ struct ib_encap_ident *handle;
+
+ handle = (struct ib_encap_ident *)flashdev->ident->encap_ident;
+ if (handle->fd > 0) {
+ (void) ioctl(handle->fd, TAVOR_IOCTL_FLASH_FINI);
+ errno = 0;
+ if (close(handle->fd) != 0) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to properly close "
+ "device %s! (%s)\n"),
+ flashdev->access_devname,
+ strerror(errno));
+ 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
+tavor_cisco_extensions(mlx_xps_t *hcaxps, mlx_xps_t *diskxps)
+{
+ uint16_t sig1, sig2;
+ uint32_t i;
+
+
+ bcopy(hcaxps->vsdpsid, &i, 4);
+ sig1 = htonl(i);
+ bcopy(&hcaxps->vsdpsid[223], &i, 4);
+ sig2 = htonl(i);
+
+
+ if (sig1 == FLASH_VSD_CISCO_SIGNATURE &&
+ sig2 == FLASH_VSD_CISCO_SIGNATURE) {
+ logmsg(MSG_INFO,
+ "tavor: CISCO signature found in HCA's VSD, copying to "
+ "new image's VSD\n");
+
+ i = htonl(FLASH_VSD_CISCO_SIGNATURE);
+ bcopy(&i, diskxps->vsdpsid, 2);
+
+ /*
+ * 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.
+ */
+
+ i = (diskxps->vsdpsid[222] | FLASH_VSD_CISCO_BOOT_VERSION);
+ bcopy(&i, &diskxps->vsdpsid[222], 2);
+ /*
+ * 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.
+ */
+
+ logmsg(MSG_INFO, "tavor: CISCO boot flags currently set "
+ "to 0x%08x\n",
+ diskxps->vsdpsid[1]);
+
+ diskxps->vsdpsid[1] =
+ htonl(diskxps->vsdpsid[1] |
+ FLASH_VSD_CISCO_FLAG_AUTOUPGRADE |
+ FLASH_VSD_CISCO_BOOT_OPTIONS |
+ FLASH_VSD_CISCO_FLAG_BOOT_ENABLE_PORT_1 |
+ FLASH_VSD_CISCO_FLAG_BOOT_ENABLE_PORT_2 |
+ FLASH_VSD_CISCO_FLAG_BOOT_ENABLE_SCAN |
+ FLASH_VSD_CISCO_FLAG_BOOT_TYPE_WELL_KNOWN |
+ FLASH_VSD_CISCO_FLAG_BOOT_TRY_FOREVER);
+
+ logmsg(MSG_INFO, "tavor: CISCO boot flags now set "
+ "to 0x%08x\n",
+ diskxps->vsdpsid[1]);
+ } else
+ logmsg(MSG_INFO,
+ "tavor: CISCO signature not found in HCA's VSD\n");
+}
+
+
+static int
+tavor_write_sector(int fd, int sectnum, int32_t *data)
+{
+ int rv, i;
+ tavor_flash_ioctl_t cmd;
+
+
+ bzero(&cmd, sizeof (tavor_flash_ioctl_t));
+
+ cmd.tf_type = TAVOR_FLASH_WRITE_SECTOR;
+ cmd.tf_sector_num = sectnum;
+ cmd.tf_sector = (caddr_t)data;
+
+ errno = 0;
+
+ logmsg(MSG_INFO,
+ "tavor: tavor_write_sector(fd %d, sectnum 0x%x, data 0x%lx)\n",
+ fd, sectnum, data);
+ logmsg(MSG_INFO,
+ "tavor:\n"
+ "\tcmd.tf_type %d\n"
+ "\tcmd.tf_sector 0x%lx\n"
+ "\tcmd.tf_sector_num %d\n",
+ cmd.tf_type, data, cmd.tf_sector_num);
+
+ /*
+ * If we're debugging, dump the first 64 uint32_t that we've
+ * been passed
+ */
+ if (fwflash_debug > 0) {
+ i = 0;
+ while (i < 64) {
+ logmsg(MSG_INFO,
+ "%02x: %08x %08x %08x %08x\n",
+ i, data[i], data[i+1],
+ data[i+2], data[i+3]);
+ i += 4;
+ }
+ }
+
+ rv = ioctl(fd, TAVOR_IOCTL_FLASH_WRITE, &cmd);
+ if (rv < 0) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: WRITE SECTOR failed for sector "
+ "%d: %s\n"),
+ sectnum, strerror(errno));
+ 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
+tavor_zero_sig_crc(int fd, uint32_t start)
+{
+ int i, rv;
+ tavor_flash_ioctl_t cmd;
+
+ /* signature first, then CRC16 */
+ bzero(&cmd, sizeof (tavor_flash_ioctl_t));
+ cmd.tf_type = TAVOR_FLASH_WRITE_BYTE;
+ cmd.tf_byte = 0x00;
+
+ logmsg(MSG_INFO,
+ "tavor: tavor_zero_sig_crc(fd %d, start 0x%04x)\n",
+ fd, start);
+
+ for (i = 0; i < 4; i++) {
+ cmd.tf_addr = start + FLASH_PS_SIGNATURE_OFFSET + i;
+
+ logmsg(MSG_INFO,
+ "tavor: invalidating xPS sig (offset from IS 0x%04x) "
+ "byte %d\n",
+ cmd.tf_addr, i);
+ errno = 0;
+
+ rv = ioctl(fd, TAVOR_IOCTL_FLASH_WRITE, &cmd);
+ if (rv < 0) {
+ logmsg(MSG_INFO,
+ gettext("tavor: Unable to write 0x00 to "
+ "offset 0x%04x from IS (sig byte %d): %s\n"),
+ cmd.tf_addr, i, strerror(errno));
+ return (FWFLASH_FAILURE);
+ }
+ }
+
+ cmd.tf_byte = 0x00;
+ for (i = 0; i < 2; i++) {
+ cmd.tf_addr = start + FLASH_PS_CRC16_OFFSET + i;
+
+ logmsg(MSG_INFO,
+ "tavor: invalidating xPS CRC16 (offset from IS 0x%04x) "
+ "byte %d\n",
+ cmd.tf_addr, i);
+ errno = 0;
+
+ rv = ioctl(fd, TAVOR_IOCTL_FLASH_WRITE, &cmd);
+ if (rv < 0) {
+ logmsg(MSG_INFO,
+ gettext("tavor: Unable to write 0x00 to "
+ "offset 0x%04x from IS (CRC16 byte %d): %s\n"),
+ cmd.tf_addr, i, strerror(errno));
+ 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
+tavor_write_xps_fia(int fd, uint32_t offset, uint32_t start)
+{
+ int i, rv;
+ uint8_t *addrbytep;
+ tavor_flash_ioctl_t cmd;
+
+ logmsg(MSG_INFO,
+ "tavor: tavor_write_xps_fia(fd %d, offset 0x%04x, "
+ "start 0x%04x)\n",
+ fd, offset, start);
+
+ addrbytep = (uint8_t *)&start;
+
+ bzero(&cmd, sizeof (tavor_flash_ioctl_t));
+ cmd.tf_type = TAVOR_FLASH_WRITE_BYTE;
+ for (i = 0; i < 4; i++) {
+ cmd.tf_byte = addrbytep[i];
+ cmd.tf_addr = offset + FLASH_PS_FI_ADDR_OFFSET + i;
+ logmsg(MSG_INFO,
+ "tavor: writing xPS' new FIA, byte %d (0x%0x) at "
+ "offset from IS 0x%04x\n",
+ i, cmd.tf_byte, cmd.tf_addr);
+ errno = 0;
+
+ rv = ioctl(fd, TAVOR_IOCTL_FLASH_WRITE, &cmd);
+ if (rv < 0) {
+ logmsg(MSG_INFO,
+ gettext("tavor: Unable to write byte %d "
+ "of xPS new FIA (0x%0x, offset from IS "
+ "0x%04x): %s\n"),
+ i, cmd.tf_byte, cmd.tf_addr, strerror(errno));
+ 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
+tavor_write_xps_crc_sig(int fd, uint32_t offset, uint16_t newcrc)
+{
+ int i, rv;
+ uint8_t *bytep;
+ uint32_t tempsig;
+ tavor_flash_ioctl_t cmd;
+
+ logmsg(MSG_INFO,
+ "tavor: tavor_write_xps_crc_sig(fd %d, offset 0x%04x, "
+ "newcrc 0x%04x)\n",
+ fd, offset, newcrc);
+
+ bytep = (uint8_t *)&newcrc;
+
+ bzero(&cmd, sizeof (tavor_flash_ioctl_t));
+ cmd.tf_type = TAVOR_FLASH_WRITE_BYTE;
+ for (i = 0; i < 2; i++) {
+ cmd.tf_byte = bytep[i];
+ cmd.tf_addr = offset + FLASH_PS_CRC16_OFFSET + i;
+ logmsg(MSG_INFO,
+ "tavor: writing new XPS CRC16, byte %d (0x%0x) at "
+ "offset from IS 0x%04x\n",
+ i, bytep[i], cmd.tf_addr);
+ errno = 0;
+
+ rv = ioctl(fd, TAVOR_IOCTL_FLASH_WRITE, &cmd);
+ if (rv < 0) {
+ logmsg(MSG_INFO,
+ gettext("tavor: Unable to write byte %d "
+ "(0x%0x) of xPS' new CRC16 to offset "
+ "from IS 0x%04x: %s\n"),
+ i, bytep[i], cmd.tf_addr, strerror(errno));
+ return (FWFLASH_FAILURE);
+ }
+ }
+
+ tempsig = htonl(FLASH_PS_SIGNATURE);
+ bytep = (uint8_t *)&tempsig;
+
+ for (i = 0; i < 4; i++) {
+ cmd.tf_byte = bytep[i];
+ cmd.tf_addr = offset + FLASH_PS_SIGNATURE_OFFSET + i;
+ logmsg(MSG_INFO,
+ "tavor: writing new xPS Signature, byte %d (0x%0x) at "
+ "offset from IS 0x%04x\n",
+ i, bytep[i], cmd.tf_addr);
+ errno = 0;
+
+ rv = ioctl(fd, TAVOR_IOCTL_FLASH_WRITE, &cmd);
+ if (rv < 0) {
+ logmsg(MSG_INFO,
+ gettext("tavor: Unable to write byte %d (0x%0x) "
+ "of xPS' signature at offset from IS 0x%04x: %s\n"),
+ i, bytep[i], cmd.tf_addr, strerror(errno));
+ return (FWFLASH_FAILURE);
+ }
+ }
+ return (FWFLASH_SUCCESS);
+}
+
+
+
+/*
+ * This function contains "Begin/End documentation departure point"
+ * 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_blast_image(int fd, int prisec, uint32_t hcafia, uint32_t sectsz,
+ struct mlx_xps *newxps)
+{
+ uint32_t i, j, rv;
+ uint32_t startsectimg, startsecthca, numsect;
+
+ if ((prisec != 1) && (prisec != 2)) {
+ logmsg(MSG_ERROR,
+ "tavor: invalid image number requested (%d)\n");
+ return (FWFLASH_FAILURE);
+ }
+
+ /* Begin documentation departure point */
+
+ /* zero the HCA's PPS signature and CRC */
+ if (tavor_zero_sig_crc(fd, (prisec * sectsz))
+ != FWFLASH_SUCCESS) {
+ logmsg(MSG_INFO,
+ "tavor: Unable zero HCA's %s signature "
+ "and CRC16 fields\n",
+ ((prisec == 1) ? "PPS" : "SPS"));
+ return (FWFLASH_FAILURE);
+ }
+
+ logmsg(MSG_INFO, "tavor: zeroing HCA's %s sig and crc\n",
+ (prisec == 1) ? "pps" : "sps");
+
+ /* End documentation departure point */
+
+ /* make sure we don't inadvertently overwrite bits */
+
+ startsectimg = MLXSWAPBITS32(newxps->fia) / sectsz;
+ startsecthca = hcafia / sectsz;
+
+ numsect = (MLXSWAPBITS32(newxps->fis) / sectsz) +
+ ((MLXSWAPBITS32(newxps->fis) % sectsz) ? 1 : 0);
+
+ logmsg(MSG_INFO, "tavor: %s imgsize 0x%0x startsecthca %d, "
+ "startsectimg %d, num sectors %d\n",
+ (prisec == 1) ? "PFI" : "SFI", MLXSWAPBITS32(newxps->fis),
+ startsecthca, startsectimg, numsect);
+
+ for (i = 0; i < numsect; i++) {
+
+ j = (MLXSWAPBITS32(newxps->fia) + (i * sectsz)) / 4;
+
+ logmsg(MSG_INFO, "tavor: image offset 0x%0x\n", j);
+ logmsg(MSG_INFO, "tavor: writing HCA sector %d\n",
+ i + startsecthca);
+
+ if (tavor_write_sector(fd, i + startsecthca,
+ &verifier->fwimage[j])
+ != FWFLASH_SUCCESS) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to write "
+ "sector %d to HCA\n"),
+ i + startsecthca);
+ return (FWFLASH_FAILURE);
+ }
+ (void) printf(" .");
+
+ rv = tavor_readback(fd, i + startsecthca, sectsz);
+ if (rv != FWFLASH_SUCCESS) {
+ logmsg(MSG_ERROR,
+ 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 */
+ newxps->signature = 0xffffffff;
+ newxps->crc16 = 0xffff;
+ /* we put the fia back to imgfia later */
+ newxps->fia = 0xffffffff;
+ /* End documentation departure point */
+
+ /* success so far, now burn the new xPS */
+ if (tavor_write_sector(fd, prisec, (int *)newxps)
+ != FWFLASH_SUCCESS) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to write new %s "
+ "pointer sector to HCA\n"),
+ (prisec == 1) ? "primary" : "secondary");
+ return (FWFLASH_FAILURE);
+ }
+ (void) printf(" .");
+
+ /* Begin documentation departure point */
+
+ /* write new fia to the HCA's pps */
+ logmsg(MSG_INFO, "tavor: writing new fia (0x%0x) to HCA\n",
+ MLXSWAPBITS32(newxps->fia));
+
+ if (tavor_write_xps_fia(fd, (prisec * sectsz),
+ MLXSWAPBITS32(hcafia)) != FWFLASH_SUCCESS) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to update HCA's %s "
+ "pointer sector FIA record\n"),
+ (prisec == 1) ? "primary" : "secondary");
+ return (FWFLASH_FAILURE);
+ }
+
+ /* don't forget the byte-swapping */
+ newxps->fia = MLXSWAPBITS32(hcafia);
+ newxps->signature =
+ (uint32_t)MLXSWAPBITS32(FLASH_PS_SIGNATURE);
+ newxps->crc16 =
+ MLXSWAPBITS16(crc16((uint8_t *)newxps, FLASH_PS_CRC16_SIZE));
+
+ logmsg(MSG_INFO, "tavor: writing new fia 0x%0x, "
+ "sig 0x%0x and new crc16 0x%0x\n",
+ newxps->fia, MLXSWAPBITS32(newxps->signature),
+ newxps->crc16);
+
+ if (tavor_write_xps_crc_sig(fd, (prisec * sectsz),
+ newxps->crc16) != FWFLASH_SUCCESS) {
+ /*
+ * Now we're REALLY hosed. If the card comes up at all,
+ * expect it to be in "Maintenance Mode".
+ */
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to update HCA's %s CRC "
+ "and Firmware Image signature fields\n"),
+ (prisec == 1) ? "PPS" : "SPS");
+ return (FWFLASH_FAILURE);
+ }
+
+ rv = tavor_readback(fd, prisec, sectsz);
+ if (rv != FWFLASH_SUCCESS) {
+ logmsg(MSG_ERROR,
+ gettext("tavor: Unable to read %s pointer sector "
+ "from HCA\n"),
+ (prisec == 1) ? "Primary" : "Secondary");
+ return (FWFLASH_FAILURE);
+ }
+ (void) printf(" |");
+ /* End documentation departure point */
+ return (FWFLASH_SUCCESS);
+}
+
+
+static int
+tavor_readback(int infd, int whichsect, int sectsz)
+{
+ uint32_t *data;
+ tavor_flash_ioctl_t cmd;
+ int rv;
+
+ bzero(&cmd, sizeof (tavor_flash_ioctl_t));
+ data = calloc(1, sectsz); /* assumption! */
+
+ cmd.tf_type = TAVOR_FLASH_READ_SECTOR;
+ cmd.tf_sector_num = whichsect;
+ cmd.tf_sector = (caddr_t)data;
+ rv = ioctl(infd, TAVOR_IOCTL_FLASH_READ, &cmd);
+ if (rv < 0) {
+ logmsg(MSG_INFO,
+ "tavor: UNABLE TO READ BACK SECTOR %d from HCA\n",
+ whichsect);
+ return (FWFLASH_FAILURE);
+ }
+ free(data);
+ 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
+crc16(uint8_t *image, uint32_t size)
+{
+ const uint16_t poly = 0x100b;
+ uint32_t crc = 0xFFFF;
+ uint32_t word;
+ uint32_t i, j;
+
+ for (i = 0; i < size / 4; i++) {
+ word = (image[4 * i] << 24) |
+ (image[4 * i + 1] << 16) |
+ (image[4 * i + 2] << 8) |
+ (image[4 * i + 3]);
+
+ for (j = 0; j < 32; j++) {
+ if (crc & 0x8000) {
+ crc = (((crc << 1) |
+ (word >> 31)) ^ poly) & 0xFFFF;
+ } else {
+ crc = ((crc << 1) | (word >> 31)) & 0xFFFF;
+ }
+ word = (word << 1) & 0xFFFFFFFF;
+ }
+ }
+
+ for (i = 0; i < 16; i++) {
+ if (crc & 0x8000) {
+ crc = ((crc << 1) ^ poly) & 0xFFFF;
+ } else {
+ crc = (crc << 1) & 0xFFFF;
+ }
+ }
+
+ crc = crc ^ 0xFFFF;
+ return (crc & 0xFFFF);
+}
diff --git a/usr/src/cmd/fwflash/plugins/transport/i386/Makefile b/usr/src/cmd/fwflash/plugins/transport/i386/Makefile
index 499f8ee4ad..260a39533d 100644
--- a/usr/src/cmd/fwflash/plugins/transport/i386/Makefile
+++ b/usr/src/cmd/fwflash/plugins/transport/i386/Makefile
@@ -18,28 +18,26 @@
#
# CDDL HEADER END
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
-#
-#
# cmd/fwflash/plugins/transport/i386
#
-SRCS= ses.c
+SRCS= ses.c tavor.c hermon.c
OBJECTS= $(SRCS:%.c=%.o)
PLUGINS= $(SRCS:%.c=%.so)
-POFILES= ses.po
+POFILES= $(SRCS:%.c=%.po)
IDENTPOFILE= fwflash_transport_identify_ses.po
-LINTFILE= ses.ln
+LINTFILE= $(SRCS:%.c=%.ln)
SLINKS= sgen.so
CLEANFILES= $(OBJECTS)
CLOBBERFILES= $(PLUGINS) $(POFILES) $(IDENTPOFILE) $(LINTFILE) $(SLINKS)
+
all: $(PLUGINS)
_msg msg: $(IDENTPOFILE)
@@ -59,17 +57,18 @@ $(PLUGINS) := FILEMODE = 0555
$(ROOTLIBFWFLASHPLUGINS)/$(SLINKS) : $(ROOTLIBFWFLASHPLUGINS)/ses.so
@$(RM) $@
- $(SYMLINK) $(PLUGINS) $@
-
+ $(SYMLINK) ses.so $@
-
-install: $(ROOTLIBFWFLASHPLUGINS) \
+install: all $(ROOTLIBFWFLASHPLUGINS) \
$(ROOTLIBFWFLASHPLUGINS)/ses.so \
+ $(ROOTLIBFWFLASHPLUGINS)/tavor.so \
+ $(ROOTLIBFWFLASHPLUGINS)/hermon.so \
$(ROOTLIBFWFLASHPLUGINS)/$(SLINKS)
clobber clean:
$(RM) $(CLEANFILES) $(CLOBBERFILES)
+lint_SRCS: $(LINTFILE)
lint: lint_SRCS
%.o: ../common/%.c
@@ -79,14 +78,17 @@ lint: lint_SRCS
%.so: %.o
$(BUILD.SO) $<
+%.ln: ../common/%.c
+ $(LINT.c) $(LINTFLAGS) -c $<
+
#
# Message catalog
#
-$(POFILES): ../common/$(SRCS)
+%.po: ../common/%.c
$(RM) messages.po
$(XGETTEXT) $(XGETFLAGS) \
- `($(GREP) -l gettext ../common/ses.c || echo /dev/null)`
+ `($(GREP) -l gettext $< || echo /dev/null)`
$(SED) "/^domain/d" messages.po > $@
$(RM) messages.po
@@ -94,6 +96,3 @@ $(IDENTPOFILE): $(POFILES)
$(RM) $@
cat $(POFILES) > $@
-lint_SRCS: ../common/$(SRCS:%.c=%.ln)
-
-msg: $(IDENTPOFILE)
diff --git a/usr/src/cmd/fwflash/plugins/transport/sparc/Makefile b/usr/src/cmd/fwflash/plugins/transport/sparc/Makefile
index 108044f881..1d428ed093 100644
--- a/usr/src/cmd/fwflash/plugins/transport/sparc/Makefile
+++ b/usr/src/cmd/fwflash/plugins/transport/sparc/Makefile
@@ -18,22 +18,19 @@
#
# CDDL HEADER END
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-#ident "%Z%%M% %I% %E% SMI"
-#
-#
# cmd/fwflash/plugins/transport/sparc
#
-SRCS= ses.c
+SRCS= ses.c tavor.c hermon.c
OBJECTS= $(SRCS:%.c=%.o)
PLUGINS= $(SRCS:%.c=%.so)
-POFILES= ses.po
+POFILES= $(SRCS:%.c=%.po)
IDENTPOFILE= fwflash_transport_identify_ses.po
-LINTFILE= ses.ln
+LINTFILE= $(SRCS:%.c=%.ln)
SLINKS= sgen.so
CLEANFILES= $(OBJECTS)
@@ -60,15 +57,18 @@ $(PLUGINS) := FILEMODE = 0555
$(ROOTLIBFWFLASHPLUGINS)/$(SLINKS) : $(ROOTLIBFWFLASHPLUGINS)/ses.so
@$(RM) $@
- $(SYMLINK) $(PLUGINS) $@
+ $(SYMLINK) ses.so $@
-install: $(ROOTLIBFWFLASHPLUGINS) \
+install: all $(ROOTLIBFWFLASHPLUGINS) \
$(ROOTLIBFWFLASHPLUGINS)/ses.so \
+ $(ROOTLIBFWFLASHPLUGINS)/tavor.so \
+ $(ROOTLIBFWFLASHPLUGINS)/hermon.so \
$(ROOTLIBFWFLASHPLUGINS)/$(SLINKS)
clobber clean:
$(RM) $(CLEANFILES) $(CLOBBERFILES)
+lint_SRCS: $(LINTFILE)
lint: lint_SRCS
%.o: ../common/%.c
@@ -78,14 +78,17 @@ lint: lint_SRCS
%.so: %.o
$(BUILD.SO) $<
+%.ln: ../common/%.c
+ $(LINT.c) $(LINTFLAGS) -c $<
+
#
# Message catalog
#
-$(POFILES): ../common/$(SRCS)
+%.po: ../common/%.c
$(RM) messages.po
$(XGETTEXT) $(XGETFLAGS) \
- `($(GREP) -l gettext ../common/ses.c || echo /dev/null)`
+ `($(GREP) -l gettext $< || echo /dev/null)`
$(SED) "/^domain/d" messages.po > $@
$(RM) messages.po
@@ -93,6 +96,3 @@ $(IDENTPOFILE): $(POFILES)
$(RM) $@
cat $(POFILES) > $@
-lint_SRCS: ../common/$(SRCS:%.c=%.ln)
-
-msg: $(IDENTPOFILE)
diff --git a/usr/src/cmd/fwflash/plugins/vendor/hermon-MELLANOX.c b/usr/src/cmd/fwflash/plugins/vendor/hermon-MELLANOX.c
new file mode 100644
index 0000000000..a42a4c7954
--- /dev/null
+++ b/usr/src/cmd/fwflash/plugins/vendor/hermon-MELLANOX.c
@@ -0,0 +1,383 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/*
+ * ConnectX (hermon) firmware image verification plugin
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <fcntl.h>
+#include <sys/condvar.h>
+#include <string.h>
+#include <strings.h>
+
+#include <sys/byteorder.h>
+
+#include <libintl.h> /* for gettext(3c) */
+
+#include <fwflash/fwflash.h>
+#include "../hdrs/hermon_ib.h"
+
+char vendor[] = "MELLANOX\0";
+
+extern struct vrfyplugin *verifier;
+
+
+/* required functions for this plugin */
+int vendorvrfy(struct devicelist *devicenode);
+
+/* helper functions */
+static uint16_t cnx_check_hwver_img(ib_cnx_encap_ident_t *handle);
+static void cnx_flash_verify_flash_match_img(ib_cnx_encap_ident_t *handle);
+static void cnx_flash_verify_flash_pn_img(ib_cnx_encap_ident_t *handle,
+ uchar_t *psid, int psid_size);
+static uchar_t *cnx_flash_get_psid_img(ib_cnx_encap_ident_t *handle);
+static void cnx_display_fwver(ib_cnx_encap_ident_t *handle);
+static int cnx_check_guid_section();
+
+
+int
+vendorvrfy(struct devicelist *devicenode)
+{
+ struct ib_cnx_encap_ident_s *handle;
+ uint16_t ver;
+
+ logmsg(MSG_INFO, "hermon: vendorvrfy \n");
+
+ handle = (struct ib_cnx_encap_ident_s *)devicenode->ident->encap_ident;
+
+ if (CNX_I_CHECK_HANDLE(handle)) {
+ logmsg(MSG_ERROR, gettext("hermon: Invalid Handle for "
+ "device %s! \n"), devicenode->access_devname);
+ return (FWFLASH_FAILURE);
+ }
+
+ /*
+ * NOTE verifier->fwimage is where file is read to.
+ */
+ if (cnx_is_magic_pattern_present(&verifier->fwimage[0], 1) !=
+ FWFLASH_SUCCESS) {
+ logmsg(MSG_ERROR, gettext("%s firmware image verifier: "
+ "No magic pattern found in firmware file %s \n"),
+ verifier->vendor, verifier->imgfile);
+ return (FWFLASH_FAILURE);
+ }
+
+ if (cnx_check_guid_section() == FWFLASH_FAILURE) {
+ logmsg(MSG_INFO, "%s firmware image verifier: "
+ "Firmware Image GUID section is invalid\n",
+ verifier->vendor);
+ }
+
+ cnx_flash_verify_flash_match_img(handle);
+
+ /* Check Hardware Rev */
+ ver = cnx_check_hwver_img(handle);
+ if (ver != 0) {
+ logmsg(MSG_ERROR, gettext("hermon: Firmware mismatch: "
+ "ver(0x%X) hw_ver(0x%X)\n"), (ver >> 8), ver & 0xFF);
+ return (FWFLASH_FAILURE);
+ }
+
+ if (handle->hwfw_match == 0) {
+ if (handle->pn_len != 0) {
+ /* HW VPD exist and a mismatch was found */
+ logmsg(MSG_ERROR, gettext("hermon: Please verify that "
+ "the firmware image is intended for use with this "
+ "hardware\n"));
+ } else {
+ logmsg(MSG_ERROR, gettext("hermon: Unable to verify "
+ "firmware is appropriate for the hardware\n"));
+ }
+ return (FWFLASH_FAILURE);
+ }
+ logmsg(MSG_INFO, "%s firmware image verifier: HCA PSID (%s) "
+ "matches firmware image %s's PSID\n", verifier->vendor,
+ handle->info.mlx_psid, verifier->imgfile);
+
+ cnx_display_fwver(handle);
+
+ return (FWFLASH_SUCCESS);
+}
+
+static uint16_t
+cnx_check_hwver_img(ib_cnx_encap_ident_t *handle)
+{
+ uint8_t hwver;
+ uint8_t local_hwver;
+
+ logmsg(MSG_INFO, "hermon: verify: cnx_check_hwver_img\n");
+ if ((handle->state & FWFLASH_IB_STATE_IMAGE_PRI) == 0 &&
+ (handle->state & FWFLASH_IB_STATE_IMAGE_SEC) == 0) {
+ logmsg(MSG_ERROR, gettext("hermon: Must read in image "
+ "first\n"));
+ return (1);
+ }
+
+ /* Read Flash HW Version */
+ hwver = (uint8_t)handle->hwrev;
+ local_hwver = (ntohl(verifier->fwimage[CNX_HWVER_OFFSET / 4]) &
+ CNX_HWVER_MASK) >> 24;
+
+ logmsg(MSG_INFO, "local_hwver: %x, hwver: %x\n", local_hwver, hwver);
+
+ if ((hwver == 0xA0 || hwver == 0x00 || hwver == 0x20) &&
+ (local_hwver == 0x00 || local_hwver == 0xA0 ||
+ local_hwver == 0x20)) {
+ logmsg(MSG_INFO, ("A0 board found.\r\n"));
+ } else if (hwver == 0xA1 && local_hwver == 0xA1) {
+ logmsg(MSG_INFO, ("A1 board found.\r\n"));
+ } else if (hwver == 0xA2 && local_hwver == 0xA2) {
+ logmsg(MSG_INFO, ("A2 board found.\r\n"));
+ } else if (hwver == 0xA3 && local_hwver == 0xA3) {
+ logmsg(MSG_INFO, ("A3 board found.\r\n"));
+ } else {
+ return ((uint16_t)(local_hwver << 8) | hwver);
+ }
+ return (0);
+}
+
+static void
+cnx_display_fwver(ib_cnx_encap_ident_t *handle)
+{
+ logmsg(MSG_INFO, "hermon: verify: cnx_display_fwver\n");
+
+ (void) fprintf(stdout, gettext(" The current HCA firmware version "
+ "is : %d.%d.%04d\n"),
+ handle->hwfw_img_info.fw_rev.major,
+ handle->hwfw_img_info.fw_rev.minor,
+ handle->hwfw_img_info.fw_rev.subminor);
+ (void) fprintf(stdout, gettext(" Will be updated to HCA firmware "
+ "ver of : %d.%d.%04d\n"),
+ handle->file_img_info.fw_rev.major,
+ handle->file_img_info.fw_rev.minor,
+ handle->file_img_info.fw_rev.subminor);
+}
+
+static uchar_t *
+cnx_flash_get_psid_img(ib_cnx_encap_ident_t *handle)
+{
+ uint32_t ii_ptr_addr;
+ uint32_t ii_size;
+
+ logmsg(MSG_INFO, "hermon: verify: cnx_flash_get_psid_img\n");
+
+ /* Get the image info pointer */
+ ii_ptr_addr = ntohl(verifier->fwimage[CNX_IMG_INF_PTR_OFFSET / 4]);
+ ii_ptr_addr &= 0xffffff; /* Bits 23:0 - Image Info Data Pointer */
+
+ /* Get the image info size, a negative offset from the image info ptr */
+ ii_size =
+ ntohl(verifier->fwimage[(ii_ptr_addr + CNX_IMG_INF_SZ_OFFSET) / 4]);
+ /* size is in dwords--convert it to bytes */
+ ii_size *= 4;
+
+ logmsg(MSG_INFO, "ImgInfo_ptr_addr: 0x%lx, ImgInfo_size: 0x%x\n",
+ ii_ptr_addr, ii_size);
+
+ /* Parse the image info section */
+ if (cnx_parse_img_info(&verifier->fwimage[ii_ptr_addr / 4], ii_size,
+ &handle->file_img_info, CNX_FILE_IMG) != FWFLASH_SUCCESS) {
+ logmsg(MSG_WARN, gettext("hermon: Failed to parse ImageInfo "
+ "section\n"));
+ return (NULL);
+ }
+
+ return (handle->file_img_info.psid);
+}
+
+static void
+cnx_flash_verify_flash_pn_img(ib_cnx_encap_ident_t *handle, uchar_t *psid,
+ int psid_size)
+{
+ int i;
+ int no_match = 0;
+
+ logmsg(MSG_INFO, "hermon: verify: cnx_flash_verify_flash_pn_img\n");
+ /* verify fw matches the hardware */
+ if (handle->hwfw_match == 1) {
+ /* already been verified */
+ return;
+ }
+
+ /* find the PSID from FW in the mlx table */
+ for (i = 0; i < MLX_MAX_ID; i++) {
+ if (handle->hwfw_match == 1) {
+ /*
+ * Need this check here and the 'continue's below
+ * because there are some cards that have a
+ * 'new' part number but the same PSID value.
+ */
+ break;
+ }
+
+ /* match PSID */
+ if (strncmp((const char *)psid, mlx_mdr[i].mlx_psid,
+ psid_size) == 0) {
+ logmsg(MSG_INFO, "Found Matching firmware image's "
+ "PSID (%s) entry in MDR Table\n", psid);
+
+ logmsg(MSG_INFO, "Search for firmware image's part# "
+ "(%s), MDR/HW PN (%s) \n",
+ handle->info.mlx_pn, mlx_mdr[i].mlx_pn);
+
+ /* match part numbers */
+ if (strncmp(handle->info.mlx_pn, mlx_mdr[i].mlx_pn,
+ handle->pn_len) == 0) {
+ handle->hwfw_match = 1;
+ logmsg(MSG_INFO, "Match Found \n");
+ continue;
+ } else {
+ handle->hwfw_match = 0;
+ no_match = i;
+ logmsg(MSG_INFO, "Match NOT Found \n");
+ continue;
+ }
+ }
+ }
+ if (i == MLX_MAX_ID && no_match == 0) {
+ /* no match found */
+ handle->hwfw_match = 0;
+ handle->pn_len = 0;
+ logmsg(MSG_WARN, gettext("hermon: No PSID match found\n"));
+ } else {
+ if (handle->hwfw_match == 0) {
+ logmsg(MSG_WARN, gettext("WARNING: Firmware "
+ "image is meant for %s but the hardware "
+ "is %s\n"), mlx_mdr[no_match].mlx_pn,
+ handle->info.mlx_pn);
+ }
+ }
+}
+
+static void
+cnx_flash_verify_flash_match_img(ib_cnx_encap_ident_t *handle)
+{
+ uchar_t *psid;
+
+ logmsg(MSG_INFO, "hermon: verify: cnx_flash_verify_flash_match_img\n");
+ /* get PSID of firmware file */
+ psid = cnx_flash_get_psid_img(handle);
+ if (psid == NULL) {
+ handle->hwfw_match = 0;
+ handle->pn_len = 0;
+ return;
+ }
+ logmsg(MSG_INFO, "FW PSID (%s)\n", psid);
+
+ /*
+ * 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.
+ */
+ if (handle->pn_len != 0) {
+ cnx_flash_verify_flash_pn_img(handle, psid, CNX_PSID_SZ);
+ }
+}
+
+
+static int
+cnx_check_guid_section()
+{
+ struct mlx_cnx_xfi xfisect;
+ struct mlx_cnx_guid_sect guidsect;
+ uint32_t nguidptr_addr;
+ uint16_t calculated_crc;
+
+ logmsg(MSG_INFO, "cnx_check_guid_section: \n");
+
+ bcopy(&verifier->fwimage[0], &xfisect, sizeof (struct mlx_cnx_xfi));
+ logmsg(MSG_INFO, "FailSafeChunkSz: 0x%08x, ImageInfoPtr: 0x%08x\n",
+ MLXSWAPBITS32(xfisect.failsafechunkinfo),
+ MLXSWAPBITS32(xfisect.imageinfoptr) & CNX_XFI_IMGINFO_PTR_MASK);
+ logmsg(MSG_INFO, "FW Size: 0x%08x NGUIDPTR: 0x%08x\n",
+ MLXSWAPBITS32(xfisect.fwimagesz), MLXSWAPBITS32(xfisect.nguidptr));
+
+ nguidptr_addr = (MLXSWAPBITS32(xfisect.nguidptr) - 0x10) / 4;
+ bcopy(&verifier->fwimage[nguidptr_addr], &guidsect,
+ sizeof (struct mlx_cnx_guid_sect));
+
+ logmsg(MSG_INFO, "Node GUID : 0x%016llx \n",
+ MLXSWAPBITS64(guidsect.nodeguid));
+ logmsg(MSG_INFO, "Port1 GUID: 0x%016llx \n",
+ MLXSWAPBITS64(guidsect.port1guid));
+ logmsg(MSG_INFO, "Port2 GUID: 0x%016llx \n",
+ MLXSWAPBITS64(guidsect.port2guid));
+ logmsg(MSG_INFO, "SysIm GUID: 0x%016llx \n",
+ MLXSWAPBITS64(guidsect.sysimguid));
+ logmsg(MSG_INFO, "Port 1 MAC: 0x%016llx \n",
+ MLXSWAPBITS64(guidsect.port1_mac));
+ logmsg(MSG_INFO, "Port 2 MAC: 0x%016llx \n",
+ MLXSWAPBITS64(guidsect.port2_mac));
+
+ calculated_crc = cnx_crc16((uint8_t *)&verifier->fwimage[nguidptr_addr],
+ CNX_GUID_CRC16_SIZE, CNX_FILE_IMG);
+ if (calculated_crc != ntohs(guidsect.guidcrc)) {
+ logmsg(MSG_WARN, gettext("hermon: calculated crc value 0x%x "
+ "differs from GUID section 0x%x\n"), calculated_crc,
+ ntohs(guidsect.guidcrc));
+ } else {
+ logmsg(MSG_INFO, "hermon: calculated crc value 0x%x MATCHES "
+ "with GUID section 0x%x\n", calculated_crc,
+ ntohs(guidsect.guidcrc));
+ }
+
+ if ((MLXSWAPBITS64(guidsect.nodeguid) == MLX_DEFAULT_NODE_GUID) &&
+ (MLXSWAPBITS64(guidsect.port1guid) == MLX_DEFAULT_P1_GUID) &&
+ (MLXSWAPBITS64(guidsect.port2guid) == MLX_DEFAULT_P2_GUID) &&
+ ((MLXSWAPBITS64(guidsect.sysimguid) == MLX_DEFAULT_SYSIMG_GUID) ||
+ (MLXSWAPBITS64(guidsect.sysimguid) == MLX_DEFAULT_NODE_GUID)) ||
+ ((((MLXSWAPBITS64(guidsect.nodeguid) & HIGHBITS64) >> 40) ==
+ MLX_OUI) ||
+ (((MLXSWAPBITS64(guidsect.port1guid) & HIGHBITS64) >> 40) ==
+ MLX_OUI) ||
+ (((MLXSWAPBITS64(guidsect.port2guid) & HIGHBITS64) >> 40) ==
+ MLX_OUI) ||
+ (((MLXSWAPBITS64(guidsect.sysimguid) & HIGHBITS64) >> 40) ==
+ MLX_OUI)) ||
+ ((((MLXSWAPBITS64(guidsect.nodeguid) & HIGHBITS64) >> 40) ==
+ SUNW_OUI) ||
+ (((MLXSWAPBITS64(guidsect.port1guid) & HIGHBITS64) >> 40) ==
+ SUNW_OUI) ||
+ (((MLXSWAPBITS64(guidsect.port2guid) & HIGHBITS64) >> 40) ==
+ SUNW_OUI) ||
+ (((MLXSWAPBITS64(guidsect.sysimguid) & HIGHBITS64) >> 40) ==
+ SUNW_OUI))) {
+ logmsg(MSG_INFO, "%s firmware image verifier: GUID Prefix "
+ "is as expected\n", verifier->vendor);
+ return (FWFLASH_SUCCESS);
+ } else {
+ logmsg(MSG_INFO, "%s firmware image verifier: GUID prefix "
+ "is not as expected\n", verifier->vendor);
+ return (FWFLASH_FAILURE);
+ }
+}
diff --git a/usr/src/cmd/fwflash/plugins/vendor/tavor-MELLANOX.c b/usr/src/cmd/fwflash/plugins/vendor/tavor-MELLANOX.c
new file mode 100644
index 0000000000..5b7f7c6fd7
--- /dev/null
+++ b/usr/src/cmd/fwflash/plugins/vendor/tavor-MELLANOX.c
@@ -0,0 +1,337 @@
+/*
+ * 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
+ * or http://www.opensolaris.org/os/licensing.
+ * 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.
+ */
+
+/*
+ * Mellanox firmware image verification plugin
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <fcntl.h>
+#include <sys/condvar.h>
+#include <string.h>
+#include <strings.h>
+
+#include <sys/byteorder.h>
+
+#include <libintl.h> /* for gettext(3c) */
+
+#include <fwflash/fwflash.h>
+#include "../hdrs/MELLANOX.h"
+#include "../hdrs/tavor_ib.h"
+
+
+
+char vendor[] = "MELLANOX\0";
+
+extern int errno;
+extern struct vrfyplugin *verifier;
+extern uint16_t crc16(uint8_t *image, uint32_t size);
+
+
+/* required functions for this plugin */
+int vendorvrfy(struct devicelist *devicenode);
+
+
+/* helper functions */
+static int check_guid_ptr(uint8_t *data);
+
+
+int
+vendorvrfy(struct devicelist *devicenode)
+{
+ struct ib_encap_ident *encap;
+ uint32_t sector_sz;
+ int *firmware;
+ uint32_t vp_fia, vs_fia;
+ uint32_t vp_imginfo, vs_imginfo;
+ struct mlx_xps *vps;
+ uint8_t *vfi;
+ int i = 0, a, b, c, d;
+ char temppsid[17];
+ char rawpsid[16];
+
+ encap = (struct ib_encap_ident *)devicenode->ident->encap_ident;
+
+ /*
+ * NOTE that since verifier->fwimage is an array of ints,
+ * we have to divide our actual desired number by 4 to get
+ * the right data.
+ */
+ firmware = verifier->fwimage;
+
+ /* sector_sz is stored as Log_2 of the real value */
+ sector_sz = 1 << MLXSWAPBITS32(firmware[FLASH_IS_SECTOR_SIZE_OFFSET/4]);
+
+ if (sector_sz != encap->sector_sz) {
+ logmsg(MSG_ERROR,
+ gettext("%s firmware image verifier: "
+ "Invariant Sector is invalid\n"),
+ verifier->vendor);
+ /* this is fatal */
+ return (FWFLASH_FAILURE);
+ }
+
+ /* now verify primary pointer sector */
+ if ((vps = calloc(1, sizeof (struct mlx_xps))) == NULL) {
+ logmsg(MSG_ERROR,
+ gettext("%s firmware image verifier: "
+ "Unable to allocate memory for Primary Pointer "
+ "Sector verification\n"));
+ return (FWFLASH_FAILURE);
+ }
+ bcopy(&firmware[sector_sz / 4], vps, sizeof (struct mlx_xps));
+ if ((MLXSWAPBITS32(vps->signature) != FLASH_PS_SIGNATURE) ||
+ (vps->xpsresv3 != 0)) {
+ logmsg(MSG_ERROR,
+ gettext("%s firmware image verifier: "
+ "Primary Pointer Sector is invalid\n"),
+ verifier->vendor);
+ }
+ vp_fia = MLXSWAPBITS32(vps->fia);
+
+ /*
+ * A slight diversion - check the PSID in the last
+ * 16 bytes of the first 256bytes in the xPS sectors.
+ * This will give us our part number to match. If the
+ * part number in the image doesn't match the part number
+ * in the encap_ident info (and pn_len > 0) then we reject
+ * this image as being incompatible with the HCA.
+ *
+ * In this bit we're only checking the info.mlx_psid field
+ * of the primary image in the on-disk image. If that's
+ * invalid we reject the image.
+ */
+
+ if (encap->info.mlx_psid != NULL) {
+ bzero(temppsid, 17);
+ bcopy(vps->vsdpsid+0xd0, &rawpsid, 16);
+
+#if !defined(_LITTLE_ENDIAN)
+ for (i = 0; i < 16; i += 4) {
+ temppsid[i] = rawpsid[i+3];
+ temppsid[i+1] = rawpsid[i+2];
+ temppsid[i+2] = rawpsid[i+1];
+ temppsid[i+3] = rawpsid[i];
+ }
+ logmsg(MSG_INFO,
+ "tavor: have raw '%s', want munged '%s'\n",
+ rawpsid, temppsid);
+#else
+ bcopy(vps->vsdpsid+0xd0, &temppsid, 16);
+#endif
+ if (strncmp(encap->info.mlx_psid, temppsid, 16) != 0) {
+ logmsg(MSG_ERROR,
+ gettext("%s firmware image verifier: "
+ "firmware image file %s is not appropriate "
+ "for device\n"
+ "%s (PSID file %s vs PSID device %s)\n"),
+ verifier->vendor, verifier->imgfile,
+ encap->info.mlx_psid,
+ ((temppsid != NULL) ? temppsid : "(null)"));
+
+ free(vps);
+ return (FWFLASH_FAILURE);
+ } else {
+ logmsg(MSG_INFO,
+ "%s firmware image verifier: HCA PSID (%s) "
+ "matches firmware image %s's PSID\n",
+ verifier->vendor,
+ encap->info.mlx_psid,
+ verifier->imgfile);
+ }
+ }
+
+
+ /* now verify secondary pointer sector */
+ bzero(vps, sizeof (struct mlx_xps));
+
+ bcopy(&firmware[sector_sz / 2], vps, sizeof (struct mlx_xps));
+ if ((MLXSWAPBITS32(vps->signature) != FLASH_PS_SIGNATURE) ||
+ (vps->xpsresv3 != 0)) {
+ logmsg(MSG_ERROR,
+ gettext("%s firmware image verifier: "
+ "Secondary Pointer Sector is invalid\n"),
+ verifier->vendor);
+ }
+ vs_fia = MLXSWAPBITS32(vps->fia);
+
+ (void) free(vps);
+
+ if ((vfi = calloc(1, sector_sz)) == NULL) {
+ logmsg(MSG_ERROR,
+ gettext("%s firmware image verifier: "
+ "Unable to allocate space for Primary "
+ "Firmware Image verification\n"),
+ verifier->vendor);
+ return (FWFLASH_FAILURE);
+ }
+ bcopy(&firmware[vp_fia / 4], vfi, sector_sz);
+ bcopy(&vfi[XFI_IMGINFO_OFFSET], &i, 4);
+ vp_imginfo = MLXSWAPBITS32(i);
+
+ /* for readability only */
+ a = (vp_imginfo & 0xff000000) >> 24;
+ b = (vp_imginfo & 0x00ff0000) >> 16;
+ c = (vp_imginfo & 0x0000ff00) >> 8;
+ d = (vp_imginfo & 0x000000ff);
+
+ /*
+ * It appears to be the case (empirically) that this particular
+ * check condition for ImageInfoPtr doesn't hold for A1 firmware
+ * images. So if the ((a+b+c+d)%0x100) fails, don't worry unless
+ * the contents of the GUID section do not match the Mellanox
+ * default GUIDs 2c9000100d05[0123]. The A2++ images also have
+ * these default GUIDS.
+ *
+ * Unfortunately we can't depend on the hwrev field of the image's
+ * Invariant Sector for another level of confirmation, since A2++
+ * images seem to have that field set to 0xa1 as well as the A1
+ * images. Annoying!
+ */
+
+ if ((((a+b+c+d) % 0x100) == 0) &&
+ (vp_imginfo != 0x00000000)) {
+ logmsg(MSG_INFO,
+ "%s firmware image verifier: "
+ "Primary Firmware Image Info pointer is valid\n",
+ verifier->vendor);
+ } else {
+
+ logmsg(MSG_ERROR,
+ gettext("%s firmware image verifier: "
+ "Primary Firmware Image Info pointer is invalid "
+ "(0x%04x)\nChecking GUID section.....\n"),
+ verifier->vendor, vp_imginfo);
+
+ if (check_guid_ptr(vfi) == FWFLASH_FAILURE) {
+ logmsg(MSG_ERROR,
+ gettext("%s firmware image verifier: "
+ "Primary Firmware Image GUID section "
+ "is invalid\n"),
+ verifier->vendor);
+ i = 1;
+ } else {
+ logmsg(MSG_INFO,
+ "%s firmware image verifier: "
+ "Primary GUID section is ok\n",
+ verifier->vendor);
+ }
+
+ }
+
+ bzero(vfi, sector_sz);
+ bcopy(&firmware[vs_fia / 4], vfi, sector_sz);
+
+ bcopy(&vfi[XFI_IMGINFO_OFFSET], &i, 4);
+ vs_imginfo = MLXSWAPBITS32(i);
+
+ /* for readability only */
+ a = (vs_imginfo & 0xff000000) >> 24;
+ b = (vs_imginfo & 0x00ff0000) >> 16;
+ c = (vs_imginfo & 0x0000ff00) >> 8;
+ d = (vs_imginfo & 0x000000ff);
+
+ if ((((a+b+c+d) % 0x100) == 0) &&
+ (vs_imginfo != 0x00000000)) {
+ logmsg(MSG_INFO,
+ "%s firmware image verifier: "
+ "Secondary Firmware Image Info pointer is valid\n",
+ verifier->vendor);
+ } else {
+ logmsg(MSG_ERROR,
+ gettext("%s firmware image verifier: "
+ "Secondary Firmware Image Info pointer is invalid "
+ "(0x%04x)\nChecking GUID section.....\n"),
+ verifier->vendor, vp_imginfo);
+
+ if (check_guid_ptr(vfi) == FWFLASH_FAILURE) {
+ logmsg(MSG_ERROR,
+ gettext("%s firmware image verifier: "
+ "Secondary Firmware Image GUID section "
+ "is invalid\n"),
+ verifier->vendor);
+ i++;
+ }
+ }
+
+ free(vfi);
+
+
+ return ((i == 2) ? (FWFLASH_FAILURE) : (FWFLASH_SUCCESS));
+}
+
+
+/*
+ * Very simple function - we're given an array of bytes,
+ * we know that we need to read the value at offset FLASH_GUID_PTR
+ * and jump to that location to read 4x uint64_t of (hopefully)
+ * GUID data. If we can read that data, and it matches the default
+ * Mellanox GUIDs, then we return success. We need all 4 default
+ * GUIDs to match otherwise we return failure.
+ */
+static int
+check_guid_ptr(uint8_t *data)
+{
+ struct mlx_xfi xfisect;
+ struct mlx_guid_sect guidsect;
+
+ bcopy(data, &xfisect, sizeof (xfisect));
+ bcopy(&data[MLXSWAPBITS32(xfisect.nguidptr) - 16], &guidsect,
+ GUIDSECTION_SZ);
+
+ logmsg(MSG_INFO, "nodeguid: %0llx\n",
+ MLXSWAPBITS64(guidsect.nodeguid));
+ logmsg(MSG_INFO, "port1guid: %0llx\n",
+ MLXSWAPBITS64(guidsect.port1guid));
+ logmsg(MSG_INFO, "port2guid: %0llx\n",
+ MLXSWAPBITS64(guidsect.port2guid));
+ logmsg(MSG_INFO, "sysimguid: %0llx\n",
+ MLXSWAPBITS64(guidsect.sysimguid));
+
+ if ((MLXSWAPBITS64(guidsect.nodeguid) == MLX_DEFAULT_NODE_GUID) &&
+ (MLXSWAPBITS64(guidsect.port1guid) == MLX_DEFAULT_P1_GUID) &&
+ (MLXSWAPBITS64(guidsect.port2guid) == MLX_DEFAULT_P2_GUID) &&
+ ((MLXSWAPBITS64(guidsect.sysimguid) == MLX_DEFAULT_SYSIMG_GUID) ||
+ (MLXSWAPBITS64(guidsect.sysimguid) == MLX_DEFAULT_NODE_GUID)) ||
+ ((((MLXSWAPBITS64(guidsect.nodeguid) & HIGHBITS64) >> 40)
+ == MLX_OUI) ||
+ (((MLXSWAPBITS64(guidsect.port1guid) & HIGHBITS64) >> 40)
+ == MLX_OUI) ||
+ (((MLXSWAPBITS64(guidsect.port2guid) & HIGHBITS64) >> 40)
+ == MLX_OUI) ||
+ (((MLXSWAPBITS64(guidsect.sysimguid) & HIGHBITS64) >> 40)
+ == MLX_OUI))) {
+ return (FWFLASH_SUCCESS);
+ } else {
+ return (FWFLASH_FAILURE);
+ }
+}