xref: /illumos-gate/usr/src/cmd/fwflash/plugins/transport/common/hermon.c (revision ee5d8455d3cff95bf8149073831be4560d60250d)
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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  * The reference for the functions in this file is the
29  *
30  *	Mellanox HCA Flash Programming Application Note
31  * (Mellanox document number 2205AN) rev 1.45, 2007.
32  * Chapter 4 in particular.
33  */
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <sys/sysmacros.h>
41 #include <sys/queue.h>
42 #include <fcntl.h>
43 #include <ctype.h>
44 #include <string.h>
45 #include <strings.h>
46 
47 #include <sys/byteorder.h>
48 
49 #include <libintl.h> /* for gettext(3c) */
50 
51 #include <fwflash/fwflash.h>
52 #include "../../hdrs/hermon_ib.h"
53 
54 char *devprefix = "/devices";
55 char drivername[] = "hermon\0";
56 char *devsuffix = ":devctl";
57 
58 extern di_node_t rootnode;
59 extern int errno;
60 extern struct fw_plugin *self;
61 extern struct vrfyplugin *verifier;
62 extern int fwflash_debug;
63 
64 /* required functions for this plugin */
65 int fw_readfw(struct devicelist *device, char *filename);
66 int fw_writefw(struct devicelist *device);
67 int fw_identify(int start);
68 int fw_devinfo();
69 
70 
71 /* helper functions */
72 static int cnx_identify(struct devicelist *thisdev);
73 static int cnx_get_guids(ib_cnx_encap_ident_t *handle);
74 static int cnx_close(struct devicelist *flashdev);
75 static int cnx_check_for_magic_pattern(ib_cnx_encap_ident_t *hdl, uint32_t adr);
76 static uint32_t cnx_get_log2_chunk_size_f_hdl(ib_cnx_encap_ident_t *handle,
77     int type);
78 static uint32_t cnx_get_log2_chunk_size(uint32_t chunk_size_word);
79 static uint32_t cnx_cont2phys(uint32_t log2_chunk_sz, uint32_t cont_addr,
80     int type);
81 static uint32_t cnx_get_image_size_f_hdl(ib_cnx_encap_ident_t *hdl, int type);
82 static void cnx_local_set_guid_crc_img(uint32_t offset, uint32_t guid_crc_size,
83     uint32_t guid_crc_offset);
84 static int cnx_read_image(ib_cnx_encap_ident_t *handle);
85 static int cnx_write_file(ib_cnx_encap_ident_t *handle, const char *filename);
86 static int cnx_verify_image(ib_cnx_encap_ident_t *handle, int type);
87 static int cnx_read_guids(ib_cnx_encap_ident_t *handle, int type);
88 static int cnx_set_guids(ib_cnx_encap_ident_t *handle, void *arg);
89 static int cnx_write_image(ib_cnx_encap_ident_t *handle, int type);
90 static int cnx_read_ioctl(ib_cnx_encap_ident_t *hdl,
91     hermon_flash_ioctl_t *info);
92 static int cnx_write_ioctl(ib_cnx_encap_ident_t *hdl,
93     hermon_flash_ioctl_t *info);
94 static int cnx_erase_sector_ioctl(ib_cnx_encap_ident_t *hdl,
95     hermon_flash_ioctl_t *info);
96 static int cnx_find_magic_n_chnk_sz(ib_cnx_encap_ident_t *handle, int type);
97 static int cnx_get_image_info(ib_cnx_encap_ident_t *handle);
98 
99 
100 int
101 fw_readfw(struct devicelist *flashdev, char *filename)
102 {
103 	ib_cnx_encap_ident_t	*manuf;
104 	int 			rv = FWFLASH_SUCCESS;
105 
106 	logmsg(MSG_INFO, "hermon: fw_readfw: filename %s\n", filename);
107 
108 	manuf = (ib_cnx_encap_ident_t *)flashdev->ident->encap_ident;
109 	if (CNX_I_CHECK_HANDLE(manuf)) {
110 		logmsg(MSG_ERROR, gettext("hermon: Invalid Handle for "
111 		    "device %s! \n"), flashdev->access_devname);
112 		return (FWFLASH_FAILURE);
113 	}
114 
115 	logmsg(MSG_INFO, "hermon: fw_identify should have read the image. "
116 	    "state 0x%x\n", manuf->state);
117 
118 	rv = cnx_read_image(manuf);
119 	if (rv != FWFLASH_SUCCESS) {
120 		logmsg(MSG_ERROR, gettext("hermon: Failed to read any valid "
121 		    "image on device (%s)\n"), flashdev->access_devname);
122 		logmsg(MSG_ERROR, gettext("Aborting read.\n"));
123 	} else {
124 		rv = cnx_write_file(manuf, filename);
125 	}
126 
127 	cnx_close(flashdev);
128 	return (rv);
129 }
130 
131 
132 /*
133  * If we're invoking fw_writefw, then flashdev is a valid,
134  * flashable device as determined by fw_identify().
135  *
136  * If verifier is null, then we haven't been called following a firmware
137  * image verification load operation.
138  */
139 int
140 fw_writefw(struct devicelist *flashdev)
141 {
142 	ib_cnx_encap_ident_t	*manuf;
143 	int			i, j, k;
144 
145 	logmsg(MSG_INFO, "hermon: fw_writefw\n");
146 
147 	manuf = (ib_cnx_encap_ident_t *)flashdev->ident->encap_ident;
148 
149 	if (CNX_I_CHECK_HANDLE(manuf)) {
150 		logmsg(MSG_ERROR, gettext("hermon: Invalid Handle for "
151 		    "device %s! \n"), flashdev->access_devname);
152 		return (FWFLASH_FAILURE);
153 	}
154 
155 	/*
156 	 * Try the primary first, then the secondary.
157 	 * If we get here, then the verifier has _already_ checked that
158 	 * the part number in the firmware image matches that in the HCA,
159 	 * so we only need this check if there's no hardware info available
160 	 * already after running through fw_identify().
161 	 */
162 	if (manuf->pn_len == 0) {
163 		int resp;
164 
165 		(void) fprintf(stderr, gettext("Unable to completely verify "
166 		    "that this firmware image (%s) is compatible with your "
167 		    "HCA %s"), verifier->imgfile, flashdev->access_devname);
168 		(void) fprintf(stderr, gettext("Do you really want to "
169 		    "continue? (Y/N): "));
170 		(void) fflush(stdin);
171 		resp = getchar();
172 		if (resp != 'Y' && resp != 'y') {
173 			(void) fprintf(stderr, gettext("Not proceeding with "
174 			    "flash operation of %s on %s"),
175 			    verifier->imgfile, flashdev->access_devname);
176 			return (FWFLASH_FAILURE);
177 		}
178 	}
179 
180 	logmsg(MSG_INFO, "hermon: fw_writefw: Using Existing GUIDs.\n");
181 	manuf->state |=
182 	    FWFLASH_IB_STATE_GUIDN |
183 	    FWFLASH_IB_STATE_GUID1 |
184 	    FWFLASH_IB_STATE_GUID2 |
185 	    FWFLASH_IB_STATE_GUIDS;
186 	if (cnx_set_guids(manuf, manuf->ibguids) != FWFLASH_SUCCESS) {
187 		logmsg(MSG_WARN, gettext("hermon: Failed to set GUIDs"));
188 	}
189 
190 	/*
191 	 * Update both Primary and Secondary images
192 	 *
193 	 * For Failsafe firmware image update, if the current image (i.e.
194 	 * containing a magic pattern) on the Flash is stored on the Primary
195 	 * location, burn the new image to the Secondary location first,
196 	 * or vice versa.
197 	 */
198 
199 	/* Note Current Image location. */
200 	j = manuf->state &
201 	    (FWFLASH_IB_STATE_IMAGE_PRI | FWFLASH_IB_STATE_IMAGE_SEC);
202 
203 	/*
204 	 * If we find that current image location is not found, no worries
205 	 * we shall default to PRIMARY, and proceed with burning anyway.
206 	 */
207 	if (j == 0)
208 		j = FWFLASH_IB_STATE_IMAGE_PRI;
209 
210 	for (i = FWFLASH_FLASH_IMAGES; i > 0; i--) {
211 		char *type;
212 
213 		if (i == 2) {
214 			if (j == 2)
215 				k = 1;	/* Burn PRI First */
216 			else
217 				k = 2;	/* Burn SEC First */
218 		} else {
219 			if (k == 2)
220 				k = 1;	/* Burn PRI next */
221 			else
222 				k = 2;	/* Burn SEC next */
223 		}
224 		type = ((k == 1) ? "Primary" : "Secondary");
225 
226 		logmsg(MSG_INFO, "hermon: fw_write: UPDATING %s image\n", type);
227 
228 		if (cnx_write_image(manuf, k) != FWFLASH_SUCCESS) {
229 			(void) fprintf(stderr,
230 			    gettext("Failed to update %s image on device %s"),
231 			    type, flashdev->access_devname);
232 			goto out;
233 		}
234 
235 		logmsg(MSG_INFO, "hermon: fw_write: Verify %s image..\n", type);
236 		if (cnx_verify_image(manuf, k) != FWFLASH_SUCCESS) {
237 			(void) fprintf(stderr,
238 			    gettext("Failed to verify %s image for device %s"),
239 			    type, flashdev->access_devname);
240 			goto out;
241 		}
242 	}
243 out:
244 	/* final update marker to the user */
245 	(void) printf(" +\n");
246 	return (cnx_close(flashdev));
247 }
248 
249 
250 /*
251  * The fw_identify() function walks the device tree trying to find
252  * devices which this plugin can work with.
253  *
254  * The parameter "start" gives us the starting index number
255  * to give the device when we add it to the fw_devices list.
256  *
257  * firstdev is allocated by us and we add space as necessary
258  */
259 int
260 fw_identify(int start)
261 {
262 	int		rv = FWFLASH_FAILURE;
263 	di_node_t	thisnode;
264 	struct devicelist *newdev;
265 	char		*devpath;
266 	int		idx = start;
267 	int		devlength = 0;
268 
269 	logmsg(MSG_INFO, "hermon: fw_identify\n");
270 	thisnode = di_drv_first_node(drivername, rootnode);
271 
272 	if (thisnode == DI_NODE_NIL) {
273 		logmsg(MSG_INFO, gettext("No %s nodes in this system\n"),
274 		    drivername);
275 		return (rv);
276 	}
277 
278 	/* we've found one, at least */
279 	for (; thisnode != DI_NODE_NIL; thisnode = di_drv_next_node(thisnode)) {
280 
281 		devpath = di_devfs_path(thisnode);
282 
283 		if ((newdev = calloc(1, sizeof (struct devicelist))) == NULL) {
284 			logmsg(MSG_ERROR, gettext("hermon: Unable to allocate "
285 			    "space for device entry\n"));
286 			di_devfs_path_free(devpath);
287 			return (FWFLASH_FAILURE);
288 		}
289 
290 		/* calloc enough for /devices + devpath + ":devctl" + '\0' */
291 		devlength = strlen(devpath) + strlen(devprefix) +
292 		    strlen(devsuffix) + 2;
293 
294 		if ((newdev->access_devname = calloc(1, devlength)) == NULL) {
295 			logmsg(MSG_ERROR, gettext("hermon: Unable to allocate "
296 			    "space for a devfs name\n"));
297 			(void) free(newdev);
298 			di_devfs_path_free(devpath);
299 			return (FWFLASH_FAILURE);
300 		}
301 		snprintf(newdev->access_devname, devlength,
302 		    "%s%s%s", devprefix, devpath, devsuffix);
303 
304 		if ((newdev->ident = calloc(1, sizeof (struct vpr))) == NULL) {
305 			logmsg(MSG_ERROR, gettext("hermon: Unable to allocate "
306 			    "space for a device identification record\n"));
307 			(void) free(newdev->access_devname);
308 			(void) free(newdev);
309 			di_devfs_path_free(devpath);
310 			return (FWFLASH_FAILURE);
311 		}
312 
313 		/* CHECK VARIOUS IB THINGS HERE */
314 		rv = cnx_identify(newdev);
315 		if (rv == FWFLASH_FAILURE) {
316 			(void) free(newdev->ident);
317 			(void) free(newdev->access_devname);
318 			(void) free(newdev);
319 			di_devfs_path_free(devpath);
320 			continue;
321 		}
322 
323 		if ((newdev->drvname = calloc(1, strlen(drivername) + 1))
324 		    == NULL) {
325 			logmsg(MSG_ERROR, gettext("hermon: Unable to allocate"
326 			    " space for a driver name\n"));
327 			(void) free(newdev->ident);
328 			(void) free(newdev->access_devname);
329 			(void) free(newdev);
330 			di_devfs_path_free(devpath);
331 			return (FWFLASH_FAILURE);
332 		}
333 
334 		(void) strlcpy(newdev->drvname, drivername,
335 		    strlen(drivername) + 1);
336 
337 		/* this next bit is backwards compatibility - "IB\0" */
338 		if ((newdev->classname = calloc(1, 3)) == NULL) {
339 			logmsg(MSG_ERROR, gettext("hermon: Unable to allocate "
340 			    "space for a class name\n"));
341 			(void) free(newdev->drvname);
342 			(void) free(newdev->ident);
343 			(void) free(newdev->access_devname);
344 			(void) free(newdev);
345 			di_devfs_path_free(devpath);
346 			return (FWFLASH_FAILURE);
347 		}
348 		(void) strlcpy(newdev->classname, "IB", 3);
349 
350 		newdev->index = idx;
351 		++idx;
352 		newdev->plugin = self;
353 
354 		di_devfs_path_free(devpath);
355 
356 		TAILQ_INSERT_TAIL(fw_devices, newdev, nextdev);
357 	}
358 
359 	if (fwflash_debug != 0) {
360 		struct devicelist *tempdev;
361 
362 		TAILQ_FOREACH(tempdev, fw_devices, nextdev) {
363 			logmsg(MSG_INFO, "fw_identify: hermon:\n");
364 			logmsg(MSG_INFO, "\ttempdev @ 0x%lx\n"
365 			    "\t\taccess_devname: %s\n"
366 			    "\t\tdrvname: %s\tclassname: %s\n"
367 			    "\t\tident->vid:   %s\n"
368 			    "\t\tident->pid:   %s\n"
369 			    "\t\tident->revid: %s\n"
370 			    "\t\tindex: %d\n"
371 			    "\t\tguid0: %s\n"
372 			    "\t\tguid1: %s\n"
373 			    "\t\tguid2: %s\n"
374 			    "\t\tguid3: %s\n"
375 			    "\t\tplugin @ 0x%lx\n\n",
376 			    &tempdev,
377 			    tempdev->access_devname,
378 			    tempdev->drvname, newdev->classname,
379 			    tempdev->ident->vid,
380 			    tempdev->ident->pid,
381 			    tempdev->ident->revid,
382 			    tempdev->index,
383 			    tempdev->addresses[0],
384 			    tempdev->addresses[1],
385 			    tempdev->addresses[2],
386 			    tempdev->addresses[3],
387 			    tempdev->plugin);
388 		}
389 	}
390 
391 	return (FWFLASH_SUCCESS);
392 }
393 
394 
395 int
396 fw_devinfo(struct devicelist *thisdev)
397 {
398 	ib_cnx_encap_ident_t	*encap;
399 
400 	logmsg(MSG_INFO, "hermon: fw_devinfo\n");
401 
402 	encap = (ib_cnx_encap_ident_t *)thisdev->ident->encap_ident;
403 	if (CNX_I_CHECK_HANDLE(encap)) {
404 		logmsg(MSG_ERROR, gettext("hermon: fw_devinfo: Invalid handle "
405 		    "for device %s! \n"), thisdev->access_devname);
406 		return (FWFLASH_FAILURE);
407 	}
408 
409 	/* Try the primary first, then the secondary */
410 	fprintf(stdout, gettext("Device[%d] %s\n"),
411 	    thisdev->index, thisdev->access_devname);
412 	fprintf(stdout, gettext("Class [%s]\n"), thisdev->classname);
413 
414 	fprintf(stdout, "\t");
415 
416 	/* Mellanox HCA Flash app note, p40, #4.2.3 table 9 */
417 	fprintf(stdout, gettext("GUID: System Image - %s\n"),
418 	    thisdev->addresses[3]);
419 	fprintf(stdout, gettext("\t\tNode Image - %s\n"),
420 	    thisdev->addresses[0]);
421 	fprintf(stdout, gettext("\t\tPort 1\t   - %s\n"),
422 	    thisdev->addresses[1]);
423 	fprintf(stdout, gettext("\t\tPort 2\t   - %s\n"),
424 	    thisdev->addresses[2]);
425 
426 	fprintf(stdout, gettext("\tFirmware revision  : %s\n"),
427 	    thisdev->ident->revid);
428 
429 	if (encap->pn_len != 0) {
430 		if (strlen(encap->info.mlx_id))
431 			fprintf(stdout, gettext("\tProduct\t\t   : %s (%s)\n"),
432 			    encap->info.mlx_pn, encap->info.mlx_id);
433 		else
434 			fprintf(stdout, gettext("\tProduct\t\t   : %s \n"),
435 			    encap->info.mlx_pn);
436 
437 		if (strlen(encap->info.mlx_psid))
438 			fprintf(stdout, gettext("\tPSID\t\t   : %s\n"),
439 			    encap->info.mlx_psid);
440 		else if (strlen(thisdev->ident->pid))
441 			fprintf(stdout, gettext("\t%s\n"), thisdev->ident->pid);
442 	} else {
443 		fprintf(stdout, gettext("\t%s\n"), thisdev->ident->pid);
444 	}
445 	fprintf(stdout, "\n\n");
446 
447 	return (cnx_close(thisdev));
448 }
449 
450 
451 /*
452  * Helper functions lurk beneath this point
453  */
454 
455 
456 /*
457  * Notes:
458  * 1. flash read is done in 32 bit quantities, and the driver returns
459  *    data in host byteorder form.
460  * 2. flash write is done in 8 bit quantities by the driver.
461  * 3. data in the flash should be in network byteorder.
462  * 4. data in image files is in network byteorder form.
463  * 5. data in image structures in memory is kept in network byteorder.
464  * 6. the functions in this file deal with data in host byteorder form.
465  */
466 
467 static int
468 cnx_read_image(ib_cnx_encap_ident_t *handle)
469 {
470 	hermon_flash_ioctl_t	ioctl_info;
471 	uint32_t		phys_addr;
472 	int			ret, i;
473 	int			image_size;
474 	int			type;
475 
476 	type = handle->state &
477 	    (FWFLASH_IB_STATE_IMAGE_PRI | FWFLASH_IB_STATE_IMAGE_SEC);
478 	logmsg(MSG_INFO, "cnx_read_image: type %lx\n", type);
479 
480 	if (type == 0) {
481 		logmsg(MSG_ERROR, gettext("cnx_read_image: Must read in "
482 		    "image first\n"));
483 		return (FWFLASH_FAILURE);
484 	}
485 
486 	image_size = handle->fw_sz;
487 	if (image_size <= 0) {
488 		logmsg(MSG_ERROR, gettext("cnx_read_image: Invalid image size "
489 		    "0x%x for %s image\n"),
490 		    image_size, (type == 0x1 ? "Primary" : "Secondary"));
491 		return (FWFLASH_FAILURE);
492 	}
493 
494 	logmsg(MSG_INFO, "hermon: fw_size: 0x%x\n", image_size);
495 
496 	handle->fw = (uint32_t *)calloc(1, image_size);
497 	if (handle->fw == NULL) {
498 		logmsg(MSG_ERROR, gettext("cnx_read_image: Unable to allocate "
499 		    "memory for fw_img : (%s)\n"), strerror(errno));
500 		return (FWFLASH_FAILURE);
501 	}
502 
503 	ioctl_info.af_type = HERMON_FLASH_READ_QUADLET;
504 	for (i = 0; i < image_size; i += 4) {
505 		phys_addr = cnx_cont2phys(handle->log2_chunk_sz, i, type);
506 		ioctl_info.af_addr = phys_addr;
507 
508 		ret = cnx_read_ioctl(handle, &ioctl_info);
509 		if (ret != 0) {
510 			logmsg(MSG_ERROR, gettext("cnx_read_image: Failed to "
511 			    "read sector %d\n"), i);
512 			free(handle->fw);
513 			return (FWFLASH_FAILURE);
514 		}
515 		handle->fw[i / 4] = htonl(ioctl_info.af_quadlet);
516 	}
517 
518 	for (i = 0; i < image_size; i += 4) {
519 		logmsg(MSG_INFO, "cnx_read_image: addr[0x%x] = 0x%08x\n", i,
520 		    ntohl(handle->fw[i / 4]));
521 	}
522 
523 	return (FWFLASH_SUCCESS);
524 }
525 
526 static int
527 cnx_write_file(ib_cnx_encap_ident_t *handle, const char *filename)
528 {
529 	FILE		*fp;
530 	int 		fd;
531 	mode_t		mode = S_IRUSR | S_IWUSR;
532 	int		len;
533 
534 	logmsg(MSG_INFO, "cnx_write_file\n");
535 
536 	errno = 0;
537 	if ((fd = open(filename, O_RDWR|O_CREAT|O_DSYNC, mode)) < 0) {
538 		logmsg(MSG_ERROR, gettext("hermon: Unable to open specified "
539 		    "file (%s) for writing: %s\n"), filename, strerror(errno));
540 		return (FWFLASH_FAILURE);
541 	}
542 
543 	errno = 0;
544 	fp = fdopen(fd, "w");
545 	if (fp == NULL) {
546 		(void) fprintf(stderr, gettext("hermon: Unknown filename %s : "
547 		    "%s\n"), filename, strerror(errno));
548 		return (FWFLASH_FAILURE);
549 	}
550 
551 	len = ntohl(handle->fw[CNX_IMG_SIZE_OFFSET / 4]);
552 	logmsg(MSG_INFO, "cnx_write_file: Writing to file. Length 0x%x\n", len);
553 
554 	if (fwrite(&handle->fw[0], len, 1, fp) == 0) {
555 		(void) fprintf(stderr, gettext("hermon: fwrite failed"));
556 		perror("fwrite");
557 		(void) fclose(fp);
558 		return (FWFLASH_FAILURE);
559 	}
560 	(void) fclose(fp);
561 	return (FWFLASH_SUCCESS);
562 }
563 
564 static int
565 cnx_verify_image(ib_cnx_encap_ident_t *handle, int type)
566 {
567 	uint32_t	new_start_addr;
568 
569 	logmsg(MSG_INFO, "hermon: cnx_verify_image\n");
570 
571 	new_start_addr = cnx_cont2phys(handle->log2_chunk_sz, 0, type);
572 
573 	return (cnx_check_for_magic_pattern(handle, new_start_addr));
574 }
575 
576 static int
577 cnx_set_guids(ib_cnx_encap_ident_t *handle, void *arg)
578 {
579 	uint32_t	addr;
580 	uint32_t	*guids;
581 
582 	logmsg(MSG_INFO, "hermon: cnx_set_guids\n");
583 
584 	guids = (uint32_t *)arg;
585 	addr = ntohl(verifier->fwimage[CNX_NGUIDPTR_OFFSET / 4]) / 4;
586 	logmsg(MSG_INFO, "cnx_set_guids: guid_start_addr: 0x%x\n", addr * 4);
587 
588 	/*
589 	 * guids are supplied by callers as 64 bit values in host byteorder.
590 	 * Storage is in network byteorder.
591 	 */
592 #ifdef _BIG_ENDIAN
593 	if (handle->state & FWFLASH_IB_STATE_GUIDN) {
594 		verifier->fwimage[addr] = guids[0];
595 		verifier->fwimage[addr + 1] = guids[1];
596 	}
597 
598 	if (handle->state & FWFLASH_IB_STATE_GUID1) {
599 		verifier->fwimage[addr + 2] = guids[2];
600 		verifier->fwimage[addr + 3] = guids[3];
601 	}
602 
603 	if (handle->state & FWFLASH_IB_STATE_GUID2) {
604 		verifier->fwimage[addr + 4] = guids[4];
605 		verifier->fwimage[addr + 5] = guids[5];
606 	}
607 
608 	if (handle->state & FWFLASH_IB_STATE_GUIDS) {
609 		verifier->fwimage[addr + 6] = guids[6];
610 		verifier->fwimage[addr + 7] = guids[7];
611 	}
612 #else
613 	if (handle->state & FWFLASH_IB_STATE_GUIDN) {
614 		verifier->fwimage[addr] = htonl(guids[1]);
615 		verifier->fwimage[addr + 1] = htonl(guids[0]);
616 	}
617 
618 	if (handle->state & FWFLASH_IB_STATE_GUID1) {
619 		verifier->fwimage[addr + 2] = htonl(guids[3]);
620 		verifier->fwimage[addr + 3] = htonl(guids[2]);
621 	}
622 
623 	if (handle->state & FWFLASH_IB_STATE_GUID2) {
624 		verifier->fwimage[addr + 4] = htonl(guids[5]);
625 		verifier->fwimage[addr + 5] = htonl(guids[4]);
626 	}
627 
628 	if (handle->state & FWFLASH_IB_STATE_GUIDS) {
629 		verifier->fwimage[addr + 6] = htonl(guids[7]);
630 		verifier->fwimage[addr + 7] = htonl(guids[6]);
631 	}
632 #endif
633 
634 	cnx_local_set_guid_crc_img((addr * 4) - 0x10, CNX_GUID_CRC16_SIZE,
635 	    CNX_GUID_CRC16_OFFSET);
636 
637 	return (FWFLASH_SUCCESS);
638 }
639 
640 /*
641  * Notes: Burn the image
642  *
643  * 1. Erase the entire sector where the new image is to be burned.
644  * 2. Burn the image WITHOUT the magic pattern. This marks the new image
645  *    as invalid during the burn process. If the current image (i.e
646  *    containing a magic pattern) on the Flash is stored on the even
647  *    chunks (PRIMARY), burn the new image to the odd chunks (SECONDARY),
648  *    or vice versa.
649  * 3. Burn the magic pattern at the beginning of the new image on the Flash.
650  *    This will validate the new image.
651  * 4. Set the BootAddress register to its new location.
652  */
653 static int
654 cnx_write_image(ib_cnx_encap_ident_t *handle, int type)
655 {
656 	hermon_flash_ioctl_t	ioctl_info;
657 	int			sector_size;
658 	int			size;
659 	int			i;
660 	uint32_t		new_start_addr;
661 	uint32_t		log2_chunk_sz;
662 	uint8_t			*fw;
663 
664 	logmsg(MSG_INFO, "hermon: cnx_write_image\n");
665 
666 	if (type == 0) {
667 		logmsg(MSG_ERROR, gettext("cnx_write_image: Must inform us "
668 		    " where to write.\n"));
669 		return (FWFLASH_FAILURE);
670 	}
671 
672 	log2_chunk_sz = cnx_get_log2_chunk_size(
673 	    ntohl(verifier->fwimage[CNX_CHUNK_SIZE_OFFSET / 4]));
674 
675 	sector_size = handle->sector_sz;
676 	new_start_addr = ((type - 1) << handle->log2_chunk_sz);
677 
678 	/* Read Image Size */
679 	size = ntohl(verifier->fwimage[CNX_IMG_SIZE_OFFSET / 4]);
680 	logmsg(MSG_INFO, "cnx_write_image: fw image size: 0x%x\n", size);
681 
682 	/* Sectors must be erased before they can be written to. */
683 	ioctl_info.af_type = HERMON_FLASH_ERASE_SECTOR;
684 	for (i = 0; i < size; i += sector_size) {
685 		ioctl_info.af_sector_num =
686 		    cnx_cont2phys(log2_chunk_sz, i, type) / sector_size;
687 		if (cnx_erase_sector_ioctl(handle, &ioctl_info) != 0) {
688 			logmsg(MSG_ERROR, gettext("cnx_write_image: Failed to "
689 			    "erase sector 0x%x\n"), ioctl_info.af_sector_num);
690 			return (FWFLASH_FAILURE);
691 		}
692 	}
693 
694 	fw = (uint8_t *)verifier->fwimage;
695 	ioctl_info.af_type = HERMON_FLASH_WRITE_BYTE;
696 
697 	/* Write the new image without the magic pattern */
698 	for (i = 16; i < size; i++) {
699 		ioctl_info.af_byte = fw[i];
700 		ioctl_info.af_addr = cnx_cont2phys(log2_chunk_sz, i, type);
701 		if (cnx_write_ioctl(handle, &ioctl_info) != 0) {
702 			logmsg(MSG_ERROR, gettext("cnx_write_image: Failed to "
703 			    "write byte 0x%x\n"), ioctl_info.af_byte);
704 			return (FWFLASH_FAILURE);
705 		}
706 
707 		if (i && !(i % handle->sector_sz)) {
708 			(void) printf(" .");
709 			(void) fflush((void *)NULL);
710 		}
711 	}
712 
713 	/* Validate the new image -- Write the magic pattern. */
714 	for (i = 0; i < 16; i++) {
715 		ioctl_info.af_byte = fw[i];
716 		ioctl_info.af_addr = cnx_cont2phys(log2_chunk_sz, i, type);
717 		if (cnx_write_ioctl(handle, &ioctl_info) != 0) {
718 			logmsg(MSG_ERROR, gettext("cnx_write_image: Failed to "
719 			    "write magic pattern byte 0x%x\n"),
720 			    ioctl_info.af_byte);
721 			return (FWFLASH_FAILURE);
722 		}
723 	}
724 
725 	/* Write new image start address to CR space */
726 	errno = 0;
727 	ioctl_info.af_addr = new_start_addr;
728 	if (ioctl(handle->fd, HERMON_IOCTL_WRITE_BOOT_ADDR, &ioctl_info) != 0) {
729 		logmsg(MSG_WARN, gettext("cnx_write_image: Failed to "
730 		    "update boot address register: %s\n"), strerror(errno));
731 	}
732 
733 	return (FWFLASH_SUCCESS);
734 }
735 
736 
737 /*
738  * cnx_identify performs the following actions:
739  *
740  *	allocates and assigns thisdev->vpr
741  *
742  *	allocates space for the 4 GUIDs which each IB device must have
743  *	queries the hermon driver for this device's GUIDs
744  *
745  *	determines the hardware vendor, so that thisdev->vpr->vid
746  *	can be set correctly
747  */
748 static int
749 cnx_identify(struct devicelist *thisdev)
750 {
751 	int				fd, ret, i;
752 	hermon_flash_init_ioctl_t	init_ioctl;
753 	ib_cnx_encap_ident_t		*manuf;
754 	cfi_t				cfi;
755 	int				hw_psid_found = 0;
756 
757 	logmsg(MSG_INFO, "hermon: cnx_identify\n");
758 	/* open the device */
759 	/* hook thisdev->ident->encap_ident to ib_cnx_encap_ident_t */
760 	/* check that all the bits are sane */
761 	/* return success, if warranted */
762 
763 	errno = 0;
764 	if ((fd = open(thisdev->access_devname, O_RDONLY)) < 0) {
765 		logmsg(MSG_ERROR, gettext("hermon: Unable to open a %s-"
766 		    "attached device node: %s: %s\n"), drivername,
767 		    thisdev->access_devname, strerror(errno));
768 		return (FWFLASH_FAILURE);
769 	}
770 
771 	if ((manuf = calloc(1, sizeof (ib_cnx_encap_ident_t))) == NULL) {
772 		logmsg(MSG_ERROR, gettext("hermon: Unable to allocate space "
773 		    "for a %s-attached handle structure\n"), drivername);
774 		close(fd);
775 		return (FWFLASH_FAILURE);
776 	}
777 	manuf->magic = FWFLASH_IB_MAGIC_NUMBER;
778 	manuf->state = FWFLASH_IB_STATE_NONE;
779 	manuf->fd = fd;
780 	manuf->log2_chunk_sz = 0;
781 
782 	thisdev->ident->encap_ident = manuf;
783 
784 	/*
785 	 * Inform driver that this command supports the Intel Extended
786 	 * CFI command set.
787 	 */
788 	cfi.cfi_char[0x10] = 'M';
789 	cfi.cfi_char[0x11] = 'X';
790 	cfi.cfi_char[0x12] = '2';
791 	init_ioctl.af_cfi_info[0x4] = ntohl(cfi.cfi_int[0x4]);
792 
793 	errno = 0;
794 	ret = ioctl(fd, HERMON_IOCTL_FLASH_INIT, &init_ioctl);
795 	if (ret < 0) {
796 		logmsg(MSG_ERROR, gettext("hermon: HERMON_IOCTL_FLASH_INIT "
797 		    "failed: %s\n"), strerror(errno));
798 		close(fd);
799 		free(manuf);
800 		return (FWFLASH_FAILURE);
801 	}
802 
803 	manuf->hwrev = init_ioctl.af_hwrev;
804 	logmsg(MSG_INFO, "hermon: init_ioctl: hwrev: %x, fwver: %d.%d.%04d, "
805 	    "PN# Len %d\n", init_ioctl.af_hwrev, init_ioctl.af_fwrev.afi_maj,
806 	    init_ioctl.af_fwrev.afi_min, init_ioctl.af_fwrev.afi_sub,
807 	    init_ioctl.af_pn_len);
808 
809 	/*
810 	 * Determine whether the attached driver supports the Intel or
811 	 * AMD Extended CFI command sets. If it doesn't support either,
812 	 * then we're hosed, so error out.
813 	 */
814 	for (i = 0; i < HERMON_FLASH_CFI_SIZE_QUADLET; i++) {
815 		cfi.cfi_int[i] = ntohl(init_ioctl.af_cfi_info[i]);
816 	}
817 	manuf->cmd_set = cfi.cfi_char[0x13];
818 
819 	if (cfi.cfi_char[0x10] == 'Q' &&
820 	    cfi.cfi_char[0x11] == 'R' &&
821 	    cfi.cfi_char[0x12] == 'Y') {
822 		/* make sure the cmd set is SPI */
823 		if (manuf->cmd_set != HERMON_FLASH_SPI_CMDSET) {
824 			logmsg(MSG_ERROR, gettext("hermon: Unsupported flash "
825 			    "device command set\n"));
826 			goto identify_end;
827 		}
828 		/* set some defaults */
829 		manuf->sector_sz = HERMON_FLASH_SECTOR_SZ_DEFAULT;
830 		manuf->device_sz = HERMON_FLASH_DEVICE_SZ_DEFAULT;
831 	} else if (manuf->cmd_set == HERMON_FLASH_SPI_CMDSET) {
832 		manuf->sector_sz = HERMON_FLASH_SPI_SECTOR_SIZE;
833 		manuf->device_sz = HERMON_FLASH_SPI_DEVICE_SIZE;
834 	} else {
835 		if (manuf->cmd_set != HERMON_FLASH_AMD_CMDSET &&
836 		    manuf->cmd_set != HERMON_FLASH_INTEL_CMDSET) {
837 			logmsg(MSG_ERROR, gettext("hermon: Unknown flash "
838 			    "device command set %lx\n"), manuf->cmd_set);
839 			goto identify_end;
840 		}
841 		/* read from the CFI data */
842 		manuf->sector_sz = ((cfi.cfi_char[0x30] << 8) |
843 		    cfi.cfi_char[0x2F]) << 8;
844 		manuf->device_sz = 0x1 << cfi.cfi_char[0x27];
845 	}
846 
847 	logmsg(MSG_INFO, "hermon: sector_sz: 0x%08x device_sz: 0x%08x\n",
848 	    manuf->sector_sz, manuf->device_sz);
849 
850 	/* set firmware revision */
851 	manuf->hwfw_img_info.fw_rev.major = init_ioctl.af_fwrev.afi_maj;
852 	manuf->hwfw_img_info.fw_rev.minor = init_ioctl.af_fwrev.afi_min;
853 	manuf->hwfw_img_info.fw_rev.subminor = init_ioctl.af_fwrev.afi_sub;
854 
855 	if (((thisdev->ident->vid = calloc(1, MLX_VPR_VIDLEN + 1)) == NULL) ||
856 	    ((thisdev->ident->revid = calloc(1, MLX_VPR_REVLEN + 1)) == NULL)) {
857 		logmsg(MSG_ERROR, gettext("hermon: Unable to allocate space "
858 		    "for a VPR record.\n"));
859 		goto identify_end;
860 	}
861 	(void) strlcpy(thisdev->ident->vid, "MELLANOX", MLX_VPR_VIDLEN);
862 
863 	/*
864 	 * We actually want the hwrev field from the ioctl above.
865 	 * Until we find out otherwise, add it onto the end of the
866 	 * firmware version details.
867 	 */
868 	snprintf(thisdev->ident->revid, MLX_VPR_REVLEN, "%d.%d.%03d",
869 	    manuf->hwfw_img_info.fw_rev.major,
870 	    manuf->hwfw_img_info.fw_rev.minor,
871 	    manuf->hwfw_img_info.fw_rev.subminor);
872 
873 	if ((ret = cnx_get_guids(manuf)) != FWFLASH_SUCCESS) {
874 		logmsg(MSG_WARN, gettext("hermon: No GUIDs found for "
875 		    "device %s!\n"), thisdev->access_devname);
876 	}
877 
878 	/* set hw part number, psid, and name in handle */
879 	/* now walk the magic decoder ring table */
880 	manuf->info.mlx_pn = NULL;
881 	manuf->info.mlx_psid = NULL;
882 	manuf->info.mlx_id = NULL;
883 
884 	if (cnx_get_image_info(manuf) != FWFLASH_SUCCESS) {
885 		logmsg(MSG_WARN, gettext("hermon: Failed to read Image Info "
886 		    "for PSID\n"));
887 		hw_psid_found = 0;
888 	} else {
889 		hw_psid_found = 1;
890 	}
891 
892 	if (init_ioctl.af_pn_len != 0) {
893 		/* part number length */
894 		for (i = 0; i < init_ioctl.af_pn_len; i++) {
895 			if (init_ioctl.af_hwpn[i] == ' ') {
896 				manuf->pn_len = i;
897 				break;
898 			}
899 		}
900 		if (i == init_ioctl.af_pn_len) {
901 			manuf->pn_len = init_ioctl.af_pn_len;
902 		}
903 	} else {
904 		logmsg(MSG_INFO, "hermon: Failed to get Part# from hermon "
905 		    "driver \n");
906 		manuf->pn_len = 0;
907 	}
908 
909 	if (manuf->pn_len != 0) {
910 		errno = 0;
911 		manuf->info.mlx_pn = calloc(1, manuf->pn_len);
912 		if (manuf->info.mlx_pn == NULL) {
913 			logmsg(MSG_ERROR, gettext("hermon: no space available "
914 			    "for the HCA PN record (%s)\n"), strerror(errno));
915 			goto identify_end;
916 		}
917 		(void) memcpy(manuf->info.mlx_pn, init_ioctl.af_hwpn,
918 		    manuf->pn_len);
919 		manuf->info.mlx_pn[manuf->pn_len] = 0;
920 
921 		logmsg(MSG_INFO, "hermon: HCA PN (%s) PN-Len %d\n",
922 		    manuf->info.mlx_pn, manuf->pn_len);
923 
924 		errno = 0;
925 		manuf->info.mlx_psid = calloc(1, MLX_PSID_SZ);
926 		if (manuf->info.mlx_psid == NULL) {
927 			logmsg(MSG_ERROR, gettext("hermon: PSID calloc "
928 			    "failed :%s\n"), strerror(errno));
929 			goto identify_end;
930 		}
931 
932 		errno = 0;
933 		if ((manuf->info.mlx_id = calloc(1, MLX_STR_ID_SZ)) == NULL) {
934 			logmsg(MSG_ERROR, gettext("hermon: "
935 			    "ID calloc failed (%s)\n"),
936 			    strerror(errno));
937 			goto identify_end;
938 		}
939 
940 		/* Find part number, set the rest */
941 		for (i = 0; i < MLX_MAX_ID; i++) {
942 			if (strncmp((const char *)init_ioctl.af_hwpn,
943 			    mlx_mdr[i].mlx_pn, manuf->pn_len) == 0) {
944 
945 				if (hw_psid_found) {
946 					logmsg(MSG_INFO, "HW-PSID: %s "
947 					    "MLX_MDR[%d]: %s\n",
948 					    manuf->hwfw_img_info.psid, i,
949 					    mlx_mdr[i].mlx_psid);
950 					if (strncmp((const char *)
951 					    manuf->hwfw_img_info.psid,
952 					    mlx_mdr[i].mlx_psid,
953 					    MLX_PSID_SZ) != 0)
954 						continue;
955 				}
956 				/* Set PSID */
957 				(void) memcpy(manuf->info.mlx_psid,
958 				    mlx_mdr[i].mlx_psid, MLX_PSID_SZ);
959 				manuf->info.mlx_psid[MLX_PSID_SZ - 1] = 0;
960 
961 				logmsg(MSG_INFO, "hermon: HCA PSID (%s)\n",
962 				    manuf->info.mlx_psid);
963 
964 				(void) strlcpy(manuf->info.mlx_id,
965 				    mlx_mdr[i].mlx_id,
966 				    strlen(mlx_mdr[i].mlx_id) + 1);
967 
968 				logmsg(MSG_INFO, "hermon: HCA Name (%s)\n",
969 				    manuf->info.mlx_id);
970 
971 				break;
972 			}
973 		}
974 	}
975 
976 	if ((manuf->pn_len == 0) || (i == MLX_MAX_ID)) {
977 		logmsg(MSG_INFO, "hermon: No hardware part number "
978 		    "information available for this HCA\n");
979 
980 		i = strlen("No hardware information available for this device");
981 
982 		thisdev->ident->pid = calloc(1, i + 2);
983 		sprintf(thisdev->ident->pid, "No additional hardware info "
984 		    "available for this device");
985 	} else {
986 		errno = 0;
987 		if ((thisdev->ident->pid = calloc(1,
988 		    strlen(manuf->info.mlx_psid) + 1)) != NULL) {
989 			(void) strlcpy(thisdev->ident->pid,
990 			    manuf->info.mlx_psid,
991 			    strlen(manuf->info.mlx_psid) + 1);
992 		} else {
993 			logmsg(MSG_ERROR,
994 			    gettext("hermon: Unable to allocate space for a "
995 			    "hardware identifier: %s\n"), strerror(errno));
996 			goto identify_end;
997 		}
998 	}
999 
1000 	for (i = 0; i < 4; i++) {
1001 		errno = 0;
1002 		if ((thisdev->addresses[i] = calloc(1,
1003 		    (2 * sizeof (uint64_t)) + 1)) == NULL) {
1004 			logmsg(MSG_ERROR,
1005 			    gettext("hermon: Unable to allocate space for a "
1006 			    "human-readable HCA guid: %s\n"), strerror(errno));
1007 			goto identify_end;
1008 		}
1009 		(void) sprintf(thisdev->addresses[i], "%016llx",
1010 		    manuf->ibguids[i]);
1011 	}
1012 
1013 	/*
1014 	 * We do NOT close the fd here, since we can close it
1015 	 * at the end of the fw_readfw() or fw_writefw() functions
1016 	 * instead and not get the poor dear confused about whether
1017 	 * it's been inited already.
1018 	 */
1019 
1020 	return (FWFLASH_SUCCESS);
1021 
1022 	/* cleanup */
1023 identify_end:
1024 	cnx_close(thisdev);
1025 	return (FWFLASH_FAILURE);
1026 }
1027 
1028 static int
1029 cnx_get_guids(ib_cnx_encap_ident_t *handle)
1030 {
1031 	int	i, rv;
1032 
1033 	logmsg(MSG_INFO, "cnx_get_guids\n");
1034 
1035 	/* make sure we've got our fallback position organised */
1036 	for (i = 0; i < 4; i++) {
1037 		handle->ibguids[i] = 0x00000000;
1038 	}
1039 
1040 	rv = cnx_find_magic_n_chnk_sz(handle, FWFLASH_IB_STATE_IMAGE_PRI);
1041 	if (rv != FWFLASH_SUCCESS) {
1042 		logmsg(MSG_INFO, "hermon: Failed to get Primary magic number. "
1043 		    "Trying Secondary... \n");
1044 		rv = cnx_find_magic_n_chnk_sz(handle,
1045 		    FWFLASH_IB_STATE_IMAGE_SEC);
1046 		if (rv != FWFLASH_SUCCESS) {
1047 			logmsg(MSG_ERROR, gettext("hermon: Failed to get "
1048 			    "Secondary magic number.\n"));
1049 			logmsg(MSG_ERROR,
1050 			    gettext("Warning: HCA Firmware corrupt.\n"));
1051 			return (FWFLASH_FAILURE);
1052 		}
1053 		rv = cnx_read_guids(handle, FWFLASH_IB_STATE_IMAGE_SEC);
1054 		if (rv != FWFLASH_SUCCESS) {
1055 			logmsg(MSG_ERROR, gettext("hermon: Failed to read "
1056 			    "secondary guids.\n"));
1057 			return (FWFLASH_FAILURE);
1058 		}
1059 	} else {
1060 		rv = cnx_read_guids(handle, FWFLASH_IB_STATE_IMAGE_PRI);
1061 		if (rv != FWFLASH_SUCCESS) {
1062 			logmsg(MSG_ERROR, gettext("hermon: Failed to read "
1063 			    "primary guids.\n"));
1064 			return (FWFLASH_FAILURE);
1065 		}
1066 	}
1067 	for (i = 0; i < 4; i++) {
1068 		logmsg(MSG_INFO, "hermon: ibguids[%d] 0x%016llx\n", i,
1069 		    handle->ibguids[i]);
1070 	}
1071 	for (i = 0; i < 2; i++) {
1072 		logmsg(MSG_INFO, "hermon: ib_portmac[%d] 0x%016llx\n", i,
1073 		    handle->ib_mac[i]);
1074 	}
1075 
1076 	return (FWFLASH_SUCCESS);
1077 }
1078 
1079 static int
1080 cnx_close(struct devicelist *flashdev)
1081 {
1082 	ib_cnx_encap_ident_t	*handle;
1083 
1084 	logmsg(MSG_INFO, "cnx_close\n");
1085 
1086 	handle = (ib_cnx_encap_ident_t *)flashdev->ident->encap_ident;
1087 
1088 	if (CNX_I_CHECK_HANDLE(handle)) {
1089 		logmsg(MSG_ERROR, gettext("hermon: Invalid Handle to close "
1090 		    "device %s! \n"), flashdev->access_devname);
1091 		return (FWFLASH_FAILURE);
1092 	}
1093 
1094 	if (handle->fd > 0) {
1095 		errno = 0;
1096 		(void) ioctl(handle->fd, HERMON_IOCTL_FLASH_FINI);
1097 		if (close(handle->fd) != 0) {
1098 			logmsg(MSG_ERROR, gettext("hermon: Unable to properly "
1099 			    "close device %s! (%s)\n"),
1100 			    flashdev->access_devname, strerror(errno));
1101 			return (FWFLASH_FAILURE);
1102 		}
1103 	}
1104 
1105 	if (handle != NULL) {
1106 		if (handle->info.mlx_id != NULL)
1107 			free(handle->info.mlx_id);
1108 
1109 		if (handle->info.mlx_psid != NULL)
1110 			free(handle->info.mlx_psid);
1111 
1112 		if (handle->fw != NULL)
1113 			free(handle->fw);
1114 		free(handle);
1115 	}
1116 
1117 	if (flashdev->ident->vid != NULL)
1118 		free(flashdev->ident->vid);
1119 
1120 	if (flashdev->ident->revid != NULL)
1121 		free(flashdev->ident->revid);
1122 
1123 	return (FWFLASH_SUCCESS);
1124 }
1125 
1126 
1127 /*
1128  * Driver read/write ioctl calls.
1129  */
1130 static int
1131 cnx_read_ioctl(ib_cnx_encap_ident_t *hdl, hermon_flash_ioctl_t *info)
1132 {
1133 	int	ret;
1134 
1135 #ifdef CNX_DEBUG
1136 	logmsg(MSG_INFO, "cnx_read_ioctl: fd %d af_type 0x%x af_addr 0x%x "
1137 	    "af_sector_num(0x%x)\n", hdl->fd, info->af_type,
1138 	    info->af_addr, info->af_sector_num);
1139 #endif
1140 
1141 	errno = 0;
1142 	ret = ioctl(hdl->fd, HERMON_IOCTL_FLASH_READ, info);
1143 	if (ret != 0) {
1144 		logmsg(MSG_ERROR, gettext("HERMON_IOCTL_FLASH_READ failed "
1145 		    "(%s)\n"), strerror(errno));
1146 	}
1147 	return (ret);
1148 }
1149 
1150 static int
1151 cnx_write_ioctl(ib_cnx_encap_ident_t *hdl, hermon_flash_ioctl_t *info)
1152 {
1153 	int	ret;
1154 
1155 #ifdef CNX_DEBUG
1156 	logmsg(MSG_INFO, "cnx_write_ioctl: fd(%d) af_type(0x%x) "
1157 	    "af_addr(0x%x) af_sector_num(0x%x) af_byte(0x%x)\n",
1158 	    hdl->fd, info->af_type, info->af_addr, info->af_sector_num,
1159 	    info->af_byte);
1160 #endif
1161 	errno = 0;
1162 	ret = ioctl(hdl->fd, HERMON_IOCTL_FLASH_WRITE, info);
1163 	if (ret != 0) {
1164 		logmsg(MSG_ERROR, gettext("HERMON_IOCTL_FLASH_WRITE "
1165 		    "failed (%s)\n"), strerror(errno));
1166 	}
1167 	return (ret);
1168 }
1169 
1170 static int
1171 cnx_erase_sector_ioctl(ib_cnx_encap_ident_t *hdl, hermon_flash_ioctl_t *info)
1172 {
1173 	int	ret;
1174 
1175 #ifdef CNX_DEBUG
1176 	logmsg(MSG_INFO, "cnx_erase_sector_ioctl: fd(%d) af_type(0x%x) "
1177 	    "af_sector_num(0x%x)\n", hdl->fd, info->af_type,
1178 	    info->af_sector_num);
1179 #endif
1180 	errno = 0;
1181 	ret = ioctl(hdl->fd, HERMON_IOCTL_FLASH_ERASE, info);
1182 	if (ret != 0) {
1183 		logmsg(MSG_ERROR, gettext("HERMON_IOCTL_FLASH_ERASE "
1184 		    "failed (%s)\n"), strerror(errno));
1185 	}
1186 	return (ret);
1187 }
1188 
1189 /*
1190  * cnx_crc16 - computes 16 bit crc of supplied buffer.
1191  *   image should be in network byteorder
1192  *   result is returned in host byteorder form
1193  */
1194 uint16_t
1195 cnx_crc16(uint8_t *image, uint32_t size, int is_image)
1196 {
1197 	const uint16_t	poly = 0x100b;
1198 	uint32_t	crc = 0xFFFF;
1199 	uint32_t	word;
1200 	uint32_t	i, j;
1201 
1202 	logmsg(MSG_INFO, "hermon: cnx_crc16\n");
1203 
1204 	for (i = 0; i < size / 4; i++) {
1205 		word = (image[4 * i] << 24) |
1206 		    (image[4 * i + 1] << 16) |
1207 		    (image[4 * i + 2] << 8) |
1208 		    (image[4 * i + 3]);
1209 
1210 		if (is_image == CNX_HW_IMG)
1211 			word = MLXSWAPBITS32(word);
1212 
1213 		for (j = 0; j < 32; j++) {
1214 			if (crc & 0x8000) {
1215 				crc = (((crc << 1) |
1216 				    (word >> 31)) ^ poly) & 0xFFFF;
1217 			} else {
1218 				crc = ((crc << 1) | (word >> 31)) & 0xFFFF;
1219 			}
1220 			word = (word << 1) & 0xFFFFFFFF;
1221 		}
1222 	}
1223 
1224 	for (i = 0; i < 16; i++) {
1225 		if (crc & 0x8000) {
1226 			crc = ((crc << 1) ^ poly) & 0xFFFF;
1227 		} else {
1228 			crc = (crc << 1) & 0xFFFF;
1229 		}
1230 	}
1231 
1232 	crc = crc ^ 0xFFFF;
1233 	return (crc & 0xFFFF);
1234 }
1235 
1236 static void
1237 cnx_local_set_guid_crc_img(uint32_t offset, uint32_t guid_crc_size,
1238     uint32_t guid_crc_offset)
1239 {
1240 	uint16_t	crc;
1241 	uint8_t		*fw_p = (uint8_t *)&verifier->fwimage[0];
1242 
1243 	crc = htons(cnx_crc16((uint8_t *)&verifier->fwimage[offset / 4],
1244 	    guid_crc_size, CNX_FILE_IMG));
1245 
1246 	logmsg(MSG_INFO, "cnx_local_set_guid_crc_img: new guid_sect crc: %x\n",
1247 	    ntohs(crc));
1248 	(void) memcpy(&fw_p[offset + guid_crc_offset], &crc, 2);
1249 }
1250 
1251 /*
1252  * Address translation functions for ConnectX
1253  * Variable definitions:
1254  * - log2_chunk_size: log2 of a Flash chunk size
1255  * - cont_addr: a contiguous image address to be translated
1256  * - is_image_in_odd_chunk: When this bit is 1, it indicates the new image is
1257  * stored in odd chunks of the Flash.
1258  */
1259 static uint32_t
1260 cnx_cont2phys(uint32_t log2_chunk_size, uint32_t cont_addr, int type)
1261 {
1262 	uint32_t	result;
1263 	int		is_image_in_odd_chunks;
1264 
1265 	is_image_in_odd_chunks = type - 1;
1266 
1267 	if (log2_chunk_size) {
1268 		result = cont_addr & (0xffffffff >> (32 - log2_chunk_size)) |
1269 		    (is_image_in_odd_chunks << log2_chunk_size) |
1270 		    (cont_addr << 1) & (0xffffffff << (log2_chunk_size + 1));
1271 	} else {
1272 		result = cont_addr;
1273 	}
1274 
1275 	return (result);
1276 }
1277 
1278 static int
1279 cnx_read_guids(ib_cnx_encap_ident_t *handle, int type)
1280 {
1281 #ifdef _LITTLE_ENDIAN
1282 	uint32_t		*ptr, tmp;
1283 #endif
1284 	hermon_flash_ioctl_t	ioctl_info;
1285 	uint32_t		*guids;
1286 	uint32_t		*ibmac;
1287 	int			ret, i;
1288 	uint32_t		nguidptr_addr;
1289 	union {
1290 		uint8_t		bytes[4];
1291 		uint32_t	dword;
1292 	} crc16_u;
1293 	uint32_t		*guid_structure;
1294 	uint16_t		crc;
1295 
1296 	logmsg(MSG_INFO, "cnx_read_guids\n");
1297 
1298 	errno = 0;
1299 	guid_structure = (uint32_t *)calloc(1,
1300 	    CNX_GUID_CRC16_SIZE / 4 * sizeof (uint32_t));
1301 	if (guid_structure == NULL) {
1302 		logmsg(MSG_WARN, gettext("hermon: Can't calloc guid_structure "
1303 		    ": (%s)\n"), strerror(errno));
1304 		return (FWFLASH_FAILURE);
1305 	}
1306 
1307 	ioctl_info.af_type = HERMON_FLASH_READ_QUADLET;
1308 	ioctl_info.af_addr = cnx_cont2phys(handle->log2_chunk_sz,
1309 	    CNX_NGUIDPTR_OFFSET, type);
1310 
1311 	ret = cnx_read_ioctl(handle, &ioctl_info);
1312 	if (ret != 0) {
1313 		logmsg(MSG_WARN, gettext("hermon: Failed to read GUID Pointer "
1314 		    "Address\n"));
1315 		goto out;
1316 	}
1317 
1318 	guids = (uint32_t *)&handle->ibguids[0];
1319 	ibmac = (uint32_t *)&handle->ib_mac[0];
1320 	nguidptr_addr = cnx_cont2phys(handle->log2_chunk_sz,
1321 	    ioctl_info.af_quadlet, type);
1322 
1323 	logmsg(MSG_INFO, "NGUIDPTR: 0x%08x \n", nguidptr_addr);
1324 	/* Read in the entire guid section in order to calculate the CRC */
1325 	ioctl_info.af_addr = nguidptr_addr - 0x10;
1326 	ioctl_info.af_type = HERMON_FLASH_READ_QUADLET;
1327 
1328 	for (i = 0; i < CNX_GUID_CRC16_SIZE / 4; i++) {
1329 		ret = cnx_read_ioctl(handle, &ioctl_info);
1330 		if (ret != 0) {
1331 			logmsg(MSG_INFO, "Failed to read guid_structure "
1332 			    "(0x%x)\n", i);
1333 			goto out;
1334 		}
1335 
1336 		if (i >= 4 && i < 12) {
1337 			guids[i - 4] = ioctl_info.af_quadlet;
1338 		}
1339 		if (i >= 12 && i < 16) {
1340 			ibmac[i - 12] = ioctl_info.af_quadlet;
1341 		}
1342 
1343 		guid_structure[i] = ioctl_info.af_quadlet;
1344 		ioctl_info.af_addr += 4;
1345 	}
1346 
1347 	for (i = 0; i < CNX_GUID_CRC16_SIZE / 4; i++) {
1348 		logmsg(MSG_INFO, "guid_structure[%x] = 0x%08x\n", i,
1349 		    guid_structure[i]);
1350 	}
1351 
1352 	/*
1353 	 * Check the CRC--make sure it computes.
1354 	 */
1355 
1356 	/* 0x12 subtracted: 0x2 for alignment, 0x10 to reach structure start */
1357 	ioctl_info.af_addr = nguidptr_addr + CNX_GUID_CRC16_OFFSET - 0x12;
1358 	ioctl_info.af_type = HERMON_FLASH_READ_QUADLET;
1359 
1360 	ret = cnx_read_ioctl(handle, &ioctl_info);
1361 	if (ret != 0) {
1362 		logmsg(MSG_WARN, gettext("hermon: Failed to read guid crc "
1363 		    "at 0x%x\n"), ioctl_info.af_addr);
1364 		goto out;
1365 	}
1366 
1367 	crc16_u.dword = ioctl_info.af_quadlet;
1368 	crc = cnx_crc16((uint8_t *)guid_structure, CNX_GUID_CRC16_SIZE,
1369 	    CNX_HW_IMG);
1370 
1371 	if (crc != crc16_u.dword) {
1372 		logmsg(MSG_WARN, gettext("hermon: calculated crc16: 0x%x "
1373 		    "differs from GUID section 0x%x\n"), crc, crc16_u.dword);
1374 	} else {
1375 		logmsg(MSG_INFO, "hermon: calculated crc16: 0x%x MATCHES with "
1376 		    "GUID section 0x%x\n", crc, crc16_u.dword);
1377 	}
1378 
1379 #ifdef _LITTLE_ENDIAN
1380 	/*
1381 	 * guids are read as pairs of 32 bit host byteorder values and treated
1382 	 * by callers as 64 bit values. So swap each pair of 32 bit values
1383 	 * to make them correct
1384 	 */
1385 	ptr = (uint32_t *)guids;
1386 	for (ret = 0; ret < 8; ret += 2) {
1387 		tmp = ptr[ret];
1388 		ptr[ret] = ptr[ret+1];
1389 		ptr[ret+1] = tmp;
1390 	}
1391 	ptr = (uint32_t *)&handle->ib_mac[0];
1392 	for (ret = 0; ret < 4; ret += 2) {
1393 		tmp = ptr[ret];
1394 		ptr[ret] = ptr[ret+1];
1395 		ptr[ret+1] = tmp;
1396 	}
1397 #endif
1398 	ret = FWFLASH_SUCCESS;
1399 
1400 out:
1401 	free(guid_structure);
1402 	return (ret);
1403 }
1404 
1405 static int
1406 cnx_find_magic_n_chnk_sz(ib_cnx_encap_ident_t *handle, int type)
1407 {
1408 	int	i, found = 0;
1409 	uint32_t addr;
1410 	uint32_t boot_addresses[] =
1411 	    {0, 0x10000, 0x20000, 0x40000, 0x80000, 0x100000};
1412 
1413 	logmsg(MSG_INFO, "cnx_find_magic_n_chnk_sz\n");
1414 
1415 	switch (type) {
1416 	case FWFLASH_IB_STATE_IMAGE_PRI:
1417 		addr = 0;
1418 		if (cnx_check_for_magic_pattern(handle, addr) !=
1419 		    FWFLASH_SUCCESS) {
1420 			goto err;
1421 		}
1422 		break;
1423 
1424 	case FWFLASH_IB_STATE_IMAGE_SEC:
1425 		for (i = 1; i < 6; i++) {
1426 			addr = boot_addresses[i];
1427 			if (cnx_check_for_magic_pattern(handle, addr) ==
1428 			    FWFLASH_SUCCESS) {
1429 				found = 1;
1430 				break;
1431 			}
1432 		}
1433 		if (!found) {
1434 			goto err;
1435 		}
1436 		break;
1437 
1438 	default:
1439 		logmsg(MSG_INFO, "cnx_find_magic_pattern: unknown type\n");
1440 		goto err;
1441 	}
1442 
1443 	logmsg(MSG_INFO, "magic_pattern found at addr %x\n", addr);
1444 	handle->img2_start_addr = addr;
1445 
1446 	handle->log2_chunk_sz = cnx_get_log2_chunk_size_f_hdl(handle, type);
1447 	if (handle->log2_chunk_sz == 0) {
1448 		logmsg(MSG_INFO, "no chunk size found for type %x. "
1449 		    "Assuming non-failsafe burn\n", type);
1450 	}
1451 
1452 	handle->fw_sz = cnx_get_image_size_f_hdl(handle, type);
1453 	if (handle->fw_sz == 0) {
1454 		logmsg(MSG_INFO, "no fw size found for type %x. \n", type);
1455 	}
1456 	handle->state |= type;
1457 
1458 	return (FWFLASH_SUCCESS);
1459 err:
1460 	logmsg(MSG_INFO, "no magic_pattern found for type %x\n", type);
1461 	return (FWFLASH_FAILURE);
1462 }
1463 
1464 static int
1465 cnx_check_for_magic_pattern(ib_cnx_encap_ident_t *handle, uint32_t addr)
1466 {
1467 	int 			i;
1468 	hermon_flash_ioctl_t	ioctl_info;
1469 	int 			magic_pattern_buf[4];
1470 
1471 	logmsg(MSG_INFO, "cnx_check_for_magic_pattern\n");
1472 
1473 	ioctl_info.af_type = HERMON_FLASH_READ_QUADLET;
1474 
1475 	for (i = 0; i < 4; i++) {
1476 		ioctl_info.af_addr = addr + (i * sizeof (uint32_t));
1477 		if (cnx_read_ioctl(handle, &ioctl_info) != 0) {
1478 			logmsg(MSG_INFO, "\nFailed to read magic pattern\n");
1479 			return (FWFLASH_FAILURE);
1480 		}
1481 
1482 		magic_pattern_buf[i] = ioctl_info.af_quadlet;
1483 	}
1484 
1485 	return (cnx_is_magic_pattern_present(magic_pattern_buf, CNX_HW_IMG));
1486 
1487 }
1488 
1489 int
1490 cnx_is_magic_pattern_present(int *data, int is_image)
1491 {
1492 	int	i;
1493 	int	dword;
1494 
1495 	logmsg(MSG_INFO, "cnx_is_magic_pattern_present\n");
1496 
1497 	for (i = 0; i < 4; i++) {
1498 		if (is_image == CNX_FILE_IMG)
1499 			dword = MLXSWAPBITS32(data[i]);
1500 		else
1501 			dword = data[i];
1502 		logmsg(MSG_INFO, "local_quadlet: %08x, magic pattern: %08x\n",
1503 		    dword, cnx_magic_pattern[i]);
1504 		if (dword != cnx_magic_pattern[i]) {
1505 			return (FWFLASH_FAILURE);
1506 		}
1507 	}
1508 
1509 	return (FWFLASH_SUCCESS);
1510 }
1511 
1512 static uint32_t
1513 cnx_get_log2_chunk_size_f_hdl(ib_cnx_encap_ident_t *handle, int type)
1514 {
1515 	hermon_flash_ioctl_t	ioctl_info;
1516 	int			ret;
1517 
1518 	logmsg(MSG_INFO, "cnx_get_log2_chunk_size_f_hdl\n");
1519 
1520 	/* If chunk size is already set, just return it. */
1521 	if (handle->log2_chunk_sz) {
1522 		return (handle->log2_chunk_sz);
1523 	}
1524 
1525 	switch (type) {
1526 	case FWFLASH_IB_STATE_IMAGE_PRI:
1527 		ioctl_info.af_addr = CNX_CHUNK_SIZE_OFFSET;
1528 		break;
1529 	case FWFLASH_IB_STATE_IMAGE_SEC:
1530 		ioctl_info.af_addr =
1531 		    handle->img2_start_addr + CNX_CHUNK_SIZE_OFFSET;
1532 		break;
1533 	default:
1534 		logmsg(MSG_INFO,
1535 		    "cnx_get_log2_chunk_size_f_hdl: unknown type\n");
1536 		return (0);
1537 	}
1538 
1539 	ioctl_info.af_type = HERMON_FLASH_READ_QUADLET;
1540 
1541 	ret = cnx_read_ioctl(handle, &ioctl_info);
1542 	if (ret != 0) {
1543 		logmsg(MSG_INFO, "\nFailed to read chunk size\n");
1544 		return (0);
1545 	}
1546 
1547 	return (cnx_get_log2_chunk_size(ioctl_info.af_quadlet));
1548 }
1549 
1550 
1551 static uint32_t
1552 cnx_get_log2_chunk_size(uint32_t chunk_size_word)
1553 {
1554 	uint8_t		checksum;
1555 	uint32_t	log2_chunk_size;
1556 
1557 	logmsg(MSG_INFO, "cnx_get_log2_chunk_size: chunk_size_word:"
1558 	    " 0x%x\n", chunk_size_word);
1559 
1560 	checksum =
1561 	    (chunk_size_word & 0xff) +
1562 	    ((chunk_size_word >> 8) & 0xff) +
1563 	    ((chunk_size_word >> 16) & 0xff) +
1564 	    ((chunk_size_word >> 24) & 0xff);
1565 
1566 	if (checksum != 0) {
1567 		logmsg(MSG_INFO, "Corrupted chunk size checksum\n");
1568 		return (0);
1569 	}
1570 
1571 	if (chunk_size_word & 0x8) {
1572 		log2_chunk_size = (chunk_size_word & 0x7) + 16;
1573 		logmsg(MSG_INFO, "log2 chunk size: 0x%x\n", log2_chunk_size);
1574 		return (log2_chunk_size);
1575 	} else {
1576 		return (0);
1577 	}
1578 }
1579 
1580 static uint32_t
1581 cnx_get_image_size_f_hdl(ib_cnx_encap_ident_t *handle, int type)
1582 {
1583 	hermon_flash_ioctl_t	ioctl_info;
1584 	int			ret;
1585 
1586 	logmsg(MSG_INFO, "cnx_get_image_size_f_hdl\n");
1587 
1588 	ioctl_info.af_addr = cnx_cont2phys(handle->log2_chunk_sz,
1589 	    CNX_IMG_SIZE_OFFSET, type);
1590 	ioctl_info.af_type = HERMON_FLASH_READ_QUADLET;
1591 
1592 	ret = cnx_read_ioctl(handle, &ioctl_info);
1593 	if (ret != 0) {
1594 		logmsg(MSG_INFO, "Failed to read image size\n");
1595 		return (0);
1596 	}
1597 
1598 	logmsg(MSG_INFO, "Image Size: 0x%x\n", ioctl_info.af_quadlet);
1599 
1600 	return (ioctl_info.af_quadlet);
1601 }
1602 
1603 static int
1604 cnx_get_image_info(ib_cnx_encap_ident_t *handle)
1605 {
1606 	uint32_t	ii_ptr_addr;
1607 	uint32_t	ii_size;
1608 	int		*buf;
1609 	int		i, type;
1610 	hermon_flash_ioctl_t	ioctl_info;
1611 
1612 	logmsg(MSG_INFO, "cnx_get_image_info: state %x\n", handle->state);
1613 
1614 	type = handle->state &
1615 	    (FWFLASH_IB_STATE_IMAGE_PRI | FWFLASH_IB_STATE_IMAGE_SEC);
1616 
1617 	/* Get the image info pointer */
1618 	ioctl_info.af_addr = cnx_cont2phys(handle->log2_chunk_sz,
1619 	    CNX_IMG_INF_PTR_OFFSET, type);
1620 	ioctl_info.af_type = HERMON_FLASH_READ_QUADLET;
1621 
1622 	if (cnx_read_ioctl(handle, &ioctl_info) != FWFLASH_SUCCESS) {
1623 		logmsg(MSG_WARN, gettext("hermon: Failed to read image info "
1624 		    "Address\n"));
1625 		return (FWFLASH_FAILURE);
1626 	}
1627 	ii_ptr_addr = ioctl_info.af_quadlet & 0xffffff;
1628 
1629 	/* Get the image info size, a negative offset from the image info ptr */
1630 	ioctl_info.af_addr = cnx_cont2phys(handle->log2_chunk_sz,
1631 	    ii_ptr_addr + CNX_IMG_INF_SZ_OFFSET, type);
1632 	ioctl_info.af_type = HERMON_FLASH_READ_QUADLET;
1633 
1634 	if (cnx_read_ioctl(handle, &ioctl_info) != FWFLASH_SUCCESS) {
1635 		logmsg(MSG_WARN, gettext("hermon: Failed to read image info "
1636 		    "size\n"));
1637 		return (FWFLASH_FAILURE);
1638 	}
1639 	logmsg(MSG_INFO, "hermon: ImageInfo Sz: 0x%x\n", ioctl_info.af_quadlet);
1640 
1641 	ii_size = ioctl_info.af_quadlet;
1642 	/* size is in dwords--convert it to bytes */
1643 	ii_size *= 4;
1644 
1645 	logmsg(MSG_INFO, "hermon: ii_ptr_addr: 0x%x ii_size: 0x%x\n",
1646 	    ii_ptr_addr, ii_size);
1647 
1648 	buf = (int *)calloc(1, ii_size);
1649 
1650 	ioctl_info.af_addr = cnx_cont2phys(handle->log2_chunk_sz,
1651 	    ii_ptr_addr, type);
1652 	ioctl_info.af_type = HERMON_FLASH_READ_QUADLET;
1653 
1654 	for (i = 0; i < ii_size/4; i++) {
1655 		if (cnx_read_ioctl(handle, &ioctl_info) != FWFLASH_SUCCESS) {
1656 			logmsg(MSG_WARN, gettext("hermon: Failed to read "
1657 			    "image info (0x%x)\n"), i);
1658 			free(buf);
1659 			return (FWFLASH_FAILURE);
1660 		}
1661 
1662 		buf[i] = ioctl_info.af_quadlet;
1663 		ioctl_info.af_addr += 4;
1664 	}
1665 
1666 	/* Parse the image info section */
1667 	if (cnx_parse_img_info(buf, ii_size, &handle->hwfw_img_info,
1668 	    CNX_HW_IMG) != FWFLASH_SUCCESS) {
1669 		logmsg(MSG_WARN, gettext("hermon: Failed to parse Image Info "
1670 		    "section\n"));
1671 		free(buf);
1672 		return (FWFLASH_FAILURE);
1673 	}
1674 
1675 	free(buf);
1676 	return (FWFLASH_SUCCESS);
1677 }
1678 
1679 int
1680 cnx_parse_img_info(int *buf, uint32_t byte_size, cnx_img_info_t *img_info,
1681     int is_image)
1682 {
1683 	uint32_t 	*p;
1684 	uint32_t 	offs = 0;
1685 	uint32_t 	tag_num = 0;
1686 	int 		end_found = 0;
1687 	uint32_t 	tag_size, tag_id;
1688 	uint32_t 	tmp;
1689 	const char 	*str;
1690 	int		i;
1691 
1692 	p = (uint32_t *)buf;
1693 
1694 	logmsg(MSG_INFO, "hermon: cnx_parse_img_info\n");
1695 
1696 	while (!end_found && (offs < byte_size)) {
1697 		if (is_image == CNX_FILE_IMG) {
1698 			tag_size = ntohl(*p) & 0xffffff;
1699 			tag_id = ntohl(*p) >> 24;
1700 			tmp = ntohl(*(p + 1));
1701 		} else {
1702 			tag_size = ((*p) & 0xffffff);
1703 			tag_id = ((*p) >> 24);
1704 			tmp = (*(p + 1));
1705 		}
1706 
1707 		logmsg(MSG_INFO, "tag_id: %d tag_size: %d\n", tag_id, tag_size);
1708 
1709 		if ((offs + tag_size) > byte_size) {
1710 			logmsg(MSG_WARN, gettext("hermon: Image Info section "
1711 			    "corrupted: Tag# %d - tag_id %d, size %d exceeds "
1712 			    "info section size (%d bytes)"), tag_num, tag_id,
1713 			    tag_size, byte_size);
1714 			return (FWFLASH_FAILURE);
1715 		}
1716 
1717 		switch (tag_id) {
1718 		case CNX_FW_VER:
1719 			if (tag_size != CNX_FW_VER_SZ) {
1720 				logmsg(MSG_INFO, "ERROR: tag_id: %d tag_size: "
1721 				    "%d expected sz %d\n", tag_id, tag_size,
1722 				    CNX_FW_VER_SZ);
1723 			}
1724 			tmp = (tmp & CNX_MASK_FW_VER_MAJ) >> 16;
1725 			img_info->fw_rev.major = tmp;
1726 			if (is_image == CNX_FILE_IMG)
1727 				tmp = ntohl(*(p + 2));
1728 			else
1729 				tmp = (*(p + 2));
1730 			img_info->fw_rev.minor =
1731 			    (tmp & CNX_MASK_FW_VER_MIN)>> 16;
1732 			img_info->fw_rev.subminor =
1733 			    tmp & CNX_MASK_FW_VER_SUBMIN;
1734 
1735 			logmsg(MSG_INFO, "FW_VER: %d.%d.%03d\n",
1736 			    img_info->fw_rev.major, img_info->fw_rev.minor,
1737 			    img_info->fw_rev.subminor);
1738 			break;
1739 
1740 		case CNX_FW_BUILD_TIME:
1741 			if (tag_size != CNX_FW_BUILD_TIME_SZ) {
1742 				logmsg(MSG_INFO, "ERROR: tag_id: %d tag_size: "
1743 				    "%d expected sz %d\n", tag_id, tag_size,
1744 				    CNX_FW_BUILD_TIME_SZ);
1745 			}
1746 			img_info->fw_buildtime.hour =
1747 			    (tmp & CNX_MASK_FW_BUILD_HOUR) >> 16;
1748 			img_info->fw_buildtime.minute =
1749 			    (tmp & CNX_MASK_FW_BUILD_MIN) >> 8;
1750 			img_info->fw_buildtime.second =
1751 			    (tmp & CNX_MASK_FW_BUILD_SEC);
1752 
1753 			if (is_image == CNX_FILE_IMG)
1754 				tmp = ntohl(*(p + 2));
1755 			else
1756 				tmp = (*(p + 2));
1757 
1758 			img_info->fw_buildtime.year =
1759 			    (tmp & CNX_MASK_FW_BUILD_YEAR) >> 16;
1760 			img_info->fw_buildtime.month =
1761 			    (tmp & CNX_MASK_FW_BUILD_MON) >> 8;
1762 			img_info->fw_buildtime.day =
1763 			    (tmp & CNX_MASK_FW_BUILD_DAY);
1764 
1765 			logmsg(MSG_INFO, "Build TIME: %d:%d:%d %d:%d:%d\n",
1766 			    img_info->fw_buildtime.year,
1767 			    img_info->fw_buildtime.month,
1768 			    img_info->fw_buildtime.day,
1769 			    img_info->fw_buildtime.hour,
1770 			    img_info->fw_buildtime.minute,
1771 			    img_info->fw_buildtime.second);
1772 			break;
1773 
1774 		case CNX_DEV_TYPE:
1775 			if (tag_size != CNX_DEV_TYPE_SZ) {
1776 				logmsg(MSG_INFO, "ERROR: tag_id: %d tag_size: "
1777 				    "%d expected sz %d\n", tag_id, tag_size,
1778 				    CNX_DEV_TYPE_SZ);
1779 			}
1780 			img_info->dev_id = tmp & CNX_MASK_DEV_TYPE_ID;
1781 			logmsg(MSG_INFO, "DEV_TYPE: %d\n", img_info->dev_id);
1782 			break;
1783 
1784 		case CNX_VSD_VENDOR_ID:
1785 			if (tag_size != CNX_VSD_VENDOR_ID_SZ) {
1786 				logmsg(MSG_INFO, "ERROR: tag_id: %d tag_size: "
1787 				    "%d expected sz %d\n", tag_id, tag_size,
1788 				    CNX_VSD_VENDOR_ID_SZ);
1789 			}
1790 			img_info->vsd_vendor_id = tmp & CNX_MASK_VSD_VENDORID;
1791 			logmsg(MSG_INFO, "VSD Vendor ID: 0x%lX\n",
1792 			    img_info->vsd_vendor_id);
1793 			break;
1794 
1795 		case CNX_PSID:
1796 			if (tag_size != CNX_PSID_SZ) {
1797 				logmsg(MSG_INFO, "ERROR: tag_id: %d tag_size: "
1798 				    "%d expected sz %d\n", tag_id, tag_size,
1799 				    CNX_PSID_SZ);
1800 			}
1801 			str = (const char *)p;
1802 			str += 4;
1803 
1804 			for (i = 0; i < CNX_PSID_SZ; i++)
1805 				img_info->psid[i] = str[i];
1806 
1807 #ifdef _LITTLE_ENDIAN
1808 			if (is_image == CNX_HW_IMG) {
1809 				for (i = 0; i < CNX_PSID_SZ; i += 4) {
1810 					img_info->psid[i+3] = str[i];
1811 					img_info->psid[i+2] = str[i+1];
1812 					img_info->psid[i+1] = str[i+2];
1813 					img_info->psid[i] = str[i+3];
1814 				}
1815 			}
1816 #endif
1817 
1818 			logmsg(MSG_INFO, "PSID: %s\n", img_info->psid);
1819 			break;
1820 
1821 		case CNX_VSD:
1822 			if (tag_size != CNX_VSD_SZ) {
1823 				logmsg(MSG_INFO, "ERROR: tag_id: %d tag_size: "
1824 				    "%d expected sz %d\n", tag_id, tag_size,
1825 				    CNX_VSD_SZ);
1826 			}
1827 			str = (const char *)p;
1828 			str += 4;
1829 
1830 			for (i = 0; i < CNX_VSD_SZ; i++)
1831 				img_info->vsd[i] = str[i];
1832 
1833 #ifdef _LITTLE_ENDIAN
1834 			if (is_image == CNX_HW_IMG) {
1835 				for (i = 0; i < CNX_VSD_SZ; i += 4) {
1836 					img_info->vsd[i+3] = str[i];
1837 					img_info->vsd[i+2] = str[i+1];
1838 					img_info->vsd[i+1] = str[i+2];
1839 					img_info->vsd[i] = str[i+3];
1840 				}
1841 			}
1842 #endif
1843 			logmsg(MSG_INFO, "VSD: %s\n", img_info->vsd);
1844 			break;
1845 
1846 		case CNX_END_TAG:
1847 			if (tag_size != CNX_END_TAG_SZ) {
1848 				logmsg(MSG_INFO, "ERROR: tag_id: %d tag_size: "
1849 				    "%d expected sz %d\n", tag_id, tag_size,
1850 				    CNX_END_TAG_SZ);
1851 			}
1852 			end_found = 1;
1853 			break;
1854 
1855 		default:
1856 			if (tag_id > CNX_END_TAG) {
1857 				logmsg(MSG_WARN, gettext("Invalid img_info "
1858 				    "tag ID %d of size %d\n"), tag_id,
1859 				    tag_size);
1860 			}
1861 			break;
1862 		}
1863 
1864 		p += (tag_size / 4) + 1;
1865 		offs += tag_size + 4;
1866 		tag_num++;
1867 	}
1868 
1869 	if (offs != byte_size) {
1870 		logmsg(MSG_WARN, gettext("hermon: Corrupt Image Info section "
1871 		    "in firmware image\n"));
1872 		if (end_found) {
1873 			logmsg(MSG_WARN, gettext("Info section corrupted: "
1874 			    "Section data size is %x bytes, but end tag found "
1875 			    "after %x bytes.\n"), byte_size, offs);
1876 		} else {
1877 			logmsg(MSG_WARN, gettext("Info section corrupted: "
1878 			    "Section data size is %x bytes, but end tag not "
1879 			    "found at section end.\n"), byte_size);
1880 		}
1881 		return (FWFLASH_FAILURE);
1882 	}
1883 
1884 	return (FWFLASH_SUCCESS);
1885 }
1886