tavor-MELLANOX.c revision 9517:b4839b0aa7a4
1/*
2 * CDDL HEADER START
3 *
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.
7 *
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.
12 *
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]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*
28 * Mellanox firmware image verification plugin
29 */
30
31
32#include <stdio.h>
33#include <stdlib.h>
34#include <unistd.h>
35#include <sys/types.h>
36#include <sys/stat.h>
37#include <sys/sysmacros.h>
38#include <fcntl.h>
39#include <sys/condvar.h>
40#include <string.h>
41#include <strings.h>
42
43#include <sys/byteorder.h>
44
45#include <libintl.h> /* for gettext(3c) */
46
47#include <fwflash/fwflash.h>
48#include "../hdrs/MELLANOX.h"
49#include "../hdrs/tavor_ib.h"
50
51
52
53char vendor[] = "MELLANOX\0";
54
55extern int errno;
56extern struct vrfyplugin *verifier;
57extern uint16_t crc16(uint8_t *image, uint32_t size);
58
59
60/* required functions for this plugin */
61int vendorvrfy(struct devicelist *devicenode);
62
63
64/* helper functions */
65static int check_guid_ptr(uint8_t *data);
66
67
68int
69vendorvrfy(struct devicelist *devicenode)
70{
71	struct ib_encap_ident	*encap;
72	uint32_t	sector_sz;
73	int		*firmware;
74	uint32_t	vp_fia, vs_fia;
75	uint32_t	vp_imginfo, vs_imginfo;
76	struct mlx_xps	*vps;
77	uint8_t		*vfi;
78	int		i = 0, a, b, c, d;
79	char		temppsid[17];
80	char		rawpsid[16];
81
82	encap = (struct ib_encap_ident *)devicenode->ident->encap_ident;
83
84	/*
85	 * NOTE that since verifier->fwimage is an array of ints,
86	 * we have to divide our actual desired number by 4 to get
87	 * the right data.
88	 */
89	firmware = verifier->fwimage;
90
91	/* sector_sz is stored as Log_2 of the real value */
92	sector_sz = 1 << MLXSWAPBITS32(firmware[FLASH_IS_SECTOR_SIZE_OFFSET/4]);
93
94	if (sector_sz != encap->sector_sz) {
95		logmsg(MSG_ERROR,
96		    gettext("%s firmware image verifier: "
97		    "Invariant Sector is invalid\n"),
98		    verifier->vendor);
99		/* this is fatal */
100		return (FWFLASH_FAILURE);
101	}
102
103	/* now verify primary pointer sector */
104	if ((vps = calloc(1, sizeof (struct mlx_xps))) == NULL) {
105		logmsg(MSG_ERROR,
106		    gettext("%s firmware image verifier: "
107		    "Unable to allocate memory for Primary Pointer "
108		    "Sector verification\n"));
109		return (FWFLASH_FAILURE);
110	}
111	bcopy(&firmware[sector_sz / 4], vps, sizeof (struct mlx_xps));
112	if ((MLXSWAPBITS32(vps->signature) != FLASH_PS_SIGNATURE) ||
113	    (vps->xpsresv3 != 0)) {
114		logmsg(MSG_ERROR,
115		    gettext("%s firmware image verifier: "
116		    "Primary Pointer Sector is invalid\n"),
117		    verifier->vendor);
118	}
119	vp_fia = MLXSWAPBITS32(vps->fia);
120
121	/*
122	 * A slight diversion - check the PSID in the last
123	 * 16 bytes of the first 256bytes in the xPS sectors.
124	 * This will give us our part number to match. If the
125	 * part number in the image doesn't match the part number
126	 * in the encap_ident info (and pn_len > 0) then we reject
127	 * this image as being incompatible with the HCA.
128	 *
129	 * In this bit we're only checking the info.mlx_psid field
130	 * of the primary image in the on-disk image. If that's
131	 * invalid we reject the image.
132	 */
133
134	if (encap->info.mlx_psid != NULL) {
135		bzero(temppsid, 17);
136		bcopy(vps->vsdpsid+0xd0, &rawpsid, 16);
137
138#if !defined(_LITTLE_ENDIAN)
139		for (i = 0; i < 16; i += 4) {
140			temppsid[i]   = rawpsid[i+3];
141			temppsid[i+1] = rawpsid[i+2];
142			temppsid[i+2] = rawpsid[i+1];
143			temppsid[i+3] = rawpsid[i];
144		}
145		logmsg(MSG_INFO,
146		    "tavor: have raw '%s', want munged '%s'\n",
147		    rawpsid, temppsid);
148#else
149		bcopy(vps->vsdpsid+0xd0, &temppsid, 16);
150#endif
151		if (strncmp(encap->info.mlx_psid, temppsid, 16) != 0) {
152			logmsg(MSG_ERROR,
153			    gettext("%s firmware image verifier: "
154			    "firmware image file %s is not appropriate "
155			    "for device\n"
156			    "%s (PSID file %s vs PSID device %s)\n"),
157			    verifier->vendor, verifier->imgfile,
158			    encap->info.mlx_psid,
159			    ((temppsid != NULL) ? temppsid : "(null)"));
160
161			free(vps);
162			return (FWFLASH_FAILURE);
163		} else {
164			logmsg(MSG_INFO,
165			    "%s firmware image verifier: HCA PSID (%s) "
166			    "matches firmware image %s's PSID\n",
167			    verifier->vendor,
168			    encap->info.mlx_psid,
169			    verifier->imgfile);
170		}
171	}
172
173
174	/* now verify secondary pointer sector */
175	bzero(vps, sizeof (struct mlx_xps));
176
177	bcopy(&firmware[sector_sz / 2], vps, sizeof (struct mlx_xps));
178	if ((MLXSWAPBITS32(vps->signature) != FLASH_PS_SIGNATURE) ||
179	    (vps->xpsresv3 != 0)) {
180		logmsg(MSG_ERROR,
181		    gettext("%s firmware image verifier: "
182		    "Secondary Pointer Sector is invalid\n"),
183		    verifier->vendor);
184	}
185	vs_fia = MLXSWAPBITS32(vps->fia);
186
187	(void) free(vps);
188
189	if ((vfi = calloc(1, sector_sz)) == NULL) {
190		logmsg(MSG_ERROR,
191		    gettext("%s firmware image verifier: "
192		    "Unable to allocate space for Primary "
193		    "Firmware Image verification\n"),
194		    verifier->vendor);
195		return (FWFLASH_FAILURE);
196	}
197	bcopy(&firmware[vp_fia / 4], vfi, sector_sz);
198	bcopy(&vfi[XFI_IMGINFO_OFFSET], &i, 4);
199	vp_imginfo = MLXSWAPBITS32(i);
200
201	/* for readability only */
202	a = (vp_imginfo & 0xff000000) >> 24;
203	b = (vp_imginfo & 0x00ff0000) >> 16;
204	c = (vp_imginfo & 0x0000ff00) >> 8;
205	d = (vp_imginfo & 0x000000ff);
206
207	/*
208	 * It appears to be the case (empirically) that this particular
209	 * check condition for ImageInfoPtr doesn't hold for A1 firmware
210	 * images. So if the ((a+b+c+d)%0x100) fails, don't worry unless
211	 * the contents of the GUID section do not match the Mellanox
212	 * default GUIDs 2c9000100d05[0123]. The A2++ images also have
213	 * these default GUIDS.
214	 *
215	 * Unfortunately we can't depend on the hwrev field of the image's
216	 * Invariant Sector for another level of confirmation, since A2++
217	 * images seem to have that field set to 0xa1 as well as the A1
218	 * images. Annoying!
219	 */
220
221	if ((((a+b+c+d) % 0x100) == 0) &&
222	    (vp_imginfo != 0x00000000)) {
223		logmsg(MSG_INFO,
224		    "%s firmware image verifier: "
225		    "Primary Firmware Image Info pointer is valid\n",
226		    verifier->vendor);
227	} else {
228
229		logmsg(MSG_ERROR,
230		    gettext("%s firmware image verifier: "
231		    "Primary Firmware Image Info pointer is invalid "
232		    "(0x%04x)\nChecking GUID section.....\n"),
233		    verifier->vendor, vp_imginfo);
234
235		if (check_guid_ptr(vfi) == FWFLASH_FAILURE) {
236			logmsg(MSG_ERROR,
237			    gettext("%s firmware image verifier: "
238			    "Primary Firmware Image GUID section "
239			    "is invalid\n"),
240			    verifier->vendor);
241			i = 1;
242		} else {
243			logmsg(MSG_INFO,
244			    "%s firmware image verifier: "
245			    "Primary GUID section is ok\n",
246			    verifier->vendor);
247		}
248
249	}
250
251	bzero(vfi, sector_sz);
252	bcopy(&firmware[vs_fia / 4], vfi, sector_sz);
253
254	bcopy(&vfi[XFI_IMGINFO_OFFSET], &i, 4);
255	vs_imginfo = MLXSWAPBITS32(i);
256
257	/* for readability only */
258	a = (vs_imginfo & 0xff000000) >> 24;
259	b = (vs_imginfo & 0x00ff0000) >> 16;
260	c = (vs_imginfo & 0x0000ff00) >> 8;
261	d = (vs_imginfo & 0x000000ff);
262
263	if ((((a+b+c+d) % 0x100) == 0) &&
264	    (vs_imginfo != 0x00000000)) {
265		logmsg(MSG_INFO,
266		    "%s firmware image verifier: "
267		    "Secondary Firmware Image Info pointer is valid\n",
268		    verifier->vendor);
269	} else {
270		logmsg(MSG_ERROR,
271		    gettext("%s firmware image verifier: "
272		    "Secondary Firmware Image Info pointer is invalid "
273		    "(0x%04x)\nChecking GUID section.....\n"),
274		    verifier->vendor, vp_imginfo);
275
276		if (check_guid_ptr(vfi) == FWFLASH_FAILURE) {
277			logmsg(MSG_ERROR,
278			    gettext("%s firmware image verifier: "
279			    "Secondary Firmware Image GUID section "
280			    "is invalid\n"),
281			    verifier->vendor);
282			i++;
283		}
284	}
285
286	free(vfi);
287
288
289	return ((i == 2) ? (FWFLASH_FAILURE) : (FWFLASH_SUCCESS));
290}
291
292
293/*
294 * Very simple function - we're given an array of bytes,
295 * we know that we need to read the value at offset FLASH_GUID_PTR
296 * and jump to that location to read 4x uint64_t of (hopefully)
297 * GUID data. If we can read that data, and it matches the default
298 * Mellanox GUIDs, then we return success. We need all 4 default
299 * GUIDs to match otherwise we return failure.
300 */
301static int
302check_guid_ptr(uint8_t *data)
303{
304	struct mlx_xfi	xfisect;
305	struct mlx_guid_sect	guidsect;
306
307	bcopy(data, &xfisect, sizeof (xfisect));
308	bcopy(&data[MLXSWAPBITS32(xfisect.nguidptr) - 16], &guidsect,
309	    GUIDSECTION_SZ);
310
311	logmsg(MSG_INFO, "nodeguid:  %0llx\n",
312	    MLXSWAPBITS64(guidsect.nodeguid));
313	logmsg(MSG_INFO, "port1guid: %0llx\n",
314	    MLXSWAPBITS64(guidsect.port1guid));
315	logmsg(MSG_INFO, "port2guid: %0llx\n",
316	    MLXSWAPBITS64(guidsect.port2guid));
317	logmsg(MSG_INFO, "sysimguid: %0llx\n",
318	    MLXSWAPBITS64(guidsect.sysimguid));
319
320	if ((MLXSWAPBITS64(guidsect.nodeguid) == MLX_DEFAULT_NODE_GUID) &&
321	    (MLXSWAPBITS64(guidsect.port1guid) == MLX_DEFAULT_P1_GUID) &&
322	    (MLXSWAPBITS64(guidsect.port2guid) == MLX_DEFAULT_P2_GUID) &&
323	    ((MLXSWAPBITS64(guidsect.sysimguid) == MLX_DEFAULT_SYSIMG_GUID) ||
324	    (MLXSWAPBITS64(guidsect.sysimguid) == MLX_DEFAULT_NODE_GUID)) ||
325	    ((((MLXSWAPBITS64(guidsect.nodeguid) & HIGHBITS64) >> 40)
326	    == MLX_OUI) ||
327	    (((MLXSWAPBITS64(guidsect.port1guid) & HIGHBITS64) >> 40)
328	    == MLX_OUI) ||
329	    (((MLXSWAPBITS64(guidsect.port2guid) & HIGHBITS64) >> 40)
330	    == MLX_OUI) ||
331	    (((MLXSWAPBITS64(guidsect.sysimguid) & HIGHBITS64) >> 40)
332	    == MLX_OUI))) {
333		return (FWFLASH_SUCCESS);
334	} else {
335		return (FWFLASH_FAILURE);
336	}
337}
338