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