tavor-MELLANOX.c revision 9517:b4839b0aa7a4
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 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27/* 28 * Mellanox firmware image verification plugin 29 */ 30 31 32#include <stdio.h> 33#include <stdlib.h> 34#include <unistd.h> 35#include <sys/types.h> 36#include <sys/stat.h> 37#include <sys/sysmacros.h> 38#include <fcntl.h> 39#include <sys/condvar.h> 40#include <string.h> 41#include <strings.h> 42 43#include <sys/byteorder.h> 44 45#include <libintl.h> /* for gettext(3c) */ 46 47#include <fwflash/fwflash.h> 48#include "../hdrs/MELLANOX.h" 49#include "../hdrs/tavor_ib.h" 50 51 52 53char vendor[] = "MELLANOX\0"; 54 55extern int errno; 56extern struct vrfyplugin *verifier; 57extern uint16_t crc16(uint8_t *image, uint32_t size); 58 59 60/* required functions for this plugin */ 61int vendorvrfy(struct devicelist *devicenode); 62 63 64/* helper functions */ 65static int check_guid_ptr(uint8_t *data); 66 67 68int 69vendorvrfy(struct devicelist *devicenode) 70{ 71 struct ib_encap_ident *encap; 72 uint32_t sector_sz; 73 int *firmware; 74 uint32_t vp_fia, vs_fia; 75 uint32_t vp_imginfo, vs_imginfo; 76 struct mlx_xps *vps; 77 uint8_t *vfi; 78 int i = 0, a, b, c, d; 79 char temppsid[17]; 80 char rawpsid[16]; 81 82 encap = (struct ib_encap_ident *)devicenode->ident->encap_ident; 83 84 /* 85 * NOTE that since verifier->fwimage is an array of ints, 86 * we have to divide our actual desired number by 4 to get 87 * the right data. 88 */ 89 firmware = verifier->fwimage; 90 91 /* sector_sz is stored as Log_2 of the real value */ 92 sector_sz = 1 << MLXSWAPBITS32(firmware[FLASH_IS_SECTOR_SIZE_OFFSET/4]); 93 94 if (sector_sz != encap->sector_sz) { 95 logmsg(MSG_ERROR, 96 gettext("%s firmware image verifier: " 97 "Invariant Sector is invalid\n"), 98 verifier->vendor); 99 /* this is fatal */ 100 return (FWFLASH_FAILURE); 101 } 102 103 /* now verify primary pointer sector */ 104 if ((vps = calloc(1, sizeof (struct mlx_xps))) == NULL) { 105 logmsg(MSG_ERROR, 106 gettext("%s firmware image verifier: " 107 "Unable to allocate memory for Primary Pointer " 108 "Sector verification\n")); 109 return (FWFLASH_FAILURE); 110 } 111 bcopy(&firmware[sector_sz / 4], vps, sizeof (struct mlx_xps)); 112 if ((MLXSWAPBITS32(vps->signature) != FLASH_PS_SIGNATURE) || 113 (vps->xpsresv3 != 0)) { 114 logmsg(MSG_ERROR, 115 gettext("%s firmware image verifier: " 116 "Primary Pointer Sector is invalid\n"), 117 verifier->vendor); 118 } 119 vp_fia = MLXSWAPBITS32(vps->fia); 120 121 /* 122 * A slight diversion - check the PSID in the last 123 * 16 bytes of the first 256bytes in the xPS sectors. 124 * This will give us our part number to match. If the 125 * part number in the image doesn't match the part number 126 * in the encap_ident info (and pn_len > 0) then we reject 127 * this image as being incompatible with the HCA. 128 * 129 * In this bit we're only checking the info.mlx_psid field 130 * of the primary image in the on-disk image. If that's 131 * invalid we reject the image. 132 */ 133 134 if (encap->info.mlx_psid != NULL) { 135 bzero(temppsid, 17); 136 bcopy(vps->vsdpsid+0xd0, &rawpsid, 16); 137 138#if !defined(_LITTLE_ENDIAN) 139 for (i = 0; i < 16; i += 4) { 140 temppsid[i] = rawpsid[i+3]; 141 temppsid[i+1] = rawpsid[i+2]; 142 temppsid[i+2] = rawpsid[i+1]; 143 temppsid[i+3] = rawpsid[i]; 144 } 145 logmsg(MSG_INFO, 146 "tavor: have raw '%s', want munged '%s'\n", 147 rawpsid, temppsid); 148#else 149 bcopy(vps->vsdpsid+0xd0, &temppsid, 16); 150#endif 151 if (strncmp(encap->info.mlx_psid, temppsid, 16) != 0) { 152 logmsg(MSG_ERROR, 153 gettext("%s firmware image verifier: " 154 "firmware image file %s is not appropriate " 155 "for device\n" 156 "%s (PSID file %s vs PSID device %s)\n"), 157 verifier->vendor, verifier->imgfile, 158 encap->info.mlx_psid, 159 ((temppsid != NULL) ? temppsid : "(null)")); 160 161 free(vps); 162 return (FWFLASH_FAILURE); 163 } else { 164 logmsg(MSG_INFO, 165 "%s firmware image verifier: HCA PSID (%s) " 166 "matches firmware image %s's PSID\n", 167 verifier->vendor, 168 encap->info.mlx_psid, 169 verifier->imgfile); 170 } 171 } 172 173 174 /* now verify secondary pointer sector */ 175 bzero(vps, sizeof (struct mlx_xps)); 176 177 bcopy(&firmware[sector_sz / 2], vps, sizeof (struct mlx_xps)); 178 if ((MLXSWAPBITS32(vps->signature) != FLASH_PS_SIGNATURE) || 179 (vps->xpsresv3 != 0)) { 180 logmsg(MSG_ERROR, 181 gettext("%s firmware image verifier: " 182 "Secondary Pointer Sector is invalid\n"), 183 verifier->vendor); 184 } 185 vs_fia = MLXSWAPBITS32(vps->fia); 186 187 (void) free(vps); 188 189 if ((vfi = calloc(1, sector_sz)) == NULL) { 190 logmsg(MSG_ERROR, 191 gettext("%s firmware image verifier: " 192 "Unable to allocate space for Primary " 193 "Firmware Image verification\n"), 194 verifier->vendor); 195 return (FWFLASH_FAILURE); 196 } 197 bcopy(&firmware[vp_fia / 4], vfi, sector_sz); 198 bcopy(&vfi[XFI_IMGINFO_OFFSET], &i, 4); 199 vp_imginfo = MLXSWAPBITS32(i); 200 201 /* for readability only */ 202 a = (vp_imginfo & 0xff000000) >> 24; 203 b = (vp_imginfo & 0x00ff0000) >> 16; 204 c = (vp_imginfo & 0x0000ff00) >> 8; 205 d = (vp_imginfo & 0x000000ff); 206 207 /* 208 * It appears to be the case (empirically) that this particular 209 * check condition for ImageInfoPtr doesn't hold for A1 firmware 210 * images. So if the ((a+b+c+d)%0x100) fails, don't worry unless 211 * the contents of the GUID section do not match the Mellanox 212 * default GUIDs 2c9000100d05[0123]. The A2++ images also have 213 * these default GUIDS. 214 * 215 * Unfortunately we can't depend on the hwrev field of the image's 216 * Invariant Sector for another level of confirmation, since A2++ 217 * images seem to have that field set to 0xa1 as well as the A1 218 * images. Annoying! 219 */ 220 221 if ((((a+b+c+d) % 0x100) == 0) && 222 (vp_imginfo != 0x00000000)) { 223 logmsg(MSG_INFO, 224 "%s firmware image verifier: " 225 "Primary Firmware Image Info pointer is valid\n", 226 verifier->vendor); 227 } else { 228 229 logmsg(MSG_ERROR, 230 gettext("%s firmware image verifier: " 231 "Primary Firmware Image Info pointer is invalid " 232 "(0x%04x)\nChecking GUID section.....\n"), 233 verifier->vendor, vp_imginfo); 234 235 if (check_guid_ptr(vfi) == FWFLASH_FAILURE) { 236 logmsg(MSG_ERROR, 237 gettext("%s firmware image verifier: " 238 "Primary Firmware Image GUID section " 239 "is invalid\n"), 240 verifier->vendor); 241 i = 1; 242 } else { 243 logmsg(MSG_INFO, 244 "%s firmware image verifier: " 245 "Primary GUID section is ok\n", 246 verifier->vendor); 247 } 248 249 } 250 251 bzero(vfi, sector_sz); 252 bcopy(&firmware[vs_fia / 4], vfi, sector_sz); 253 254 bcopy(&vfi[XFI_IMGINFO_OFFSET], &i, 4); 255 vs_imginfo = MLXSWAPBITS32(i); 256 257 /* for readability only */ 258 a = (vs_imginfo & 0xff000000) >> 24; 259 b = (vs_imginfo & 0x00ff0000) >> 16; 260 c = (vs_imginfo & 0x0000ff00) >> 8; 261 d = (vs_imginfo & 0x000000ff); 262 263 if ((((a+b+c+d) % 0x100) == 0) && 264 (vs_imginfo != 0x00000000)) { 265 logmsg(MSG_INFO, 266 "%s firmware image verifier: " 267 "Secondary Firmware Image Info pointer is valid\n", 268 verifier->vendor); 269 } else { 270 logmsg(MSG_ERROR, 271 gettext("%s firmware image verifier: " 272 "Secondary Firmware Image Info pointer is invalid " 273 "(0x%04x)\nChecking GUID section.....\n"), 274 verifier->vendor, vp_imginfo); 275 276 if (check_guid_ptr(vfi) == FWFLASH_FAILURE) { 277 logmsg(MSG_ERROR, 278 gettext("%s firmware image verifier: " 279 "Secondary Firmware Image GUID section " 280 "is invalid\n"), 281 verifier->vendor); 282 i++; 283 } 284 } 285 286 free(vfi); 287 288 289 return ((i == 2) ? (FWFLASH_FAILURE) : (FWFLASH_SUCCESS)); 290} 291 292 293/* 294 * Very simple function - we're given an array of bytes, 295 * we know that we need to read the value at offset FLASH_GUID_PTR 296 * and jump to that location to read 4x uint64_t of (hopefully) 297 * GUID data. If we can read that data, and it matches the default 298 * Mellanox GUIDs, then we return success. We need all 4 default 299 * GUIDs to match otherwise we return failure. 300 */ 301static int 302check_guid_ptr(uint8_t *data) 303{ 304 struct mlx_xfi xfisect; 305 struct mlx_guid_sect guidsect; 306 307 bcopy(data, &xfisect, sizeof (xfisect)); 308 bcopy(&data[MLXSWAPBITS32(xfisect.nguidptr) - 16], &guidsect, 309 GUIDSECTION_SZ); 310 311 logmsg(MSG_INFO, "nodeguid: %0llx\n", 312 MLXSWAPBITS64(guidsect.nodeguid)); 313 logmsg(MSG_INFO, "port1guid: %0llx\n", 314 MLXSWAPBITS64(guidsect.port1guid)); 315 logmsg(MSG_INFO, "port2guid: %0llx\n", 316 MLXSWAPBITS64(guidsect.port2guid)); 317 logmsg(MSG_INFO, "sysimguid: %0llx\n", 318 MLXSWAPBITS64(guidsect.sysimguid)); 319 320 if ((MLXSWAPBITS64(guidsect.nodeguid) == MLX_DEFAULT_NODE_GUID) && 321 (MLXSWAPBITS64(guidsect.port1guid) == MLX_DEFAULT_P1_GUID) && 322 (MLXSWAPBITS64(guidsect.port2guid) == MLX_DEFAULT_P2_GUID) && 323 ((MLXSWAPBITS64(guidsect.sysimguid) == MLX_DEFAULT_SYSIMG_GUID) || 324 (MLXSWAPBITS64(guidsect.sysimguid) == MLX_DEFAULT_NODE_GUID)) || 325 ((((MLXSWAPBITS64(guidsect.nodeguid) & HIGHBITS64) >> 40) 326 == MLX_OUI) || 327 (((MLXSWAPBITS64(guidsect.port1guid) & HIGHBITS64) >> 40) 328 == MLX_OUI) || 329 (((MLXSWAPBITS64(guidsect.port2guid) & HIGHBITS64) >> 40) 330 == MLX_OUI) || 331 (((MLXSWAPBITS64(guidsect.sysimguid) & HIGHBITS64) >> 40) 332 == MLX_OUI))) { 333 return (FWFLASH_SUCCESS); 334 } else { 335 return (FWFLASH_FAILURE); 336 } 337} 338