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