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