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