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.
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.
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]
23 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
27 * IB (InfiniBand) specific functions.
31 * The reference for the functions in this file is the
33 * Mellanox HCA Flash Programming Application Note
34 * (Mellanox document number 2205AN)
35 * rev 1.44, 2007. Chapter 4 in particular.
37 * NOTE: this Mellanox document is labelled Confidential
38 * so DO NOT move this file out of usr/closed without
39 * explicit approval from Sun Legal.
44 * 1. flash read is done in 32 bit quantities, and the driver returns
45 * data in host byteorder form.
46 * 2. flash write is done in 8 bit quantities by the driver.
47 * 3. data in the flash should be in network byteorder (bigendian).
48 * 4. data in image files is in network byteorder form.
49 * 5. data in image structures in memory is kept in network byteorder.
50 * 6. the functions in this file deal with data in host byteorder form.
57 #include <sys/types.h>
59 #include <sys/sysmacros.h>
60 #include <sys/queue.h>
66 #include <sys/byteorder.h>
68 #include <libintl.h> /* for gettext(3c) */
70 #include <fwflash/fwflash.h>
71 #include "../../hdrs/MELLANOX.h"
72 #include "../../hdrs/tavor_ib.h"
76 char *devprefix
= "/devices";
77 char drivername
[] = "tavor\0";
78 char *devsuffix
= ":devctl";
81 extern di_node_t rootnode
;
83 extern struct fw_plugin
*self
;
84 extern struct vrfyplugin
*verifier
;
85 extern int fwflash_debug
;
88 /* required functions for this plugin */
89 int fw_readfw(struct devicelist
*device
, char *filename
);
90 int fw_writefw(struct devicelist
*device
);
91 int fw_identify(int start
);
95 /* helper functions */
97 static int tavor_identify(struct devicelist
*thisdev
);
98 static int tavor_get_guids(struct ib_encap_ident
*handle
);
99 static int tavor_close(struct devicelist
*flashdev
);
100 static void tavor_cisco_extensions(mlx_xps_t
*hcaxps
, mlx_xps_t
*diskxps
);
101 static uint16_t crc16(uint8_t *image
, uint32_t size
);
102 static int tavor_write_sector(int fd
, int sectnum
, int32_t *data
);
103 static int tavor_zero_sig_crc(int fd
, uint32_t start
);
104 static int tavor_write_xps_fia(int fd
, uint32_t offset
, uint32_t start
);
105 static int tavor_write_xps_crc_sig(int fd
, uint32_t offset
, uint16_t newcrc
);
106 static int tavor_blast_image(int fd
, int prisec
, uint32_t hcafia
,
107 uint32_t sectsz
, struct mlx_xps
*newxps
);
108 static int tavor_readback(int infd
, int whichsect
, int sectsz
);
113 fw_readfw(struct devicelist
*flashdev
, char *filename
)
116 int rv
= FWFLASH_SUCCESS
;
118 mode_t mode
= S_IRUSR
| S_IWUSR
;
123 uint32_t pfia
, sfia
, psz
, ssz
;
124 tavor_flash_ioctl_t tfi_data
;
125 struct ib_encap_ident
*manuf
;
126 struct mlx_xps
*lpps
;
127 struct mlx_xps
*lsps
;
128 #if defined(_LITTLE_ENDIAN)
133 if ((fd
= open(filename
, O_RDWR
|O_CREAT
|O_DSYNC
, mode
)) < 0) {
135 gettext("tavor: Unable to open specified file "
136 "(%s) for writing: %s\n"), filename
, strerror(errno
));
137 return (FWFLASH_FAILURE
);
141 (struct ib_encap_ident
*)(uintptr_t)flashdev
->ident
->encap_ident
;
142 lpps
= (struct mlx_xps
*)(uintptr_t)manuf
->pps
;
143 lsps
= (struct mlx_xps
*)(uintptr_t)manuf
->sps
;
146 * Now that we've got an open, init'd fd, we can read the
147 * xFI from the device itself. We've already got the IS
148 * and xPS stored in manuf.
151 /* stash some values for later */
152 pfia
= MLXSWAPBITS32(lpps
->fia
);
153 sfia
= MLXSWAPBITS32(lsps
->fia
);
154 psz
= MLXSWAPBITS32(lpps
->fis
);
155 ssz
= MLXSWAPBITS32(lsps
->fis
);
157 /* Invariant Sector comes first */
158 if ((j
= write(fd
, manuf
->inv
, manuf
->sector_sz
)) !=
161 gettext("tavor: Unable to write HCA Invariant Sector "
162 "(%d of %d bytes)\n"),
163 j
, manuf
->sector_sz
);
164 (void) tavor_close(flashdev
);
165 return (FWFLASH_FAILURE
);
167 fprintf(stdout
, gettext("Writing ."));
170 /* followed by Primary Pointer Sector */
171 if ((j
= write(fd
, manuf
->pps
, manuf
->sector_sz
)) !=
174 gettext("tavor: Unable to write HCA Primary Pointer "
175 "Sector (%d of %d bytes)\n)"),
176 j
, manuf
->sector_sz
);
177 (void) tavor_close(flashdev
);
178 return (FWFLASH_FAILURE
);
180 fprintf(stdout
, " .");
183 /* followed by Secondary Pointer Sector */
184 if ((j
= write(fd
, manuf
->sps
, manuf
->sector_sz
)) !=
187 gettext("tavor: Unable to write HCA Secondary Pointer "
188 "Sector (%d of %d bytes)\n"),
189 j
, manuf
->sector_sz
);
190 (void) tavor_close(flashdev
);
191 return (FWFLASH_FAILURE
);
193 fprintf(stdout
, " .");
196 /* Now for the xFI sectors */
197 pchunks
= psz
/ manuf
->sector_sz
;
199 if ((psz
% manuf
->sector_sz
) != 0)
202 /* Get the PFI, then the SFI */
203 if ((raw_pfi
= calloc(1, pchunks
* manuf
->sector_sz
)) == NULL
) {
205 gettext("tavor: Unable to allocate space for "
206 "device's Primary Firmware Image\n"));
207 return (FWFLASH_FAILURE
);
209 bzero(&tfi_data
, sizeof (tavor_flash_ioctl_t
));
210 tfi_data
.tf_type
= TAVOR_FLASH_READ_SECTOR
;
211 j
= pfia
/ manuf
->sector_sz
;
213 for (offset
= 0; offset
< psz
; offset
+= manuf
->sector_sz
) {
214 tfi_data
.tf_sector_num
= j
;
215 tfi_data
.tf_sector
= (caddr_t
)&raw_pfi
[offset
];
216 rv
= ioctl(manuf
->fd
, TAVOR_IOCTL_FLASH_READ
, &tfi_data
);
219 gettext("tavor: Unable to read sector %d of "
220 "HCA Primary Firmware Image\n"), j
);
222 (void) tavor_close(flashdev
);
223 return (FWFLASH_FAILURE
);
229 * It appears that the tavor driver is returning a signed
230 * -1 (0xffff) in unassigned quadlets if we read a sector
231 * that isn't full, so for backwards compatibility with
232 * earlier fwflash versions, we need to zero out what
233 * remains in the sector.
235 bzero(&raw_pfi
[psz
], (pchunks
* manuf
->sector_sz
) - psz
);
237 #if defined(_LITTLE_ENDIAN)
238 ptr
= (uint32_t *)(uintptr_t)raw_pfi
;
239 for (j
= 0; j
< (pchunks
* manuf
->sector_sz
/ 4); j
++) {
240 ptr
[j
] = htonl(ptr
[j
]);
246 if ((j
= write(fd
, raw_pfi
, pchunks
* manuf
->sector_sz
))
247 != pchunks
* manuf
->sector_sz
) {
249 gettext("tavor: Unable to write HCA Primary Firmware "
250 "Image data (%d of %d bytes)\n"),
251 j
, pchunks
* manuf
->sector_sz
);
253 (void) tavor_close(flashdev
);
254 return (FWFLASH_FAILURE
);
256 fprintf(stdout
, " .");
259 pchunks
= ssz
/ manuf
->sector_sz
;
261 if ((ssz
% manuf
->sector_sz
) != 0)
265 * We allocate wholenum sectors, but only write out what we
266 * really need (ssz bytes)
268 if ((raw_sfi
= calloc(1, pchunks
* manuf
->sector_sz
)) == NULL
) {
270 gettext("tavor: Unable to allocate space for "
271 "device's Secondary Firmware Image\n"));
273 return (FWFLASH_FAILURE
);
275 bzero(&tfi_data
, sizeof (tavor_flash_ioctl_t
));
276 tfi_data
.tf_type
= TAVOR_FLASH_READ_SECTOR
;
278 /* get our starting sector number */
279 j
= sfia
/ manuf
->sector_sz
;
281 for (offset
= 0; offset
< ssz
; offset
+= manuf
->sector_sz
) {
282 tfi_data
.tf_sector_num
= j
;
283 tfi_data
.tf_sector
= (caddr_t
)&raw_sfi
[offset
];
284 if ((rv
= ioctl(manuf
->fd
, TAVOR_IOCTL_FLASH_READ
,
287 gettext("tavor: Unable to read sector %d of "
288 "HCA Secondary Firmware Image\n"), j
);
289 (void) tavor_close(flashdev
);
292 return (FWFLASH_FAILURE
);
298 * It appears that the tavor driver is returning a signed
299 * -1 (0xffff) in unassigned quadlets if we read a sector
300 * that isn't full, so for backwards compatibility with
301 * earlier fwflash versions, we need to zero out what
302 * remains in the sector.
304 bzero(&raw_sfi
[ssz
], (pchunks
* manuf
->sector_sz
) - ssz
);
306 #if defined(_LITTLE_ENDIAN)
307 ptr
= (uint32_t *)(uintptr_t)raw_sfi
;
308 for (j
= 0; j
< ssz
/ 4; j
++) {
309 ptr
[j
] = htonl(ptr
[j
]);
313 /* only write out ssz bytes */
314 if ((j
= write(fd
, raw_sfi
, ssz
)) != ssz
) {
316 gettext("tavor: Unable to write HCA Secondary Firmware "
317 "Image data (%d of %d bytes)\n"),
319 (void) tavor_close(flashdev
);
322 return (FWFLASH_FAILURE
);
324 fprintf(stdout
, " .\n");
333 * this should succeed, but we don't just blindly ignore
334 * the return code cos that would be obnoxious.
336 return (tavor_close(flashdev
));
341 * If we're invoking fw_writefw, then flashdev is a valid,
342 * flashable device as determined by fw_identify().
344 * If verifier is null, then we haven't been called following a firmware
345 * image verification load operation.
348 fw_writefw(struct devicelist
*flashdev
)
352 uint32_t j
, sectsz
, hpfia
, hsfia
;
353 uint32_t ipfia
, isfia
, ipfis
, isfis
;
354 struct ib_encap_ident
*manuf
;
356 struct mlx_xps
*ipps
, *lpps
;
357 struct mlx_xps
*isps
, *lsps
;
358 struct mlx_xfi
*ipfi
, *isfi
;
361 * linv, lpps/lsps are from the HCA whereas
362 * iinv/ipps/isps are in the on-disk firmware image that
363 * we've read in to the verifier->fwimage field, and are
364 * about to do some hand-waving with.
368 * From the Mellanox HCA Flash programming app note,
369 * start of ch4, page36:
370 * ===========================================================
371 * Failsafe firmware programming ensures that an HCA device
372 * can boot up in a functional mode even if the burn process
373 * was interrupted (because of a power failure, reboot, user
374 * interrupt, etc.). This can be implemented by burning the
375 * new image to a vacant region on the Flash, and erasing the
376 * old image only after the new image is successfully burnt.
377 * This method ensures that there is at least one valid firmware
378 * image on the Flash at all times. Thus, in case a firmware
379 * image programming process is aborted for any reason, the HCA
380 * will still be able to boot up properly using the valid image
384 * 4.1 Notes on Image Programming of HCA Flashes
385 * Following are some general notes regarding the Flash memory
386 * in the context of Mellanox HCA devices:
387 * > The Flash memory is divided into sectors, and each sector
388 * must be erased prior to its programming.
389 * > The image to be burnt is byte packed and should be programmed
390 * into the Flash byte by byte, preserving the byte order, starting
391 * at offset zero. No amendments are needed for endianess.
392 * > It is recommended to program the Flash while the device is idle.
393 * ===========================================================
395 * The comment about endianness is particularly important for us
396 * since we operate on both big- and litte-endian hosts - it means
397 * we have to do some byte-swapping gymnastics
401 * From the Mellanox HCA Flash programming app note,
402 * section 4.2.5 on page 41/42:
403 * ===========================================================
404 * 4.2.5 Failsafe Programming Example
405 * This section provides an example of a programming utility
406 * that performs a Failsafe firmware image update. The flow
407 * ensures that there is at least one valid firmware image on
408 * the Flash at all times. Thus, in case a firmware image pro-
409 * gramming process is aborted for any reason, the HCA will
410 * still be able to boot up properly using the valid image on
411 * the Flash. Any other flow that ensures the above is also
412 * considered a Failsafe firmware update.
415 * * Check the validity of the PPS and SPS:
416 * > If both PSs are valid, arbitrarily invalidate one of them
417 * > If both PSs are invalid, the image on flash is corrupted
418 * and cannot be updated in a Failsafe way. The user must
419 * burn a full image in a non-failsafe way.
421 * > If only the PPS is valid:
422 * i.Burn the secondary image (erase each sector first)
423 * ii.Burn the SPS with the correct image address (FIA field)
424 * iii.Invalidate the PPS
426 * > If only the SPS is valid:
427 * i.Burn the primary image (erase each sector first)
428 * ii.Burn the PPS with the correct image address (FIA field)
429 * iii.Invalidate the SPS
430 * ===========================================================
434 * Other required tasks called from this function:
436 * * check for CISCO boot extensions in the current xPS, and
437 * if found, set them in the new xPS
439 * * update the xPS CRC field
441 * _then_ you can setup the outbound transfer to the HCA flash.
445 * VERY IMPORTANT NOTE:
446 * The above text from the app note programming guide v1.44 does
447 * NOT match reality. If you try to do exactly what the above
448 * text specifies then you'll wind up with a warm, brick-like
449 * HCA that if you're really lucky has booted up in maintenance
450 * mode for you to re-flash.
452 * What you need to do is follow the example of the previous
453 * (v1.2 etc) version from the ON gate - which is what happens
454 * in this file. Basically - don't erase prior to writing a new
455 * sector, and _read back_ each sector after writing it. Especially
456 * the pointer sectors. Otherwise you'll get a warm brick.
460 (struct ib_encap_ident
*)(uintptr_t)flashdev
->ident
->encap_ident
;
461 lpps
= (struct mlx_xps
*)(uintptr_t)manuf
->pps
;
462 lsps
= (struct mlx_xps
*)(uintptr_t)manuf
->sps
;
463 iinv
= (struct mlx_is
*)&verifier
->fwimage
[0];
464 sectsz
= 1 << MLXSWAPBITS16(iinv
->log2sectsz
+ iinv
->log2sectszp
);
465 ipps
= (struct mlx_xps
*)&verifier
->fwimage
[sectsz
/4];
466 isps
= (struct mlx_xps
*)&verifier
->fwimage
[sectsz
/2];
469 * If we get here, then the verifier has _already_ checked that
470 * the part number in the firmware image matches that in the HCA,
471 * so we only need this check if there's no hardware info available
472 * already after running through fw_identify().
474 if (manuf
->pn_len
== 0) {
477 (void) printf("\nUnable to completely verify that this "
478 "firmware image\n\t(%s)\nis compatible with your "
480 verifier
->imgfile
, flashdev
->access_devname
);
481 (void) printf("\n\tDo you really want to continue? (Y/N): ");
483 (void) fflush(stdin
);
485 if (resp
!= 'Y' && resp
!= 'y') {
486 (void) printf("\nNot proceeding with flash "
487 "operation of %s on %s\n",
488 verifier
->imgfile
, flashdev
->access_devname
);
489 return (FWFLASH_FAILURE
);
493 /* stash these for later */
494 hpfia
= MLXSWAPBITS32(lpps
->fia
);
495 hsfia
= MLXSWAPBITS32(lsps
->fia
);
497 /* where does the on-disk image think everything is at? */
498 ipfia
= MLXSWAPBITS32(ipps
->fia
);
499 isfia
= MLXSWAPBITS32(isps
->fia
);
500 ipfis
= MLXSWAPBITS32(ipps
->fis
);
501 isfis
= MLXSWAPBITS32(isps
->fis
);
503 logmsg(MSG_INFO
, "tavor: hpfia 0x%0x hsfia 0x%0x "
504 "ipfia 0x%0x isfia 0x%0x ipfis 0x%0x isfis 0x%0x\n",
505 hpfia
, hsfia
, ipfia
, isfia
, ipfis
, isfis
);
507 if ((ipfis
+ isfis
) > manuf
->device_sz
) {
509 * This is bad - don't flash an image which is larger
510 * than the size of the HCA's flash
513 gettext("tavor: on-disk firmware image size (0x%lx bytes) "
514 "exceeds HCA's flash memory size (0x%lx bytes)!\n"),
515 ipfis
+ isfis
, manuf
->device_sz
);
517 gettext("tavor: not flashing this image (%s)\n"),
519 return (FWFLASH_FAILURE
);
523 * The Mellanox HCA Flash app programming note does _not_
524 * specify that you have to insert the HCA's guid section
525 * into the flash image before burning it.
527 * HOWEVER it was determined during testing that this is
528 * actually required (otherwise your HCA's GUIDs revert to
529 * the manufacturer's defaults, ugh!), so we'll do it too.
532 ipfi
= (struct mlx_xfi
*)&verifier
->fwimage
[ipfia
/4];
533 isfi
= (struct mlx_xfi
*)&verifier
->fwimage
[isfia
/4];
536 * Here we check against our stored, properly-bitwise-munged copy
537 * of the HCA's GUIDS. If they're not set to default AND the OUI
538 * is MLX_OUI, then they're ok so we copy the HCA's version into
539 * our in-memory copy and blat it. If the GUIDs don't match this
540 * condition, then we use the default GUIDs which are in the on-disk
541 * firmware image instead.
543 if (((manuf
->ibguids
[0] != MLX_DEFAULT_NODE_GUID
) &&
544 (manuf
->ibguids
[1] != MLX_DEFAULT_P1_GUID
) &&
545 (manuf
->ibguids
[2] != MLX_DEFAULT_P2_GUID
) &&
546 (manuf
->ibguids
[3] != MLX_DEFAULT_SYSIMG_GUID
)) &&
547 ((((manuf
->ibguids
[0] & HIGHBITS64
) >> OUISHIFT
) == MLX_OUI
) ||
548 (((manuf
->ibguids
[1] & HIGHBITS64
) >> OUISHIFT
) == MLX_OUI
) ||
549 (((manuf
->ibguids
[2] & HIGHBITS64
) >> OUISHIFT
) == MLX_OUI
) ||
550 (((manuf
->ibguids
[3] & HIGHBITS64
) >> OUISHIFT
) == MLX_OUI
))) {
551 /* The GUIDs are ok, blat them into the in-memory image */
552 j
= ((ipfia
+ MLXSWAPBITS32(ipfi
->nguidptr
)) / 4) - 4;
553 bcopy(manuf
->pri_guid_section
, &verifier
->fwimage
[j
],
554 sizeof (struct mlx_guid_sect
));
555 j
= ((isfia
+ MLXSWAPBITS32(isfi
->nguidptr
)) / 4) - 4;
556 bcopy(manuf
->sec_guid_section
, &verifier
->fwimage
[j
],
557 sizeof (struct mlx_guid_sect
));
560 * The GUIDs are hosed, we'll have to use
561 * the vendor defaults in the image instead
564 gettext("tavor: HCA's GUID section is set to defaults or "
565 " is invalid, using firmware image manufacturer's "
566 "default GUID section instead\n"));
569 /* Just in case somebody is booting from this card... */
570 tavor_cisco_extensions(lpps
, ipps
);
571 tavor_cisco_extensions(lsps
, isps
);
573 /* first we write the secondary image and SPS, then the primary */
574 rv
= tavor_blast_image(manuf
->fd
, 2, hsfia
, manuf
->sector_sz
, isps
);
575 if (rv
!= FWFLASH_SUCCESS
) {
577 "tavor: failed to update #2 firmware image\n");
578 (void) tavor_close(flashdev
);
579 return (FWFLASH_FAILURE
);
582 rv
= tavor_blast_image(manuf
->fd
, 1, hpfia
, manuf
->sector_sz
, ipps
);
583 if (rv
!= FWFLASH_SUCCESS
) {
585 "tavor: failed to update #1 firmware image\n");
586 (void) tavor_close(flashdev
);
587 return (FWFLASH_FAILURE
);
590 /* final update marker to the user */
591 (void) printf(" +\n");
592 return (tavor_close(flashdev
));
597 * The fw_identify() function walks the device
598 * tree trying to find devices which this plugin
601 * The parameter "start" gives us the starting index number
602 * to give the device when we add it to the fw_devices list.
604 * firstdev is allocated by us and we add space as necessary
608 fw_identify(int start
)
610 int rv
= FWFLASH_FAILURE
;
612 struct devicelist
*newdev
;
617 thisnode
= di_drv_first_node(drivername
, rootnode
);
619 if (thisnode
== DI_NODE_NIL
) {
620 logmsg(MSG_INFO
, gettext("No %s nodes in this system\n"),
625 /* we've found one, at least */
626 for (; thisnode
!= DI_NODE_NIL
; thisnode
= di_drv_next_node(thisnode
)) {
628 devpath
= di_devfs_path(thisnode
);
630 if ((newdev
= calloc(1, sizeof (struct devicelist
)))
633 gettext("tavor identification function: unable "
634 "to allocate space for device entry\n"));
635 di_devfs_path_free(devpath
);
639 /* calloc enough for /devices + devpath + ":devctl" + '\0' */
640 devlength
= strlen(devpath
) + strlen(devprefix
) +
641 strlen(devsuffix
) + 2;
643 if ((newdev
->access_devname
= calloc(1, devlength
)) == NULL
) {
644 logmsg(MSG_ERROR
, gettext("Unable to calloc space "
645 "for a devfs name\n"));
646 di_devfs_path_free(devpath
);
648 return (FWFLASH_FAILURE
);
650 snprintf(newdev
->access_devname
, devlength
,
651 "%s%s%s", devprefix
, devpath
, devsuffix
);
653 /* CHECK VARIOUS IB THINGS HERE */
655 if ((newdev
->ident
= calloc(1, sizeof (struct vpr
))) == NULL
) {
657 gettext("tavor: Unable to allocate space for a "
658 "device identification record\n"));
659 (void) free(newdev
->access_devname
);
661 di_devfs_path_free(devpath
);
662 return (FWFLASH_FAILURE
);
665 rv
= tavor_identify(newdev
);
666 if (rv
== FWFLASH_FAILURE
) {
667 (void) free(newdev
->ident
);
668 (void) free(newdev
->access_devname
);
670 di_devfs_path_free(devpath
);
674 if ((newdev
->drvname
= calloc(1, strlen(drivername
) + 1))
676 logmsg(MSG_ERROR
, gettext("Unable to allocate space "
677 "for a driver name\n"));
678 (void) free(newdev
->ident
);
679 (void) free(newdev
->access_devname
);
681 di_devfs_path_free(devpath
);
682 return (FWFLASH_FAILURE
);
685 (void) strlcpy(newdev
->drvname
, drivername
,
686 strlen(drivername
) + 1);
688 /* this next bit is backwards compatibility - "IB\0" */
689 if ((newdev
->classname
= calloc(1, 3)) == NULL
) {
690 logmsg(MSG_ERROR
, gettext("Unable to allocate space "
691 "for a class name\n"));
692 (void) free(newdev
->drvname
);
693 (void) free(newdev
->ident
);
694 (void) free(newdev
->access_devname
);
696 di_devfs_path_free(devpath
);
697 return (FWFLASH_FAILURE
);
699 (void) strlcpy(newdev
->classname
, "IB", 3);
703 newdev
->plugin
= self
;
705 di_devfs_path_free(devpath
);
706 TAILQ_INSERT_TAIL(fw_devices
, newdev
, nextdev
);
709 if (fwflash_debug
!= 0) {
710 struct devicelist
*tempdev
;
712 TAILQ_FOREACH(tempdev
, fw_devices
, nextdev
) {
713 logmsg(MSG_INFO
, "fw_identify:\n");
714 logmsg(MSG_INFO
, "\ttempdev @ 0x%lx\n"
715 "\t\taccess_devname: %s\n"
716 "\t\tdrvname: %s\tclassname: %s\n"
717 "\t\tident->vid: %s\n"
718 "\t\tident->pid: %s\n"
719 "\t\tident->revid: %s\n"
725 "\t\tplugin @ 0x%lx\n\n",
727 tempdev
->access_devname
,
728 tempdev
->drvname
, newdev
->classname
,
731 tempdev
->ident
->revid
,
733 (tempdev
->addresses
[0] ? tempdev
->addresses
[0] :
735 (tempdev
->addresses
[1] ? tempdev
->addresses
[1] :
737 (tempdev
->addresses
[2] ? tempdev
->addresses
[2] :
739 (tempdev
->addresses
[3] ? tempdev
->addresses
[3] :
745 return (FWFLASH_SUCCESS
);
751 fw_devinfo(struct devicelist
*thisdev
)
754 struct ib_encap_ident
*encap
;
757 encap
= (struct ib_encap_ident
*)thisdev
->ident
->encap_ident
;
759 fprintf(stdout
, gettext("Device[%d] %s\n Class [%s]\n"),
760 thisdev
->index
, thisdev
->access_devname
, thisdev
->classname
);
762 fprintf(stdout
, "\t");
764 /* Mellanox HCA Flash app note, p40, #4.2.3 table 9 */
766 gettext("GUID: System Image - %s\n"),
767 thisdev
->addresses
[3]);
769 gettext("\t\tNode Image - %s\n"),
770 thisdev
->addresses
[0]);
772 gettext("\t\tPort 1\t - %s\n"),
773 thisdev
->addresses
[1]);
775 gettext("\t\tPort 2\t - %s\n"),
776 thisdev
->addresses
[2]);
778 if (encap
->pn_len
!= 0) {
780 gettext("\tFirmware revision : %s\n"
781 "\tProduct\t\t: %s %X\n"
783 thisdev
->ident
->revid
,
786 encap
->info
.mlx_psid
);
789 gettext("\tFirmware revision : %s\n"
790 "\tNo hardware information available for this "
791 "device\n"), thisdev
->ident
->revid
);
793 fprintf(stdout
, "\n\n");
795 return (tavor_close(thisdev
));
800 * Helper functions lurk beneath this point
805 * tavor_identify performs the following actions:
807 * allocates and assigns thisdev->vpr
809 * allocates space for the 4 GUIDs which each IB device must have
810 * queries the tavor driver for this device's GUIDs
812 * determines the hardware vendor, so that thisdev->vpr->vid
813 * can be set correctly
816 tavor_identify(struct devicelist
*thisdev
)
818 int rv
= FWFLASH_SUCCESS
;
821 tavor_flash_init_ioctl_t init_ioctl
;
822 tavor_flash_ioctl_t info
;
823 struct ib_encap_ident
*manuf
;
828 #if defined(_LITTLE_ENDIAN)
832 /* open the device */
833 /* hook thisdev->ident->encap_ident to ib_encap_ident */
834 /* check that all the bits are sane */
835 /* return success, if warranted */
838 if ((fd
= open(thisdev
->access_devname
, O_RDONLY
)) < 0) {
840 gettext("tavor: Unable to open a %s-attached "
841 "device node: %s: %s\n"), drivername
,
842 thisdev
->access_devname
, strerror(errno
));
843 return (FWFLASH_FAILURE
);
846 if ((manuf
= calloc(1, sizeof (ib_encap_ident_t
))) == NULL
) {
848 gettext("tavor: Unable to calloc space for a "
849 "%s-attached handle structure\n"),
851 return (FWFLASH_FAILURE
);
853 manuf
->magic
= FWFLASH_IB_MAGIC_NUMBER
;
854 manuf
->state
= FWFLASH_IB_STATE_NONE
;
857 thisdev
->ident
->encap_ident
= manuf
;
859 bzero(&init_ioctl
, sizeof (tavor_flash_init_ioctl_t
));
860 bzero(&cfi
, sizeof (cfi_t
));
862 * Inform driver that this command supports the Intel Extended
865 cfi
.cfi_char
[0x10] = 'M';
866 cfi
.cfi_char
[0x11] = 'X';
867 cfi
.cfi_char
[0x12] = '2';
868 init_ioctl
.tf_cfi_info
[0x4] = MLXSWAPBITS32(cfi
.cfi_int
[0x4]);
871 ret
= ioctl(fd
, TAVOR_IOCTL_FLASH_INIT
, &init_ioctl
);
874 gettext("ib: TAVOR_IOCTL_FLASH_INIT failed: %s\n"),
878 return (FWFLASH_FAILURE
);
881 manuf
->hwrev
= init_ioctl
.tf_hwrev
;
883 logmsg(MSG_INFO
, "tavor_identify: init_ioctl: hwrev: %X, "
884 "fwver: %d.%d.%04d\n", init_ioctl
.tf_hwrev
,
885 init_ioctl
.tf_fwrev
.tfi_maj
, init_ioctl
.tf_fwrev
.tfi_min
,
886 init_ioctl
.tf_fwrev
.tfi_sub
);
889 * Determine whether the attached driver supports the Intel or
890 * AMD Extended CFI command sets. If it doesn't support either,
891 * then we're hosed, so error out.
893 for (i
= 0; i
< TAVOR_FLASH_CFI_SIZE_QUADLET
; i
++) {
894 cfi
.cfi_int
[i
] = MLXSWAPBITS32(init_ioctl
.tf_cfi_info
[i
]);
896 manuf
->cmd_set
= cfi
.cfi_char
[0x13];
898 if (cfi
.cfi_char
[0x10] == 'Q' &&
899 cfi
.cfi_char
[0x11] == 'R' &&
900 cfi
.cfi_char
[0x12] == 'Y') {
901 /* make sure the cmd set is AMD */
902 if (manuf
->cmd_set
!= TAVOR_FLASH_AMD_CMDSET
) {
904 gettext("tavor: Unsupported flash device "
908 return (FWFLASH_FAILURE
);
910 /* set some defaults */
911 manuf
->sector_sz
= TAVOR_FLASH_SECTOR_SZ_DEFAULT
;
912 manuf
->device_sz
= TAVOR_FLASH_DEVICE_SZ_DEFAULT
;
913 logmsg(MSG_INFO
, "tavor_identify: CMDSET is AMD, SectorSz "
916 if (manuf
->cmd_set
!= TAVOR_FLASH_AMD_CMDSET
&&
917 manuf
->cmd_set
!= TAVOR_FLASH_INTEL_CMDSET
) {
919 gettext("ib: Unknown flash device command set\n"));
922 return (FWFLASH_FAILURE
);
924 /* read from the CFI data */
925 manuf
->sector_sz
= ((cfi
.cfi_char
[0x30] << 8) |
926 cfi
.cfi_char
[0x2F]) << 8;
927 manuf
->device_sz
= 0x1 << cfi
.cfi_char
[0x27];
928 logmsg(MSG_INFO
, "tavor_identify: SectorSz is from CFI Data\n");
931 logmsg(MSG_INFO
, "tavor_identify: sector_sz: 0x%08x dev_sz: 0x%08x\n",
932 manuf
->sector_sz
, manuf
->device_sz
);
934 manuf
->state
|= FWFLASH_IB_STATE_MMAP
;
936 /* set firmware revision */
937 manuf
->fw_rev
.major
= init_ioctl
.tf_fwrev
.tfi_maj
;
938 manuf
->fw_rev
.minor
= init_ioctl
.tf_fwrev
.tfi_min
;
939 manuf
->fw_rev
.subminor
= init_ioctl
.tf_fwrev
.tfi_sub
;
941 logmsg(MSG_INFO
, "tavor_identify: pn_len %d hwpn %s \n",
942 init_ioctl
.tf_pn_len
,
943 (init_ioctl
.tf_pn_len
!= 0) ? init_ioctl
.tf_hwpn
: "(null)");
945 if (((thisdev
->ident
->vid
= calloc(1, MLX_VPR_VIDLEN
+ 1)) == NULL
) ||
946 ((thisdev
->ident
->revid
= calloc(1, MLX_VPR_REVLEN
+ 1)) == NULL
)) {
949 gettext("ib: Unable to allocate space for a VPR "
951 free(thisdev
->ident
);
952 free(manuf
->info
.mlx_pn
);
953 free(manuf
->info
.mlx_psid
);
954 free(manuf
->info
.mlx_id
);
957 return (FWFLASH_FAILURE
);
959 (void) strlcpy(thisdev
->ident
->vid
, "MELLANOX", MLX_VPR_VIDLEN
);
961 * We actually want the hwrev field from the ioctl above.
962 * Until we find out otherwise, add it onto the end of the
963 * firmware version details.
966 snprintf(thisdev
->ident
->revid
, MLX_VPR_REVLEN
, "%d.%d.%03d",
967 manuf
->fw_rev
.major
, manuf
->fw_rev
.minor
,
968 manuf
->fw_rev
.subminor
);
970 bzero(manuf
->ibguids
, sizeof (manuf
->ibguids
));
973 * For convenience we read in the Invariant Sector as
974 * well as both the Primary and Secondary Pointer Sectors
977 if ((manuf
->inv
= calloc(1, manuf
->sector_sz
)) == NULL
) {
979 gettext("tavor: Unable to allocate space for storing "
980 "the HCA's Invariant Sector\n"));
981 return (FWFLASH_FAILURE
);
983 bzero(&info
, sizeof (tavor_flash_ioctl_t
));
985 info
.tf_type
= TAVOR_FLASH_READ_SECTOR
;
986 info
.tf_sector
= (caddr_t
)manuf
->inv
;
987 info
.tf_sector_num
= 0;
991 if ((rv
= ioctl(manuf
->fd
, TAVOR_IOCTL_FLASH_READ
, &info
))
994 gettext("tavor: Unable to read HCA Invariant Sector\n"));
995 return (FWFLASH_FAILURE
);
998 #if defined(_LITTLE_ENDIAN)
999 ptr
= (uint32_t *)(uintptr_t)manuf
->inv
;
1000 for (i
= 0; i
< (manuf
->sector_sz
/ 4); i
++) {
1001 ptr
[i
] = htonl(ptr
[i
]);
1005 if ((manuf
->pps
= calloc(1, manuf
->sector_sz
)) == NULL
) {
1007 gettext("tavor: Unable to allocate space for storing "
1008 "the HCA's Primary Pointer Sector\n"));
1009 return (FWFLASH_FAILURE
);
1011 bzero(&info
, sizeof (tavor_flash_ioctl_t
));
1013 info
.tf_type
= TAVOR_FLASH_READ_SECTOR
;
1014 info
.tf_sector
= (caddr_t
)manuf
->pps
;
1015 info
.tf_sector_num
= 1;
1019 if ((rv
= ioctl(manuf
->fd
, TAVOR_IOCTL_FLASH_READ
, &info
))
1022 gettext("tavor: Unable to read HCA Primary "
1023 "Pointer Sector\n"));
1024 return (FWFLASH_FAILURE
);
1027 #if defined(_LITTLE_ENDIAN)
1028 ptr
= (uint32_t *)(uintptr_t)manuf
->pps
;
1029 for (i
= 0; i
< (manuf
->sector_sz
/ 4); i
++) {
1030 ptr
[i
] = htonl(ptr
[i
]);
1034 if ((manuf
->sps
= calloc(1, manuf
->sector_sz
)) == NULL
) {
1036 gettext("tavor: Unable to allocate space for storing "
1037 "the HCA's Secondary Pointer Sector\n"));
1038 return (FWFLASH_FAILURE
);
1040 bzero(&info
, sizeof (tavor_flash_ioctl_t
));
1042 info
.tf_type
= TAVOR_FLASH_READ_SECTOR
;
1043 info
.tf_sector
= (caddr_t
)manuf
->sps
;
1044 info
.tf_sector_num
= 2;
1048 if ((rv
= ioctl(manuf
->fd
, TAVOR_IOCTL_FLASH_READ
, &info
))
1051 gettext("tavor: Unable to read HCA Secondary "
1052 "Pointer Sector\n"));
1053 return (FWFLASH_FAILURE
);
1056 #if defined(_LITTLE_ENDIAN)
1057 ptr
= (uint32_t *)(uintptr_t)manuf
->sps
;
1058 for (i
= 0; i
< (manuf
->sector_sz
/ 4); i
++) {
1059 ptr
[i
] = htonl(ptr
[i
]);
1063 if ((ret
= tavor_get_guids(manuf
)) != FWFLASH_SUCCESS
) {
1065 gettext("ib: No guids found for device %s!\n"),
1066 thisdev
->access_devname
);
1069 /* set hw part number, psid, and name in handle */
1070 bzero(temppsid
, 17);
1071 bcopy(manuf
->pps
+FLASH_PS_PSID_OFFSET
, &rawpsid
, 16);
1073 for (i
= 0; i
< 16; i
+= 4) {
1074 temppsid
[i
] = rawpsid
[i
+3];
1075 temppsid
[i
+1] = rawpsid
[i
+2];
1076 temppsid
[i
+2] = rawpsid
[i
+1];
1077 temppsid
[i
+3] = rawpsid
[i
];
1080 "tavor: have raw '%s', want munged '%s'\n",
1083 /* now walk the magic decoder ring table */
1084 manuf
->info
.mlx_pn
= NULL
;
1085 manuf
->info
.mlx_psid
= NULL
;
1086 manuf
->info
.mlx_id
= NULL
;
1089 for (i
= 0; i
< MLX_MAX_ID
; i
++) {
1090 if ((strncmp(temppsid
, mlx_mdr
[i
].mlx_psid
,
1091 MLX_PSID_SZ
)) == 0) {
1093 if ((manuf
->info
.mlx_pn
= calloc(1,
1094 strlen(mlx_mdr
[i
].mlx_pn
) + 1)) == NULL
) {
1096 "tavor: no space available for the "
1097 "HCA PSID record (1)\n");
1099 (void) strlcpy(manuf
->info
.mlx_pn
,
1101 strlen(mlx_mdr
[i
].mlx_pn
) + 1);
1102 manuf
->pn_len
= strlen(mlx_mdr
[i
].mlx_pn
);
1105 if ((manuf
->info
.mlx_psid
= calloc(1,
1106 strlen(mlx_mdr
[i
].mlx_psid
) + 1)) == NULL
) {
1108 "tavor: no space available for the "
1109 "HCA PSID record (2)\n");
1111 (void) strlcpy(manuf
->info
.mlx_psid
,
1112 mlx_mdr
[i
].mlx_psid
,
1113 strlen(mlx_mdr
[i
].mlx_psid
) + 1);
1115 if ((manuf
->info
.mlx_id
= calloc(1,
1116 strlen(mlx_mdr
[i
].mlx_id
) + 1)) == NULL
) {
1118 "tavor: no space available for the "
1119 "HCA PSID record (3)\n");
1121 (void) strlcpy(manuf
->info
.mlx_id
,
1123 strlen(mlx_mdr
[i
].mlx_id
) + 1);
1127 if ((manuf
->pn_len
== 0) || (i
== MLX_MAX_ID
)) {
1129 "tavor: No hardware part number information available "
1131 /* Until we deliver the arbel driver, it's all Mellanox */
1132 i
= strlen("No hardware information available for this device");
1134 thisdev
->ident
->pid
= calloc(1, i
+ 2);
1135 sprintf(thisdev
->ident
->pid
, "No hardware information "
1136 "available for this device");
1138 if ((thisdev
->ident
->pid
= calloc(1,
1139 strlen(manuf
->info
.mlx_psid
) + 1)) != NULL
) {
1140 (void) strlcpy(thisdev
->ident
->pid
,
1141 manuf
->info
.mlx_psid
,
1142 strlen(manuf
->info
.mlx_psid
) + 1);
1145 gettext("ib: Unable to allocate space for a "
1146 "hardware identifier\n"));
1147 free(thisdev
->ident
);
1148 free(manuf
->info
.mlx_pn
);
1149 free(manuf
->info
.mlx_psid
);
1150 free(manuf
->info
.mlx_id
);
1153 return (FWFLASH_FAILURE
);
1157 for (i
= 0; i
< 4; i
++) {
1158 if ((thisdev
->addresses
[i
] = calloc(1,
1159 (2 * sizeof (uint64_t)) + 1)) == NULL
) {
1161 gettext("tavor: Unable to allocate space for a "
1162 "human-readable HCA guid\n"));
1163 return (FWFLASH_FAILURE
);
1165 (void) sprintf(thisdev
->addresses
[i
], "%016llx",
1170 * We do NOT close the fd here, since we can close it
1171 * at the end of the fw_readfw() or fw_writefw() functions
1172 * instead and not get the poor dear confused about whether
1173 * it's been inited already.
1181 tavor_get_guids(struct ib_encap_ident
*handle
)
1185 tavor_flash_ioctl_t info
;
1186 struct mlx_guid_sect
*p
, *s
;
1188 #if defined(_LITTLE_ENDIAN)
1193 * The reference for this function is the
1194 * Mellanox HCA Flash Programming Application Note
1195 * rev 1.44, 2007. Chapter 4 in particular.
1197 * NOTE: this Mellanox document is labelled Confidential
1198 * so DO NOT move this file out of usr/closed without
1199 * explicit approval from Sun Legal.
1203 * We need to check for both the Primary and Secondary
1204 * Image GUIDs. handle->pps and handle->sps should be
1205 * non-NULL by the time we're called, since we depend
1206 * on them being stashed in handle. Saves on an ioctl().
1209 /* make sure we've got our fallback position organised */
1210 for (i
= 0; i
< 4; i
++) {
1211 handle
->ibguids
[i
] = 0x00000000;
1214 /* convenience .... */
1216 if ((p
= calloc(1, sizeof (mlx_guid_sect_t
))) == NULL
) {
1218 gettext("tavor: Unable to allocate space for "
1219 "HCA guid record (1)\n"));
1220 return (FWFLASH_FAILURE
);
1222 if ((s
= calloc(1, sizeof (mlx_guid_sect_t
))) == NULL
) {
1224 gettext("tavor: Unable to allocate space for "
1225 "HCA guid record (2)\n"));
1227 return (FWFLASH_FAILURE
);
1230 bcopy(&handle
->pps
[0], &i
, 4);
1231 handle
->pfi_guid_addr
= MLXSWAPBITS32(i
) + FLASH_GUID_PTR
;
1232 bcopy(&handle
->sps
[0], &i
, 4);
1233 handle
->sfi_guid_addr
= MLXSWAPBITS32(i
) + FLASH_GUID_PTR
;
1235 bzero(&info
, sizeof (tavor_flash_ioctl_t
));
1236 info
.tf_type
= TAVOR_FLASH_READ_QUADLET
;
1237 info
.tf_addr
= handle
->pfi_guid_addr
;
1241 rv
= ioctl(handle
->fd
, TAVOR_IOCTL_FLASH_READ
, &info
);
1244 gettext("tavor: Unable to read Primary Image "
1248 return (FWFLASH_FAILURE
);
1252 * This is because we want the whole of the section
1253 * including the 16 reserved bytes at the front so
1254 * that if we recalculate the CRC we've got the correct
1255 * data to do it with
1257 info
.tf_addr
= handle
->pfi_guid_addr
+ info
.tf_quadlet
1258 - FLASH_GUID_PTR
- 16;
1260 bzero(handle
->pri_guid_section
, sizeof (mlx_guid_sect_t
));
1262 for (j
= 0; j
< 13; j
++) {
1264 if ((rv
= ioctl(handle
->fd
, TAVOR_IOCTL_FLASH_READ
,
1267 gettext("tavor: Unable to read Primary Image "
1268 "guid chunk %d\n"), j
);
1270 handle
->pri_guid_section
[j
] = info
.tf_quadlet
;
1273 bcopy(&handle
->pri_guid_section
, p
, sizeof (struct mlx_guid_sect
));
1275 /* now grab the secondary guid set */
1276 bzero(&info
, sizeof (tavor_flash_ioctl_t
));
1277 info
.tf_type
= TAVOR_FLASH_READ_QUADLET
;
1278 info
.tf_addr
= handle
->sfi_guid_addr
;
1282 if ((rv
= ioctl(handle
->fd
, TAVOR_IOCTL_FLASH_READ
,
1285 gettext("tavor: Unable to read Secondary Image "
1286 "guid offset (%s)\n"), strerror(errno
));
1289 return (FWFLASH_FAILURE
);
1292 info
.tf_addr
= handle
->sfi_guid_addr
+ info
.tf_quadlet
1293 - FLASH_GUID_PTR
- 16;
1295 bzero(handle
->sec_guid_section
, sizeof (mlx_guid_sect_t
));
1297 for (j
= 0; j
< 13; j
++) {
1299 if ((rv
= ioctl(handle
->fd
, TAVOR_IOCTL_FLASH_READ
,
1302 gettext("tavor: Unable to read Secondary Image "
1303 "guid chunk %d (%s)\n"), j
, strerror(errno
));
1304 return (FWFLASH_FAILURE
);
1306 handle
->sec_guid_section
[j
] = info
.tf_quadlet
;
1310 bcopy(&handle
->sec_guid_section
, s
, sizeof (struct mlx_guid_sect
));
1312 #if defined(_LITTLE_ENDIAN)
1315 * We don't actually care about p or s later on if we
1316 * write to the HCA - we've already stored the binary
1317 * form in handle->pri_guid_section and handle->sec_guid_section.
1318 * What we're doing here is creating human-readable forms.
1321 ptr
= (uint32_t *)(uintptr_t)p
;
1322 for (j
= 0; j
< 14; j
+= 2) {
1328 ptr
= (uint32_t *)(uintptr_t)s
;
1329 for (j
= 0; j
< 14; j
+= 2) {
1337 * We don't check and munge the GUIDs to the manufacturer's
1338 * defaults, because if the GUIDs are actually set incorrectly
1339 * at identify time, we really need to know that.
1341 * If the GUIDs are bogus, then we'll fix that in fw_writefw()
1342 * by blatting the manufacturer's defaults from the firmware
1343 * image file instead.
1345 if ((p
->nodeguid
== s
->nodeguid
) &&
1346 (p
->port1guid
== s
->port1guid
) &&
1347 (p
->port2guid
== s
->port2guid
) &&
1348 (p
->sysimguid
== s
->sysimguid
)) {
1350 "tavor: primary and secondary guids are the same\n");
1351 handle
->ibguids
[0] = p
->nodeguid
;
1352 handle
->ibguids
[1] = p
->port1guid
;
1353 handle
->ibguids
[2] = p
->port2guid
;
1354 handle
->ibguids
[3] = p
->sysimguid
;
1357 * We're going to assume that the guids which are numerically
1358 * larger than the others are correct and copy them to
1361 * For those in the know wrt InfiniBand, if this assumption
1362 * is incorrect, _please_ bug this and fix it, adding a
1363 * comment or two to indicate why
1366 "tavor: primary and secondary guids don't all match\n");
1368 if (s
->nodeguid
> p
->nodeguid
) {
1369 handle
->ibguids
[0] = s
->nodeguid
;
1370 handle
->ibguids
[1] = s
->port1guid
;
1371 handle
->ibguids
[2] = s
->port2guid
;
1372 handle
->ibguids
[3] = s
->sysimguid
;
1373 bzero(p
, sizeof (struct mlx_guid_sect
));
1375 handle
->ibguids
[0] = p
->nodeguid
;
1376 handle
->ibguids
[1] = p
->port1guid
;
1377 handle
->ibguids
[2] = p
->port2guid
;
1378 handle
->ibguids
[3] = p
->sysimguid
;
1379 bzero(s
, sizeof (struct mlx_guid_sect
));
1386 if (fwflash_debug
) {
1387 for (i
= 0; i
< 4; i
++) {
1388 logmsg(MSG_INFO
, "ibguids[%d] %0llx\n", i
,
1389 handle
->ibguids
[i
]);
1393 return (FWFLASH_SUCCESS
);
1398 tavor_close(struct devicelist
*flashdev
)
1401 struct ib_encap_ident
*handle
;
1403 handle
= (struct ib_encap_ident
*)flashdev
->ident
->encap_ident
;
1404 if (handle
->fd
> 0) {
1405 (void) ioctl(handle
->fd
, TAVOR_IOCTL_FLASH_FINI
);
1407 if (close(handle
->fd
) != 0) {
1409 gettext("tavor: Unable to properly close "
1410 "device %s! (%s)\n"),
1411 flashdev
->access_devname
,
1413 return (FWFLASH_FAILURE
);
1415 return (FWFLASH_SUCCESS
);
1417 return (FWFLASH_FAILURE
);
1422 * We would not need this if it were not for Cisco's image using the
1423 * VSD to store boot options and flags for their PXE boot extension,
1424 * but not setting the proper default values for the extension in
1425 * their image. As it turns out, some of the data for the extension
1426 * is stored in the VSD in the firmware file, and the rest is set by
1427 * their firmware utility. That's not very nice for us, since it could
1428 * change at any time without our knowledge. Well, for the time being,
1429 * we can use this to examine and fix up anything in the VSD that we might
1430 * need to handle, for any vendor specific settings.
1433 tavor_cisco_extensions(mlx_xps_t
*hcaxps
, mlx_xps_t
*diskxps
)
1435 uint16_t sig1
, sig2
;
1439 bcopy(hcaxps
->vsdpsid
, &i
, 4);
1441 bcopy(&hcaxps
->vsdpsid
[223], &i
, 4);
1445 if (sig1
== FLASH_VSD_CISCO_SIGNATURE
&&
1446 sig2
== FLASH_VSD_CISCO_SIGNATURE
) {
1448 "tavor: CISCO signature found in HCA's VSD, copying to "
1449 "new image's VSD\n");
1451 i
= htonl(FLASH_VSD_CISCO_SIGNATURE
);
1452 bcopy(&i
, diskxps
->vsdpsid
, 2);
1455 * Set the boot_version field to '2'. This value is
1456 * located in the 2nd byte of the last uint32_t.
1457 * Per the previous version of fwflash, we just or
1458 * the bit in and get on with it.
1461 i
= (diskxps
->vsdpsid
[222] | FLASH_VSD_CISCO_BOOT_VERSION
);
1462 bcopy(&i
, &diskxps
->vsdpsid
[222], 2);
1464 * Now set some defaults for the SRP boot extension,
1465 * currently the only extension we support. These flags
1466 * are located in the second uint32_t of the VSD.
1469 logmsg(MSG_INFO
, "tavor: CISCO boot flags currently set "
1471 diskxps
->vsdpsid
[1]);
1473 diskxps
->vsdpsid
[1] =
1474 htonl(diskxps
->vsdpsid
[1] |
1475 FLASH_VSD_CISCO_FLAG_AUTOUPGRADE
|
1476 FLASH_VSD_CISCO_BOOT_OPTIONS
|
1477 FLASH_VSD_CISCO_FLAG_BOOT_ENABLE_PORT_1
|
1478 FLASH_VSD_CISCO_FLAG_BOOT_ENABLE_PORT_2
|
1479 FLASH_VSD_CISCO_FLAG_BOOT_ENABLE_SCAN
|
1480 FLASH_VSD_CISCO_FLAG_BOOT_TYPE_WELL_KNOWN
|
1481 FLASH_VSD_CISCO_FLAG_BOOT_TRY_FOREVER
);
1483 logmsg(MSG_INFO
, "tavor: CISCO boot flags now set "
1485 diskxps
->vsdpsid
[1]);
1488 "tavor: CISCO signature not found in HCA's VSD\n");
1493 tavor_write_sector(int fd
, int sectnum
, int32_t *data
)
1496 tavor_flash_ioctl_t cmd
;
1499 bzero(&cmd
, sizeof (tavor_flash_ioctl_t
));
1501 cmd
.tf_type
= TAVOR_FLASH_WRITE_SECTOR
;
1502 cmd
.tf_sector_num
= sectnum
;
1503 cmd
.tf_sector
= (caddr_t
)data
;
1508 "tavor: tavor_write_sector(fd %d, sectnum 0x%x, data 0x%lx)\n",
1512 "\tcmd.tf_type %d\n"
1513 "\tcmd.tf_sector 0x%lx\n"
1514 "\tcmd.tf_sector_num %d\n",
1515 cmd
.tf_type
, data
, cmd
.tf_sector_num
);
1518 * If we're debugging, dump the first 64 uint32_t that we've
1521 if (fwflash_debug
> 0) {
1525 "%02x: %08x %08x %08x %08x\n",
1526 i
, data
[i
], data
[i
+1],
1527 data
[i
+2], data
[i
+3]);
1532 rv
= ioctl(fd
, TAVOR_IOCTL_FLASH_WRITE
, &cmd
);
1535 gettext("tavor: WRITE SECTOR failed for sector "
1537 sectnum
, strerror(errno
));
1538 return (FWFLASH_FAILURE
);
1540 return (FWFLASH_SUCCESS
);
1544 * Write zeros to the on-HCA signature and CRC16 fields of sector.
1546 * NOTE we do _not_ divide start by 4 because we're talking to the
1547 * HCA, and not finding an offset into verifier->fwimage.
1551 tavor_zero_sig_crc(int fd
, uint32_t start
)
1554 tavor_flash_ioctl_t cmd
;
1556 /* signature first, then CRC16 */
1557 bzero(&cmd
, sizeof (tavor_flash_ioctl_t
));
1558 cmd
.tf_type
= TAVOR_FLASH_WRITE_BYTE
;
1562 "tavor: tavor_zero_sig_crc(fd %d, start 0x%04x)\n",
1565 for (i
= 0; i
< 4; i
++) {
1566 cmd
.tf_addr
= start
+ FLASH_PS_SIGNATURE_OFFSET
+ i
;
1569 "tavor: invalidating xPS sig (offset from IS 0x%04x) "
1574 rv
= ioctl(fd
, TAVOR_IOCTL_FLASH_WRITE
, &cmd
);
1577 gettext("tavor: Unable to write 0x00 to "
1578 "offset 0x%04x from IS (sig byte %d): %s\n"),
1579 cmd
.tf_addr
, i
, strerror(errno
));
1580 return (FWFLASH_FAILURE
);
1585 for (i
= 0; i
< 2; i
++) {
1586 cmd
.tf_addr
= start
+ FLASH_PS_CRC16_OFFSET
+ i
;
1589 "tavor: invalidating xPS CRC16 (offset from IS 0x%04x) "
1594 rv
= ioctl(fd
, TAVOR_IOCTL_FLASH_WRITE
, &cmd
);
1597 gettext("tavor: Unable to write 0x00 to "
1598 "offset 0x%04x from IS (CRC16 byte %d): %s\n"),
1599 cmd
.tf_addr
, i
, strerror(errno
));
1600 return (FWFLASH_FAILURE
);
1603 return (FWFLASH_SUCCESS
);
1608 * Write a new FIA for the given xPS. The _caller_ handles
1609 * any required byte-swapping for us.
1611 * NOTE we do _not_ divide start by 4 because we're talking to the
1612 * HCA, and not finding an offset into verifier->fwimage.
1615 tavor_write_xps_fia(int fd
, uint32_t offset
, uint32_t start
)
1619 tavor_flash_ioctl_t cmd
;
1622 "tavor: tavor_write_xps_fia(fd %d, offset 0x%04x, "
1626 addrbytep
= (uint8_t *)&start
;
1628 bzero(&cmd
, sizeof (tavor_flash_ioctl_t
));
1629 cmd
.tf_type
= TAVOR_FLASH_WRITE_BYTE
;
1630 for (i
= 0; i
< 4; i
++) {
1631 cmd
.tf_byte
= addrbytep
[i
];
1632 cmd
.tf_addr
= offset
+ FLASH_PS_FI_ADDR_OFFSET
+ i
;
1634 "tavor: writing xPS' new FIA, byte %d (0x%0x) at "
1635 "offset from IS 0x%04x\n",
1636 i
, cmd
.tf_byte
, cmd
.tf_addr
);
1639 rv
= ioctl(fd
, TAVOR_IOCTL_FLASH_WRITE
, &cmd
);
1642 gettext("tavor: Unable to write byte %d "
1643 "of xPS new FIA (0x%0x, offset from IS "
1645 i
, cmd
.tf_byte
, cmd
.tf_addr
, strerror(errno
));
1646 return (FWFLASH_FAILURE
);
1649 return (FWFLASH_SUCCESS
);
1654 * Write the new CRC16 and Signature to the given xPS. The caller
1655 * has already byte-swapped newcrc if that's necessary.
1657 * NOTE we do _not_ divide start by 4 because we're talking to the
1658 * HCA, and not finding an offset into verifier->fwimage.
1661 tavor_write_xps_crc_sig(int fd
, uint32_t offset
, uint16_t newcrc
)
1666 tavor_flash_ioctl_t cmd
;
1669 "tavor: tavor_write_xps_crc_sig(fd %d, offset 0x%04x, "
1671 fd
, offset
, newcrc
);
1673 bytep
= (uint8_t *)&newcrc
;
1675 bzero(&cmd
, sizeof (tavor_flash_ioctl_t
));
1676 cmd
.tf_type
= TAVOR_FLASH_WRITE_BYTE
;
1677 for (i
= 0; i
< 2; i
++) {
1678 cmd
.tf_byte
= bytep
[i
];
1679 cmd
.tf_addr
= offset
+ FLASH_PS_CRC16_OFFSET
+ i
;
1681 "tavor: writing new XPS CRC16, byte %d (0x%0x) at "
1682 "offset from IS 0x%04x\n",
1683 i
, bytep
[i
], cmd
.tf_addr
);
1686 rv
= ioctl(fd
, TAVOR_IOCTL_FLASH_WRITE
, &cmd
);
1689 gettext("tavor: Unable to write byte %d "
1690 "(0x%0x) of xPS' new CRC16 to offset "
1691 "from IS 0x%04x: %s\n"),
1692 i
, bytep
[i
], cmd
.tf_addr
, strerror(errno
));
1693 return (FWFLASH_FAILURE
);
1697 tempsig
= htonl(FLASH_PS_SIGNATURE
);
1698 bytep
= (uint8_t *)&tempsig
;
1700 for (i
= 0; i
< 4; i
++) {
1701 cmd
.tf_byte
= bytep
[i
];
1702 cmd
.tf_addr
= offset
+ FLASH_PS_SIGNATURE_OFFSET
+ i
;
1704 "tavor: writing new xPS Signature, byte %d (0x%0x) at "
1705 "offset from IS 0x%04x\n",
1706 i
, bytep
[i
], cmd
.tf_addr
);
1709 rv
= ioctl(fd
, TAVOR_IOCTL_FLASH_WRITE
, &cmd
);
1712 gettext("tavor: Unable to write byte %d (0x%0x) "
1713 "of xPS' signature at offset from IS 0x%04x: %s\n"),
1714 i
, bytep
[i
], cmd
.tf_addr
, strerror(errno
));
1715 return (FWFLASH_FAILURE
);
1718 return (FWFLASH_SUCCESS
);
1724 * This function contains "Begin/End documentation departure point"
1725 * because the reality of what actually _works_ is quite, quite
1726 * different to what is written in the Mellanox HCA Flash Application
1727 * Programming Guide.
1730 tavor_blast_image(int fd
, int prisec
, uint32_t hcafia
, uint32_t sectsz
,
1731 struct mlx_xps
*newxps
)
1734 uint32_t startsectimg
, startsecthca
, numsect
;
1736 if ((prisec
!= 1) && (prisec
!= 2)) {
1738 gettext("tavor: invalid image number requested (%d)\n"),
1740 return (FWFLASH_FAILURE
);
1743 /* Begin documentation departure point */
1745 /* zero the HCA's PPS signature and CRC */
1746 if (tavor_zero_sig_crc(fd
, (prisec
* sectsz
))
1747 != FWFLASH_SUCCESS
) {
1749 "tavor: Unable zero HCA's %s signature "
1750 "and CRC16 fields\n",
1751 ((prisec
== 1) ? "PPS" : "SPS"));
1752 return (FWFLASH_FAILURE
);
1755 logmsg(MSG_INFO
, "tavor: zeroing HCA's %s sig and crc\n",
1756 (prisec
== 1) ? "pps" : "sps");
1758 /* End documentation departure point */
1760 /* make sure we don't inadvertently overwrite bits */
1762 startsectimg
= MLXSWAPBITS32(newxps
->fia
) / sectsz
;
1763 startsecthca
= hcafia
/ sectsz
;
1765 numsect
= (MLXSWAPBITS32(newxps
->fis
) / sectsz
) +
1766 ((MLXSWAPBITS32(newxps
->fis
) % sectsz
) ? 1 : 0);
1768 logmsg(MSG_INFO
, "tavor: %s imgsize 0x%0x startsecthca %d, "
1769 "startsectimg %d, num sectors %d\n",
1770 (prisec
== 1) ? "PFI" : "SFI", MLXSWAPBITS32(newxps
->fis
),
1771 startsecthca
, startsectimg
, numsect
);
1773 for (i
= 0; i
< numsect
; i
++) {
1775 j
= (MLXSWAPBITS32(newxps
->fia
) + (i
* sectsz
)) / 4;
1777 logmsg(MSG_INFO
, "tavor: image offset 0x%0x\n", j
);
1778 logmsg(MSG_INFO
, "tavor: writing HCA sector %d\n",
1781 if (tavor_write_sector(fd
, i
+ startsecthca
,
1782 &verifier
->fwimage
[j
])
1783 != FWFLASH_SUCCESS
) {
1785 gettext("tavor: Unable to write "
1786 "sector %d to HCA\n"),
1788 return (FWFLASH_FAILURE
);
1790 (void) printf(" .");
1792 rv
= tavor_readback(fd
, i
+ startsecthca
, sectsz
);
1793 if (rv
!= FWFLASH_SUCCESS
) {
1795 gettext("tavor: Unable to read sector %d "
1796 "back from HCA\n"), i
+ startsecthca
);
1797 return (FWFLASH_FAILURE
);
1799 (void) printf(" | ");
1802 /* Begin documentation departure point */
1804 /* invalidate the xps signature and fia fields */
1805 newxps
->signature
= 0xffffffff;
1806 newxps
->crc16
= 0xffff;
1807 /* we put the fia back to imgfia later */
1808 newxps
->fia
= 0xffffffff;
1809 /* End documentation departure point */
1811 /* success so far, now burn the new xPS */
1812 if (tavor_write_sector(fd
, prisec
, (int *)newxps
)
1813 != FWFLASH_SUCCESS
) {
1815 gettext("tavor: Unable to write new %s "
1816 "pointer sector to HCA\n"),
1817 (prisec
== 1) ? "primary" : "secondary");
1818 return (FWFLASH_FAILURE
);
1820 (void) printf(" .");
1822 /* Begin documentation departure point */
1824 /* write new fia to the HCA's pps */
1825 logmsg(MSG_INFO
, "tavor: writing new fia (0x%0x) to HCA\n",
1826 MLXSWAPBITS32(newxps
->fia
));
1828 if (tavor_write_xps_fia(fd
, (prisec
* sectsz
),
1829 MLXSWAPBITS32(hcafia
)) != FWFLASH_SUCCESS
) {
1831 gettext("tavor: Unable to update HCA's %s "
1832 "pointer sector FIA record\n"),
1833 (prisec
== 1) ? "primary" : "secondary");
1834 return (FWFLASH_FAILURE
);
1837 /* don't forget the byte-swapping */
1838 newxps
->fia
= MLXSWAPBITS32(hcafia
);
1840 (uint32_t)MLXSWAPBITS32(FLASH_PS_SIGNATURE
);
1842 MLXSWAPBITS16(crc16((uint8_t *)newxps
, FLASH_PS_CRC16_SIZE
));
1844 logmsg(MSG_INFO
, "tavor: writing new fia 0x%0x, "
1845 "sig 0x%0x and new crc16 0x%0x\n",
1846 newxps
->fia
, MLXSWAPBITS32(newxps
->signature
),
1849 if (tavor_write_xps_crc_sig(fd
, (prisec
* sectsz
),
1850 newxps
->crc16
) != FWFLASH_SUCCESS
) {
1852 * Now we're REALLY hosed. If the card comes up at all,
1853 * expect it to be in "Maintenance Mode".
1856 gettext("tavor: Unable to update HCA's %s CRC "
1857 "and Firmware Image signature fields\n"),
1858 (prisec
== 1) ? "PPS" : "SPS");
1859 return (FWFLASH_FAILURE
);
1862 rv
= tavor_readback(fd
, prisec
, sectsz
);
1863 if (rv
!= FWFLASH_SUCCESS
) {
1865 gettext("tavor: Unable to read %s pointer sector "
1867 (prisec
== 1) ? "Primary" : "Secondary");
1868 return (FWFLASH_FAILURE
);
1870 (void) printf(" |");
1871 /* End documentation departure point */
1872 return (FWFLASH_SUCCESS
);
1877 tavor_readback(int infd
, int whichsect
, int sectsz
)
1880 tavor_flash_ioctl_t cmd
;
1883 bzero(&cmd
, sizeof (tavor_flash_ioctl_t
));
1884 data
= calloc(1, sectsz
); /* assumption! */
1886 cmd
.tf_type
= TAVOR_FLASH_READ_SECTOR
;
1887 cmd
.tf_sector_num
= whichsect
;
1888 cmd
.tf_sector
= (caddr_t
)data
;
1889 rv
= ioctl(infd
, TAVOR_IOCTL_FLASH_READ
, &cmd
);
1892 "tavor: UNABLE TO READ BACK SECTOR %d from HCA\n",
1894 return (FWFLASH_FAILURE
);
1897 return (FWFLASH_SUCCESS
);
1902 * crc16 - computes 16 bit crc of supplied buffer.
1903 * image should be in network byteorder
1904 * result is returned in host byteorder form
1907 crc16(uint8_t *image
, uint32_t size
)
1909 const uint16_t poly
= 0x100b;
1910 uint32_t crc
= 0xFFFF;
1914 for (i
= 0; i
< size
/ 4; i
++) {
1915 word
= (image
[4 * i
] << 24) |
1916 (image
[4 * i
+ 1] << 16) |
1917 (image
[4 * i
+ 2] << 8) |
1920 for (j
= 0; j
< 32; j
++) {
1922 crc
= (((crc
<< 1) |
1923 (word
>> 31)) ^ poly
) & 0xFFFF;
1925 crc
= ((crc
<< 1) | (word
>> 31)) & 0xFFFF;
1927 word
= (word
<< 1) & 0xFFFFFFFF;
1931 for (i
= 0; i
< 16; i
++) {
1933 crc
= ((crc
<< 1) ^ poly
) & 0xFFFF;
1935 crc
= (crc
<< 1) & 0xFFFF;
1940 return (crc
& 0xFFFF);