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