4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
27 * Mellanox firmware image verification plugin
34 #include <sys/types.h>
36 #include <sys/sysmacros.h>
38 #include <sys/condvar.h>
42 #include <sys/byteorder.h>
44 #include <libintl.h> /* for gettext(3c) */
46 #include <fwflash/fwflash.h>
47 #include "../hdrs/MELLANOX.h"
48 #include "../hdrs/tavor_ib.h"
50 char vendor
[] = "MELLANOX\0";
53 extern struct vrfyplugin
*verifier
;
56 /* required functions for this plugin */
57 int vendorvrfy(struct devicelist
*devicenode
);
60 /* helper functions */
61 static int check_guid_ptr(uint8_t *data
);
65 vendorvrfy(struct devicelist
*devicenode
)
67 struct ib_encap_ident
*encap
;
70 uint32_t vp_fia
, vs_fia
;
71 uint32_t vp_imginfo
, vs_imginfo
;
74 int i
= 0, a
, b
, c
, d
;
79 encap
= (struct ib_encap_ident
*)devicenode
->ident
->encap_ident
;
82 * NOTE that since verifier->fwimage is an array of ints,
83 * we have to divide our actual desired number by 4 to get
86 firmware
= verifier
->fwimage
;
89 * The actual location of log2_sector_sz can be calculated
90 * by adding 0x32 to the value that is written in the
91 * log2_sector_sz_ptr field. The log2_sector_sz_ptr is located
92 * at 0x16 byte offset in Invariant Sector.
94 offset
= FLASH_IS_SECTOR_SIZE_OFFSET
+
95 MLXSWAPBITS32(firmware
[FLASH_IS_SECT_SIZE_PTR
/4]);
97 sector_sz
= 1 << MLXSWAPBITS32(firmware
[offset
/4]);
99 if (sector_sz
!= encap
->sector_sz
) {
101 gettext("%s firmware image verifier: "
102 "Invariant Sector is invalid\n"), verifier
->vendor
);
103 logmsg(MSG_ERROR
, gettext("Mis-match in sector size: "
104 "device's 0x%X file 0x%X\n"), encap
->sector_sz
, sector_sz
);
105 logmsg(MSG_ERROR
, gettext("Firmware image file is not "
106 "appropriate for this device.\n"));
108 return (FWFLASH_FAILURE
);
111 /* now verify primary pointer sector */
112 if ((vps
= calloc(1, sizeof (struct mlx_xps
))) == NULL
) {
114 gettext("%s firmware image verifier: "
115 "Unable to allocate memory for Primary Pointer "
116 "Sector verification\n"), verifier
->vendor
);
117 return (FWFLASH_FAILURE
);
119 bcopy(&firmware
[sector_sz
/ 4], vps
, sizeof (struct mlx_xps
));
120 if ((MLXSWAPBITS32(vps
->signature
) != FLASH_PS_SIGNATURE
) ||
121 (vps
->xpsresv3
!= 0)) {
123 gettext("%s firmware image verifier: "
124 "Primary Pointer Sector is invalid\n"),
127 vp_fia
= MLXSWAPBITS32(vps
->fia
);
130 * A slight diversion - check the PSID in the last
131 * 16 bytes of the first 256bytes in the xPS sectors.
132 * This will give us our part number to match. If the
133 * part number in the image doesn't match the part number
134 * in the encap_ident info (and pn_len > 0) then we reject
135 * this image as being incompatible with the HCA.
137 * In this bit we're only checking the info.mlx_psid field
138 * of the primary image in the on-disk image. If that's
139 * invalid we reject the image.
143 bcopy(vps
->vsdpsid
+0xd0, &rawpsid
, 16);
145 for (i
= 0; i
< 16; i
+= 4) {
146 temppsid
[i
] = rawpsid
[i
+3];
147 temppsid
[i
+1] = rawpsid
[i
+2];
148 temppsid
[i
+2] = rawpsid
[i
+1];
149 temppsid
[i
+3] = rawpsid
[i
];
152 "tavor: have raw '%s', want munged '%s'\n",
154 logmsg(MSG_INFO
, "tavor_vrfy: PSID file '%s' HCA's PSID '%s'\n",
155 (temppsid
!= NULL
) ? temppsid
: "(null)",
156 (encap
->info
.mlx_psid
!= NULL
) ? encap
->info
.mlx_psid
: "(null)");
158 if (encap
->info
.mlx_psid
!= NULL
) {
160 if (strncmp(encap
->info
.mlx_psid
, temppsid
, 16) != 0) {
162 gettext("%s firmware image verifier: "
163 "firmware image file %s is not appropriate "
165 "%s (PSID file %s vs PSID device %s)\n"),
166 verifier
->vendor
, verifier
->imgfile
,
168 ((temppsid
!= NULL
) ? temppsid
: "(null)"),
169 encap
->info
.mlx_psid
);
172 gettext("Do you want to continue? (Y/N): "));
173 (void) fflush(stdin
);
175 if (resp
!= 'Y' && resp
!= 'y') {
177 logmsg(MSG_ERROR
, gettext("Not proceeding with "
178 "flash operation of %s on %s\n"),
179 verifier
->imgfile
, devicenode
->drvname
);
180 return (FWFLASH_FAILURE
);
184 "%s firmware image verifier: HCA PSID (%s) "
185 "matches firmware image %s's PSID\n",
187 encap
->info
.mlx_psid
,
193 /* now verify secondary pointer sector */
194 bzero(vps
, sizeof (struct mlx_xps
));
196 bcopy(&firmware
[sector_sz
/ 2], vps
, sizeof (struct mlx_xps
));
197 if ((MLXSWAPBITS32(vps
->signature
) != FLASH_PS_SIGNATURE
) ||
198 (vps
->xpsresv3
!= 0)) {
200 gettext("%s firmware image verifier: "
201 "Secondary Pointer Sector is invalid\n"),
204 vs_fia
= MLXSWAPBITS32(vps
->fia
);
208 if ((vfi
= calloc(1, sector_sz
)) == NULL
) {
210 gettext("%s firmware image verifier: "
211 "Unable to allocate space for Primary "
212 "Firmware Image verification\n"),
214 return (FWFLASH_FAILURE
);
216 bcopy(&firmware
[vp_fia
/ 4], vfi
, sector_sz
);
217 bcopy(&vfi
[XFI_IMGINFO_OFFSET
], &i
, 4);
218 vp_imginfo
= MLXSWAPBITS32(i
);
220 /* for readability only */
221 a
= (vp_imginfo
& 0xff000000) >> 24;
222 b
= (vp_imginfo
& 0x00ff0000) >> 16;
223 c
= (vp_imginfo
& 0x0000ff00) >> 8;
224 d
= (vp_imginfo
& 0x000000ff);
227 * It appears to be the case (empirically) that this particular
228 * check condition for ImageInfoPtr doesn't hold for A1 firmware
229 * images. So if the ((a+b+c+d)%0x100) fails, don't worry unless
230 * the contents of the GUID section do not match the Mellanox
231 * default GUIDs 2c9000100d05[0123]. The A2++ images also have
232 * these default GUIDS.
234 * Unfortunately we can't depend on the hwrev field of the image's
235 * Invariant Sector for another level of confirmation, since A2++
236 * images seem to have that field set to 0xa1 as well as the A1
240 if ((((a
+b
+c
+d
) % 0x100) == 0) &&
241 (vp_imginfo
!= 0x00000000)) {
243 "%s firmware image verifier: "
244 "Primary Firmware Image Info pointer is valid\n",
249 gettext("%s firmware image verifier: "
250 "Primary Firmware Image Info pointer is invalid "
251 "(0x%04x)\nChecking GUID section.....\n"),
252 verifier
->vendor
, vp_imginfo
);
254 if (check_guid_ptr(vfi
) == FWFLASH_FAILURE
) {
256 gettext("%s firmware image verifier: "
257 "Primary Firmware Image GUID section "
263 "%s firmware image verifier: "
264 "Primary GUID section is ok\n",
270 bzero(vfi
, sector_sz
);
271 bcopy(&firmware
[vs_fia
/ 4], vfi
, sector_sz
);
273 bcopy(&vfi
[XFI_IMGINFO_OFFSET
], &i
, 4);
274 vs_imginfo
= MLXSWAPBITS32(i
);
276 /* for readability only */
277 a
= (vs_imginfo
& 0xff000000) >> 24;
278 b
= (vs_imginfo
& 0x00ff0000) >> 16;
279 c
= (vs_imginfo
& 0x0000ff00) >> 8;
280 d
= (vs_imginfo
& 0x000000ff);
282 if ((((a
+b
+c
+d
) % 0x100) == 0) &&
283 (vs_imginfo
!= 0x00000000)) {
285 "%s firmware image verifier: "
286 "Secondary Firmware Image Info pointer is valid\n",
290 gettext("%s firmware image verifier: "
291 "Secondary Firmware Image Info pointer is invalid "
292 "(0x%04x)\nChecking GUID section.....\n"),
293 verifier
->vendor
, vp_imginfo
);
295 if (check_guid_ptr(vfi
) == FWFLASH_FAILURE
) {
297 gettext("%s firmware image verifier: "
298 "Secondary Firmware Image GUID section "
308 logmsg(MSG_WARN
, gettext("%s firmware image verifier: "
309 "FAILED\n"), verifier
->vendor
);
311 return ((i
== 2) ? (FWFLASH_FAILURE
) : (FWFLASH_SUCCESS
));
316 * Very simple function - we're given an array of bytes,
317 * we know that we need to read the value at offset FLASH_GUID_PTR
318 * and jump to that location to read 4x uint64_t of (hopefully)
319 * GUID data. If we can read that data, and it matches the default
320 * Mellanox GUIDs, then we return success. We need all 4 default
321 * GUIDs to match otherwise we return failure.
324 check_guid_ptr(uint8_t *data
)
326 struct mlx_xfi xfisect
;
327 struct mlx_guid_sect guidsect
;
329 bcopy(data
, &xfisect
, sizeof (xfisect
));
330 bcopy(&data
[MLXSWAPBITS32(xfisect
.nguidptr
) - 16], &guidsect
,
333 logmsg(MSG_INFO
, "nodeguid: %0llx\n",
334 MLXSWAPBITS64(guidsect
.nodeguid
));
335 logmsg(MSG_INFO
, "port1guid: %0llx\n",
336 MLXSWAPBITS64(guidsect
.port1guid
));
337 logmsg(MSG_INFO
, "port2guid: %0llx\n",
338 MLXSWAPBITS64(guidsect
.port2guid
));
339 logmsg(MSG_INFO
, "sysimguid: %0llx\n",
340 MLXSWAPBITS64(guidsect
.sysimguid
));
342 if ((MLXSWAPBITS64(guidsect
.nodeguid
) == MLX_DEFAULT_NODE_GUID
) &&
343 (MLXSWAPBITS64(guidsect
.port1guid
) == MLX_DEFAULT_P1_GUID
) &&
344 (MLXSWAPBITS64(guidsect
.port2guid
) == MLX_DEFAULT_P2_GUID
) &&
345 ((MLXSWAPBITS64(guidsect
.sysimguid
) == MLX_DEFAULT_SYSIMG_GUID
) ||
346 (MLXSWAPBITS64(guidsect
.sysimguid
) == MLX_DEFAULT_NODE_GUID
)) ||
347 ((((MLXSWAPBITS64(guidsect
.nodeguid
) & HIGHBITS64
) >> 40)
349 (((MLXSWAPBITS64(guidsect
.port1guid
) & HIGHBITS64
) >> 40)
351 (((MLXSWAPBITS64(guidsect
.port2guid
) & HIGHBITS64
) >> 40)
353 (((MLXSWAPBITS64(guidsect
.sysimguid
) & HIGHBITS64
) >> 40)
355 return (FWFLASH_SUCCESS
);
357 return (FWFLASH_FAILURE
);