xref: /illumos-gate/usr/src/cmd/fwflash/plugins/vendor/hermon-MELLANOX.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * ConnectX (hermon) firmware image verification plugin
29  */
30 
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <sys/types.h>
35 #include <sys/stat.h>
36 #include <sys/sysmacros.h>
37 #include <fcntl.h>
38 #include <sys/condvar.h>
39 #include <string.h>
40 #include <strings.h>
41 
42 #include <sys/byteorder.h>
43 
44 #include <libintl.h> /* for gettext(3c) */
45 
46 #include <fwflash/fwflash.h>
47 #include "../hdrs/hermon_ib.h"
48 
49 char vendor[] = "MELLANOX\0";
50 
51 extern struct vrfyplugin *verifier;
52 
53 
54 /* required functions for this plugin */
55 int vendorvrfy(struct devicelist *devicenode);
56 
57 /* helper functions */
58 static uint16_t cnx_check_hwver_img(ib_cnx_encap_ident_t *handle);
59 static void cnx_flash_verify_flash_match_img(ib_cnx_encap_ident_t *handle);
60 static void cnx_flash_verify_flash_pn_img(ib_cnx_encap_ident_t *handle,
61     uchar_t *psid, int psid_size);
62 static uchar_t *cnx_flash_get_psid_img(ib_cnx_encap_ident_t *handle);
63 static void cnx_display_fwver(ib_cnx_encap_ident_t *handle);
64 static int cnx_check_guid_section();
65 
66 
67 int
68 vendorvrfy(struct devicelist *devicenode)
69 {
70 	struct ib_cnx_encap_ident_s	*handle;
71 	uint16_t	ver;
72 
73 	logmsg(MSG_INFO, "hermon: vendorvrfy \n");
74 
75 	handle = (struct ib_cnx_encap_ident_s *)devicenode->ident->encap_ident;
76 
77 	if (CNX_I_CHECK_HANDLE(handle)) {
78 		logmsg(MSG_ERROR, gettext("hermon: Invalid Handle for "
79 		    "device %s! \n"), devicenode->access_devname);
80 		return (FWFLASH_FAILURE);
81 	}
82 
83 	/*
84 	 * NOTE verifier->fwimage is where file is read to.
85 	 */
86 	if (cnx_is_magic_pattern_present(&verifier->fwimage[0], 1) !=
87 	    FWFLASH_SUCCESS) {
88 		logmsg(MSG_ERROR, gettext("%s firmware image verifier: "
89 		    "No magic pattern found in firmware file %s \n"),
90 		    verifier->vendor, verifier->imgfile);
91 		return (FWFLASH_FAILURE);
92 	}
93 
94 	if (cnx_check_guid_section() == FWFLASH_FAILURE) {
95 		logmsg(MSG_INFO, "%s firmware image verifier: "
96 		    "Firmware Image GUID section is invalid\n",
97 		    verifier->vendor);
98 	}
99 
100 	cnx_flash_verify_flash_match_img(handle);
101 
102 	/* Check Hardware Rev */
103 	ver = cnx_check_hwver_img(handle);
104 	if (ver != 0) {
105 		logmsg(MSG_ERROR, gettext("hermon: Firmware mismatch: "
106 		    "ver(0x%X) hw_ver(0x%X)\n"), (ver >> 8), ver & 0xFF);
107 		return (FWFLASH_FAILURE);
108 	}
109 
110 	if (handle->hwfw_match == 0) {
111 		if (handle->pn_len != 0) {
112 			/* HW VPD exist and a mismatch was found */
113 			logmsg(MSG_ERROR, gettext("hermon: Please verify that "
114 			    "the firmware image is intended for use with this "
115 			    "hardware\n"));
116 		} else {
117 			logmsg(MSG_ERROR, gettext("hermon: Unable to verify "
118 			    "firmware is appropriate for the hardware\n"));
119 		}
120 		return (FWFLASH_FAILURE);
121 	}
122 	logmsg(MSG_INFO, "%s firmware image verifier: HCA PSID (%s) "
123 	    "matches firmware image %s's PSID\n", verifier->vendor,
124 	    handle->info.mlx_psid, verifier->imgfile);
125 
126 	cnx_display_fwver(handle);
127 
128 	return (FWFLASH_SUCCESS);
129 }
130 
131 static uint16_t
132 cnx_check_hwver_img(ib_cnx_encap_ident_t *handle)
133 {
134 	uint8_t	hwver;
135 	uint8_t	local_hwver;
136 
137 	logmsg(MSG_INFO, "hermon: verify: cnx_check_hwver_img\n");
138 	if ((handle->state & FWFLASH_IB_STATE_IMAGE_PRI) == 0 &&
139 	    (handle->state & FWFLASH_IB_STATE_IMAGE_SEC) == 0) {
140 		logmsg(MSG_ERROR, gettext("hermon: Must read in image "
141 		    "first\n"));
142 		return (1);
143 	}
144 
145 	/* Read Flash HW Version */
146 	hwver = (uint8_t)handle->hwrev;
147 	local_hwver = (ntohl(verifier->fwimage[CNX_HWVER_OFFSET / 4]) &
148 	    CNX_HWVER_MASK) >> 24;
149 
150 	logmsg(MSG_INFO, "local_hwver: %x, hwver: %x\n", local_hwver, hwver);
151 
152 	if ((hwver == 0xA0 || hwver == 0x00 || hwver == 0x20) &&
153 	    (local_hwver == 0x00 || local_hwver == 0xA0 ||
154 	    local_hwver == 0x20)) {
155 		logmsg(MSG_INFO, ("A0 board found.\r\n"));
156 	} else if (hwver == 0xA1 && local_hwver == 0xA1) {
157 		logmsg(MSG_INFO, ("A1 board found.\r\n"));
158 	} else if (hwver == 0xA2 && local_hwver == 0xA2) {
159 		logmsg(MSG_INFO, ("A2 board found.\r\n"));
160 	} else if (hwver == 0xA3 && local_hwver == 0xA3) {
161 		logmsg(MSG_INFO, ("A3 board found.\r\n"));
162 	} else {
163 		return ((uint16_t)(local_hwver << 8) | hwver);
164 	}
165 	return (0);
166 }
167 
168 static void
169 cnx_display_fwver(ib_cnx_encap_ident_t *handle)
170 {
171 	logmsg(MSG_INFO, "hermon: verify: cnx_display_fwver\n");
172 
173 	(void) fprintf(stdout, gettext("  The current HCA firmware version "
174 	    "is    : %d.%d.%04d\n"),
175 	    handle->hwfw_img_info.fw_rev.major,
176 	    handle->hwfw_img_info.fw_rev.minor,
177 	    handle->hwfw_img_info.fw_rev.subminor);
178 	(void) fprintf(stdout, gettext("  Will be updated to HCA firmware "
179 	    "ver of : %d.%d.%04d\n"),
180 	    handle->file_img_info.fw_rev.major,
181 	    handle->file_img_info.fw_rev.minor,
182 	    handle->file_img_info.fw_rev.subminor);
183 }
184 
185 static uchar_t *
186 cnx_flash_get_psid_img(ib_cnx_encap_ident_t *handle)
187 {
188 	uint32_t	ii_ptr_addr;
189 	uint32_t	ii_size;
190 
191 	logmsg(MSG_INFO, "hermon: verify: cnx_flash_get_psid_img\n");
192 
193 	/* Get the image info pointer */
194 	ii_ptr_addr = ntohl(verifier->fwimage[CNX_IMG_INF_PTR_OFFSET / 4]);
195 	ii_ptr_addr &= 0xffffff; /* Bits 23:0 - Image Info Data Pointer */
196 
197 	/* Get the image info size, a negative offset from the image info ptr */
198 	ii_size =
199 	    ntohl(verifier->fwimage[(ii_ptr_addr + CNX_IMG_INF_SZ_OFFSET) / 4]);
200 	/* size is in dwords--convert it to bytes */
201 	ii_size *= 4;
202 
203 	logmsg(MSG_INFO, "ImgInfo_ptr_addr: 0x%lx, ImgInfo_size: 0x%x\n",
204 	    ii_ptr_addr, ii_size);
205 
206 	/* Parse the image info section */
207 	if (cnx_parse_img_info(&verifier->fwimage[ii_ptr_addr / 4], ii_size,
208 	    &handle->file_img_info, CNX_FILE_IMG) != FWFLASH_SUCCESS) {
209 		logmsg(MSG_WARN, gettext("hermon: Failed to parse ImageInfo "
210 		    "section\n"));
211 		return (NULL);
212 	}
213 
214 	return (handle->file_img_info.psid);
215 }
216 
217 static void
218 cnx_flash_verify_flash_pn_img(ib_cnx_encap_ident_t *handle, uchar_t *psid,
219     int psid_size)
220 {
221 	int	i;
222 	int	no_match = 0;
223 
224 	logmsg(MSG_INFO, "hermon: verify: cnx_flash_verify_flash_pn_img\n");
225 	/* verify fw matches the hardware */
226 	if (handle->hwfw_match == 1) {
227 		/* already been verified */
228 		return;
229 	}
230 
231 	/* find the PSID from FW in the mlx table */
232 	for (i = 0; i < MLX_MAX_ID; i++) {
233 		if (handle->hwfw_match == 1) {
234 			/*
235 			 * Need this check here and the 'continue's below
236 			 * because there are some cards that have a
237 			 * 'new' part number but the same PSID value.
238 			 */
239 			break;
240 		}
241 
242 		/* match PSID */
243 		if (strncmp((const char *)psid, mlx_mdr[i].mlx_psid,
244 		    psid_size) == 0) {
245 			logmsg(MSG_INFO, "Found Matching firmware image's "
246 			    "PSID (%s) entry in MDR Table\n", psid);
247 
248 			logmsg(MSG_INFO, "Search for firmware image's part# "
249 			    "(%s), MDR/HW PN (%s) \n",
250 			    handle->info.mlx_pn, mlx_mdr[i].mlx_pn);
251 
252 			/* match part numbers */
253 			if (strncmp(handle->info.mlx_pn, mlx_mdr[i].mlx_pn,
254 			    handle->pn_len) == 0) {
255 				handle->hwfw_match = 1;
256 				logmsg(MSG_INFO, "Match Found \n");
257 				continue;
258 			} else {
259 				handle->hwfw_match = 0;
260 				no_match = i;
261 				logmsg(MSG_INFO, "Match NOT Found \n");
262 				continue;
263 			}
264 		}
265 	}
266 	if (i == MLX_MAX_ID && no_match == 0) {
267 		/* no match found */
268 		handle->hwfw_match = 0;
269 		handle->pn_len = 0;
270 		logmsg(MSG_WARN, gettext("hermon: No PSID match found\n"));
271 	} else {
272 		if (handle->hwfw_match == 0) {
273 			logmsg(MSG_WARN, gettext("WARNING: Firmware "
274 			    "image is meant for %s but the hardware "
275 			    "is %s\n"), mlx_mdr[no_match].mlx_pn,
276 			    handle->info.mlx_pn);
277 		}
278 	}
279 }
280 
281 static void
282 cnx_flash_verify_flash_match_img(ib_cnx_encap_ident_t *handle)
283 {
284 	uchar_t	*psid;
285 
286 	logmsg(MSG_INFO, "hermon: verify: cnx_flash_verify_flash_match_img\n");
287 	/* get PSID of firmware file */
288 	psid = cnx_flash_get_psid_img(handle);
289 	if (psid == NULL) {
290 		handle->hwfw_match = 0;
291 		handle->pn_len = 0;
292 		return;
293 	}
294 	logmsg(MSG_INFO, "FW PSID (%s)\n", psid);
295 
296 	/*
297 	 * Check the part number of the hardware against the part number
298 	 * of the firmware file. If the hardware information is not
299 	 * available, check the currently loaded firmware against the
300 	 * firmware file to be uploaded.
301 	 */
302 	if (handle->pn_len != 0) {
303 		cnx_flash_verify_flash_pn_img(handle, psid, CNX_PSID_SZ);
304 	}
305 }
306 
307 
308 static int
309 cnx_check_guid_section()
310 {
311 	struct mlx_cnx_xfi  		xfisect;
312 	struct mlx_cnx_guid_sect	guidsect;
313 	uint32_t			nguidptr_addr;
314 	uint16_t			calculated_crc;
315 
316 	logmsg(MSG_INFO, "cnx_check_guid_section: \n");
317 
318 	bcopy(&verifier->fwimage[0], &xfisect, sizeof (struct mlx_cnx_xfi));
319 	logmsg(MSG_INFO, "FailSafeChunkSz: 0x%08x, ImageInfoPtr: 0x%08x\n",
320 	    MLXSWAPBITS32(xfisect.failsafechunkinfo),
321 	    MLXSWAPBITS32(xfisect.imageinfoptr) & CNX_XFI_IMGINFO_PTR_MASK);
322 	logmsg(MSG_INFO, "FW Size: 0x%08x NGUIDPTR: 0x%08x\n",
323 	    MLXSWAPBITS32(xfisect.fwimagesz), MLXSWAPBITS32(xfisect.nguidptr));
324 
325 	nguidptr_addr = (MLXSWAPBITS32(xfisect.nguidptr) - 0x10) / 4;
326 	bcopy(&verifier->fwimage[nguidptr_addr], &guidsect,
327 	    sizeof (struct mlx_cnx_guid_sect));
328 
329 	logmsg(MSG_INFO, "Node GUID : 0x%016llx \n",
330 	    MLXSWAPBITS64(guidsect.nodeguid));
331 	logmsg(MSG_INFO, "Port1 GUID: 0x%016llx \n",
332 	    MLXSWAPBITS64(guidsect.port1guid));
333 	logmsg(MSG_INFO, "Port2 GUID: 0x%016llx \n",
334 	    MLXSWAPBITS64(guidsect.port2guid));
335 	logmsg(MSG_INFO, "SysIm GUID: 0x%016llx \n",
336 	    MLXSWAPBITS64(guidsect.sysimguid));
337 	logmsg(MSG_INFO, "Port 1 MAC: 0x%016llx \n",
338 	    MLXSWAPBITS64(guidsect.port1_mac));
339 	logmsg(MSG_INFO, "Port 2 MAC: 0x%016llx \n",
340 	    MLXSWAPBITS64(guidsect.port2_mac));
341 
342 	calculated_crc = cnx_crc16((uint8_t *)&verifier->fwimage[nguidptr_addr],
343 	    CNX_GUID_CRC16_SIZE, CNX_FILE_IMG);
344 	if (calculated_crc != ntohs(guidsect.guidcrc)) {
345 		logmsg(MSG_WARN, gettext("hermon: calculated crc value 0x%x "
346 		    "differs from GUID section 0x%x\n"), calculated_crc,
347 		    ntohs(guidsect.guidcrc));
348 	} else {
349 		logmsg(MSG_INFO, "hermon: calculated crc value 0x%x MATCHES "
350 		    "with GUID section 0x%x\n", calculated_crc,
351 		    ntohs(guidsect.guidcrc));
352 	}
353 
354 	if ((MLXSWAPBITS64(guidsect.nodeguid) == MLX_DEFAULT_NODE_GUID) &&
355 	    (MLXSWAPBITS64(guidsect.port1guid) == MLX_DEFAULT_P1_GUID) &&
356 	    (MLXSWAPBITS64(guidsect.port2guid) == MLX_DEFAULT_P2_GUID) &&
357 	    ((MLXSWAPBITS64(guidsect.sysimguid) == MLX_DEFAULT_SYSIMG_GUID) ||
358 	    (MLXSWAPBITS64(guidsect.sysimguid) == MLX_DEFAULT_NODE_GUID)) ||
359 	    ((((MLXSWAPBITS64(guidsect.nodeguid) & HIGHBITS64) >> 40) ==
360 	    MLX_OUI) ||
361 	    (((MLXSWAPBITS64(guidsect.port1guid) & HIGHBITS64) >> 40) ==
362 	    MLX_OUI) ||
363 	    (((MLXSWAPBITS64(guidsect.port2guid) & HIGHBITS64) >> 40) ==
364 	    MLX_OUI) ||
365 	    (((MLXSWAPBITS64(guidsect.sysimguid) & HIGHBITS64) >> 40) ==
366 	    MLX_OUI)) ||
367 	    ((((MLXSWAPBITS64(guidsect.nodeguid) & HIGHBITS64) >> 40) ==
368 	    SUNW_OUI) ||
369 	    (((MLXSWAPBITS64(guidsect.port1guid) & HIGHBITS64) >> 40) ==
370 	    SUNW_OUI) ||
371 	    (((MLXSWAPBITS64(guidsect.port2guid) & HIGHBITS64) >> 40) ==
372 	    SUNW_OUI) ||
373 	    (((MLXSWAPBITS64(guidsect.sysimguid) & HIGHBITS64) >> 40) ==
374 	    SUNW_OUI))) {
375 		logmsg(MSG_INFO, "%s firmware image verifier: GUID Prefix "
376 		    "is as expected\n", verifier->vendor);
377 		return (FWFLASH_SUCCESS);
378 	} else {
379 		logmsg(MSG_INFO, "%s firmware image verifier: GUID prefix "
380 		    "is not as expected\n", verifier->vendor);
381 		return (FWFLASH_FAILURE);
382 	}
383 }
384