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