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
53char *devprefix = "/devices";
54char drivername[] = "hermon\0";
55char *devsuffix = ":devctl";
56
57extern di_node_t rootnode;
58extern int errno;
59extern struct fw_plugin *self;
60extern struct vrfyplugin *verifier;
61extern int fwflash_debug;
62
63/* required functions for this plugin */
64int fw_readfw(struct devicelist *device, char *filename);
65int fw_writefw(struct devicelist *device);
66int fw_identify(int start);
67int fw_devinfo();
68
69
70/* helper functions */
71static int cnx_identify(struct devicelist *thisdev);
72static int cnx_get_guids(ib_cnx_encap_ident_t *handle);
73static int cnx_close(struct devicelist *flashdev);
74static int cnx_check_for_magic_pattern(ib_cnx_encap_ident_t *hdl, uint32_t adr);
75static uint32_t cnx_get_log2_chunk_size_f_hdl(ib_cnx_encap_ident_t *handle,
76    int type);
77static uint32_t cnx_get_log2_chunk_size(uint32_t chunk_size_word);
78static uint32_t cnx_cont2phys(uint32_t log2_chunk_sz, uint32_t cont_addr,
79    int type);
80static uint32_t cnx_get_image_size_f_hdl(ib_cnx_encap_ident_t *hdl, int type);
81static void cnx_local_set_guid_crc_img(uint32_t offset, uint32_t guid_crc_size,
82    uint32_t guid_crc_offset);
83static int cnx_read_image(ib_cnx_encap_ident_t *handle);
84static int cnx_write_file(ib_cnx_encap_ident_t *handle, const char *filename);
85static int cnx_verify_image(ib_cnx_encap_ident_t *handle, int type);
86static int cnx_read_guids(ib_cnx_encap_ident_t *handle, int type);
87static int cnx_set_guids(ib_cnx_encap_ident_t *handle, void *arg);
88static int cnx_write_image(ib_cnx_encap_ident_t *handle, int type);
89static int cnx_read_ioctl(ib_cnx_encap_ident_t *hdl,
90    hermon_flash_ioctl_t *info);
91static int cnx_write_ioctl(ib_cnx_encap_ident_t *hdl,
92    hermon_flash_ioctl_t *info);
93static int cnx_erase_sector_ioctl(ib_cnx_encap_ident_t *hdl,
94    hermon_flash_ioctl_t *info);
95static int cnx_find_magic_n_chnk_sz(ib_cnx_encap_ident_t *handle, int type);
96static int cnx_get_image_info(ib_cnx_encap_ident_t *handle);
97
98
99int
100fw_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 */
138int
139fw_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	}
242out:
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 */
258int
259fw_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
398int
399fw_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
471static int
472cnx_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
530static int
531cnx_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
568static int
569cnx_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
580static int
581cnx_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 */
657static int
658cnx_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 */
752static int
753cnx_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 */
1027identify_end:
1028	cnx_close(thisdev);
1029	return (FWFLASH_FAILURE);
1030}
1031
1032static int
1033cnx_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
1083static int
1084cnx_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 */
1134static int
1135cnx_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
1154static int
1155cnx_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
1174static int
1175cnx_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 */
1198uint16_t
1199cnx_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
1240static void
1241cnx_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 */
1263static uint32_t
1264cnx_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
1282static int
1283cnx_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
1404out:
1405	free(guid_structure);
1406	return (ret);
1407}
1408
1409static int
1410cnx_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);
1463err:
1464	logmsg(MSG_INFO, "no magic_pattern found for type %x\n", type);
1465	return (FWFLASH_FAILURE);
1466}
1467
1468static int
1469cnx_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
1493int
1494cnx_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
1516static uint32_t
1517cnx_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
1555static uint32_t
1556cnx_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
1584static uint32_t
1585cnx_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
1607static int
1608cnx_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
1683int
1684cnx_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