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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * I18N message number ranges
28 * This file: 21000 - 21499
29 * Shared common messages: 1 - 1999
33 * Functions to support the download of FCode to PCI HBAs
34 * Qlogic ISP21XX/22XX boards: FC100/P single port, ISP2200 dual port
51 #include <sys/mnttab.h>
54 #include <sys/scsi/impl/uscsi.h>
55 #include <sys/fibre-channel/fcio.h>
57 #include <sys/scsi/adapters/ifpio.h>
58 #include <libdevinfo.h>
61 /* Error codes - used by the fcode_load_file routine */
62 #define FCODE_SUCCESS 0 /* successful completion */
63 #define FCODE_LOAD_FAILURE 1 /* general failure */
64 #define FCODE_IOCTL_FAILURE 2 /* FCODE ioctl download failure */
69 #define MAX_WAIT_TIME 30
72 * EMULEX Fcode attributes
74 #define EMULEX_FCODE_VERSION_LENGTH 16
75 #define EMULEX_READ_BUFFER_SIZE 128
77 /* Emulex specific error codes */
78 #define EMLX_ERRNO_START 0x100
80 /* Diagnostic error codes */
81 #define EMLX_TEST_FAILED (EMLX_ERRNO_START + 0)
83 /* Download image contains bad data */
84 #define EMLX_IMAGE_BAD (EMLX_ERRNO_START + 1)
85 /* Download image not compatible with current hardware */
86 #define EMLX_IMAGE_INCOMPATIBLE (EMLX_ERRNO_START + 2)
87 /* Unable to take adapter offline */
88 #define EMLX_IMAGE_FAILED (EMLX_ERRNO_START + 3)
89 /* Image download failed */
90 #define EMLX_OFFLINE_FAILED (EMLX_ERRNO_START + 4)
96 * This is just a random value chosen to identify Sbus Fcodes. Sbus FCode
97 * for Ivory is based on a 2200 chip but this value does not reflect that.
99 #define SBUS_CHIP_ID 0x1969
100 #define IVORY_BUS "/sbus@"
101 #define IVORY_DRVR "/SUNW,qlc@"
103 /* Global variables */
104 static char fc_trans
[] = "SUNW,ifp"; /* fibre channel transport */
105 static char fp_trans
[] = "SUNW,qlc"; /* fca layer driver */
106 static char fp_trans_id
[] = "fp@"; /* transport layer id */
107 static char qlgc2100
[] = "FC100/P"; /* product name for 2100 */
108 static char qlgc2200
[] = "ISP2200"; /* product name for 2200 */
109 static char qlgc2300
[] = "ISP2300"; /* product name for 2300 */
110 static char qlgc2312
[] = "ISP2312"; /* product name for 2312 */
112 * The variable qlgc2200Sbus represents the string which is always the
113 * starting string of the version information in an ISP2200 Sbus Fcode.
115 static char qlgc2200Sbus
[] = "ISP2200 Sbus FC-AL Host Adapter Driver";
116 static char pcibus_list
[HBA_MAX
][PATH_MAX
];
117 /* Internal functions */
118 static int q_load_file(int, char *);
119 static int q_getbootdev(uchar_t
*);
120 static int q_getdevctlpath(char *, int *);
121 static int q_warn(int);
122 static int q_findversion(int, int, uchar_t
*, uint16_t *);
123 static int q_findfileversion(char *, uchar_t
*, uint16_t *, int, int *);
124 static int q_findSbusfile(int, int *);
125 static int memstrstr(char *, char *, int, int);
126 static int fcode_load_file(int, char *, int *);
129 * Functions to support Fcode download for Emulex HBAs
131 static int emulex_fcodeversion(di_node_t
, uchar_t
*);
132 static void handle_emulex_error(int, char *);
135 * Searches for and updates the cards. This is the "main" function
136 * and will give the output to the user by calling the subfunctions.
137 * args: FCode file; if NULL only the current FCode version is printed
140 q_qlgc_update(unsigned int verbose
, char *file
)
143 int fd
, fcode_fd
= -1, errnum
= 0, devcnt
= 0, retval
= 0, isSbus
= 0;
146 uint16_t chip_id
= 0, file_id
= 0;
147 uchar_t fcode_buf
[FCODE_HDR
];
148 static uchar_t bootpath
[PATH_MAX
];
149 static uchar_t version
[MAXNAMELEN
], version_file
[MAXNAMELEN
];
150 char devpath
[PATH_MAX
], tmppath
[PATH_MAX
];
151 void (*sigint
)(); /* to store default SIGTERM setting */
152 static struct utmpx
*utmpp
= NULL
; /* pointer for getutxent() */
154 char phys_path
[PATH_MAX
];
156 * The variables port1 and port2 are used to store the bus id
157 * e.g. the bus id for this path:
158 * /devices/sbus@12,0/SUNW,qlc@2,30000/fp@0,0:devctl
159 * is "sbus@12". They are initialized to a random value and are
160 * set such that they are not equal initially.
162 static char port1
[MAXNAMELEN
] = {NULL
};
163 static char port2
[MAXNAMELEN
] = {NULL
};
168 /* check for a valid file */
169 if ((fcode_fd
= open(file
, O_RDONLY
)) < 0) {
170 (void) fprintf(stderr
,
171 MSGSTR(21000, "Error: Could not open %s\n"), file
);
174 if (read(fcode_fd
, fcode_buf
, FCODE_HDR
) != FCODE_HDR
) {
175 perror(MSGSTR(21001, "read"));
176 (void) close(fcode_fd
);
181 * Check if it's SBUS FCode by calling q_findSbusfile
182 * if it is then isSbus will be 1, if not it will be 0
183 * in case of an error, it will be -1
185 isSbus
= q_findSbusfile(fcode_fd
, &sbus_off
);
187 (void) close(fcode_fd
);
192 * FCode header check - make sure it's PCI FCode
193 * Structure of FCode header (byte# refers to byte numbering
194 * in FCode spec, not the byte# of our fcode_buf buffer):
195 * header byte 00 0x55 prom signature byte one
196 * byte 01 0xaa prom signature byte two
197 * data byte 00-03 P C I R
199 * header byte 32 0x55
201 * data byte 60-63 P C I R
202 * The second format with an offset of 32 is used for ifp prom
204 if (!(((fcode_buf
[0x00] == 0x55) &&
205 (fcode_buf
[0x01] == 0xaa) &&
206 (fcode_buf
[0x1c] == 'P') &&
207 (fcode_buf
[0x1d] == 'C') &&
208 (fcode_buf
[0x1e] == 'I') &&
209 (fcode_buf
[0x1f] == 'R')) ||
211 ((fcode_buf
[0x20] == 0x55) &&
212 (fcode_buf
[0x21] == 0xaa) &&
213 (fcode_buf
[0x3c] == 'P') &&
214 (fcode_buf
[0x3d] == 'C') &&
215 (fcode_buf
[0x3e] == 'I') &&
216 (fcode_buf
[0x3f] == 'R')) ||
219 (void) fprintf(stderr
, MSGSTR(21002,
220 "Error: %s is not a valid FC100/P, "
221 "ISP2200, ISP23xx FCode file.\n"),
223 (void) close(fcode_fd
);
227 /* check for single user mode */
228 while ((utmpp
= getutxent()) != NULL
) {
229 if (strstr(utmpp
->ut_line
, "run-level") &&
230 (strcmp(utmpp
->ut_line
, "run-level S") &&
231 strcmp(utmpp
->ut_line
, "run-level 1"))) {
234 (void) close(fcode_fd
);
243 if (!q_getbootdev((uchar_t
*)&bootpath
[0]) &&
244 getenv("_LUX_D_DEBUG") != NULL
) {
245 (void) fprintf(stdout
, " Bootpath: %s\n", bootpath
);
249 * Get count of, and names of PCI slots with ifp device control
250 * (devctl) nodes. Search /devices.
252 (void) strcpy(devpath
, "/devices");
253 if (q_getdevctlpath(devpath
, (int *)&devcnt
) == 0) {
254 (void) fprintf(stdout
, MSGSTR(21003,
255 "\n Found Path to %d FC100/P, ISP2200, ISP23xx Devices\n"),
258 (void) fprintf(stderr
, MSGSTR(21004,
259 "Error: Could not get /devices path to FC100/P,"
260 "ISP2200, ISP23xx Cards.\n"));
264 for (i
= 0; i
< devcnt
; i
++) {
266 (void) strncpy((char *)phys_path
, &pcibus_list
[i
][0],
267 strlen(&pcibus_list
[i
][0]));
268 if (fflag
&& (strstr((char *)bootpath
,
269 strtok((char *)phys_path
, ":")) != NULL
)) {
270 (void) fprintf(stderr
,
271 MSGSTR(21005, "Ignoring %s (bootpath)\n"),
276 (void) fprintf(stdout
,
277 MSGSTR(21006, "\n Opening Device: %s\n"), &pcibus_list
[i
][0]);
278 /* Check if the device is valid */
279 if ((fd
= open(&pcibus_list
[i
][0], O_RDWR
)) < 0) {
280 (void) fprintf(stderr
,
281 MSGSTR(21000, "Error: Could not open %s\n"),
288 * Check FCode version present on the adapter (at last boot)
290 if (q_findversion(verbose
, i
, (uchar_t
*)&version
[0],
292 if (strlen((char *)version
) == 0) {
293 (void) fprintf(stdout
, MSGSTR(21007,
294 " Detected FCode Version:\tNo version available for this FCode\n"));
296 (void) fprintf(stdout
, MSGSTR(21008,
297 " Detected FCode Version:\t%s\n"), version
);
305 * For ISP2200, Sbus HBA, do just 1 download
306 * for both the ports (dual port HBA)
307 * Here it is assumed that readdir() always
308 * returns the paths in pcibus_list[] in the
311 (void) strcpy(tmppath
, pcibus_list
[i
]);
312 if (ptr1
= strstr(tmppath
, IVORY_BUS
)) {
313 if (ptr2
= strstr(ptr1
, IVORY_DRVR
)) {
314 ptr2
= strchr(ptr2
, ',');
315 if (ptr2
= strchr(++ptr2
, ',')) {
319 (void) strcpy(port2
, ptr1
);
320 if (strcmp(port1
, port2
) == 0) {
321 (void) fprintf(stdout
, MSGSTR(21037,
322 "/n New FCode has already been downloaded "
323 "to this ISP2200 SBus HBA Card.\n"
324 "It is sufficient to download to one "
325 "port of the ISP2200 SBus HBA Card. "
331 * Check version of the supplied FCode file (once)
333 if ((file_id
!= 0 && version_file
!= NULL
) ||
334 (q_findfileversion((char *)
335 &fcode_buf
[0], (uchar_t
*)&version_file
[0],
336 &file_id
, isSbus
, &sbus_off
) == 0)) {
337 (void) fprintf(stdout
, MSGSTR(21009,
338 " New FCode Version:\t\t%s\n"),
341 (void) close(fcode_fd
);
347 * Give warning if file doesn't appear to be correct
351 errnum
= 2; /* can't get chip_id */
353 } else if (chip_id
- file_id
!= 0) {
354 errnum
= 3; /* file/card mismatch */
357 errnum
= 0; /* everything is ok */
360 if (!q_warn(errnum
)) {
361 /* Disable user-interrupt Control-C */
363 (void (*)(int)) signal(SIGINT
, SIG_IGN
);
366 (void) fprintf(stdout
, MSGSTR(21010,
367 " Loading FCode: %s\n"), file
);
369 if (q_load_file(fcode_fd
,
370 &pcibus_list
[i
][0]) == 0) {
371 (void) fprintf(stdout
, MSGSTR(21011,
372 " Successful FCode download: %s\n"),
374 (void) strcpy(port1
, port2
);
376 (void) fprintf(stderr
, MSGSTR(21012,
377 "Error: FCode download failed: %s\n"),
381 /* Restore SIGINT (user interrupt) setting */
382 (void) signal(SIGINT
, sigint
);
386 (void) fprintf(stdout
, " ");
387 (void) fprintf(stdout
, MSGSTR(125, "Complete\n"));
389 (void) close(fcode_fd
);
395 * Retrieve the version banner from the card
396 * uses ioctl: FCIO_FCODE_MCODE_VERSION FCode revision
399 q_findversion(int verbose
, int index
, uchar_t
*version
, uint16_t *chip_id
)
403 struct ifp_fm_version
*version_buffer
= NULL
;
404 char prom_ver
[100] = {NULL
};
405 char mcode_ver
[100] = {NULL
};
408 if (strstr(&pcibus_list
[index
][0], fc_trans
)) {
410 if ((fd
= open(&pcibus_list
[index
][0], O_RDWR
)) < 0) {
411 (void) fprintf(stderr
,
412 MSGSTR(21000, "Error: Could not open %s\n"),
413 &pcibus_list
[index
][0]);
417 if ((version_buffer
= (struct ifp_fm_version
*)malloc(
418 sizeof (struct ifp_fm_version
))) == NULL
) {
419 (void) fprintf(stderr
,
420 MSGSTR(21013, "Error: Memory allocation failed\n"));
425 version_buffer
->fcode_ver
= (char *)version
;
426 version_buffer
->mcode_ver
= mcode_ver
;
427 version_buffer
->prom_ver
= prom_ver
;
428 version_buffer
->fcode_ver_len
= MAXNAMELEN
- 1;
429 version_buffer
->mcode_ver_len
= 100;
430 version_buffer
->prom_ver_len
= 100;
432 if (ioctl(fd
, FCIO_FCODE_MCODE_VERSION
, version_buffer
) < 0) {
433 (void) fprintf(stderr
, MSGSTR(21014,
434 "Error: Driver interface FCIO_FCODE_MCODE_VERSION failed\n"));
435 free(version_buffer
);
439 version
[version_buffer
->fcode_ver_len
] = '\0';
441 /* Need a way to get card MCODE (firmware) to track certain HW bugs */
442 if (getenv("_LUX_D_DEBUG") != NULL
) {
443 (void) fprintf(stdout
, " Device %i: QLGC chip_id %x\n",
445 (void) fprintf(stdout
, " FCode:%s\n MCODE:%s\n PROM:%s\n",
446 (char *)version
, mcode_ver
, prom_ver
);
448 free(version_buffer
);
450 } else if (strstr(&pcibus_list
[index
][0], fp_trans
)) {
452 * Get the fcode and prom's fw version
453 * using the fp ioctls. Currently, we pass
454 * only the fcode version to the calling function
455 * and ignore the FW version (using the existing
459 if ((fd
= open(&pcibus_list
[index
][0], O_RDWR
)) < 0) {
460 (void) fprintf(stderr
,
461 MSGSTR(4511, "Could not open %s\n"),
462 &pcibus_list
[index
][0]);
466 /* Get the fcode version */
467 bzero(version
, sizeof (version
));
468 fcio
.fcio_cmd
= FCIO_GET_FCODE_REV
;
469 /* Information read operation */
470 fcio
.fcio_xfer
= FCIO_XFER_READ
;
471 fcio
.fcio_obuf
= (caddr_t
)version
;
472 fcio
.fcio_olen
= MAXNAMELEN
;
474 for (ntries
= 0; ntries
< MAX_RETRIES
; ntries
++) {
475 if (ioctl(fd
, FCIO_CMD
, &fcio
) != 0) {
476 if ((errno
== EAGAIN
) &&
477 (ntries
+1 < MAX_RETRIES
)) {
479 (void) sleep(MAX_WAIT_TIME
);
483 return (L_FCIO_GET_FCODE_REV_FAIL
);
487 version
[MAXNAMELEN
-1] = '\0';
490 /* Get type of card from product name in FCode version banner */
491 if (strstr((char *)version
, qlgc2100
)) {
493 } else if (strstr((char *)version
, qlgc2200
)) {
495 if (strstr((char *)version
, "Sbus")) {
496 *chip_id
= SBUS_CHIP_ID
;
498 } else if (strstr((char *)version
, qlgc2300
)) {
500 } else if (strstr((char *)version
, qlgc2312
)) {
511 * Retrieve the version banner and file type (2100 or 2200) from the file
514 q_findfileversion(char *dl_fcode
, uchar_t
*version_file
, uint16_t *file_id
,
515 int isSbus
, int *sbus_offset
)
519 char temp
[4] = {NULL
};
523 * Get file version from FCode for 2100 or 2202
526 *file_id
= SBUS_CHIP_ID
;
528 if ((dl_fcode
[0x23] == 0x22) ||
529 (dl_fcode
[0x23] == 0x23)) {
530 *file_id
= dl_fcode
[0x22] & 0xff;
531 *file_id
|= (dl_fcode
[0x23] << 8) & 0xff00;
533 *file_id
= dl_fcode
[0x42] & 0xff;
534 *file_id
|= (dl_fcode
[0x43] << 8) & 0xff00;
539 * Ok, we're just checking for 2200 here. If it is we need
540 * to offset to find the banner.
542 if ((*file_id
== 0x2200) ||
543 (*file_id
== 0x2300) ||
544 (*file_id
== 0x2312)) {
549 * If this is an ISP2200 Sbus Fcode file, then search for the string
550 * "ISP2200 FC-AL Host Adapter Driver" in the whole fcode file
553 *file_id
= SBUS_CHIP_ID
;
554 qlc_offset
= *sbus_offset
;
555 /* Subtract 111 from the offset we add below for PCI Fcodes */
559 /* Banner length varies; grab banner to end of date marker yr/mo/da */
560 version_file
[0] = '\0';
561 for (mark
= (111 + qlc_offset
); mark
< (191 + qlc_offset
); mark
++) {
562 (void) strncpy(temp
, (char *)&dl_fcode
[mark
], 4);
563 if ((strncmp(&temp
[0], "/", 1) == 0) &&
564 (strncmp(&temp
[3], "/", 1) == 0)) {
565 (void) strncat((char *)version_file
,
566 (char *)&dl_fcode
[mark
], 6);
569 (void) strncat((char *)version_file
, temp
, 1);
575 * Find if the FCode file is a ISP2200 SBUS Fcode file
578 q_findSbusfile(int fd
, int *sbus_offset
)
580 static int file_size
;
582 struct stat statinfo
;
584 if (lseek(fd
, 0, SEEK_SET
) == -1) {
585 perror(MSGSTR(21022, "seek"));
588 if (fstat(fd
, &statinfo
)) {
589 perror(MSGSTR(21023, "fstat"));
592 file_size
= statinfo
.st_size
;
594 if ((sbus_info
= (char *)malloc(file_size
)) == NULL
) {
595 (void) fprintf(stderr
,
596 MSGSTR(21013, "Error: Memory allocation failed\n"));
600 if (read(fd
, sbus_info
, file_size
) < 0) {
601 perror(MSGSTR(21001, "read"));
607 * Search for the version string in the whole file
609 if ((*sbus_offset
= memstrstr((char *)sbus_info
, qlgc2200Sbus
,
610 file_size
, strlen(qlgc2200Sbus
))) != -1) {
621 * Build a list of all the devctl entries for all the 2100/2200 based adapters
624 q_getdevctlpath(char *devpath
, int *devcnt
)
627 struct dirent
*dirp
= NULL
;
633 if (lstat(devpath
, &statbuf
) < 0) {
634 (void) fprintf(stderr
,
635 MSGSTR(21016, "Error: %s lstat() error\n"), devpath
);
639 if ((strstr(devpath
, fc_trans
) ||
640 (strstr(devpath
, fp_trans_id
) && strstr(devpath
, fp_trans
))) &&
641 strstr(devpath
, "devctl")) {
642 /* Verify the path is valid */
643 if ((testopen
= open(devpath
, O_RDONLY
)) >= 0) {
644 (void) close(testopen
);
645 (void) strcpy(pcibus_list
[*devcnt
], devpath
);
651 if (S_ISDIR(statbuf
.st_mode
) == 0) {
654 * we don't care about it - return
660 * It's a directory. Call ourself to
661 * traverse the path(s)
663 ptr
= devpath
+ strlen(devpath
);
667 /* Forget the /devices/pseudo/ directory */
668 if (strcmp(devpath
, "/devices/pseudo/") == 0) {
672 if ((dp
= opendir(devpath
)) == NULL
) {
673 (void) fprintf(stderr
,
674 MSGSTR(21017, "Error: %s Can't read directory\n"), devpath
);
678 while ((dirp
= readdir(dp
)) != NULL
) {
680 if (strcmp(dirp
->d_name
, ".") == 0 ||
681 strcmp(dirp
->d_name
, "..") == 0) {
684 (void) strcpy(ptr
, dirp
->d_name
); /* append name */
685 err
= q_getdevctlpath(devpath
, devcnt
);
688 if (closedir(dp
) < 0) {
689 (void) fprintf(stderr
,
690 MSGSTR(21018, "Error: Can't close directory %s\n"), devpath
);
697 * Get the boot device. Cannot load FCode to current boot device.
698 * Boot devices under volume management will prompt a warning.
701 q_getbootdev(uchar_t
*bootpath
)
706 static char buf
[BUFSIZ
];
707 char *p
= NULL
, *p1
= NULL
; /* p = full device, p1 = chunk to rm */
708 char *slot
= ":devctl";
711 if ((fp
= fopen(MNTTAB
, "r")) == NULL
) {
712 (void) fprintf(stderr
,
713 MSGSTR(21000, "Error: Could not open %s\n"), MNTTAB
);
718 mpref
.mnt_mountp
= (char *)root
;
720 if (getmntany(fp
, &mp
, &mpref
) != 0 ||
721 mpref
.mnt_mountp
== NULL
) {
722 (void) fprintf(stderr
, MSGSTR(21019,
723 "Error: Cannot get boot device, check %s.\n"), MNTTAB
);
730 * If we can't get a link, we may be dealing with a volume mgr
731 * so give a warning. If a colon is present, we likely have a
732 * non-local disk or cd-rom, so no warning is necessary.
733 * e.g. /devices/pci@1f,4000/scsi@3/sd@6,0:b (cdrom, no link) or
734 * storage-e4:/blah/blah remote boot server
736 if (readlink(mp
.mnt_special
, buf
, BUFSIZ
) < 0) {
737 if (strstr(mp
.mnt_special
, ":") == NULL
) {
738 (void) fprintf(stderr
, MSGSTR(21020,
739 "\nWarning: Cannot read boot device link, check %s.\n"), MNTTAB
);
740 (void) fprintf(stderr
, MSGSTR(21021,
741 "Do not upgrade FCode on adapters controlling the boot device.\n"));
746 * Copy boot device path to bootpath. First remove leading
747 * path junk (../../..) then if it's an ifp device, chop off
748 * the disk and add the devctl to the end of the path.
750 if (p
= strstr(buf
, "/devices")) {
751 if (strstr(buf
, fc_trans
) != NULL
) {
752 p1
= strrchr(p
, '/');
756 (void) strcpy((char *)bootpath
, (char *)p
);
758 (void) strcat((char *)bootpath
, slot
);
764 * Load FCode to card.
765 * uses ioctl: IFPIO_FCODE_DOWNLOAD
768 q_load_file(int fcode_fd
, char *device
)
770 static int dev_fd
, fcode_size
;
772 ifp_download_t
*download_p
= NULL
;
774 uint16_t file_id
= 0;
777 if (lseek(fcode_fd
, 0, SEEK_SET
) == -1) {
778 perror(MSGSTR(21022, "seek"));
779 (void) close(fcode_fd
);
782 if (fstat(fcode_fd
, &stat
) == -1) {
783 perror(MSGSTR(21023, "fstat"));
784 (void) close(fcode_fd
);
788 fcode_size
= stat
.st_size
;
790 if (strstr(device
, fc_trans
)) {
791 if ((download_p
= (ifp_download_t
*)malloc(
792 sizeof (ifp_download_t
) + fcode_size
)) == NULL
) {
793 (void) fprintf(stderr
,
794 MSGSTR(21013, "Error: Memory allocation failed\n"));
795 (void) close(fcode_fd
);
799 if ((bin
= (uchar_t
*)malloc(fcode_size
)) == NULL
) {
800 (void) fprintf(stderr
,
801 MSGSTR(21013, "Error: Memory allocation failed\n"));
802 (void) close(fcode_fd
);
807 if (strstr(device
, fc_trans
)) {
808 if (read(fcode_fd
, download_p
->dl_fcode
, fcode_size
)
810 perror(MSGSTR(21001, "read"));
812 (void) close(fcode_fd
);
816 if (read(fcode_fd
, bin
, fcode_size
)
818 perror(MSGSTR(21001, "read"));
820 (void) close(fcode_fd
);
826 if ((dev_fd
= open(device
, O_RDWR
|O_EXCL
)) < 0) {
827 (void) fprintf(stderr
,
828 MSGSTR(21000, "Error: Could not open %s\n"), device
);
832 if (strstr(device
, fc_trans
)) {
833 download_p
->dl_fcode_len
= fcode_size
;
834 file_id
= download_p
->dl_fcode
[0x42] & 0xff;
835 file_id
|= (download_p
->dl_fcode
[0x43] << 8) & 0xff00;
836 download_p
->dl_chip_id
= file_id
;
837 if (ioctl(dev_fd
, IFPIO_FCODE_DOWNLOAD
, download_p
) < 0) {
838 (void) fprintf(stderr
, MSGSTR(21024,
839 "Error: Driver interface IFPIO_FCODE_DOWNLOAD failed\n"));
841 (void) close(dev_fd
);
845 } else if (strstr(device
, fp_trans
)) {
846 fcio
.fcio_cmd
= FCIO_DOWNLOAD_FCODE
;
847 /* Information read operation */
848 fcio
.fcio_xfer
= FCIO_XFER_WRITE
;
849 fcio
.fcio_ibuf
= (caddr_t
)bin
;
850 fcio
.fcio_ilen
= fcode_size
;
852 if (ioctl(dev_fd
, FCIO_CMD
, &fcio
) != 0) {
853 (void) fprintf(stderr
, MSGSTR(21036,
854 "Error: Driver interface FCIO_DOWNLOAD_FCODE failed\n"));
856 (void) close(dev_fd
);
861 (void) close(dev_fd
);
866 * Issue warning strings and loop for Yes/No user interaction
867 * err# 0 -- we're ok, warn for pending FCode load
868 * 1 -- not in single user mode
869 * 2 -- can't get chip_id
870 * 3 -- card and file do not have same type (2100/2200)
879 (void) fprintf(stderr
, MSGSTR(21025,
880 "\nWarning: System is not in single-user mode.\n"));
881 (void) fprintf(stderr
, MSGSTR(21026,
882 "Loading FCode will reset the adapter and terminate I/O activity\n"));
885 (void) fprintf(stderr
, MSGSTR(21027,
886 " Warning: FCode is missing or existing FCode has"
887 " unrecognized version.\n"));
889 } else if (errnum
== 3) {
890 (void) fprintf(stderr
, MSGSTR(21028,
891 " Warning: New FCode file version does not match this"
892 " board type. Skipping...\n"));
895 (void) fprintf(stderr
, MSGSTR(21029,
896 "\nWARNING!! This program will update the FCode in this"
897 " FC100/PCI, ISP2200/PCI, ISP23xx/PCI "
898 " and Emulex devices.\n"));
899 (void) fprintf(stderr
, MSGSTR(21030,
900 "This may take a few (5) minutes. Please be patient.\n"));
904 (void) fprintf(stderr
, MSGSTR(21031,
905 "Do you wish to continue ? (y/n) "));
909 if ((strcmp(input
, MSGSTR(21032, "y")) == 0) ||
910 (strcmp(input
, MSGSTR(40, "yes")) == 0)) {
912 } else if ((strcmp(input
, MSGSTR(21033, "n")) == 0) ||
913 (strcmp(input
, MSGSTR(45, "no")) == 0)) {
914 (void) fprintf(stderr
,
915 MSGSTR(21034, "Not Downloading FCode\n"));
918 (void) fprintf(stderr
, MSGSTR(21035, "Invalid input\n"));
925 * Input : pointer to buf1, pointer to buf2, size of buf1, size of buf2
927 * Offset of the start of contents-of-buf2 in buf1 if it is found
928 * -1 if buf1 does not contain contents of buf2
930 * This function works similar to strstr(). The difference is that null
931 * characters in the buffer are treated like any other character. So, buf1
932 * and buf2 can have embedded null characters in them.
935 memstrstr(char *s1
, char *s2
, int size1
, int size2
)
938 char *s1_ptr
, *s2_ptr
;
940 count1
= size1
; count2
= size2
;
941 s1_ptr
= s1
; s2_ptr
= s2
;
943 if ((size2
== 0)||(size1
== 0))
946 for (count1
= 0; count1
< (size1
- size2
+ 1); count1
++) {
947 if (*s1_ptr
++ == *s2_ptr
++) {
949 return (count1
- size2
+ 1);
961 * generic fcode load file routine. given a file descriptor to a fcode file
962 * this routine will issue the FCIO_DOWNLOAD_FCODE ioctl to the given
963 * device. Any ioctl errors will be returned in fcio_errno
966 * fcode_fd file descriptor to a fcode file
967 * device path to the device we will be downloading the fcode onto
968 * fcio_errno pointer to an int that will be used to return any errors
971 * 0 successful download
975 fcode_load_file(int fcode_fd
, char *device
, int *fcio_errno
)
979 static int dev_fd
, fcode_size
;
983 if (device
== NULL
|| fcio_errno
== NULL
) {
984 return (FCODE_LOAD_FAILURE
);
988 if (lseek(fcode_fd
, 0, SEEK_SET
) == -1) {
989 perror(MSGSTR(21022, "seek"));
990 return (FCODE_LOAD_FAILURE
);
993 if (fstat(fcode_fd
, &stat
) == -1) {
994 perror(MSGSTR(21023, "fstat"));
995 return (FCODE_LOAD_FAILURE
);
998 fcode_size
= stat
.st_size
;
1000 if ((bin
= (uchar_t
*)malloc(fcode_size
)) == NULL
) {
1001 (void) fprintf(stderr
,
1002 MSGSTR(21013, "Error: Memory allocation failed\n"));
1003 return (FCODE_LOAD_FAILURE
);
1006 if (read(fcode_fd
, bin
, fcode_size
)
1008 perror(MSGSTR(21001, "read"));
1010 return (FCODE_LOAD_FAILURE
);
1013 if ((dev_fd
= open(device
, O_RDWR
|O_EXCL
)) < 0) {
1014 (void) fprintf(stderr
,
1015 MSGSTR(21122, "Error: Could not open %s, failed "
1016 "with errno %d\n"), device
, errno
);
1018 return (FCODE_LOAD_FAILURE
);
1021 fcio
.fcio_cmd
= FCIO_DOWNLOAD_FCODE
;
1022 fcio
.fcio_xfer
= FCIO_XFER_WRITE
;
1023 fcio
.fcio_ibuf
= (caddr_t
)bin
;
1024 fcio
.fcio_ilen
= fcode_size
;
1026 if (ioctl(dev_fd
, FCIO_CMD
, &fcio
) != 0) {
1027 (void) close(dev_fd
);
1028 *fcio_errno
= fcio
.fcio_errno
;
1030 return (FCODE_IOCTL_FAILURE
);
1034 (void) close(dev_fd
);
1035 return (FCODE_SUCCESS
);
1039 * Searches for and updates the fcode for Emulex HBA cards
1040 * args: FCode file; if NULL only the current FCode
1041 * version is printed
1045 emulex_update(char *file
)
1050 uint_t state
= 0, fflag
= 0;
1051 static uchar_t bootpath
[PATH_MAX
];
1053 static struct utmpx
*utmpp
= NULL
;
1055 di_node_t node
, sib_node
, count_node
;
1056 di_minor_t minor_node
;
1057 char phys_path
[PATH_MAX
], *path
;
1058 int errnum
= 0, fcio_errno
= 0;
1059 static uchar_t prom_ver_data
[MAXNAMELEN
];
1060 static char ver_file
[EMULEX_FCODE_VERSION_LENGTH
];
1062 int prop_entries
= -1;
1063 int *port_data
= NULL
;
1066 /* set the fcode download flag */
1069 /* check for a valid file */
1070 if ((fcode_fd
= open(file
, O_RDONLY
)) < 0) {
1071 (void) fprintf(stderr
,
1072 MSGSTR(21118, "Error: Could not open %s, failed "
1073 "with errno %d\n"), file
, errno
);
1077 /* check for single user mode */
1078 while ((utmpp
= getutxent()) != NULL
) {
1079 if (strstr(utmpp
->ut_line
, "run-level") &&
1080 (strcmp(utmpp
->ut_line
, "run-level S") &&
1081 strcmp(utmpp
->ut_line
, "run-level 1"))) {
1084 (void) close(fcode_fd
);
1093 if (!q_getbootdev((uchar_t
*)&bootpath
[0]) &&
1094 getenv("_LUX_D_DEBUG") != NULL
) {
1095 (void) fprintf(stdout
, " Bootpath: %s\n", bootpath
);
1100 * Download the Fcode to all the emulex cards found
1103 /* Create a snapshot of the kernel device tree */
1104 if ((root
= di_init("/", DINFOCPYALL
)) == DI_NODE_NIL
) {
1105 (void) fprintf(stderr
, MSGSTR(21114,
1106 "Error: Could not get /devices path to "
1107 "Emulex Devices.\n"));
1111 /* point to first node which matches emulex driver */
1112 node
= di_drv_first_node("emlxs", root
);
1114 if (node
== DI_NODE_NIL
) {
1116 * Could not find any emulex cards
1118 (void) di_fini(root
);
1119 (void) fprintf(stderr
, MSGSTR(21115,
1120 "\n Found Path to %d Emulex Devices.\n"), devcnt
);
1124 while (count_node
!= DI_NODE_NIL
) {
1125 state
= di_state(count_node
);
1126 if ((state
& DI_DRIVER_DETACHED
)
1127 != DI_DRIVER_DETACHED
) {
1128 sib_node
= di_child_node(count_node
);
1129 while (sib_node
!= DI_NODE_NIL
) {
1130 state
= di_state(sib_node
);
1131 if ((state
& DI_DRIVER_DETACHED
) !=
1132 DI_DRIVER_DETACHED
) {
1133 /* Found an attached node */
1135 di_prop_lookup_ints(
1136 DDI_DEV_T_ANY
, sib_node
,
1137 "port", &port_data
);
1138 if (prop_entries
!= -1) {
1144 sib_node
= di_sibling_node(sib_node
);
1147 count_node
= di_drv_next_node(count_node
);
1149 (void) fprintf(stdout
, MSGSTR(21116,
1150 "\n Found Path to %d Emulex Devices.\n"), devcnt
);
1155 * Traverse device tree to find all emulex cards
1157 while (node
!= DI_NODE_NIL
) {
1159 state
= di_state(node
);
1160 if ((state
& DI_DRIVER_DETACHED
) == DI_DRIVER_DETACHED
) {
1161 node
= di_drv_next_node(node
);
1165 sib_node
= di_child_node(node
);
1166 while (sib_node
!= DI_NODE_NIL
) {
1167 state
= di_state(sib_node
);
1168 if ((state
& DI_DRIVER_DETACHED
) !=
1169 DI_DRIVER_DETACHED
) {
1171 /* Found an attached node */
1172 prop_entries
= di_prop_lookup_ints(
1173 DDI_DEV_T_ANY
, sib_node
,
1174 "port", &port_data
);
1175 if (prop_entries
!= -1) {
1177 /* Found a node with "port" property */
1178 minor_node
= di_minor_next(sib_node
,
1183 sib_node
= di_sibling_node(sib_node
);
1186 if (sib_node
== DI_NODE_NIL
) {
1190 path
= di_devfs_path(sib_node
);
1191 (void) strcpy(phys_path
, "/devices");
1192 (void) strncat(phys_path
, path
, strlen(path
));
1193 di_devfs_path_free(path
);
1195 if (fflag
&& (strstr((char *)bootpath
,
1196 (char *)phys_path
) != NULL
)) {
1197 (void) fprintf(stderr
,
1198 MSGSTR(21117, "Ignoring %s (bootpath)\n"),
1200 node
= di_drv_next_node(node
);
1205 (void) strncat(phys_path
, ":", 1);
1206 (void) strncat(phys_path
,
1207 di_minor_name(minor_node
),
1208 strlen(di_minor_name(minor_node
)));
1211 (void) fprintf(stdout
,
1212 MSGSTR(21107, "\n Opening Device: %s\n"),
1215 /* Check if the device is valid */
1216 if ((fd
= open(phys_path
, O_RDWR
)) < 0) {
1217 (void) fprintf(stderr
,
1218 MSGSTR(21121, "Error: Could not open %s, failed "
1219 "with errno %d\n"), phys_path
, errno
);
1221 node
= di_drv_next_node(node
);
1228 * Check FCode version present on the adapter
1231 memset(prom_ver_data
, 0, sizeof (prom_ver_data
));
1232 if (emulex_fcodeversion(node
, (uchar_t
*)&prom_ver_data
[0])
1235 if (strlen((char *)prom_ver_data
) == 0) {
1236 (void) fprintf(stdout
, MSGSTR(21108,
1237 " Detected FCode Version:\tNo version available for this FCode\n"));
1239 (void) fprintf(stdout
, MSGSTR(21109,
1240 " Detected FCode Version:\t%s\n"),
1244 errnum
= 2; /* can't get prom properties */
1250 memset(ver_file
, 0, sizeof (ver_file
));
1251 if (emulex_fcode_reader(fcode_fd
, "fcode-version",
1252 ver_file
, sizeof (ver_file
)) == 0) {
1253 (void) fprintf(stdout
, MSGSTR(21110,
1254 " New FCode Version:\t\t%s\n"),
1258 (void) close(fcode_fd
);
1263 * Load the New FCode
1264 * Give warning if file doesn't appear to be correct
1266 if (!q_warn(errnum
)) {
1267 /* Disable user-interrupt Control-C */
1269 (void (*)(int)) signal(SIGINT
, SIG_IGN
);
1271 (void) fprintf(stdout
, MSGSTR(21111,
1272 " Loading FCode: %s\n"), file
);
1273 if (fcode_load_file(fcode_fd
, phys_path
,
1274 &fcio_errno
) == FCODE_SUCCESS
) {
1275 (void) fprintf(stdout
, MSGSTR(21112,
1276 " Successful FCode download: %s\n"),
1279 handle_emulex_error(fcio_errno
,
1284 /* Restore SIGINT (user interrupt) setting */
1285 (void) signal(SIGINT
, sigint
);
1290 node
= di_drv_next_node(node
);
1294 (void) fprintf(stdout
, " ");
1295 (void) fprintf(stdout
, MSGSTR(125, "Complete\n"));
1297 (void) close(fcode_fd
);
1303 * Retrieve the version from the card.
1304 * uses PROM properties
1307 emulex_fcodeversion(di_node_t node
, uchar_t
*ver
) {
1308 di_prom_prop_t promprop
;
1309 di_prom_handle_t ph
;
1311 uchar_t
*ver_data
= NULL
;
1312 int size
, found
= 0;
1314 /* check to make sure ver is not NULL */
1319 if ((ph
= di_prom_init()) == DI_PROM_HANDLE_NIL
) {
1323 for (promprop
= di_prom_prop_next(ph
, node
,
1325 promprop
!= DI_PROM_PROP_NIL
;
1326 promprop
= di_prom_prop_next(ph
, node
, promprop
)) {
1327 if (((promname
= di_prom_prop_name(
1328 promprop
)) != NULL
) &&
1329 (strcmp(promname
, "fcode-version") == 0)) {
1330 size
= di_prom_prop_data(promprop
, &ver_data
);
1331 (void) memset(ver
, NULL
, size
);
1332 (void) memcpy(ver
, ver_data
, size
);
1345 * Retrieves information from the Emulex fcode
1347 * Given a pattern, this routine will look for this pattern in the fcode
1348 * file and if found will return the pattern value
1350 * possible patterns are manufacturer and fcode-version
1353 emulex_fcode_reader(int fcode_fd
, char *pattern
, char *pattern_value
,
1354 uint32_t pattern_value_size
) {
1362 char buffer1
[EMULEX_READ_BUFFER_SIZE
];
1363 char buffer2
[EMULEX_READ_BUFFER_SIZE
];
1364 uint32_t plen
, image_size
;
1368 /* Check the arguments */
1369 if (!fcode_fd
|| !pattern_value
|| pattern_value_size
< 8) {
1373 if (fstat(fcode_fd
, &stat
) == -1) {
1374 perror(MSGSTR(21023, "fstat"));
1377 image_size
= stat
.st_size
;
1378 if (image_size
< 2) {
1381 if ((image
= (uchar_t
*)calloc(image_size
, 1)) == NULL
) {
1382 (void) fprintf(stderr
,
1383 MSGSTR(21013, "Error: Memory allocation failed\n"));
1387 /* Read the fcode image file */
1388 lseek(fcode_fd
, 0, SEEK_SET
);
1389 read(fcode_fd
, image
, image_size
);
1392 bzero(buffer1
, sizeof (buffer1
));
1393 bzero(buffer2
, sizeof (buffer2
));
1394 /* Default pattern_value string */
1395 strcpy((char *)pattern_value
, "<unknown>");
1396 plen
= strlen(pattern
);
1401 /* Search entire image for pattern string */
1402 while (i
<= (image_size
- 2)) {
1403 /* Read next two bytes */
1407 /* Check second byte first due to endianness */
1409 /* Save byte in circular buffer */
1410 buffer1
[b
++] = byte2
;
1411 if (b
== sizeof (buffer1
)) {
1415 /* Check byte for pattern match */
1416 if (pattern
[n
++] != byte2
) {
1417 /* If no match, then reset pattern */
1421 * If complete pattern has been matched then
1430 /* Check first byte second due to endianness */
1431 /* Save byte in circular buffer */
1432 buffer1
[b
++] = byte1
;
1433 if (b
== sizeof (buffer1
)) {
1436 /* Check byte for pattern match */
1437 if (pattern
[n
++] != byte1
) {
1438 /* If no match, then reset pattern */
1442 * If complete pattern has been matched
1451 /* Not found. Try again with different endianess */
1454 bzero(buffer1
, sizeof (buffer1
));
1455 bzero(buffer2
, sizeof (buffer2
));
1460 /* Search entire 32bit endian image for pattern string */
1461 while (i
<= (image_size
- 4)) {
1462 /* Read next four bytes */
1468 /* Save byte in circular buffer */
1469 buffer1
[b
++] = byte4
;
1470 if (b
== sizeof (buffer1
)) {
1474 /* Check byte for pattern match */
1475 if (pattern
[n
++] != byte4
) {
1476 /* If no match, then reset pattern */
1480 * If complete pattern has been matched then exit loop
1487 /* Save byte in circular buffer */
1488 buffer1
[b
++] = byte3
;
1489 if (b
== sizeof (buffer1
)) {
1493 /* Check byte for pattern match */
1494 if (pattern
[n
++] != byte3
) {
1495 /* If no match, then reset pattern */
1499 * If complete pattern has been matched then exit loop
1506 /* Save byte in circular buffer */
1507 buffer1
[b
++] = byte2
;
1508 if (b
== sizeof (buffer1
)) {
1512 /* Check byte for pattern match */
1513 if (pattern
[n
++] != byte2
) {
1514 /* If no match, then reset pattern */
1518 * If complete pattern has been matched then exit loop
1525 /* Save byte in circular buffer */
1526 buffer1
[b
++] = byte1
;
1527 if (b
== sizeof (buffer1
)) {
1531 /* Check byte for pattern match */
1532 if (pattern
[n
++] != byte1
) {
1533 /* If no match, then reset pattern */
1537 * If complete pattern has been matched then exit loop
1551 /* Align buffer and eliminate non-printable characters */
1552 for (i
= 0; i
< (sizeof (buffer1
)-plen
); i
++) {
1553 byte1
= buffer1
[b
++];
1554 if (b
== sizeof (buffer1
)) {
1557 /* Zero any non-printable characters */
1558 if (byte1
>= 33 && byte1
<= 126) {
1566 * Scan backwards for first non-zero string. This will be the
1569 for (i
= sizeof (buffer1
)-plen
-1; i
>= 0; i
--) {
1570 if (buffer2
[i
] != 0) {
1571 for (; i
>= 0; i
--) {
1572 if (buffer2
[i
] == 0) {
1574 strncpy((char *)pattern_value
,
1575 &buffer2
[i
], pattern_value_size
);
1586 * error handling routine to handle emulex error conditions
1589 handle_emulex_error(int fcio_errno
, char *phys_path
) {
1590 if (fcio_errno
== EMLX_IMAGE_BAD
) {
1591 fprintf(stderr
, MSGSTR(21119,
1592 "Error: Fcode download failed. "
1593 "Bad fcode image.\n"));
1594 } else if (fcio_errno
== EMLX_IMAGE_INCOMPATIBLE
) {
1595 fprintf(stderr
, MSGSTR(21120,
1596 "Error: Fcode download failed. Fcode is not "
1597 "compatible with card.\n"));
1599 (void) fprintf(stderr
, MSGSTR(21036,
1600 "Error: Driver interface FCIO_DOWNLOAD_FCODE failed\n"));
1601 (void) fprintf(stderr
,
1603 "Error: FCode download failed: %s\n"),