tavor.c revision 9517:b4839b0aa7a4
1/* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22/* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27/* 28 * 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 77char *devprefix = "/devices"; 78char drivername[] = "tavor\0"; 79char *devsuffix = ":devctl"; 80 81 82extern di_node_t rootnode; 83extern int errno; 84extern struct fw_plugin *self; 85extern struct vrfyplugin *verifier; 86extern int fwflash_debug; 87 88 89/* required functions for this plugin */ 90int fw_readfw(struct devicelist *device, char *filename); 91int fw_writefw(struct devicelist *device); 92int fw_identify(int start); 93int fw_devinfo(); 94 95 96/* helper functions */ 97 98static int tavor_identify(struct devicelist *thisdev); 99static int tavor_get_guids(struct ib_encap_ident *handle); 100static int tavor_close(struct devicelist *flashdev); 101static void tavor_cisco_extensions(mlx_xps_t *hcaxps, mlx_xps_t *diskxps); 102static uint16_t crc16(uint8_t *image, uint32_t size); 103static int tavor_write_sector(int fd, int sectnum, int32_t *data); 104static int tavor_zero_sig_crc(int fd, uint32_t start); 105static int tavor_write_xps_fia(int fd, uint32_t offset, uint32_t start); 106static int tavor_write_xps_crc_sig(int fd, uint32_t offset, uint16_t newcrc); 107static int tavor_blast_image(int fd, int prisec, uint32_t hcafia, 108 uint32_t sectsz, struct mlx_xps *newxps); 109static int tavor_readback(int infd, int whichsect, int sectsz); 110 111 112 113int 114fw_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 */ 348int 349fw_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 */ 608int 609fw_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("%s 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 747int 748fw_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 */ 811static int 812tavor_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 /* 856 * Inform driver that this command supports the Intel Extended 857 * CFI command set. 858 */ 859 cfi.cfi_char[0x10] = 'M'; 860 cfi.cfi_char[0x11] = 'X'; 861 cfi.cfi_char[0x12] = '2'; 862 init_ioctl.tf_cfi_info[0x4] = MLXSWAPBITS32(cfi.cfi_int[0x4]); 863 864 errno = 0; 865 ret = ioctl(fd, TAVOR_IOCTL_FLASH_INIT, &init_ioctl); 866 if (ret < 0) { 867 logmsg(MSG_ERROR, 868 gettext("ib: TAVOR_IOCTL_FLASH_INIT failed: %s\n"), 869 strerror(errno)); 870 free(manuf); 871 close(fd); 872 return (FWFLASH_FAILURE); 873 } 874 875 manuf->hwrev = init_ioctl.tf_hwrev; 876 877 /* 878 * Determine whether the attached driver supports the Intel or 879 * AMD Extended CFI command sets. If it doesn't support either, 880 * then we're hosed, so error out. 881 */ 882 for (i = 0; i < TAVOR_FLASH_CFI_SIZE_QUADLET; i++) { 883 cfi.cfi_int[i] = MLXSWAPBITS32(init_ioctl.tf_cfi_info[i]); 884 } 885 manuf->cmd_set = cfi.cfi_char[0x13]; 886 887 if (cfi.cfi_char[0x10] == 'Q' && 888 cfi.cfi_char[0x11] == 'R' && 889 cfi.cfi_char[0x12] == 'Y') { 890 /* make sure the cmd set is AMD */ 891 if (manuf->cmd_set != TAVOR_FLASH_AMD_CMDSET) { 892 logmsg(MSG_ERROR, 893 gettext("tavor: Unsupported flash device " 894 "command set\n")); 895 free(manuf); 896 close(fd); 897 return (FWFLASH_FAILURE); 898 } 899 /* set some defaults */ 900 manuf->device_sz = TAVOR_FLASH_DEVICE_SZ_DEFAULT; 901 } else { 902 if (manuf->cmd_set != TAVOR_FLASH_AMD_CMDSET && 903 manuf->cmd_set != TAVOR_FLASH_INTEL_CMDSET) { 904 logmsg(MSG_ERROR, 905 gettext("ib: Unknown flash device command set\n")); 906 free(manuf); 907 close(fd); 908 return (FWFLASH_FAILURE); 909 } 910 /* read from the CFI data */ 911 manuf->sector_sz = ((cfi.cfi_char[0x30] << 8) | 912 cfi.cfi_char[0x2F]) << 8; 913 manuf->device_sz = 0x1 << cfi.cfi_char[0x27]; 914 } 915 916 logmsg(MSG_INFO, "sector_sz: 0x%08x\ndevice_sz: 0x%08x\n", 917 manuf->sector_sz, manuf->device_sz); 918 919 manuf->state |= FWFLASH_IB_STATE_MMAP; 920 921 /* set firmware revision */ 922 manuf->fw_rev.major = init_ioctl.tf_fwrev.tfi_maj; 923 manuf->fw_rev.minor = init_ioctl.tf_fwrev.tfi_min; 924 manuf->fw_rev.subminor = init_ioctl.tf_fwrev.tfi_sub; 925 926 if (((thisdev->ident->vid = calloc(1, MLX_VPR_VIDLEN + 1)) == NULL) || 927 ((thisdev->ident->revid = calloc(1, MLX_VPR_REVLEN + 1)) == NULL)) { 928 929 logmsg(MSG_ERROR, 930 gettext("ib: Unable to allocate space for a VPR " 931 "record.\n")); 932 free(thisdev->ident); 933 free(manuf->info.mlx_pn); 934 free(manuf->info.mlx_psid); 935 free(manuf->info.mlx_id); 936 free(manuf); 937 close(fd); 938 return (FWFLASH_FAILURE); 939 } 940 (void) strlcpy(thisdev->ident->vid, "MELLANOX", MLX_VPR_VIDLEN); 941 /* 942 * We actually want the hwrev field from the ioctl above. 943 * Until we find out otherwise, add it onto the end of the 944 * firmware version details. 945 */ 946 947 snprintf(thisdev->ident->revid, MLX_VPR_REVLEN, "%d.%d.%04d", 948 manuf->fw_rev.major, manuf->fw_rev.minor, 949 manuf->fw_rev.subminor); 950 951 bzero(manuf->ibguids, sizeof (manuf->ibguids)); 952 953 /* 954 * For convenience we read in the Invariant Sector as 955 * well as both the Primary and Secondary Pointer Sectors 956 */ 957 958 if ((manuf->inv = calloc(1, manuf->sector_sz)) == NULL) { 959 logmsg(MSG_ERROR, 960 gettext("tavor: Unable to allocate space for storing " 961 "the HCA's Invariant Sector\n")); 962 return (FWFLASH_FAILURE); 963 } 964 bzero(&info, sizeof (tavor_flash_ioctl_t)); 965 966 info.tf_type = TAVOR_FLASH_READ_SECTOR; 967 info.tf_sector = (caddr_t)manuf->inv; 968 info.tf_sector_num = 0; 969 970 errno = 0; 971 972 if ((rv = ioctl(manuf->fd, TAVOR_IOCTL_FLASH_READ, &info)) 973 < 0) { 974 logmsg(MSG_ERROR, 975 gettext("tavor: Unable to read HCA Invariant Sector\n")); 976 return (FWFLASH_FAILURE); 977 } 978 979#if defined(_LITTLE_ENDIAN) 980 ptr = (uint32_t *)(uintptr_t)manuf->inv; 981 for (i = 0; i < (manuf->sector_sz / 4); i++) { 982 ptr[i] = htonl(ptr[i]); 983 } 984#endif 985 986 if ((manuf->pps = calloc(1, manuf->sector_sz)) == NULL) { 987 logmsg(MSG_ERROR, 988 gettext("tavor: Unable to allocate space for storing " 989 "the HCA's Primary Pointer Sector\n")); 990 return (FWFLASH_FAILURE); 991 } 992 bzero(&info, sizeof (tavor_flash_ioctl_t)); 993 994 info.tf_type = TAVOR_FLASH_READ_SECTOR; 995 info.tf_sector = (caddr_t)manuf->pps; 996 info.tf_sector_num = 1; 997 998 errno = 0; 999 1000 if ((rv = ioctl(manuf->fd, TAVOR_IOCTL_FLASH_READ, &info)) 1001 < 0) { 1002 logmsg(MSG_ERROR, 1003 gettext("tavor: Unable to read HCA Primary " 1004 "Pointer Sector\n")); 1005 return (FWFLASH_FAILURE); 1006 } 1007 1008#if defined(_LITTLE_ENDIAN) 1009 ptr = (uint32_t *)(uintptr_t)manuf->pps; 1010 for (i = 0; i < (manuf->sector_sz / 4); i++) { 1011 ptr[i] = htonl(ptr[i]); 1012 } 1013#endif 1014 1015 if ((manuf->sps = calloc(1, manuf->sector_sz)) == NULL) { 1016 logmsg(MSG_ERROR, 1017 gettext("tavor: Unable to allocate space for storing " 1018 "the HCA's Secondary Pointer Sector\n")); 1019 return (FWFLASH_FAILURE); 1020 } 1021 bzero(&info, sizeof (tavor_flash_ioctl_t)); 1022 1023 info.tf_type = TAVOR_FLASH_READ_SECTOR; 1024 info.tf_sector = (caddr_t)manuf->sps; 1025 info.tf_sector_num = 2; 1026 1027 errno = 0; 1028 1029 if ((rv = ioctl(manuf->fd, TAVOR_IOCTL_FLASH_READ, &info)) 1030 < 0) { 1031 logmsg(MSG_ERROR, 1032 gettext("tavor: Unable to read HCA Secondary " 1033 "Pointer Sector\n")); 1034 return (FWFLASH_FAILURE); 1035 } 1036 1037#if defined(_LITTLE_ENDIAN) 1038 ptr = (uint32_t *)(uintptr_t)manuf->sps; 1039 for (i = 0; i < (manuf->sector_sz / 4); i++) { 1040 ptr[i] = htonl(ptr[i]); 1041 } 1042#endif 1043 1044 if ((ret = tavor_get_guids(manuf)) != FWFLASH_SUCCESS) { 1045 logmsg(MSG_INFO, 1046 gettext("ib: No guids found for device %s!\n"), 1047 thisdev->access_devname); 1048 } 1049 1050 /* set hw part number, psid, and name in handle */ 1051 bzero(temppsid, 17); 1052 bcopy(manuf->pps+FLASH_PS_PSID_OFFSET, &rawpsid, 16); 1053 1054 for (i = 0; i < 16; i += 4) { 1055 temppsid[i] = rawpsid[i+3]; 1056 temppsid[i+1] = rawpsid[i+2]; 1057 temppsid[i+2] = rawpsid[i+1]; 1058 temppsid[i+3] = rawpsid[i]; 1059 } 1060 logmsg(MSG_INFO, 1061 "tavor: have raw '%s', want munged '%s'\n", 1062 rawpsid, temppsid); 1063 1064 /* now walk the magic decoder ring table */ 1065 manuf->info.mlx_pn = NULL; 1066 manuf->info.mlx_psid = NULL; 1067 manuf->info.mlx_id = NULL; 1068 manuf->pn_len = 0; 1069 1070 for (i = 0; i < MLX_MAX_ID; i++) { 1071 if ((strncmp(temppsid, mlx_mdr[i].mlx_psid, 1072 MLX_PSID_SZ)) == 0) { 1073 /* matched */ 1074 if ((manuf->info.mlx_pn = calloc(1, 1075 strlen(mlx_mdr[i].mlx_pn) + 1)) == NULL) { 1076 logmsg(MSG_INFO, 1077 "tavor: no space available for the " 1078 "HCA PSID record (1)\n"); 1079 } else { 1080 (void) strlcpy(manuf->info.mlx_pn, 1081 mlx_mdr[i].mlx_pn, 1082 strlen(mlx_mdr[i].mlx_pn) + 1); 1083 manuf->pn_len = strlen(mlx_mdr[i].mlx_pn); 1084 } 1085 1086 if ((manuf->info.mlx_psid = calloc(1, 1087 strlen(mlx_mdr[i].mlx_psid) + 1)) == NULL) { 1088 logmsg(MSG_INFO, 1089 "tavor: no space available for the " 1090 "HCA PSID record (2)\n"); 1091 } else { 1092 (void) strlcpy(manuf->info.mlx_psid, 1093 mlx_mdr[i].mlx_psid, 1094 strlen(mlx_mdr[i].mlx_psid) + 1); 1095 } 1096 if ((manuf->info.mlx_id = calloc(1, 1097 strlen(mlx_mdr[i].mlx_id) + 1)) == NULL) { 1098 logmsg(MSG_INFO, 1099 "tavor: no space available for the " 1100 "HCA PSID record (3)\n"); 1101 } else { 1102 (void) strlcpy(manuf->info.mlx_id, 1103 mlx_mdr[i].mlx_id, 1104 strlen(mlx_mdr[i].mlx_id) + 1); 1105 } 1106 } 1107 } 1108 if ((manuf->pn_len == 0) || (i == MLX_MAX_ID)) { 1109 logmsg(MSG_INFO, 1110 "tavor: No hardware part number information available " 1111 "for this HCA\n"); 1112 /* Until we deliver the arbel driver, it's all Mellanox */ 1113 i = strlen("No hardware information available for this device"); 1114 1115 thisdev->ident->pid = calloc(1, i + 2); 1116 sprintf(thisdev->ident->pid, "No hardware information " 1117 "available for this device"); 1118 } else { 1119 if ((thisdev->ident->pid = calloc(1, 1120 strlen(manuf->info.mlx_psid) + 1)) != NULL) { 1121 (void) strlcpy(thisdev->ident->pid, 1122 manuf->info.mlx_psid, 1123 strlen(manuf->info.mlx_psid) + 1); 1124 } else { 1125 logmsg(MSG_ERROR, 1126 gettext("ib: Unable to allocate space for a " 1127 "hardware identifier\n")); 1128 free(thisdev->ident); 1129 free(manuf->info.mlx_pn); 1130 free(manuf->info.mlx_psid); 1131 free(manuf->info.mlx_id); 1132 free(manuf); 1133 close(fd); 1134 return (FWFLASH_FAILURE); 1135 } 1136 } 1137 1138 for (i = 0; i < 4; i++) { 1139 if ((thisdev->addresses[i] = calloc(1, 1140 (2 * sizeof (uint64_t)) + 1)) == NULL) { 1141 logmsg(MSG_ERROR, 1142 gettext("tavor: Unable to allocate space for a " 1143 "human-readable HCA guid\n")); 1144 return (FWFLASH_FAILURE); 1145 } 1146 (void) sprintf(thisdev->addresses[i], "%016llx", 1147 manuf->ibguids[i]); 1148 } 1149 1150 /* 1151 * We do NOT close the fd here, since we can close it 1152 * at the end of the fw_readfw() or fw_writefw() functions 1153 * instead and not get the poor dear confused about whether 1154 * it's been inited already. 1155 */ 1156 1157 return (rv); 1158} 1159 1160/*ARGSUSED*/ 1161static int 1162tavor_get_guids(struct ib_encap_ident *handle) 1163{ 1164 int rv, j; 1165 uint32_t i = 0x00; 1166 tavor_flash_ioctl_t info; 1167 struct mlx_guid_sect *p, *s; 1168 1169#if defined(_LITTLE_ENDIAN) 1170 uint32_t *ptr, tmp; 1171#endif 1172 1173 /* 1174 * The reference for this function is the 1175 * Mellanox HCA Flash Programming Application Note 1176 * rev 1.44, 2007. Chapter 4 in particular. 1177 * 1178 * NOTE: this Mellanox document is labelled Confidential 1179 * so DO NOT move this file out of usr/closed without 1180 * explicit approval from Sun Legal. 1181 */ 1182 1183 /* 1184 * We need to check for both the Primary and Secondary 1185 * Image GUIDs. handle->pps and handle->sps should be 1186 * non-NULL by the time we're called, since we depend 1187 * on them being stashed in handle. Saves on an ioctl(). 1188 */ 1189 1190 /* make sure we've got our fallback position organised */ 1191 for (i = 0; i < 4; i++) { 1192 handle->ibguids[i] = 0x00000000; 1193 } 1194 1195 /* convenience .... */ 1196 1197 if ((p = calloc(1, sizeof (mlx_guid_sect_t))) == NULL) { 1198 logmsg(MSG_ERROR, 1199 gettext("tavor: Unable to allocate space for " 1200 "HCA guid record (1)\n")); 1201 return (FWFLASH_FAILURE); 1202 } 1203 if ((s = calloc(1, sizeof (mlx_guid_sect_t))) == NULL) { 1204 logmsg(MSG_ERROR, 1205 gettext("tavor: Unable to allocate space for " 1206 "HCA guid record (2)\n")); 1207 free(p); 1208 return (FWFLASH_FAILURE); 1209 } 1210 1211 bcopy(&handle->pps[0], &i, 4); 1212 handle->pfi_guid_addr = MLXSWAPBITS32(i) + FLASH_GUID_PTR; 1213 bcopy(&handle->sps[0], &i, 4); 1214 handle->sfi_guid_addr = MLXSWAPBITS32(i) + FLASH_GUID_PTR; 1215 1216 bzero(&info, sizeof (tavor_flash_ioctl_t)); 1217 info.tf_type = TAVOR_FLASH_READ_QUADLET; 1218 info.tf_addr = handle->pfi_guid_addr; 1219 1220 errno = 0; 1221 1222 rv = ioctl(handle->fd, TAVOR_IOCTL_FLASH_READ, &info); 1223 if (rv < 0) { 1224 logmsg(MSG_ERROR, 1225 gettext("tavor: Unable to read Primary Image " 1226 "guid offset\n")); 1227 free(p); 1228 free(s); 1229 return (FWFLASH_FAILURE); 1230 } 1231 1232 /* 1233 * This is because we want the whole of the section 1234 * including the 16 reserved bytes at the front so 1235 * that if we recalculate the CRC we've got the correct 1236 * data to do it with 1237 */ 1238 info.tf_addr = handle->pfi_guid_addr + info.tf_quadlet 1239 - FLASH_GUID_PTR - 16; 1240 1241 bzero(handle->pri_guid_section, sizeof (mlx_guid_sect_t)); 1242 1243 for (j = 0; j < 13; j++) { 1244 errno = 0; 1245 if ((rv = ioctl(handle->fd, TAVOR_IOCTL_FLASH_READ, 1246 &info)) < 0) { 1247 logmsg(MSG_ERROR, 1248 gettext("tavor: Unable to read Primary Image " 1249 "guid chunk %d\n"), j); 1250 } 1251 handle->pri_guid_section[j] = info.tf_quadlet; 1252 info.tf_addr += 4; 1253 } 1254 bcopy(&handle->pri_guid_section, p, sizeof (struct mlx_guid_sect)); 1255 1256 /* now grab the secondary guid set */ 1257 bzero(&info, sizeof (tavor_flash_ioctl_t)); 1258 info.tf_type = TAVOR_FLASH_READ_QUADLET; 1259 info.tf_addr = handle->sfi_guid_addr; 1260 1261 errno = 0; 1262 1263 if ((rv = ioctl(handle->fd, TAVOR_IOCTL_FLASH_READ, 1264 &info)) < 0) { 1265 logmsg(MSG_ERROR, 1266 gettext("tavor: Unable to read Secondary Image " 1267 "guid offset (%s)\n"), strerror(errno)); 1268 free(p); 1269 free(s); 1270 return (FWFLASH_FAILURE); 1271 } 1272 1273 info.tf_addr = handle->sfi_guid_addr + info.tf_quadlet 1274 - FLASH_GUID_PTR - 16; 1275 1276 bzero(handle->sec_guid_section, sizeof (mlx_guid_sect_t)); 1277 1278 for (j = 0; j < 13; j++) { 1279 errno = 0; 1280 if ((rv = ioctl(handle->fd, TAVOR_IOCTL_FLASH_READ, 1281 &info)) < 0) { 1282 logmsg(MSG_ERROR, 1283 gettext("tavor: Unable to read Secondary Image " 1284 "guid chunk %d (%s)\n"), j, strerror(errno)); 1285 return (FWFLASH_FAILURE); 1286 } 1287 handle->sec_guid_section[j] = info.tf_quadlet; 1288 info.tf_addr += 4; 1289 } 1290 1291 bcopy(&handle->sec_guid_section, s, sizeof (struct mlx_guid_sect)); 1292 1293#if defined(_LITTLE_ENDIAN) 1294 1295 /* 1296 * We don't actually care about p or s later on if we 1297 * write to the HCA - we've already stored the binary 1298 * form in handle->pri_guid_section and handle->sec_guid_section. 1299 * What we're doing here is creating human-readable forms. 1300 */ 1301 1302 ptr = (uint32_t *)(uintptr_t)p; 1303 for (j = 0; j < 14; j += 2) { 1304 tmp = ptr[j]; 1305 ptr[j] = ptr[j+1]; 1306 ptr[j+1] = tmp; 1307 } 1308 1309 ptr = (uint32_t *)(uintptr_t)s; 1310 for (j = 0; j < 14; j += 2) { 1311 tmp = ptr[j]; 1312 ptr[j] = ptr[j+1]; 1313 ptr[j+1] = tmp; 1314 } 1315#endif 1316 1317 /* 1318 * We don't check and munge the GUIDs to the manufacturer's 1319 * defaults, because if the GUIDs are actually set incorrectly 1320 * at identify time, we really need to know that. 1321 * 1322 * If the GUIDs are bogus, then we'll fix that in fw_writefw() 1323 * by blatting the manufacturer's defaults from the firmware 1324 * image file instead. 1325 */ 1326 if ((p->nodeguid == s->nodeguid) && 1327 (p->port1guid == s->port1guid) && 1328 (p->port2guid == s->port2guid) && 1329 (p->sysimguid == s->sysimguid)) { 1330 logmsg(MSG_INFO, 1331 "tavor: primary and secondary guids are the same\n"); 1332 handle->ibguids[0] = p->nodeguid; 1333 handle->ibguids[1] = p->port1guid; 1334 handle->ibguids[2] = p->port2guid; 1335 handle->ibguids[3] = p->sysimguid; 1336 } else { 1337 /* 1338 * We're going to assume that the guids which are numerically 1339 * larger than the others are correct and copy them to 1340 * handle->ibguids. 1341 * 1342 * For those in the know wrt InfiniBand, if this assumption 1343 * is incorrect, _please_ bug this and fix it, adding a 1344 * comment or two to indicate why 1345 */ 1346 logmsg(MSG_INFO, 1347 "tavor: primary and secondary guids don't all match\n"); 1348 1349 if (s->nodeguid > p->nodeguid) { 1350 handle->ibguids[0] = s->nodeguid; 1351 handle->ibguids[1] = s->port1guid; 1352 handle->ibguids[2] = s->port2guid; 1353 handle->ibguids[3] = s->sysimguid; 1354 bzero(p, sizeof (struct mlx_guid_sect)); 1355 } else { 1356 handle->ibguids[0] = p->nodeguid; 1357 handle->ibguids[1] = p->port1guid; 1358 handle->ibguids[2] = p->port2guid; 1359 handle->ibguids[3] = p->sysimguid; 1360 bzero(s, sizeof (struct mlx_guid_sect)); 1361 } 1362 } 1363 1364 free(p); 1365 free(s); 1366 1367 if (fwflash_debug) { 1368 for (i = 0; i < 4; i++) { 1369 logmsg(MSG_INFO, "ibguids[%d] %0llx\n", i, 1370 handle->ibguids[i]); 1371 } 1372 } 1373 1374 return (FWFLASH_SUCCESS); 1375} 1376 1377 1378int 1379tavor_close(struct devicelist *flashdev) 1380{ 1381 1382 struct ib_encap_ident *handle; 1383 1384 handle = (struct ib_encap_ident *)flashdev->ident->encap_ident; 1385 if (handle->fd > 0) { 1386 (void) ioctl(handle->fd, TAVOR_IOCTL_FLASH_FINI); 1387 errno = 0; 1388 if (close(handle->fd) != 0) { 1389 logmsg(MSG_ERROR, 1390 gettext("tavor: Unable to properly close " 1391 "device %s! (%s)\n"), 1392 flashdev->access_devname, 1393 strerror(errno)); 1394 return (FWFLASH_FAILURE); 1395 } 1396 return (FWFLASH_SUCCESS); 1397 } else 1398 return (FWFLASH_FAILURE); 1399} 1400 1401 1402/* 1403 * We would not need this if it were not for Cisco's image using the 1404 * VSD to store boot options and flags for their PXE boot extension, 1405 * but not setting the proper default values for the extension in 1406 * their image. As it turns out, some of the data for the extension 1407 * is stored in the VSD in the firmware file, and the rest is set by 1408 * their firmware utility. That's not very nice for us, since it could 1409 * change at any time without our knowledge. Well, for the time being, 1410 * we can use this to examine and fix up anything in the VSD that we might 1411 * need to handle, for any vendor specific settings. 1412 */ 1413static void 1414tavor_cisco_extensions(mlx_xps_t *hcaxps, mlx_xps_t *diskxps) 1415{ 1416 uint16_t sig1, sig2; 1417 uint32_t i; 1418 1419 1420 bcopy(hcaxps->vsdpsid, &i, 4); 1421 sig1 = htonl(i); 1422 bcopy(&hcaxps->vsdpsid[223], &i, 4); 1423 sig2 = htonl(i); 1424 1425 1426 if (sig1 == FLASH_VSD_CISCO_SIGNATURE && 1427 sig2 == FLASH_VSD_CISCO_SIGNATURE) { 1428 logmsg(MSG_INFO, 1429 "tavor: CISCO signature found in HCA's VSD, copying to " 1430 "new image's VSD\n"); 1431 1432 i = htonl(FLASH_VSD_CISCO_SIGNATURE); 1433 bcopy(&i, diskxps->vsdpsid, 2); 1434 1435 /* 1436 * Set the boot_version field to '2'. This value is 1437 * located in the 2nd byte of the last uint32_t. 1438 * Per the previous version of fwflash, we just or 1439 * the bit in and get on with it. 1440 */ 1441 1442 i = (diskxps->vsdpsid[222] | FLASH_VSD_CISCO_BOOT_VERSION); 1443 bcopy(&i, &diskxps->vsdpsid[222], 2); 1444 /* 1445 * Now set some defaults for the SRP boot extension, 1446 * currently the only extension we support. These flags 1447 * are located in the second uint32_t of the VSD. 1448 */ 1449 1450 logmsg(MSG_INFO, "tavor: CISCO boot flags currently set " 1451 "to 0x%08x\n", 1452 diskxps->vsdpsid[1]); 1453 1454 diskxps->vsdpsid[1] = 1455 htonl(diskxps->vsdpsid[1] | 1456 FLASH_VSD_CISCO_FLAG_AUTOUPGRADE | 1457 FLASH_VSD_CISCO_BOOT_OPTIONS | 1458 FLASH_VSD_CISCO_FLAG_BOOT_ENABLE_PORT_1 | 1459 FLASH_VSD_CISCO_FLAG_BOOT_ENABLE_PORT_2 | 1460 FLASH_VSD_CISCO_FLAG_BOOT_ENABLE_SCAN | 1461 FLASH_VSD_CISCO_FLAG_BOOT_TYPE_WELL_KNOWN | 1462 FLASH_VSD_CISCO_FLAG_BOOT_TRY_FOREVER); 1463 1464 logmsg(MSG_INFO, "tavor: CISCO boot flags now set " 1465 "to 0x%08x\n", 1466 diskxps->vsdpsid[1]); 1467 } else 1468 logmsg(MSG_INFO, 1469 "tavor: CISCO signature not found in HCA's VSD\n"); 1470} 1471 1472 1473static int 1474tavor_write_sector(int fd, int sectnum, int32_t *data) 1475{ 1476 int rv, i; 1477 tavor_flash_ioctl_t cmd; 1478 1479 1480 bzero(&cmd, sizeof (tavor_flash_ioctl_t)); 1481 1482 cmd.tf_type = TAVOR_FLASH_WRITE_SECTOR; 1483 cmd.tf_sector_num = sectnum; 1484 cmd.tf_sector = (caddr_t)data; 1485 1486 errno = 0; 1487 1488 logmsg(MSG_INFO, 1489 "tavor: tavor_write_sector(fd %d, sectnum 0x%x, data 0x%lx)\n", 1490 fd, sectnum, data); 1491 logmsg(MSG_INFO, 1492 "tavor:\n" 1493 "\tcmd.tf_type %d\n" 1494 "\tcmd.tf_sector 0x%lx\n" 1495 "\tcmd.tf_sector_num %d\n", 1496 cmd.tf_type, data, cmd.tf_sector_num); 1497 1498 /* 1499 * If we're debugging, dump the first 64 uint32_t that we've 1500 * been passed 1501 */ 1502 if (fwflash_debug > 0) { 1503 i = 0; 1504 while (i < 64) { 1505 logmsg(MSG_INFO, 1506 "%02x: %08x %08x %08x %08x\n", 1507 i, data[i], data[i+1], 1508 data[i+2], data[i+3]); 1509 i += 4; 1510 } 1511 } 1512 1513 rv = ioctl(fd, TAVOR_IOCTL_FLASH_WRITE, &cmd); 1514 if (rv < 0) { 1515 logmsg(MSG_ERROR, 1516 gettext("tavor: WRITE SECTOR failed for sector " 1517 "%d: %s\n"), 1518 sectnum, strerror(errno)); 1519 return (FWFLASH_FAILURE); 1520 } else 1521 return (FWFLASH_SUCCESS); 1522} 1523 1524/* 1525 * Write zeros to the on-HCA signature and CRC16 fields of sector. 1526 * 1527 * NOTE we do _not_ divide start by 4 because we're talking to the 1528 * HCA, and not finding an offset into verifier->fwimage. 1529 */ 1530 1531static int 1532tavor_zero_sig_crc(int fd, uint32_t start) 1533{ 1534 int i, rv; 1535 tavor_flash_ioctl_t cmd; 1536 1537 /* signature first, then CRC16 */ 1538 bzero(&cmd, sizeof (tavor_flash_ioctl_t)); 1539 cmd.tf_type = TAVOR_FLASH_WRITE_BYTE; 1540 cmd.tf_byte = 0x00; 1541 1542 logmsg(MSG_INFO, 1543 "tavor: tavor_zero_sig_crc(fd %d, start 0x%04x)\n", 1544 fd, start); 1545 1546 for (i = 0; i < 4; i++) { 1547 cmd.tf_addr = start + FLASH_PS_SIGNATURE_OFFSET + i; 1548 1549 logmsg(MSG_INFO, 1550 "tavor: invalidating xPS sig (offset from IS 0x%04x) " 1551 "byte %d\n", 1552 cmd.tf_addr, i); 1553 errno = 0; 1554 1555 rv = ioctl(fd, TAVOR_IOCTL_FLASH_WRITE, &cmd); 1556 if (rv < 0) { 1557 logmsg(MSG_INFO, 1558 gettext("tavor: Unable to write 0x00 to " 1559 "offset 0x%04x from IS (sig byte %d): %s\n"), 1560 cmd.tf_addr, i, strerror(errno)); 1561 return (FWFLASH_FAILURE); 1562 } 1563 } 1564 1565 cmd.tf_byte = 0x00; 1566 for (i = 0; i < 2; i++) { 1567 cmd.tf_addr = start + FLASH_PS_CRC16_OFFSET + i; 1568 1569 logmsg(MSG_INFO, 1570 "tavor: invalidating xPS CRC16 (offset from IS 0x%04x) " 1571 "byte %d\n", 1572 cmd.tf_addr, i); 1573 errno = 0; 1574 1575 rv = ioctl(fd, TAVOR_IOCTL_FLASH_WRITE, &cmd); 1576 if (rv < 0) { 1577 logmsg(MSG_INFO, 1578 gettext("tavor: Unable to write 0x00 to " 1579 "offset 0x%04x from IS (CRC16 byte %d): %s\n"), 1580 cmd.tf_addr, i, strerror(errno)); 1581 return (FWFLASH_FAILURE); 1582 } 1583 } 1584 return (FWFLASH_SUCCESS); 1585} 1586 1587 1588/* 1589 * Write a new FIA for the given xPS. The _caller_ handles 1590 * any required byte-swapping for us. 1591 * 1592 * NOTE we do _not_ divide start by 4 because we're talking to the 1593 * HCA, and not finding an offset into verifier->fwimage. 1594 */ 1595static int 1596tavor_write_xps_fia(int fd, uint32_t offset, uint32_t start) 1597{ 1598 int i, rv; 1599 uint8_t *addrbytep; 1600 tavor_flash_ioctl_t cmd; 1601 1602 logmsg(MSG_INFO, 1603 "tavor: tavor_write_xps_fia(fd %d, offset 0x%04x, " 1604 "start 0x%04x)\n", 1605 fd, offset, start); 1606 1607 addrbytep = (uint8_t *)&start; 1608 1609 bzero(&cmd, sizeof (tavor_flash_ioctl_t)); 1610 cmd.tf_type = TAVOR_FLASH_WRITE_BYTE; 1611 for (i = 0; i < 4; i++) { 1612 cmd.tf_byte = addrbytep[i]; 1613 cmd.tf_addr = offset + FLASH_PS_FI_ADDR_OFFSET + i; 1614 logmsg(MSG_INFO, 1615 "tavor: writing xPS' new FIA, byte %d (0x%0x) at " 1616 "offset from IS 0x%04x\n", 1617 i, cmd.tf_byte, cmd.tf_addr); 1618 errno = 0; 1619 1620 rv = ioctl(fd, TAVOR_IOCTL_FLASH_WRITE, &cmd); 1621 if (rv < 0) { 1622 logmsg(MSG_INFO, 1623 gettext("tavor: Unable to write byte %d " 1624 "of xPS new FIA (0x%0x, offset from IS " 1625 "0x%04x): %s\n"), 1626 i, cmd.tf_byte, cmd.tf_addr, strerror(errno)); 1627 return (FWFLASH_FAILURE); 1628 } 1629 } 1630 return (FWFLASH_SUCCESS); 1631} 1632 1633 1634/* 1635 * Write the new CRC16 and Signature to the given xPS. The caller 1636 * has already byte-swapped newcrc if that's necessary. 1637 * 1638 * NOTE we do _not_ divide start by 4 because we're talking to the 1639 * HCA, and not finding an offset into verifier->fwimage. 1640 */ 1641static int 1642tavor_write_xps_crc_sig(int fd, uint32_t offset, uint16_t newcrc) 1643{ 1644 int i, rv; 1645 uint8_t *bytep; 1646 uint32_t tempsig; 1647 tavor_flash_ioctl_t cmd; 1648 1649 logmsg(MSG_INFO, 1650 "tavor: tavor_write_xps_crc_sig(fd %d, offset 0x%04x, " 1651 "newcrc 0x%04x)\n", 1652 fd, offset, newcrc); 1653 1654 bytep = (uint8_t *)&newcrc; 1655 1656 bzero(&cmd, sizeof (tavor_flash_ioctl_t)); 1657 cmd.tf_type = TAVOR_FLASH_WRITE_BYTE; 1658 for (i = 0; i < 2; i++) { 1659 cmd.tf_byte = bytep[i]; 1660 cmd.tf_addr = offset + FLASH_PS_CRC16_OFFSET + i; 1661 logmsg(MSG_INFO, 1662 "tavor: writing new XPS CRC16, byte %d (0x%0x) at " 1663 "offset from IS 0x%04x\n", 1664 i, bytep[i], cmd.tf_addr); 1665 errno = 0; 1666 1667 rv = ioctl(fd, TAVOR_IOCTL_FLASH_WRITE, &cmd); 1668 if (rv < 0) { 1669 logmsg(MSG_INFO, 1670 gettext("tavor: Unable to write byte %d " 1671 "(0x%0x) of xPS' new CRC16 to offset " 1672 "from IS 0x%04x: %s\n"), 1673 i, bytep[i], cmd.tf_addr, strerror(errno)); 1674 return (FWFLASH_FAILURE); 1675 } 1676 } 1677 1678 tempsig = htonl(FLASH_PS_SIGNATURE); 1679 bytep = (uint8_t *)&tempsig; 1680 1681 for (i = 0; i < 4; i++) { 1682 cmd.tf_byte = bytep[i]; 1683 cmd.tf_addr = offset + FLASH_PS_SIGNATURE_OFFSET + i; 1684 logmsg(MSG_INFO, 1685 "tavor: writing new xPS Signature, byte %d (0x%0x) at " 1686 "offset from IS 0x%04x\n", 1687 i, bytep[i], cmd.tf_addr); 1688 errno = 0; 1689 1690 rv = ioctl(fd, TAVOR_IOCTL_FLASH_WRITE, &cmd); 1691 if (rv < 0) { 1692 logmsg(MSG_INFO, 1693 gettext("tavor: Unable to write byte %d (0x%0x) " 1694 "of xPS' signature at offset from IS 0x%04x: %s\n"), 1695 i, bytep[i], cmd.tf_addr, strerror(errno)); 1696 return (FWFLASH_FAILURE); 1697 } 1698 } 1699 return (FWFLASH_SUCCESS); 1700} 1701 1702 1703 1704/* 1705 * This function contains "Begin/End documentation departure point" 1706 * because the reality of what actually _works_ is quite, quite 1707 * different to what is written in the Mellanox HCA Flash Application 1708 * Programming Guide. 1709 */ 1710static int 1711tavor_blast_image(int fd, int prisec, uint32_t hcafia, uint32_t sectsz, 1712 struct mlx_xps *newxps) 1713{ 1714 uint32_t i, j, rv; 1715 uint32_t startsectimg, startsecthca, numsect; 1716 1717 if ((prisec != 1) && (prisec != 2)) { 1718 logmsg(MSG_ERROR, 1719 "tavor: invalid image number requested (%d)\n"); 1720 return (FWFLASH_FAILURE); 1721 } 1722 1723 /* Begin documentation departure point */ 1724 1725 /* zero the HCA's PPS signature and CRC */ 1726 if (tavor_zero_sig_crc(fd, (prisec * sectsz)) 1727 != FWFLASH_SUCCESS) { 1728 logmsg(MSG_INFO, 1729 "tavor: Unable zero HCA's %s signature " 1730 "and CRC16 fields\n", 1731 ((prisec == 1) ? "PPS" : "SPS")); 1732 return (FWFLASH_FAILURE); 1733 } 1734 1735 logmsg(MSG_INFO, "tavor: zeroing HCA's %s sig and crc\n", 1736 (prisec == 1) ? "pps" : "sps"); 1737 1738 /* End documentation departure point */ 1739 1740 /* make sure we don't inadvertently overwrite bits */ 1741 1742 startsectimg = MLXSWAPBITS32(newxps->fia) / sectsz; 1743 startsecthca = hcafia / sectsz; 1744 1745 numsect = (MLXSWAPBITS32(newxps->fis) / sectsz) + 1746 ((MLXSWAPBITS32(newxps->fis) % sectsz) ? 1 : 0); 1747 1748 logmsg(MSG_INFO, "tavor: %s imgsize 0x%0x startsecthca %d, " 1749 "startsectimg %d, num sectors %d\n", 1750 (prisec == 1) ? "PFI" : "SFI", MLXSWAPBITS32(newxps->fis), 1751 startsecthca, startsectimg, numsect); 1752 1753 for (i = 0; i < numsect; i++) { 1754 1755 j = (MLXSWAPBITS32(newxps->fia) + (i * sectsz)) / 4; 1756 1757 logmsg(MSG_INFO, "tavor: image offset 0x%0x\n", j); 1758 logmsg(MSG_INFO, "tavor: writing HCA sector %d\n", 1759 i + startsecthca); 1760 1761 if (tavor_write_sector(fd, i + startsecthca, 1762 &verifier->fwimage[j]) 1763 != FWFLASH_SUCCESS) { 1764 logmsg(MSG_ERROR, 1765 gettext("tavor: Unable to write " 1766 "sector %d to HCA\n"), 1767 i + startsecthca); 1768 return (FWFLASH_FAILURE); 1769 } 1770 (void) printf(" ."); 1771 1772 rv = tavor_readback(fd, i + startsecthca, sectsz); 1773 if (rv != FWFLASH_SUCCESS) { 1774 logmsg(MSG_ERROR, 1775 gettext("tavor: Unable to read sector %d " 1776 "back from HCA\n"), i + startsecthca); 1777 return (FWFLASH_FAILURE); 1778 } 1779 (void) printf(" | "); 1780 } 1781 1782 /* Begin documentation departure point */ 1783 1784 /* invalidate the xps signature and fia fields */ 1785 newxps->signature = 0xffffffff; 1786 newxps->crc16 = 0xffff; 1787 /* we put the fia back to imgfia later */ 1788 newxps->fia = 0xffffffff; 1789 /* End documentation departure point */ 1790 1791 /* success so far, now burn the new xPS */ 1792 if (tavor_write_sector(fd, prisec, (int *)newxps) 1793 != FWFLASH_SUCCESS) { 1794 logmsg(MSG_ERROR, 1795 gettext("tavor: Unable to write new %s " 1796 "pointer sector to HCA\n"), 1797 (prisec == 1) ? "primary" : "secondary"); 1798 return (FWFLASH_FAILURE); 1799 } 1800 (void) printf(" ."); 1801 1802 /* Begin documentation departure point */ 1803 1804 /* write new fia to the HCA's pps */ 1805 logmsg(MSG_INFO, "tavor: writing new fia (0x%0x) to HCA\n", 1806 MLXSWAPBITS32(newxps->fia)); 1807 1808 if (tavor_write_xps_fia(fd, (prisec * sectsz), 1809 MLXSWAPBITS32(hcafia)) != FWFLASH_SUCCESS) { 1810 logmsg(MSG_ERROR, 1811 gettext("tavor: Unable to update HCA's %s " 1812 "pointer sector FIA record\n"), 1813 (prisec == 1) ? "primary" : "secondary"); 1814 return (FWFLASH_FAILURE); 1815 } 1816 1817 /* don't forget the byte-swapping */ 1818 newxps->fia = MLXSWAPBITS32(hcafia); 1819 newxps->signature = 1820 (uint32_t)MLXSWAPBITS32(FLASH_PS_SIGNATURE); 1821 newxps->crc16 = 1822 MLXSWAPBITS16(crc16((uint8_t *)newxps, FLASH_PS_CRC16_SIZE)); 1823 1824 logmsg(MSG_INFO, "tavor: writing new fia 0x%0x, " 1825 "sig 0x%0x and new crc16 0x%0x\n", 1826 newxps->fia, MLXSWAPBITS32(newxps->signature), 1827 newxps->crc16); 1828 1829 if (tavor_write_xps_crc_sig(fd, (prisec * sectsz), 1830 newxps->crc16) != FWFLASH_SUCCESS) { 1831 /* 1832 * Now we're REALLY hosed. If the card comes up at all, 1833 * expect it to be in "Maintenance Mode". 1834 */ 1835 logmsg(MSG_ERROR, 1836 gettext("tavor: Unable to update HCA's %s CRC " 1837 "and Firmware Image signature fields\n"), 1838 (prisec == 1) ? "PPS" : "SPS"); 1839 return (FWFLASH_FAILURE); 1840 } 1841 1842 rv = tavor_readback(fd, prisec, sectsz); 1843 if (rv != FWFLASH_SUCCESS) { 1844 logmsg(MSG_ERROR, 1845 gettext("tavor: Unable to read %s pointer sector " 1846 "from HCA\n"), 1847 (prisec == 1) ? "Primary" : "Secondary"); 1848 return (FWFLASH_FAILURE); 1849 } 1850 (void) printf(" |"); 1851 /* End documentation departure point */ 1852 return (FWFLASH_SUCCESS); 1853} 1854 1855 1856static int 1857tavor_readback(int infd, int whichsect, int sectsz) 1858{ 1859 uint32_t *data; 1860 tavor_flash_ioctl_t cmd; 1861 int rv; 1862 1863 bzero(&cmd, sizeof (tavor_flash_ioctl_t)); 1864 data = calloc(1, sectsz); /* assumption! */ 1865 1866 cmd.tf_type = TAVOR_FLASH_READ_SECTOR; 1867 cmd.tf_sector_num = whichsect; 1868 cmd.tf_sector = (caddr_t)data; 1869 rv = ioctl(infd, TAVOR_IOCTL_FLASH_READ, &cmd); 1870 if (rv < 0) { 1871 logmsg(MSG_INFO, 1872 "tavor: UNABLE TO READ BACK SECTOR %d from HCA\n", 1873 whichsect); 1874 return (FWFLASH_FAILURE); 1875 } 1876 free(data); 1877 return (FWFLASH_SUCCESS); 1878} 1879 1880 1881/* 1882 * crc16 - computes 16 bit crc of supplied buffer. 1883 * image should be in network byteorder 1884 * result is returned in host byteorder form 1885 */ 1886static uint16_t 1887crc16(uint8_t *image, uint32_t size) 1888{ 1889 const uint16_t poly = 0x100b; 1890 uint32_t crc = 0xFFFF; 1891 uint32_t word; 1892 uint32_t i, j; 1893 1894 for (i = 0; i < size / 4; i++) { 1895 word = (image[4 * i] << 24) | 1896 (image[4 * i + 1] << 16) | 1897 (image[4 * i + 2] << 8) | 1898 (image[4 * i + 3]); 1899 1900 for (j = 0; j < 32; j++) { 1901 if (crc & 0x8000) { 1902 crc = (((crc << 1) | 1903 (word >> 31)) ^ poly) & 0xFFFF; 1904 } else { 1905 crc = ((crc << 1) | (word >> 31)) & 0xFFFF; 1906 } 1907 word = (word << 1) & 0xFFFFFFFF; 1908 } 1909 } 1910 1911 for (i = 0; i < 16; i++) { 1912 if (crc & 0x8000) { 1913 crc = ((crc << 1) ^ poly) & 0xFFFF; 1914 } else { 1915 crc = (crc << 1) & 0xFFFF; 1916 } 1917 } 1918 1919 crc = crc ^ 0xFFFF; 1920 return (crc & 0xFFFF); 1921} 1922