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 * IB (InfiniBand) specific functions. 28 */ 29 30 /* 31 * The reference for the functions in this file is the 32 * 33 * Mellanox HCA Flash Programming Application Note 34 * (Mellanox document number 2205AN) 35 * rev 1.44, 2007. Chapter 4 in particular. 36 * 37 * NOTE: this Mellanox document is labelled Confidential 38 * so DO NOT move this file out of usr/closed without 39 * explicit approval from Sun Legal. 40 */ 41 42 /* 43 * IMPORTANT NOTE: 44 * 1. flash read is done in 32 bit quantities, and the driver returns 45 * data in host byteorder form. 46 * 2. flash write is done in 8 bit quantities by the driver. 47 * 3. data in the flash should be in network byteorder (bigendian). 48 * 4. data in image files is in network byteorder form. 49 * 5. data in image structures in memory is kept in network byteorder. 50 * 6. the functions in this file deal with data in host byteorder form. 51 */ 52 53 54 #include <stdio.h> 55 #include <stdlib.h> 56 #include <unistd.h> 57 #include <sys/types.h> 58 #include <sys/stat.h> 59 #include <sys/sysmacros.h> 60 #include <sys/queue.h> 61 #include <fcntl.h> 62 #include <ctype.h> 63 #include <string.h> 64 #include <strings.h> 65 66 #include <sys/byteorder.h> 67 68 #include <libintl.h> /* for gettext(3c) */ 69 70 #include <fwflash/fwflash.h> 71 #include "../../hdrs/MELLANOX.h" 72 #include "../../hdrs/tavor_ib.h" 73 74 75 76 char *devprefix = "/devices"; 77 char drivername[] = "tavor\0"; 78 char *devsuffix = ":devctl"; 79 80 81 extern di_node_t rootnode; 82 extern int errno; 83 extern struct fw_plugin *self; 84 extern struct vrfyplugin *verifier; 85 extern int fwflash_debug; 86 87 88 /* required functions for this plugin */ 89 int fw_readfw(struct devicelist *device, char *filename); 90 int fw_writefw(struct devicelist *device); 91 int fw_identify(int start); 92 int fw_devinfo(); 93 94 95 /* helper functions */ 96 97 static int tavor_identify(struct devicelist *thisdev); 98 static int tavor_get_guids(struct ib_encap_ident *handle); 99 static int tavor_close(struct devicelist *flashdev); 100 static void tavor_cisco_extensions(mlx_xps_t *hcaxps, mlx_xps_t *diskxps); 101 static uint16_t crc16(uint8_t *image, uint32_t size); 102 static int tavor_write_sector(int fd, int sectnum, int32_t *data); 103 static int tavor_zero_sig_crc(int fd, uint32_t start); 104 static int tavor_write_xps_fia(int fd, uint32_t offset, uint32_t start); 105 static int tavor_write_xps_crc_sig(int fd, uint32_t offset, uint16_t newcrc); 106 static int tavor_blast_image(int fd, int prisec, uint32_t hcafia, 107 uint32_t sectsz, struct mlx_xps *newxps); 108 static int tavor_readback(int infd, int whichsect, int sectsz); 109 110 111 112 int 113 fw_readfw(struct devicelist *flashdev, char *filename) 114 { 115 116 int rv = FWFLASH_SUCCESS; 117 int fd; 118 mode_t mode = S_IRUSR | S_IWUSR; 119 uint8_t pchunks; 120 uint8_t *raw_pfi; 121 uint8_t *raw_sfi; 122 uint32_t j, offset; 123 uint32_t pfia, sfia, psz, ssz; 124 tavor_flash_ioctl_t tfi_data; 125 struct ib_encap_ident *manuf; 126 struct mlx_xps *lpps; 127 struct mlx_xps *lsps; 128 #if defined(_LITTLE_ENDIAN) 129 uint32_t *ptr; 130 #endif 131 132 errno = 0; 133 if ((fd = open(filename, O_RDWR|O_CREAT|O_DSYNC, mode)) < 0) { 134 logmsg(MSG_ERROR, 135 gettext("tavor: Unable to open specified file " 136 "(%s) for writing: %s\n"), filename, strerror(errno)); 137 return (FWFLASH_FAILURE); 138 } 139 140 manuf = 141 (struct ib_encap_ident *)(uintptr_t)flashdev->ident->encap_ident; 142 lpps = (struct mlx_xps *)(uintptr_t)manuf->pps; 143 lsps = (struct mlx_xps *)(uintptr_t)manuf->sps; 144 145 /* 146 * Now that we've got an open, init'd fd, we can read the 147 * xFI from the device itself. We've already got the IS 148 * and xPS stored in manuf. 149 */ 150 151 /* stash some values for later */ 152 pfia = MLXSWAPBITS32(lpps->fia); 153 sfia = MLXSWAPBITS32(lsps->fia); 154 psz = MLXSWAPBITS32(lpps->fis); 155 ssz = MLXSWAPBITS32(lsps->fis); 156 157 /* Invariant Sector comes first */ 158 if ((j = write(fd, manuf->inv, manuf->sector_sz)) != 159 manuf->sector_sz) { 160 logmsg(MSG_ERROR, 161 gettext("tavor: Unable to write HCA Invariant Sector " 162 "(%d of %d bytes)\n"), 163 j, manuf->sector_sz); 164 (void) tavor_close(flashdev); 165 return (FWFLASH_FAILURE); 166 } else { 167 fprintf(stdout, gettext("Writing .")); 168 } 169 170 /* followed by Primary Pointer Sector */ 171 if ((j = write(fd, manuf->pps, manuf->sector_sz)) != 172 manuf->sector_sz) { 173 logmsg(MSG_ERROR, 174 gettext("tavor: Unable to write HCA Primary Pointer " 175 "Sector (%d of %d bytes)\n)"), 176 j, manuf->sector_sz); 177 (void) tavor_close(flashdev); 178 return (FWFLASH_FAILURE); 179 } else { 180 fprintf(stdout, " ."); 181 } 182 183 /* followed by Secondary Pointer Sector */ 184 if ((j = write(fd, manuf->sps, manuf->sector_sz)) != 185 manuf->sector_sz) { 186 logmsg(MSG_ERROR, 187 gettext("tavor: Unable to write HCA Secondary Pointer " 188 "Sector (%d of %d bytes)\n"), 189 j, manuf->sector_sz); 190 (void) tavor_close(flashdev); 191 return (FWFLASH_FAILURE); 192 } else { 193 fprintf(stdout, " ."); 194 } 195 196 /* Now for the xFI sectors */ 197 pchunks = psz / manuf->sector_sz; 198 199 if ((psz % manuf->sector_sz) != 0) 200 pchunks++; 201 202 /* Get the PFI, then the SFI */ 203 if ((raw_pfi = calloc(1, pchunks * manuf->sector_sz)) == NULL) { 204 logmsg(MSG_ERROR, 205 gettext("tavor: Unable to allocate space for " 206 "device's Primary Firmware Image\n")); 207 return (FWFLASH_FAILURE); 208 } 209 bzero(&tfi_data, sizeof (tavor_flash_ioctl_t)); 210 tfi_data.tf_type = TAVOR_FLASH_READ_SECTOR; 211 j = pfia / manuf->sector_sz; 212 213 for (offset = 0; offset < psz; offset += manuf->sector_sz) { 214 tfi_data.tf_sector_num = j; 215 tfi_data.tf_sector = (caddr_t)&raw_pfi[offset]; 216 rv = ioctl(manuf->fd, TAVOR_IOCTL_FLASH_READ, &tfi_data); 217 if (rv < 0) { 218 logmsg(MSG_ERROR, 219 gettext("tavor: Unable to read sector %d of " 220 "HCA Primary Firmware Image\n"), j); 221 free(raw_pfi); 222 (void) tavor_close(flashdev); 223 return (FWFLASH_FAILURE); 224 } 225 ++j; 226 } 227 228 /* 229 * It appears that the tavor driver is returning a signed 230 * -1 (0xffff) in unassigned quadlets if we read a sector 231 * that isn't full, so for backwards compatibility with 232 * earlier fwflash versions, we need to zero out what 233 * remains in the sector. 234 */ 235 bzero(&raw_pfi[psz], (pchunks * manuf->sector_sz) - psz); 236 237 #if defined(_LITTLE_ENDIAN) 238 ptr = (uint32_t *)(uintptr_t)raw_pfi; 239 for (j = 0; j < (pchunks * manuf->sector_sz / 4); j++) { 240 ptr[j] = htonl(ptr[j]); 241 if (j > psz) 242 break; 243 } 244 #endif 245 246 if ((j = write(fd, raw_pfi, pchunks * manuf->sector_sz)) 247 != pchunks * manuf->sector_sz) { 248 logmsg(MSG_ERROR, 249 gettext("tavor: Unable to write HCA Primary Firmware " 250 "Image data (%d of %d bytes)\n"), 251 j, pchunks * manuf->sector_sz); 252 free(raw_pfi); 253 (void) tavor_close(flashdev); 254 return (FWFLASH_FAILURE); 255 } else { 256 fprintf(stdout, " ."); 257 } 258 259 pchunks = ssz / manuf->sector_sz; 260 261 if ((ssz % manuf->sector_sz) != 0) 262 pchunks++; 263 264 /* 265 * We allocate wholenum sectors, but only write out what we 266 * really need (ssz bytes) 267 */ 268 if ((raw_sfi = calloc(1, pchunks * manuf->sector_sz)) == NULL) { 269 logmsg(MSG_ERROR, 270 gettext("tavor: Unable to allocate space for " 271 "device's Secondary Firmware Image\n")); 272 free(raw_pfi); 273 return (FWFLASH_FAILURE); 274 } 275 bzero(&tfi_data, sizeof (tavor_flash_ioctl_t)); 276 tfi_data.tf_type = TAVOR_FLASH_READ_SECTOR; 277 278 /* get our starting sector number */ 279 j = sfia / manuf->sector_sz; 280 281 for (offset = 0; offset < ssz; offset += manuf->sector_sz) { 282 tfi_data.tf_sector_num = j; 283 tfi_data.tf_sector = (caddr_t)&raw_sfi[offset]; 284 if ((rv = ioctl(manuf->fd, TAVOR_IOCTL_FLASH_READ, 285 &tfi_data)) < 0) { 286 logmsg(MSG_ERROR, 287 gettext("tavor: Unable to read sector %d of " 288 "HCA Secondary Firmware Image\n"), j); 289 (void) tavor_close(flashdev); 290 free(raw_pfi); 291 free(raw_sfi); 292 return (FWFLASH_FAILURE); 293 } 294 ++j; 295 } 296 297 /* 298 * It appears that the tavor driver is returning a signed 299 * -1 (0xffff) in unassigned quadlets if we read a sector 300 * that isn't full, so for backwards compatibility with 301 * earlier fwflash versions, we need to zero out what 302 * remains in the sector. 303 */ 304 bzero(&raw_sfi[ssz], (pchunks * manuf->sector_sz) - ssz); 305 306 #if defined(_LITTLE_ENDIAN) 307 ptr = (uint32_t *)(uintptr_t)raw_sfi; 308 for (j = 0; j < ssz / 4; j++) { 309 ptr[j] = htonl(ptr[j]); 310 } 311 #endif 312 313 /* only write out ssz bytes */ 314 if ((j = write(fd, raw_sfi, ssz)) != ssz) { 315 logmsg(MSG_ERROR, 316 gettext("tavor: Unable to write HCA Secondary Firmware " 317 "Image data (%d of %d bytes)\n"), 318 j, ssz); 319 (void) tavor_close(flashdev); 320 free(raw_pfi); 321 free(raw_sfi); 322 return (FWFLASH_FAILURE); 323 } else { 324 fprintf(stdout, " .\n"); 325 } 326 327 fprintf(stdout, 328 gettext("Done.\n")); 329 330 free(raw_pfi); 331 free(raw_sfi); 332 /* 333 * this should succeed, but we don't just blindly ignore 334 * the return code cos that would be obnoxious. 335 */ 336 return (tavor_close(flashdev)); 337 } 338 339 340 /* 341 * If we're invoking fw_writefw, then flashdev is a valid, 342 * flashable device as determined by fw_identify(). 343 * 344 * If verifier is null, then we haven't been called following a firmware 345 * image verification load operation. 346 */ 347 int 348 fw_writefw(struct devicelist *flashdev) 349 { 350 351 int rv; 352 uint32_t j, sectsz, hpfia, hsfia; 353 uint32_t ipfia, isfia, ipfis, isfis; 354 struct ib_encap_ident *manuf; 355 struct mlx_is *iinv; 356 struct mlx_xps *ipps, *lpps; 357 struct mlx_xps *isps, *lsps; 358 struct mlx_xfi *ipfi, *isfi; 359 360 /* 361 * linv, lpps/lsps are from the HCA whereas 362 * iinv/ipps/isps are in the on-disk firmware image that 363 * we've read in to the verifier->fwimage field, and are 364 * about to do some hand-waving with. 365 */ 366 367 /* 368 * From the Mellanox HCA Flash programming app note, 369 * start of ch4, page36: 370 * =========================================================== 371 * Failsafe firmware programming ensures that an HCA device 372 * can boot up in a functional mode even if the burn process 373 * was interrupted (because of a power failure, reboot, user 374 * interrupt, etc.). This can be implemented by burning the 375 * new image to a vacant region on the Flash, and erasing the 376 * old image only after the new image is successfully burnt. 377 * This method ensures that there is at least one valid firmware 378 * image on the Flash at all times. Thus, in case a firmware 379 * image programming process is aborted for any reason, the HCA 380 * will still be able to boot up properly using the valid image 381 * on the Flash. 382 * ... 383 * 384 * 4.1 Notes on Image Programming of HCA Flashes 385 * Following are some general notes regarding the Flash memory 386 * in the context of Mellanox HCA devices: 387 * > The Flash memory is divided into sectors, and each sector 388 * must be erased prior to its programming. 389 * > The image to be burnt is byte packed and should be programmed 390 * into the Flash byte by byte, preserving the byte order, starting 391 * at offset zero. No amendments are needed for endianess. 392 * > It is recommended to program the Flash while the device is idle. 393 * =========================================================== 394 * 395 * The comment about endianness is particularly important for us 396 * since we operate on both big- and litte-endian hosts - it means 397 * we have to do some byte-swapping gymnastics 398 */ 399 400 /* 401 * From the Mellanox HCA Flash programming app note, 402 * section 4.2.5 on page 41/42: 403 * =========================================================== 404 * 4.2.5 Failsafe Programming Example 405 * This section provides an example of a programming utility 406 * that performs a Failsafe firmware image update. The flow 407 * ensures that there is at least one valid firmware image on 408 * the Flash at all times. Thus, in case a firmware image pro- 409 * gramming process is aborted for any reason, the HCA will 410 * still be able to boot up properly using the valid image on 411 * the Flash. Any other flow that ensures the above is also 412 * considered a Failsafe firmware update. 413 * 414 * Update Flow: 415 * * Check the validity of the PPS and SPS: 416 * > If both PSs are valid, arbitrarily invalidate one of them 417 * > If both PSs are invalid, the image on flash is corrupted 418 * and cannot be updated in a Failsafe way. The user must 419 * burn a full image in a non-failsafe way. 420 * 421 * > If only the PPS is valid: 422 * i.Burn the secondary image (erase each sector first) 423 * ii.Burn the SPS with the correct image address (FIA field) 424 * iii.Invalidate the PPS 425 * 426 * > If only the SPS is valid: 427 * i.Burn the primary image (erase each sector first) 428 * ii.Burn the PPS with the correct image address (FIA field) 429 * iii.Invalidate the SPS 430 * =========================================================== 431 */ 432 433 /* 434 * Other required tasks called from this function: 435 * 436 * * check for CISCO boot extensions in the current xPS, and 437 * if found, set them in the new xPS 438 * 439 * * update the xPS CRC field 440 * 441 * _then_ you can setup the outbound transfer to the HCA flash. 442 */ 443 444 /* 445 * VERY IMPORTANT NOTE: 446 * The above text from the app note programming guide v1.44 does 447 * NOT match reality. If you try to do exactly what the above 448 * text specifies then you'll wind up with a warm, brick-like 449 * HCA that if you're really lucky has booted up in maintenance 450 * mode for you to re-flash. 451 * 452 * What you need to do is follow the example of the previous 453 * (v1.2 etc) version from the ON gate - which is what happens 454 * in this file. Basically - don't erase prior to writing a new 455 * sector, and _read back_ each sector after writing it. Especially 456 * the pointer sectors. Otherwise you'll get a warm brick. 457 */ 458 459 manuf = 460 (struct ib_encap_ident *)(uintptr_t)flashdev->ident->encap_ident; 461 lpps = (struct mlx_xps *)(uintptr_t)manuf->pps; 462 lsps = (struct mlx_xps *)(uintptr_t)manuf->sps; 463 iinv = (struct mlx_is *)&verifier->fwimage[0]; 464 sectsz = 1 << MLXSWAPBITS16(iinv->log2sectsz + iinv->log2sectszp); 465 ipps = (struct mlx_xps *)&verifier->fwimage[sectsz/4]; 466 isps = (struct mlx_xps *)&verifier->fwimage[sectsz/2]; 467 468 /* 469 * If we get here, then the verifier has _already_ checked that 470 * the part number in the firmware image matches that in the HCA, 471 * so we only need this check if there's no hardware info available 472 * already after running through fw_identify(). 473 */ 474 if (manuf->pn_len == 0) { 475 int resp; 476 477 (void) printf("\nUnable to completely verify that this " 478 "firmware image\n\t(%s)\nis compatible with your " 479 "HCA\n\t%s\n", 480 verifier->imgfile, flashdev->access_devname); 481 (void) printf("\n\tDo you really want to continue? (Y/N): "); 482 483 (void) fflush(stdin); 484 resp = getchar(); 485 if (resp != 'Y' && resp != 'y') { 486 (void) printf("\nNot proceeding with flash " 487 "operation of %s on %s\n", 488 verifier->imgfile, flashdev->access_devname); 489 return (FWFLASH_FAILURE); 490 } 491 } 492 493 /* stash these for later */ 494 hpfia = MLXSWAPBITS32(lpps->fia); 495 hsfia = MLXSWAPBITS32(lsps->fia); 496 497 /* where does the on-disk image think everything is at? */ 498 ipfia = MLXSWAPBITS32(ipps->fia); 499 isfia = MLXSWAPBITS32(isps->fia); 500 ipfis = MLXSWAPBITS32(ipps->fis); 501 isfis = MLXSWAPBITS32(isps->fis); 502 503 logmsg(MSG_INFO, "tavor: hpfia 0x%0x hsfia 0x%0x " 504 "ipfia 0x%0x isfia 0x%0x ipfis 0x%0x isfis 0x%0x\n", 505 hpfia, hsfia, ipfia, isfia, ipfis, isfis); 506 507 if ((ipfis + isfis) > manuf->device_sz) { 508 /* 509 * This is bad - don't flash an image which is larger 510 * than the size of the HCA's flash 511 */ 512 logmsg(MSG_ERROR, 513 gettext("tavor: on-disk firmware image size (0x%lx bytes) " 514 "exceeds HCA's flash memory size (0x%lx bytes)!\n"), 515 ipfis + isfis, manuf->device_sz); 516 logmsg(MSG_ERROR, 517 gettext("tavor: not flashing this image (%s)\n"), 518 verifier->imgfile); 519 return (FWFLASH_FAILURE); 520 } 521 522 /* 523 * The Mellanox HCA Flash app programming note does _not_ 524 * specify that you have to insert the HCA's guid section 525 * into the flash image before burning it. 526 * 527 * HOWEVER it was determined during testing that this is 528 * actually required (otherwise your HCA's GUIDs revert to 529 * the manufacturer's defaults, ugh!), so we'll do it too. 530 */ 531 532 ipfi = (struct mlx_xfi *)&verifier->fwimage[ipfia/4]; 533 isfi = (struct mlx_xfi *)&verifier->fwimage[isfia/4]; 534 535 /* 536 * Here we check against our stored, properly-bitwise-munged copy 537 * of the HCA's GUIDS. If they're not set to default AND the OUI 538 * is MLX_OUI, then they're ok so we copy the HCA's version into 539 * our in-memory copy and blat it. If the GUIDs don't match this 540 * condition, then we use the default GUIDs which are in the on-disk 541 * firmware image instead. 542 */ 543 if (((manuf->ibguids[0] != MLX_DEFAULT_NODE_GUID) && 544 (manuf->ibguids[1] != MLX_DEFAULT_P1_GUID) && 545 (manuf->ibguids[2] != MLX_DEFAULT_P2_GUID) && 546 (manuf->ibguids[3] != MLX_DEFAULT_SYSIMG_GUID)) && 547 ((((manuf->ibguids[0] & HIGHBITS64) >> OUISHIFT) == MLX_OUI) || 548 (((manuf->ibguids[1] & HIGHBITS64) >> OUISHIFT) == MLX_OUI) || 549 (((manuf->ibguids[2] & HIGHBITS64) >> OUISHIFT) == MLX_OUI) || 550 (((manuf->ibguids[3] & HIGHBITS64) >> OUISHIFT) == MLX_OUI))) { 551 /* The GUIDs are ok, blat them into the in-memory image */ 552 j = ((ipfia + MLXSWAPBITS32(ipfi->nguidptr)) / 4) - 4; 553 bcopy(manuf->pri_guid_section, &verifier->fwimage[j], 554 sizeof (struct mlx_guid_sect)); 555 j = ((isfia + MLXSWAPBITS32(isfi->nguidptr)) / 4) - 4; 556 bcopy(manuf->sec_guid_section, &verifier->fwimage[j], 557 sizeof (struct mlx_guid_sect)); 558 } else { 559 /* 560 * The GUIDs are hosed, we'll have to use 561 * the vendor defaults in the image instead 562 */ 563 logmsg(MSG_ERROR, 564 gettext("tavor: HCA's GUID section is set to defaults or " 565 " is invalid, using firmware image manufacturer's " 566 "default GUID section instead\n")); 567 } 568 569 /* Just in case somebody is booting from this card... */ 570 tavor_cisco_extensions(lpps, ipps); 571 tavor_cisco_extensions(lsps, isps); 572 573 /* first we write the secondary image and SPS, then the primary */ 574 rv = tavor_blast_image(manuf->fd, 2, hsfia, manuf->sector_sz, isps); 575 if (rv != FWFLASH_SUCCESS) { 576 logmsg(MSG_INFO, 577 "tavor: failed to update #2 firmware image\n"); 578 (void) tavor_close(flashdev); 579 return (FWFLASH_FAILURE); 580 } 581 582 rv = tavor_blast_image(manuf->fd, 1, hpfia, manuf->sector_sz, ipps); 583 if (rv != FWFLASH_SUCCESS) { 584 logmsg(MSG_INFO, 585 "tavor: failed to update #1 firmware image\n"); 586 (void) tavor_close(flashdev); 587 return (FWFLASH_FAILURE); 588 } 589 590 /* final update marker to the user */ 591 (void) printf(" +\n"); 592 return (tavor_close(flashdev)); 593 } 594 595 596 /* 597 * The fw_identify() function walks the device 598 * tree trying to find devices which this plugin 599 * can work with. 600 * 601 * The parameter "start" gives us the starting index number 602 * to give the device when we add it to the fw_devices list. 603 * 604 * firstdev is allocated by us and we add space as necessary 605 * 606 */ 607 int 608 fw_identify(int start) 609 { 610 int rv = FWFLASH_FAILURE; 611 di_node_t thisnode; 612 struct devicelist *newdev; 613 char *devpath; 614 int idx = start; 615 int devlength = 0; 616 617 thisnode = di_drv_first_node(drivername, rootnode); 618 619 if (thisnode == DI_NODE_NIL) { 620 logmsg(MSG_INFO, gettext("No %s nodes in this system\n"), 621 drivername); 622 return (rv); 623 } 624 625 /* we've found one, at least */ 626 for (; thisnode != DI_NODE_NIL; thisnode = di_drv_next_node(thisnode)) { 627 628 devpath = di_devfs_path(thisnode); 629 630 if ((newdev = calloc(1, sizeof (struct devicelist))) 631 == NULL) { 632 logmsg(MSG_ERROR, 633 gettext("tavor identification function: unable " 634 "to allocate space for device entry\n")); 635 di_devfs_path_free(devpath); 636 return (rv); 637 } 638 639 /* calloc enough for /devices + devpath + ":devctl" + '\0' */ 640 devlength = strlen(devpath) + strlen(devprefix) + 641 strlen(devsuffix) + 2; 642 643 if ((newdev->access_devname = calloc(1, devlength)) == NULL) { 644 logmsg(MSG_ERROR, gettext("Unable to calloc space " 645 "for a devfs name\n")); 646 di_devfs_path_free(devpath); 647 (void) free(newdev); 648 return (FWFLASH_FAILURE); 649 } 650 snprintf(newdev->access_devname, devlength, 651 "%s%s%s", devprefix, devpath, devsuffix); 652 653 /* CHECK VARIOUS IB THINGS HERE */ 654 655 if ((newdev->ident = calloc(1, sizeof (struct vpr))) == NULL) { 656 logmsg(MSG_ERROR, 657 gettext("tavor: Unable to allocate space for a " 658 "device identification record\n")); 659 (void) free(newdev->access_devname); 660 (void) free(newdev); 661 di_devfs_path_free(devpath); 662 return (FWFLASH_FAILURE); 663 } 664 665 rv = tavor_identify(newdev); 666 if (rv == FWFLASH_FAILURE) { 667 (void) free(newdev->ident); 668 (void) free(newdev->access_devname); 669 (void) free(newdev); 670 di_devfs_path_free(devpath); 671 continue; 672 } 673 674 if ((newdev->drvname = calloc(1, strlen(drivername) + 1)) 675 == NULL) { 676 logmsg(MSG_ERROR, gettext("Unable to allocate space " 677 "for a driver name\n")); 678 (void) free(newdev->ident); 679 (void) free(newdev->access_devname); 680 (void) free(newdev); 681 di_devfs_path_free(devpath); 682 return (FWFLASH_FAILURE); 683 } 684 685 (void) strlcpy(newdev->drvname, drivername, 686 strlen(drivername) + 1); 687 688 /* this next bit is backwards compatibility - "IB\0" */ 689 if ((newdev->classname = calloc(1, 3)) == NULL) { 690 logmsg(MSG_ERROR, gettext("Unable to allocate space " 691 "for a class name\n")); 692 (void) free(newdev->drvname); 693 (void) free(newdev->ident); 694 (void) free(newdev->access_devname); 695 (void) free(newdev); 696 di_devfs_path_free(devpath); 697 return (FWFLASH_FAILURE); 698 } 699 (void) strlcpy(newdev->classname, "IB", 3); 700 701 newdev->index = idx; 702 ++idx; 703 newdev->plugin = self; 704 705 di_devfs_path_free(devpath); 706 TAILQ_INSERT_TAIL(fw_devices, newdev, nextdev); 707 } 708 709 if (fwflash_debug != 0) { 710 struct devicelist *tempdev; 711 712 TAILQ_FOREACH(tempdev, fw_devices, nextdev) { 713 logmsg(MSG_INFO, "fw_identify:\n"); 714 logmsg(MSG_INFO, "\ttempdev @ 0x%lx\n" 715 "\t\taccess_devname: %s\n" 716 "\t\tdrvname: %s\tclassname: %s\n" 717 "\t\tident->vid: %s\n" 718 "\t\tident->pid: %s\n" 719 "\t\tident->revid: %s\n" 720 "\t\tindex: %d\n" 721 "\t\tguid0: %s\n" 722 "\t\tguid1: %s\n" 723 "\t\tguid2: %s\n" 724 "\t\tguid3: %s\n" 725 "\t\tplugin @ 0x%lx\n\n", 726 &tempdev, 727 tempdev->access_devname, 728 tempdev->drvname, newdev->classname, 729 tempdev->ident->vid, 730 tempdev->ident->pid, 731 tempdev->ident->revid, 732 tempdev->index, 733 (tempdev->addresses[0] ? tempdev->addresses[0] : 734 "(not supported)"), 735 (tempdev->addresses[1] ? tempdev->addresses[1] : 736 "(not supported)"), 737 (tempdev->addresses[2] ? tempdev->addresses[2] : 738 "(not supported)"), 739 (tempdev->addresses[3] ? tempdev->addresses[3] : 740 "(not supported)"), 741 tempdev->plugin); 742 } 743 } 744 745 return (FWFLASH_SUCCESS); 746 } 747 748 749 750 int 751 fw_devinfo(struct devicelist *thisdev) 752 { 753 754 struct ib_encap_ident *encap; 755 756 757 encap = (struct ib_encap_ident *)thisdev->ident->encap_ident; 758 759 fprintf(stdout, gettext("Device[%d] %s\n Class [%s]\n"), 760 thisdev->index, thisdev->access_devname, thisdev->classname); 761 762 fprintf(stdout, "\t"); 763 764 /* Mellanox HCA Flash app note, p40, #4.2.3 table 9 */ 765 fprintf(stdout, 766 gettext("GUID: System Image - %s\n"), 767 thisdev->addresses[3]); 768 fprintf(stdout, 769 gettext("\t\tNode Image - %s\n"), 770 thisdev->addresses[0]); 771 fprintf(stdout, 772 gettext("\t\tPort 1\t - %s\n"), 773 thisdev->addresses[1]); 774 fprintf(stdout, 775 gettext("\t\tPort 2\t - %s\n"), 776 thisdev->addresses[2]); 777 778 if (encap->pn_len != 0) { 779 fprintf(stdout, 780 gettext("\tFirmware revision : %s\n" 781 "\tProduct\t\t: %s %X\n" 782 "\tPSID\t\t: %s\n"), 783 thisdev->ident->revid, 784 encap->info.mlx_pn, 785 encap->hwrev, 786 encap->info.mlx_psid); 787 } else { 788 fprintf(stdout, 789 gettext("\tFirmware revision : %s\n" 790 "\tNo hardware information available for this " 791 "device\n"), thisdev->ident->revid); 792 } 793 fprintf(stdout, "\n\n"); 794 795 return (tavor_close(thisdev)); 796 } 797 798 799 /* 800 * Helper functions lurk beneath this point 801 */ 802 803 804 /* 805 * tavor_identify performs the following actions: 806 * 807 * allocates and assigns thisdev->vpr 808 * 809 * allocates space for the 4 GUIDs which each IB device must have 810 * queries the tavor driver for this device's GUIDs 811 * 812 * determines the hardware vendor, so that thisdev->vpr->vid 813 * can be set correctly 814 */ 815 static int 816 tavor_identify(struct devicelist *thisdev) 817 { 818 int rv = FWFLASH_SUCCESS; 819 int fd, ret, i; 820 821 tavor_flash_init_ioctl_t init_ioctl; 822 tavor_flash_ioctl_t info; 823 struct ib_encap_ident *manuf; 824 cfi_t cfi; 825 char temppsid[17]; 826 char rawpsid[16]; 827 828 #if defined(_LITTLE_ENDIAN) 829 uint32_t *ptr; 830 #endif 831 832 /* open the device */ 833 /* hook thisdev->ident->encap_ident to ib_encap_ident */ 834 /* check that all the bits are sane */ 835 /* return success, if warranted */ 836 837 errno = 0; 838 if ((fd = open(thisdev->access_devname, O_RDONLY)) < 0) { 839 logmsg(MSG_INFO, 840 gettext("tavor: Unable to open a %s-attached " 841 "device node: %s: %s\n"), drivername, 842 thisdev->access_devname, strerror(errno)); 843 return (FWFLASH_FAILURE); 844 } 845 846 if ((manuf = calloc(1, sizeof (ib_encap_ident_t))) == NULL) { 847 logmsg(MSG_ERROR, 848 gettext("tavor: Unable to calloc space for a " 849 "%s-attached handle structure\n"), 850 drivername); 851 return (FWFLASH_FAILURE); 852 } 853 manuf->magic = FWFLASH_IB_MAGIC_NUMBER; 854 manuf->state = FWFLASH_IB_STATE_NONE; 855 manuf->fd = fd; 856 857 thisdev->ident->encap_ident = manuf; 858 859 bzero(&init_ioctl, sizeof (tavor_flash_init_ioctl_t)); 860 bzero(&cfi, sizeof (cfi_t)); 861 /* 862 * Inform driver that this command supports the Intel Extended 863 * CFI command set. 864 */ 865 cfi.cfi_char[0x10] = 'M'; 866 cfi.cfi_char[0x11] = 'X'; 867 cfi.cfi_char[0x12] = '2'; 868 init_ioctl.tf_cfi_info[0x4] = MLXSWAPBITS32(cfi.cfi_int[0x4]); 869 870 errno = 0; 871 ret = ioctl(fd, TAVOR_IOCTL_FLASH_INIT, &init_ioctl); 872 if (ret < 0) { 873 logmsg(MSG_ERROR, 874 gettext("ib: TAVOR_IOCTL_FLASH_INIT failed: %s\n"), 875 strerror(errno)); 876 free(manuf); 877 close(fd); 878 return (FWFLASH_FAILURE); 879 } 880 881 manuf->hwrev = init_ioctl.tf_hwrev; 882 883 logmsg(MSG_INFO, "tavor_identify: init_ioctl: hwrev: %X, " 884 "fwver: %d.%d.%04d\n", init_ioctl.tf_hwrev, 885 init_ioctl.tf_fwrev.tfi_maj, init_ioctl.tf_fwrev.tfi_min, 886 init_ioctl.tf_fwrev.tfi_sub); 887 888 /* 889 * Determine whether the attached driver supports the Intel or 890 * AMD Extended CFI command sets. If it doesn't support either, 891 * then we're hosed, so error out. 892 */ 893 for (i = 0; i < TAVOR_FLASH_CFI_SIZE_QUADLET; i++) { 894 cfi.cfi_int[i] = MLXSWAPBITS32(init_ioctl.tf_cfi_info[i]); 895 } 896 manuf->cmd_set = cfi.cfi_char[0x13]; 897 898 if (cfi.cfi_char[0x10] == 'Q' && 899 cfi.cfi_char[0x11] == 'R' && 900 cfi.cfi_char[0x12] == 'Y') { 901 /* make sure the cmd set is AMD */ 902 if (manuf->cmd_set != TAVOR_FLASH_AMD_CMDSET) { 903 logmsg(MSG_ERROR, 904 gettext("tavor: Unsupported flash device " 905 "command set\n")); 906 free(manuf); 907 close(fd); 908 return (FWFLASH_FAILURE); 909 } 910 /* set some defaults */ 911 manuf->sector_sz = TAVOR_FLASH_SECTOR_SZ_DEFAULT; 912 manuf->device_sz = TAVOR_FLASH_DEVICE_SZ_DEFAULT; 913 logmsg(MSG_INFO, "tavor_identify: CMDSET is AMD, SectorSz " 914 "are default \n"); 915 } else { 916 if (manuf->cmd_set != TAVOR_FLASH_AMD_CMDSET && 917 manuf->cmd_set != TAVOR_FLASH_INTEL_CMDSET) { 918 logmsg(MSG_ERROR, 919 gettext("ib: Unknown flash device command set\n")); 920 free(manuf); 921 close(fd); 922 return (FWFLASH_FAILURE); 923 } 924 /* read from the CFI data */ 925 manuf->sector_sz = ((cfi.cfi_char[0x30] << 8) | 926 cfi.cfi_char[0x2F]) << 8; 927 manuf->device_sz = 0x1 << cfi.cfi_char[0x27]; 928 logmsg(MSG_INFO, "tavor_identify: SectorSz is from CFI Data\n"); 929 } 930 931 logmsg(MSG_INFO, "tavor_identify: sector_sz: 0x%08x dev_sz: 0x%08x\n", 932 manuf->sector_sz, manuf->device_sz); 933 934 manuf->state |= FWFLASH_IB_STATE_MMAP; 935 936 /* set firmware revision */ 937 manuf->fw_rev.major = init_ioctl.tf_fwrev.tfi_maj; 938 manuf->fw_rev.minor = init_ioctl.tf_fwrev.tfi_min; 939 manuf->fw_rev.subminor = init_ioctl.tf_fwrev.tfi_sub; 940 941 logmsg(MSG_INFO, "tavor_identify: pn_len %d hwpn %s \n", 942 init_ioctl.tf_pn_len, 943 (init_ioctl.tf_pn_len != 0) ? init_ioctl.tf_hwpn : "(null)"); 944 945 if (((thisdev->ident->vid = calloc(1, MLX_VPR_VIDLEN + 1)) == NULL) || 946 ((thisdev->ident->revid = calloc(1, MLX_VPR_REVLEN + 1)) == NULL)) { 947 948 logmsg(MSG_ERROR, 949 gettext("ib: Unable to allocate space for a VPR " 950 "record.\n")); 951 free(thisdev->ident); 952 free(manuf->info.mlx_pn); 953 free(manuf->info.mlx_psid); 954 free(manuf->info.mlx_id); 955 free(manuf); 956 close(fd); 957 return (FWFLASH_FAILURE); 958 } 959 (void) strlcpy(thisdev->ident->vid, "MELLANOX", MLX_VPR_VIDLEN); 960 /* 961 * We actually want the hwrev field from the ioctl above. 962 * Until we find out otherwise, add it onto the end of the 963 * firmware version details. 964 */ 965 966 snprintf(thisdev->ident->revid, MLX_VPR_REVLEN, "%d.%d.%03d", 967 manuf->fw_rev.major, manuf->fw_rev.minor, 968 manuf->fw_rev.subminor); 969 970 bzero(manuf->ibguids, sizeof (manuf->ibguids)); 971 972 /* 973 * For convenience we read in the Invariant Sector as 974 * well as both the Primary and Secondary Pointer Sectors 975 */ 976 977 if ((manuf->inv = calloc(1, manuf->sector_sz)) == NULL) { 978 logmsg(MSG_ERROR, 979 gettext("tavor: Unable to allocate space for storing " 980 "the HCA's Invariant Sector\n")); 981 return (FWFLASH_FAILURE); 982 } 983 bzero(&info, sizeof (tavor_flash_ioctl_t)); 984 985 info.tf_type = TAVOR_FLASH_READ_SECTOR; 986 info.tf_sector = (caddr_t)manuf->inv; 987 info.tf_sector_num = 0; 988 989 errno = 0; 990 991 if ((rv = ioctl(manuf->fd, TAVOR_IOCTL_FLASH_READ, &info)) 992 < 0) { 993 logmsg(MSG_ERROR, 994 gettext("tavor: Unable to read HCA Invariant Sector\n")); 995 return (FWFLASH_FAILURE); 996 } 997 998 #if defined(_LITTLE_ENDIAN) 999 ptr = (uint32_t *)(uintptr_t)manuf->inv; 1000 for (i = 0; i < (manuf->sector_sz / 4); i++) { 1001 ptr[i] = htonl(ptr[i]); 1002 } 1003 #endif 1004 1005 if ((manuf->pps = calloc(1, manuf->sector_sz)) == NULL) { 1006 logmsg(MSG_ERROR, 1007 gettext("tavor: Unable to allocate space for storing " 1008 "the HCA's Primary Pointer Sector\n")); 1009 return (FWFLASH_FAILURE); 1010 } 1011 bzero(&info, sizeof (tavor_flash_ioctl_t)); 1012 1013 info.tf_type = TAVOR_FLASH_READ_SECTOR; 1014 info.tf_sector = (caddr_t)manuf->pps; 1015 info.tf_sector_num = 1; 1016 1017 errno = 0; 1018 1019 if ((rv = ioctl(manuf->fd, TAVOR_IOCTL_FLASH_READ, &info)) 1020 < 0) { 1021 logmsg(MSG_ERROR, 1022 gettext("tavor: Unable to read HCA Primary " 1023 "Pointer Sector\n")); 1024 return (FWFLASH_FAILURE); 1025 } 1026 1027 #if defined(_LITTLE_ENDIAN) 1028 ptr = (uint32_t *)(uintptr_t)manuf->pps; 1029 for (i = 0; i < (manuf->sector_sz / 4); i++) { 1030 ptr[i] = htonl(ptr[i]); 1031 } 1032 #endif 1033 1034 if ((manuf->sps = calloc(1, manuf->sector_sz)) == NULL) { 1035 logmsg(MSG_ERROR, 1036 gettext("tavor: Unable to allocate space for storing " 1037 "the HCA's Secondary Pointer Sector\n")); 1038 return (FWFLASH_FAILURE); 1039 } 1040 bzero(&info, sizeof (tavor_flash_ioctl_t)); 1041 1042 info.tf_type = TAVOR_FLASH_READ_SECTOR; 1043 info.tf_sector = (caddr_t)manuf->sps; 1044 info.tf_sector_num = 2; 1045 1046 errno = 0; 1047 1048 if ((rv = ioctl(manuf->fd, TAVOR_IOCTL_FLASH_READ, &info)) 1049 < 0) { 1050 logmsg(MSG_ERROR, 1051 gettext("tavor: Unable to read HCA Secondary " 1052 "Pointer Sector\n")); 1053 return (FWFLASH_FAILURE); 1054 } 1055 1056 #if defined(_LITTLE_ENDIAN) 1057 ptr = (uint32_t *)(uintptr_t)manuf->sps; 1058 for (i = 0; i < (manuf->sector_sz / 4); i++) { 1059 ptr[i] = htonl(ptr[i]); 1060 } 1061 #endif 1062 1063 if ((ret = tavor_get_guids(manuf)) != FWFLASH_SUCCESS) { 1064 logmsg(MSG_INFO, 1065 gettext("ib: No guids found for device %s!\n"), 1066 thisdev->access_devname); 1067 } 1068 1069 /* set hw part number, psid, and name in handle */ 1070 bzero(temppsid, 17); 1071 bcopy(manuf->pps+FLASH_PS_PSID_OFFSET, &rawpsid, 16); 1072 1073 for (i = 0; i < 16; i += 4) { 1074 temppsid[i] = rawpsid[i+3]; 1075 temppsid[i+1] = rawpsid[i+2]; 1076 temppsid[i+2] = rawpsid[i+1]; 1077 temppsid[i+3] = rawpsid[i]; 1078 } 1079 logmsg(MSG_INFO, 1080 "tavor: have raw '%s', want munged '%s'\n", 1081 rawpsid, temppsid); 1082 1083 /* now walk the magic decoder ring table */ 1084 manuf->info.mlx_pn = NULL; 1085 manuf->info.mlx_psid = NULL; 1086 manuf->info.mlx_id = NULL; 1087 manuf->pn_len = 0; 1088 1089 for (i = 0; i < MLX_MAX_ID; i++) { 1090 if ((strncmp(temppsid, mlx_mdr[i].mlx_psid, 1091 MLX_PSID_SZ)) == 0) { 1092 /* matched */ 1093 if ((manuf->info.mlx_pn = calloc(1, 1094 strlen(mlx_mdr[i].mlx_pn) + 1)) == NULL) { 1095 logmsg(MSG_INFO, 1096 "tavor: no space available for the " 1097 "HCA PSID record (1)\n"); 1098 } else { 1099 (void) strlcpy(manuf->info.mlx_pn, 1100 mlx_mdr[i].mlx_pn, 1101 strlen(mlx_mdr[i].mlx_pn) + 1); 1102 manuf->pn_len = strlen(mlx_mdr[i].mlx_pn); 1103 } 1104 1105 if ((manuf->info.mlx_psid = calloc(1, 1106 strlen(mlx_mdr[i].mlx_psid) + 1)) == NULL) { 1107 logmsg(MSG_INFO, 1108 "tavor: no space available for the " 1109 "HCA PSID record (2)\n"); 1110 } else { 1111 (void) strlcpy(manuf->info.mlx_psid, 1112 mlx_mdr[i].mlx_psid, 1113 strlen(mlx_mdr[i].mlx_psid) + 1); 1114 } 1115 if ((manuf->info.mlx_id = calloc(1, 1116 strlen(mlx_mdr[i].mlx_id) + 1)) == NULL) { 1117 logmsg(MSG_INFO, 1118 "tavor: no space available for the " 1119 "HCA PSID record (3)\n"); 1120 } else { 1121 (void) strlcpy(manuf->info.mlx_id, 1122 mlx_mdr[i].mlx_id, 1123 strlen(mlx_mdr[i].mlx_id) + 1); 1124 } 1125 } 1126 } 1127 if ((manuf->pn_len == 0) || (i == MLX_MAX_ID)) { 1128 logmsg(MSG_INFO, 1129 "tavor: No hardware part number information available " 1130 "for this HCA\n"); 1131 /* Until we deliver the arbel driver, it's all Mellanox */ 1132 i = strlen("No hardware information available for this device"); 1133 1134 thisdev->ident->pid = calloc(1, i + 2); 1135 sprintf(thisdev->ident->pid, "No hardware information " 1136 "available for this device"); 1137 } else { 1138 if ((thisdev->ident->pid = calloc(1, 1139 strlen(manuf->info.mlx_psid) + 1)) != NULL) { 1140 (void) strlcpy(thisdev->ident->pid, 1141 manuf->info.mlx_psid, 1142 strlen(manuf->info.mlx_psid) + 1); 1143 } else { 1144 logmsg(MSG_ERROR, 1145 gettext("ib: Unable to allocate space for a " 1146 "hardware identifier\n")); 1147 free(thisdev->ident); 1148 free(manuf->info.mlx_pn); 1149 free(manuf->info.mlx_psid); 1150 free(manuf->info.mlx_id); 1151 free(manuf); 1152 close(fd); 1153 return (FWFLASH_FAILURE); 1154 } 1155 } 1156 1157 for (i = 0; i < 4; i++) { 1158 if ((thisdev->addresses[i] = calloc(1, 1159 (2 * sizeof (uint64_t)) + 1)) == NULL) { 1160 logmsg(MSG_ERROR, 1161 gettext("tavor: Unable to allocate space for a " 1162 "human-readable HCA guid\n")); 1163 return (FWFLASH_FAILURE); 1164 } 1165 (void) sprintf(thisdev->addresses[i], "%016llx", 1166 manuf->ibguids[i]); 1167 } 1168 1169 /* 1170 * We do NOT close the fd here, since we can close it 1171 * at the end of the fw_readfw() or fw_writefw() functions 1172 * instead and not get the poor dear confused about whether 1173 * it's been inited already. 1174 */ 1175 1176 return (rv); 1177 } 1178 1179 /*ARGSUSED*/ 1180 static int 1181 tavor_get_guids(struct ib_encap_ident *handle) 1182 { 1183 int rv, j; 1184 uint32_t i = 0x00; 1185 tavor_flash_ioctl_t info; 1186 struct mlx_guid_sect *p, *s; 1187 1188 #if defined(_LITTLE_ENDIAN) 1189 uint32_t *ptr, tmp; 1190 #endif 1191 1192 /* 1193 * The reference for this function is the 1194 * Mellanox HCA Flash Programming Application Note 1195 * rev 1.44, 2007. Chapter 4 in particular. 1196 * 1197 * NOTE: this Mellanox document is labelled Confidential 1198 * so DO NOT move this file out of usr/closed without 1199 * explicit approval from Sun Legal. 1200 */ 1201 1202 /* 1203 * We need to check for both the Primary and Secondary 1204 * Image GUIDs. handle->pps and handle->sps should be 1205 * non-NULL by the time we're called, since we depend 1206 * on them being stashed in handle. Saves on an ioctl(). 1207 */ 1208 1209 /* make sure we've got our fallback position organised */ 1210 for (i = 0; i < 4; i++) { 1211 handle->ibguids[i] = 0x00000000; 1212 } 1213 1214 /* convenience .... */ 1215 1216 if ((p = calloc(1, sizeof (mlx_guid_sect_t))) == NULL) { 1217 logmsg(MSG_ERROR, 1218 gettext("tavor: Unable to allocate space for " 1219 "HCA guid record (1)\n")); 1220 return (FWFLASH_FAILURE); 1221 } 1222 if ((s = calloc(1, sizeof (mlx_guid_sect_t))) == NULL) { 1223 logmsg(MSG_ERROR, 1224 gettext("tavor: Unable to allocate space for " 1225 "HCA guid record (2)\n")); 1226 free(p); 1227 return (FWFLASH_FAILURE); 1228 } 1229 1230 bcopy(&handle->pps[0], &i, 4); 1231 handle->pfi_guid_addr = MLXSWAPBITS32(i) + FLASH_GUID_PTR; 1232 bcopy(&handle->sps[0], &i, 4); 1233 handle->sfi_guid_addr = MLXSWAPBITS32(i) + FLASH_GUID_PTR; 1234 1235 bzero(&info, sizeof (tavor_flash_ioctl_t)); 1236 info.tf_type = TAVOR_FLASH_READ_QUADLET; 1237 info.tf_addr = handle->pfi_guid_addr; 1238 1239 errno = 0; 1240 1241 rv = ioctl(handle->fd, TAVOR_IOCTL_FLASH_READ, &info); 1242 if (rv < 0) { 1243 logmsg(MSG_ERROR, 1244 gettext("tavor: Unable to read Primary Image " 1245 "guid offset\n")); 1246 free(p); 1247 free(s); 1248 return (FWFLASH_FAILURE); 1249 } 1250 1251 /* 1252 * This is because we want the whole of the section 1253 * including the 16 reserved bytes at the front so 1254 * that if we recalculate the CRC we've got the correct 1255 * data to do it with 1256 */ 1257 info.tf_addr = handle->pfi_guid_addr + info.tf_quadlet 1258 - FLASH_GUID_PTR - 16; 1259 1260 bzero(handle->pri_guid_section, sizeof (mlx_guid_sect_t)); 1261 1262 for (j = 0; j < 13; j++) { 1263 errno = 0; 1264 if ((rv = ioctl(handle->fd, TAVOR_IOCTL_FLASH_READ, 1265 &info)) < 0) { 1266 logmsg(MSG_ERROR, 1267 gettext("tavor: Unable to read Primary Image " 1268 "guid chunk %d\n"), j); 1269 } 1270 handle->pri_guid_section[j] = info.tf_quadlet; 1271 info.tf_addr += 4; 1272 } 1273 bcopy(&handle->pri_guid_section, p, sizeof (struct mlx_guid_sect)); 1274 1275 /* now grab the secondary guid set */ 1276 bzero(&info, sizeof (tavor_flash_ioctl_t)); 1277 info.tf_type = TAVOR_FLASH_READ_QUADLET; 1278 info.tf_addr = handle->sfi_guid_addr; 1279 1280 errno = 0; 1281 1282 if ((rv = ioctl(handle->fd, TAVOR_IOCTL_FLASH_READ, 1283 &info)) < 0) { 1284 logmsg(MSG_ERROR, 1285 gettext("tavor: Unable to read Secondary Image " 1286 "guid offset (%s)\n"), strerror(errno)); 1287 free(p); 1288 free(s); 1289 return (FWFLASH_FAILURE); 1290 } 1291 1292 info.tf_addr = handle->sfi_guid_addr + info.tf_quadlet 1293 - FLASH_GUID_PTR - 16; 1294 1295 bzero(handle->sec_guid_section, sizeof (mlx_guid_sect_t)); 1296 1297 for (j = 0; j < 13; j++) { 1298 errno = 0; 1299 if ((rv = ioctl(handle->fd, TAVOR_IOCTL_FLASH_READ, 1300 &info)) < 0) { 1301 logmsg(MSG_ERROR, 1302 gettext("tavor: Unable to read Secondary Image " 1303 "guid chunk %d (%s)\n"), j, strerror(errno)); 1304 return (FWFLASH_FAILURE); 1305 } 1306 handle->sec_guid_section[j] = info.tf_quadlet; 1307 info.tf_addr += 4; 1308 } 1309 1310 bcopy(&handle->sec_guid_section, s, sizeof (struct mlx_guid_sect)); 1311 1312 #if defined(_LITTLE_ENDIAN) 1313 1314 /* 1315 * We don't actually care about p or s later on if we 1316 * write to the HCA - we've already stored the binary 1317 * form in handle->pri_guid_section and handle->sec_guid_section. 1318 * What we're doing here is creating human-readable forms. 1319 */ 1320 1321 ptr = (uint32_t *)(uintptr_t)p; 1322 for (j = 0; j < 14; j += 2) { 1323 tmp = ptr[j]; 1324 ptr[j] = ptr[j+1]; 1325 ptr[j+1] = tmp; 1326 } 1327 1328 ptr = (uint32_t *)(uintptr_t)s; 1329 for (j = 0; j < 14; j += 2) { 1330 tmp = ptr[j]; 1331 ptr[j] = ptr[j+1]; 1332 ptr[j+1] = tmp; 1333 } 1334 #endif 1335 1336 /* 1337 * We don't check and munge the GUIDs to the manufacturer's 1338 * defaults, because if the GUIDs are actually set incorrectly 1339 * at identify time, we really need to know that. 1340 * 1341 * If the GUIDs are bogus, then we'll fix that in fw_writefw() 1342 * by blatting the manufacturer's defaults from the firmware 1343 * image file instead. 1344 */ 1345 if ((p->nodeguid == s->nodeguid) && 1346 (p->port1guid == s->port1guid) && 1347 (p->port2guid == s->port2guid) && 1348 (p->sysimguid == s->sysimguid)) { 1349 logmsg(MSG_INFO, 1350 "tavor: primary and secondary guids are the same\n"); 1351 handle->ibguids[0] = p->nodeguid; 1352 handle->ibguids[1] = p->port1guid; 1353 handle->ibguids[2] = p->port2guid; 1354 handle->ibguids[3] = p->sysimguid; 1355 } else { 1356 /* 1357 * We're going to assume that the guids which are numerically 1358 * larger than the others are correct and copy them to 1359 * handle->ibguids. 1360 * 1361 * For those in the know wrt InfiniBand, if this assumption 1362 * is incorrect, _please_ bug this and fix it, adding a 1363 * comment or two to indicate why 1364 */ 1365 logmsg(MSG_INFO, 1366 "tavor: primary and secondary guids don't all match\n"); 1367 1368 if (s->nodeguid > p->nodeguid) { 1369 handle->ibguids[0] = s->nodeguid; 1370 handle->ibguids[1] = s->port1guid; 1371 handle->ibguids[2] = s->port2guid; 1372 handle->ibguids[3] = s->sysimguid; 1373 bzero(p, sizeof (struct mlx_guid_sect)); 1374 } else { 1375 handle->ibguids[0] = p->nodeguid; 1376 handle->ibguids[1] = p->port1guid; 1377 handle->ibguids[2] = p->port2guid; 1378 handle->ibguids[3] = p->sysimguid; 1379 bzero(s, sizeof (struct mlx_guid_sect)); 1380 } 1381 } 1382 1383 free(p); 1384 free(s); 1385 1386 if (fwflash_debug) { 1387 for (i = 0; i < 4; i++) { 1388 logmsg(MSG_INFO, "ibguids[%d] %0llx\n", i, 1389 handle->ibguids[i]); 1390 } 1391 } 1392 1393 return (FWFLASH_SUCCESS); 1394 } 1395 1396 1397 int 1398 tavor_close(struct devicelist *flashdev) 1399 { 1400 1401 struct ib_encap_ident *handle; 1402 1403 handle = (struct ib_encap_ident *)flashdev->ident->encap_ident; 1404 if (handle->fd > 0) { 1405 (void) ioctl(handle->fd, TAVOR_IOCTL_FLASH_FINI); 1406 errno = 0; 1407 if (close(handle->fd) != 0) { 1408 logmsg(MSG_ERROR, 1409 gettext("tavor: Unable to properly close " 1410 "device %s! (%s)\n"), 1411 flashdev->access_devname, 1412 strerror(errno)); 1413 return (FWFLASH_FAILURE); 1414 } 1415 return (FWFLASH_SUCCESS); 1416 } else 1417 return (FWFLASH_FAILURE); 1418 } 1419 1420 1421 /* 1422 * We would not need this if it were not for Cisco's image using the 1423 * VSD to store boot options and flags for their PXE boot extension, 1424 * but not setting the proper default values for the extension in 1425 * their image. As it turns out, some of the data for the extension 1426 * is stored in the VSD in the firmware file, and the rest is set by 1427 * their firmware utility. That's not very nice for us, since it could 1428 * change at any time without our knowledge. Well, for the time being, 1429 * we can use this to examine and fix up anything in the VSD that we might 1430 * need to handle, for any vendor specific settings. 1431 */ 1432 static void 1433 tavor_cisco_extensions(mlx_xps_t *hcaxps, mlx_xps_t *diskxps) 1434 { 1435 uint16_t sig1, sig2; 1436 uint32_t i; 1437 1438 1439 bcopy(hcaxps->vsdpsid, &i, 4); 1440 sig1 = htonl(i); 1441 bcopy(&hcaxps->vsdpsid[223], &i, 4); 1442 sig2 = htonl(i); 1443 1444 1445 if (sig1 == FLASH_VSD_CISCO_SIGNATURE && 1446 sig2 == FLASH_VSD_CISCO_SIGNATURE) { 1447 logmsg(MSG_INFO, 1448 "tavor: CISCO signature found in HCA's VSD, copying to " 1449 "new image's VSD\n"); 1450 1451 i = htonl(FLASH_VSD_CISCO_SIGNATURE); 1452 bcopy(&i, diskxps->vsdpsid, 2); 1453 1454 /* 1455 * Set the boot_version field to '2'. This value is 1456 * located in the 2nd byte of the last uint32_t. 1457 * Per the previous version of fwflash, we just or 1458 * the bit in and get on with it. 1459 */ 1460 1461 i = (diskxps->vsdpsid[222] | FLASH_VSD_CISCO_BOOT_VERSION); 1462 bcopy(&i, &diskxps->vsdpsid[222], 2); 1463 /* 1464 * Now set some defaults for the SRP boot extension, 1465 * currently the only extension we support. These flags 1466 * are located in the second uint32_t of the VSD. 1467 */ 1468 1469 logmsg(MSG_INFO, "tavor: CISCO boot flags currently set " 1470 "to 0x%08x\n", 1471 diskxps->vsdpsid[1]); 1472 1473 diskxps->vsdpsid[1] = 1474 htonl(diskxps->vsdpsid[1] | 1475 FLASH_VSD_CISCO_FLAG_AUTOUPGRADE | 1476 FLASH_VSD_CISCO_BOOT_OPTIONS | 1477 FLASH_VSD_CISCO_FLAG_BOOT_ENABLE_PORT_1 | 1478 FLASH_VSD_CISCO_FLAG_BOOT_ENABLE_PORT_2 | 1479 FLASH_VSD_CISCO_FLAG_BOOT_ENABLE_SCAN | 1480 FLASH_VSD_CISCO_FLAG_BOOT_TYPE_WELL_KNOWN | 1481 FLASH_VSD_CISCO_FLAG_BOOT_TRY_FOREVER); 1482 1483 logmsg(MSG_INFO, "tavor: CISCO boot flags now set " 1484 "to 0x%08x\n", 1485 diskxps->vsdpsid[1]); 1486 } else 1487 logmsg(MSG_INFO, 1488 "tavor: CISCO signature not found in HCA's VSD\n"); 1489 } 1490 1491 1492 static int 1493 tavor_write_sector(int fd, int sectnum, int32_t *data) 1494 { 1495 int rv, i; 1496 tavor_flash_ioctl_t cmd; 1497 1498 1499 bzero(&cmd, sizeof (tavor_flash_ioctl_t)); 1500 1501 cmd.tf_type = TAVOR_FLASH_WRITE_SECTOR; 1502 cmd.tf_sector_num = sectnum; 1503 cmd.tf_sector = (caddr_t)data; 1504 1505 errno = 0; 1506 1507 logmsg(MSG_INFO, 1508 "tavor: tavor_write_sector(fd %d, sectnum 0x%x, data 0x%lx)\n", 1509 fd, sectnum, data); 1510 logmsg(MSG_INFO, 1511 "tavor:\n" 1512 "\tcmd.tf_type %d\n" 1513 "\tcmd.tf_sector 0x%lx\n" 1514 "\tcmd.tf_sector_num %d\n", 1515 cmd.tf_type, data, cmd.tf_sector_num); 1516 1517 /* 1518 * If we're debugging, dump the first 64 uint32_t that we've 1519 * been passed 1520 */ 1521 if (fwflash_debug > 0) { 1522 i = 0; 1523 while (i < 64) { 1524 logmsg(MSG_INFO, 1525 "%02x: %08x %08x %08x %08x\n", 1526 i, data[i], data[i+1], 1527 data[i+2], data[i+3]); 1528 i += 4; 1529 } 1530 } 1531 1532 rv = ioctl(fd, TAVOR_IOCTL_FLASH_WRITE, &cmd); 1533 if (rv < 0) { 1534 logmsg(MSG_ERROR, 1535 gettext("tavor: WRITE SECTOR failed for sector " 1536 "%d: %s\n"), 1537 sectnum, strerror(errno)); 1538 return (FWFLASH_FAILURE); 1539 } else 1540 return (FWFLASH_SUCCESS); 1541 } 1542 1543 /* 1544 * Write zeros to the on-HCA signature and CRC16 fields of sector. 1545 * 1546 * NOTE we do _not_ divide start by 4 because we're talking to the 1547 * HCA, and not finding an offset into verifier->fwimage. 1548 */ 1549 1550 static int 1551 tavor_zero_sig_crc(int fd, uint32_t start) 1552 { 1553 int i, rv; 1554 tavor_flash_ioctl_t cmd; 1555 1556 /* signature first, then CRC16 */ 1557 bzero(&cmd, sizeof (tavor_flash_ioctl_t)); 1558 cmd.tf_type = TAVOR_FLASH_WRITE_BYTE; 1559 cmd.tf_byte = 0x00; 1560 1561 logmsg(MSG_INFO, 1562 "tavor: tavor_zero_sig_crc(fd %d, start 0x%04x)\n", 1563 fd, start); 1564 1565 for (i = 0; i < 4; i++) { 1566 cmd.tf_addr = start + FLASH_PS_SIGNATURE_OFFSET + i; 1567 1568 logmsg(MSG_INFO, 1569 "tavor: invalidating xPS sig (offset from IS 0x%04x) " 1570 "byte %d\n", 1571 cmd.tf_addr, i); 1572 errno = 0; 1573 1574 rv = ioctl(fd, TAVOR_IOCTL_FLASH_WRITE, &cmd); 1575 if (rv < 0) { 1576 logmsg(MSG_INFO, 1577 gettext("tavor: Unable to write 0x00 to " 1578 "offset 0x%04x from IS (sig byte %d): %s\n"), 1579 cmd.tf_addr, i, strerror(errno)); 1580 return (FWFLASH_FAILURE); 1581 } 1582 } 1583 1584 cmd.tf_byte = 0x00; 1585 for (i = 0; i < 2; i++) { 1586 cmd.tf_addr = start + FLASH_PS_CRC16_OFFSET + i; 1587 1588 logmsg(MSG_INFO, 1589 "tavor: invalidating xPS CRC16 (offset from IS 0x%04x) " 1590 "byte %d\n", 1591 cmd.tf_addr, i); 1592 errno = 0; 1593 1594 rv = ioctl(fd, TAVOR_IOCTL_FLASH_WRITE, &cmd); 1595 if (rv < 0) { 1596 logmsg(MSG_INFO, 1597 gettext("tavor: Unable to write 0x00 to " 1598 "offset 0x%04x from IS (CRC16 byte %d): %s\n"), 1599 cmd.tf_addr, i, strerror(errno)); 1600 return (FWFLASH_FAILURE); 1601 } 1602 } 1603 return (FWFLASH_SUCCESS); 1604 } 1605 1606 1607 /* 1608 * Write a new FIA for the given xPS. The _caller_ handles 1609 * any required byte-swapping for us. 1610 * 1611 * NOTE we do _not_ divide start by 4 because we're talking to the 1612 * HCA, and not finding an offset into verifier->fwimage. 1613 */ 1614 static int 1615 tavor_write_xps_fia(int fd, uint32_t offset, uint32_t start) 1616 { 1617 int i, rv; 1618 uint8_t *addrbytep; 1619 tavor_flash_ioctl_t cmd; 1620 1621 logmsg(MSG_INFO, 1622 "tavor: tavor_write_xps_fia(fd %d, offset 0x%04x, " 1623 "start 0x%04x)\n", 1624 fd, offset, start); 1625 1626 addrbytep = (uint8_t *)&start; 1627 1628 bzero(&cmd, sizeof (tavor_flash_ioctl_t)); 1629 cmd.tf_type = TAVOR_FLASH_WRITE_BYTE; 1630 for (i = 0; i < 4; i++) { 1631 cmd.tf_byte = addrbytep[i]; 1632 cmd.tf_addr = offset + FLASH_PS_FI_ADDR_OFFSET + i; 1633 logmsg(MSG_INFO, 1634 "tavor: writing xPS' new FIA, byte %d (0x%0x) at " 1635 "offset from IS 0x%04x\n", 1636 i, cmd.tf_byte, cmd.tf_addr); 1637 errno = 0; 1638 1639 rv = ioctl(fd, TAVOR_IOCTL_FLASH_WRITE, &cmd); 1640 if (rv < 0) { 1641 logmsg(MSG_INFO, 1642 gettext("tavor: Unable to write byte %d " 1643 "of xPS new FIA (0x%0x, offset from IS " 1644 "0x%04x): %s\n"), 1645 i, cmd.tf_byte, cmd.tf_addr, strerror(errno)); 1646 return (FWFLASH_FAILURE); 1647 } 1648 } 1649 return (FWFLASH_SUCCESS); 1650 } 1651 1652 1653 /* 1654 * Write the new CRC16 and Signature to the given xPS. The caller 1655 * has already byte-swapped newcrc if that's necessary. 1656 * 1657 * NOTE we do _not_ divide start by 4 because we're talking to the 1658 * HCA, and not finding an offset into verifier->fwimage. 1659 */ 1660 static int 1661 tavor_write_xps_crc_sig(int fd, uint32_t offset, uint16_t newcrc) 1662 { 1663 int i, rv; 1664 uint8_t *bytep; 1665 uint32_t tempsig; 1666 tavor_flash_ioctl_t cmd; 1667 1668 logmsg(MSG_INFO, 1669 "tavor: tavor_write_xps_crc_sig(fd %d, offset 0x%04x, " 1670 "newcrc 0x%04x)\n", 1671 fd, offset, newcrc); 1672 1673 bytep = (uint8_t *)&newcrc; 1674 1675 bzero(&cmd, sizeof (tavor_flash_ioctl_t)); 1676 cmd.tf_type = TAVOR_FLASH_WRITE_BYTE; 1677 for (i = 0; i < 2; i++) { 1678 cmd.tf_byte = bytep[i]; 1679 cmd.tf_addr = offset + FLASH_PS_CRC16_OFFSET + i; 1680 logmsg(MSG_INFO, 1681 "tavor: writing new XPS CRC16, byte %d (0x%0x) at " 1682 "offset from IS 0x%04x\n", 1683 i, bytep[i], cmd.tf_addr); 1684 errno = 0; 1685 1686 rv = ioctl(fd, TAVOR_IOCTL_FLASH_WRITE, &cmd); 1687 if (rv < 0) { 1688 logmsg(MSG_INFO, 1689 gettext("tavor: Unable to write byte %d " 1690 "(0x%0x) of xPS' new CRC16 to offset " 1691 "from IS 0x%04x: %s\n"), 1692 i, bytep[i], cmd.tf_addr, strerror(errno)); 1693 return (FWFLASH_FAILURE); 1694 } 1695 } 1696 1697 tempsig = htonl(FLASH_PS_SIGNATURE); 1698 bytep = (uint8_t *)&tempsig; 1699 1700 for (i = 0; i < 4; i++) { 1701 cmd.tf_byte = bytep[i]; 1702 cmd.tf_addr = offset + FLASH_PS_SIGNATURE_OFFSET + i; 1703 logmsg(MSG_INFO, 1704 "tavor: writing new xPS Signature, byte %d (0x%0x) at " 1705 "offset from IS 0x%04x\n", 1706 i, bytep[i], cmd.tf_addr); 1707 errno = 0; 1708 1709 rv = ioctl(fd, TAVOR_IOCTL_FLASH_WRITE, &cmd); 1710 if (rv < 0) { 1711 logmsg(MSG_INFO, 1712 gettext("tavor: Unable to write byte %d (0x%0x) " 1713 "of xPS' signature at offset from IS 0x%04x: %s\n"), 1714 i, bytep[i], cmd.tf_addr, strerror(errno)); 1715 return (FWFLASH_FAILURE); 1716 } 1717 } 1718 return (FWFLASH_SUCCESS); 1719 } 1720 1721 1722 1723 /* 1724 * This function contains "Begin/End documentation departure point" 1725 * because the reality of what actually _works_ is quite, quite 1726 * different to what is written in the Mellanox HCA Flash Application 1727 * Programming Guide. 1728 */ 1729 static int 1730 tavor_blast_image(int fd, int prisec, uint32_t hcafia, uint32_t sectsz, 1731 struct mlx_xps *newxps) 1732 { 1733 uint32_t i, j, rv; 1734 uint32_t startsectimg, startsecthca, numsect; 1735 1736 if ((prisec != 1) && (prisec != 2)) { 1737 logmsg(MSG_ERROR, 1738 gettext("tavor: invalid image number requested (%d)\n"), 1739 prisec); 1740 return (FWFLASH_FAILURE); 1741 } 1742 1743 /* Begin documentation departure point */ 1744 1745 /* zero the HCA's PPS signature and CRC */ 1746 if (tavor_zero_sig_crc(fd, (prisec * sectsz)) 1747 != FWFLASH_SUCCESS) { 1748 logmsg(MSG_INFO, 1749 "tavor: Unable zero HCA's %s signature " 1750 "and CRC16 fields\n", 1751 ((prisec == 1) ? "PPS" : "SPS")); 1752 return (FWFLASH_FAILURE); 1753 } 1754 1755 logmsg(MSG_INFO, "tavor: zeroing HCA's %s sig and crc\n", 1756 (prisec == 1) ? "pps" : "sps"); 1757 1758 /* End documentation departure point */ 1759 1760 /* make sure we don't inadvertently overwrite bits */ 1761 1762 startsectimg = MLXSWAPBITS32(newxps->fia) / sectsz; 1763 startsecthca = hcafia / sectsz; 1764 1765 numsect = (MLXSWAPBITS32(newxps->fis) / sectsz) + 1766 ((MLXSWAPBITS32(newxps->fis) % sectsz) ? 1 : 0); 1767 1768 logmsg(MSG_INFO, "tavor: %s imgsize 0x%0x startsecthca %d, " 1769 "startsectimg %d, num sectors %d\n", 1770 (prisec == 1) ? "PFI" : "SFI", MLXSWAPBITS32(newxps->fis), 1771 startsecthca, startsectimg, numsect); 1772 1773 for (i = 0; i < numsect; i++) { 1774 1775 j = (MLXSWAPBITS32(newxps->fia) + (i * sectsz)) / 4; 1776 1777 logmsg(MSG_INFO, "tavor: image offset 0x%0x\n", j); 1778 logmsg(MSG_INFO, "tavor: writing HCA sector %d\n", 1779 i + startsecthca); 1780 1781 if (tavor_write_sector(fd, i + startsecthca, 1782 &verifier->fwimage[j]) 1783 != FWFLASH_SUCCESS) { 1784 logmsg(MSG_ERROR, 1785 gettext("tavor: Unable to write " 1786 "sector %d to HCA\n"), 1787 i + startsecthca); 1788 return (FWFLASH_FAILURE); 1789 } 1790 (void) printf(" ."); 1791 1792 rv = tavor_readback(fd, i + startsecthca, sectsz); 1793 if (rv != FWFLASH_SUCCESS) { 1794 logmsg(MSG_ERROR, 1795 gettext("tavor: Unable to read sector %d " 1796 "back from HCA\n"), i + startsecthca); 1797 return (FWFLASH_FAILURE); 1798 } 1799 (void) printf(" | "); 1800 } 1801 1802 /* Begin documentation departure point */ 1803 1804 /* invalidate the xps signature and fia fields */ 1805 newxps->signature = 0xffffffff; 1806 newxps->crc16 = 0xffff; 1807 /* we put the fia back to imgfia later */ 1808 newxps->fia = 0xffffffff; 1809 /* End documentation departure point */ 1810 1811 /* success so far, now burn the new xPS */ 1812 if (tavor_write_sector(fd, prisec, (int *)newxps) 1813 != FWFLASH_SUCCESS) { 1814 logmsg(MSG_ERROR, 1815 gettext("tavor: Unable to write new %s " 1816 "pointer sector to HCA\n"), 1817 (prisec == 1) ? "primary" : "secondary"); 1818 return (FWFLASH_FAILURE); 1819 } 1820 (void) printf(" ."); 1821 1822 /* Begin documentation departure point */ 1823 1824 /* write new fia to the HCA's pps */ 1825 logmsg(MSG_INFO, "tavor: writing new fia (0x%0x) to HCA\n", 1826 MLXSWAPBITS32(newxps->fia)); 1827 1828 if (tavor_write_xps_fia(fd, (prisec * sectsz), 1829 MLXSWAPBITS32(hcafia)) != FWFLASH_SUCCESS) { 1830 logmsg(MSG_ERROR, 1831 gettext("tavor: Unable to update HCA's %s " 1832 "pointer sector FIA record\n"), 1833 (prisec == 1) ? "primary" : "secondary"); 1834 return (FWFLASH_FAILURE); 1835 } 1836 1837 /* don't forget the byte-swapping */ 1838 newxps->fia = MLXSWAPBITS32(hcafia); 1839 newxps->signature = 1840 (uint32_t)MLXSWAPBITS32(FLASH_PS_SIGNATURE); 1841 newxps->crc16 = 1842 MLXSWAPBITS16(crc16((uint8_t *)newxps, FLASH_PS_CRC16_SIZE)); 1843 1844 logmsg(MSG_INFO, "tavor: writing new fia 0x%0x, " 1845 "sig 0x%0x and new crc16 0x%0x\n", 1846 newxps->fia, MLXSWAPBITS32(newxps->signature), 1847 newxps->crc16); 1848 1849 if (tavor_write_xps_crc_sig(fd, (prisec * sectsz), 1850 newxps->crc16) != FWFLASH_SUCCESS) { 1851 /* 1852 * Now we're REALLY hosed. If the card comes up at all, 1853 * expect it to be in "Maintenance Mode". 1854 */ 1855 logmsg(MSG_ERROR, 1856 gettext("tavor: Unable to update HCA's %s CRC " 1857 "and Firmware Image signature fields\n"), 1858 (prisec == 1) ? "PPS" : "SPS"); 1859 return (FWFLASH_FAILURE); 1860 } 1861 1862 rv = tavor_readback(fd, prisec, sectsz); 1863 if (rv != FWFLASH_SUCCESS) { 1864 logmsg(MSG_ERROR, 1865 gettext("tavor: Unable to read %s pointer sector " 1866 "from HCA\n"), 1867 (prisec == 1) ? "Primary" : "Secondary"); 1868 return (FWFLASH_FAILURE); 1869 } 1870 (void) printf(" |"); 1871 /* End documentation departure point */ 1872 return (FWFLASH_SUCCESS); 1873 } 1874 1875 1876 static int 1877 tavor_readback(int infd, int whichsect, int sectsz) 1878 { 1879 uint32_t *data; 1880 tavor_flash_ioctl_t cmd; 1881 int rv; 1882 1883 bzero(&cmd, sizeof (tavor_flash_ioctl_t)); 1884 data = calloc(1, sectsz); /* assumption! */ 1885 1886 cmd.tf_type = TAVOR_FLASH_READ_SECTOR; 1887 cmd.tf_sector_num = whichsect; 1888 cmd.tf_sector = (caddr_t)data; 1889 rv = ioctl(infd, TAVOR_IOCTL_FLASH_READ, &cmd); 1890 if (rv < 0) { 1891 logmsg(MSG_INFO, 1892 "tavor: UNABLE TO READ BACK SECTOR %d from HCA\n", 1893 whichsect); 1894 return (FWFLASH_FAILURE); 1895 } 1896 free(data); 1897 return (FWFLASH_SUCCESS); 1898 } 1899 1900 1901 /* 1902 * crc16 - computes 16 bit crc of supplied buffer. 1903 * image should be in network byteorder 1904 * result is returned in host byteorder form 1905 */ 1906 static uint16_t 1907 crc16(uint8_t *image, uint32_t size) 1908 { 1909 const uint16_t poly = 0x100b; 1910 uint32_t crc = 0xFFFF; 1911 uint32_t word; 1912 uint32_t i, j; 1913 1914 for (i = 0; i < size / 4; i++) { 1915 word = (image[4 * i] << 24) | 1916 (image[4 * i + 1] << 16) | 1917 (image[4 * i + 2] << 8) | 1918 (image[4 * i + 3]); 1919 1920 for (j = 0; j < 32; j++) { 1921 if (crc & 0x8000) { 1922 crc = (((crc << 1) | 1923 (word >> 31)) ^ poly) & 0xFFFF; 1924 } else { 1925 crc = ((crc << 1) | (word >> 31)) & 0xFFFF; 1926 } 1927 word = (word << 1) & 0xFFFFFFFF; 1928 } 1929 } 1930 1931 for (i = 0; i < 16; i++) { 1932 if (crc & 0x8000) { 1933 crc = ((crc << 1) ^ poly) & 0xFFFF; 1934 } else { 1935 crc = (crc << 1) & 0xFFFF; 1936 } 1937 } 1938 1939 crc = crc ^ 0xFFFF; 1940 return (crc & 0xFFFF); 1941 } 1942