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 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 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 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 * 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 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 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 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