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