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