17836SJohn.Forte@Sun.COM /*
27836SJohn.Forte@Sun.COM * CDDL HEADER START
37836SJohn.Forte@Sun.COM *
47836SJohn.Forte@Sun.COM * The contents of this file are subject to the terms of the
57836SJohn.Forte@Sun.COM * Common Development and Distribution License (the "License").
67836SJohn.Forte@Sun.COM * You may not use this file except in compliance with the License.
77836SJohn.Forte@Sun.COM *
87836SJohn.Forte@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97836SJohn.Forte@Sun.COM * or http://www.opensolaris.org/os/licensing.
107836SJohn.Forte@Sun.COM * See the License for the specific language governing permissions
117836SJohn.Forte@Sun.COM * and limitations under the License.
127836SJohn.Forte@Sun.COM *
137836SJohn.Forte@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
147836SJohn.Forte@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157836SJohn.Forte@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
167836SJohn.Forte@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
177836SJohn.Forte@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
187836SJohn.Forte@Sun.COM *
197836SJohn.Forte@Sun.COM * CDDL HEADER END
207836SJohn.Forte@Sun.COM */
217836SJohn.Forte@Sun.COM /*
22*8538SReed.Liu@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
237836SJohn.Forte@Sun.COM * Use is subject to license terms.
247836SJohn.Forte@Sun.COM */
257836SJohn.Forte@Sun.COM
267836SJohn.Forte@Sun.COM /*
277836SJohn.Forte@Sun.COM * I18N message number ranges
287836SJohn.Forte@Sun.COM * This file: 21000 - 21499
297836SJohn.Forte@Sun.COM * Shared common messages: 1 - 1999
307836SJohn.Forte@Sun.COM */
317836SJohn.Forte@Sun.COM
327836SJohn.Forte@Sun.COM /*
337836SJohn.Forte@Sun.COM * Functions to support the download of FCode to PCI HBAs
347836SJohn.Forte@Sun.COM * Qlogic ISP21XX/22XX boards: FC100/P single port, ISP2200 dual port
357836SJohn.Forte@Sun.COM * and Emulex cards
367836SJohn.Forte@Sun.COM */
377836SJohn.Forte@Sun.COM #include <errno.h>
387836SJohn.Forte@Sun.COM #include <ctype.h>
397836SJohn.Forte@Sun.COM #include <fcntl.h>
407836SJohn.Forte@Sun.COM #include <stdio.h>
417836SJohn.Forte@Sun.COM #include <string.h>
427836SJohn.Forte@Sun.COM #include <strings.h>
437836SJohn.Forte@Sun.COM #include <unistd.h>
447836SJohn.Forte@Sun.COM #include <stdlib.h>
457836SJohn.Forte@Sun.COM #include <sys/stat.h>
467836SJohn.Forte@Sun.COM #include <limits.h>
477836SJohn.Forte@Sun.COM #include <signal.h>
487836SJohn.Forte@Sun.COM #include <dirent.h>
497836SJohn.Forte@Sun.COM #include <nl_types.h>
507836SJohn.Forte@Sun.COM #include <utmpx.h>
517836SJohn.Forte@Sun.COM #include <sys/mnttab.h>
527836SJohn.Forte@Sun.COM #include <sys/file.h>
537836SJohn.Forte@Sun.COM #include <sys/mtio.h>
547836SJohn.Forte@Sun.COM #include <sys/scsi/impl/uscsi.h>
557836SJohn.Forte@Sun.COM #include <sys/fibre-channel/fcio.h>
567836SJohn.Forte@Sun.COM #include <stgcom.h>
577836SJohn.Forte@Sun.COM #include <sys/scsi/adapters/ifpio.h>
587836SJohn.Forte@Sun.COM #include <libdevinfo.h>
597836SJohn.Forte@Sun.COM #include "luxadm.h"
607836SJohn.Forte@Sun.COM
617836SJohn.Forte@Sun.COM /* Error codes - used by the fcode_load_file routine */
627836SJohn.Forte@Sun.COM #define FCODE_SUCCESS 0 /* successful completion */
637836SJohn.Forte@Sun.COM #define FCODE_LOAD_FAILURE 1 /* general failure */
647836SJohn.Forte@Sun.COM #define FCODE_IOCTL_FAILURE 2 /* FCODE ioctl download failure */
657836SJohn.Forte@Sun.COM
667836SJohn.Forte@Sun.COM #define HBA_MAX 128
677836SJohn.Forte@Sun.COM #define FCODE_HDR 200
687836SJohn.Forte@Sun.COM #define MAX_RETRIES 3
697836SJohn.Forte@Sun.COM #define MAX_WAIT_TIME 30
707836SJohn.Forte@Sun.COM
717836SJohn.Forte@Sun.COM /*
727836SJohn.Forte@Sun.COM * EMULEX Fcode attributes
737836SJohn.Forte@Sun.COM */
747836SJohn.Forte@Sun.COM #define EMULEX_FCODE_VERSION_LENGTH 16
757836SJohn.Forte@Sun.COM #define EMULEX_READ_BUFFER_SIZE 128
767836SJohn.Forte@Sun.COM
777836SJohn.Forte@Sun.COM /* Emulex specific error codes */
787836SJohn.Forte@Sun.COM #define EMLX_ERRNO_START 0x100
797836SJohn.Forte@Sun.COM
807836SJohn.Forte@Sun.COM /* Diagnostic error codes */
817836SJohn.Forte@Sun.COM #define EMLX_TEST_FAILED (EMLX_ERRNO_START + 0)
827836SJohn.Forte@Sun.COM
837836SJohn.Forte@Sun.COM /* Download image contains bad data */
847836SJohn.Forte@Sun.COM #define EMLX_IMAGE_BAD (EMLX_ERRNO_START + 1)
857836SJohn.Forte@Sun.COM /* Download image not compatible with current hardware */
867836SJohn.Forte@Sun.COM #define EMLX_IMAGE_INCOMPATIBLE (EMLX_ERRNO_START + 2)
877836SJohn.Forte@Sun.COM /* Unable to take adapter offline */
887836SJohn.Forte@Sun.COM #define EMLX_IMAGE_FAILED (EMLX_ERRNO_START + 3)
897836SJohn.Forte@Sun.COM /* Image download failed */
907836SJohn.Forte@Sun.COM #define EMLX_OFFLINE_FAILED (EMLX_ERRNO_START + 4)
917836SJohn.Forte@Sun.COM
927836SJohn.Forte@Sun.COM
937836SJohn.Forte@Sun.COM
947836SJohn.Forte@Sun.COM
957836SJohn.Forte@Sun.COM /*
967836SJohn.Forte@Sun.COM * This is just a random value chosen to identify Sbus Fcodes. Sbus FCode
977836SJohn.Forte@Sun.COM * for Ivory is based on a 2200 chip but this value does not reflect that.
987836SJohn.Forte@Sun.COM */
997836SJohn.Forte@Sun.COM #define SBUS_CHIP_ID 0x1969
1007836SJohn.Forte@Sun.COM #define IVORY_BUS "/sbus@"
1017836SJohn.Forte@Sun.COM #define IVORY_DRVR "/SUNW,qlc@"
1027836SJohn.Forte@Sun.COM
1037836SJohn.Forte@Sun.COM /* Global variables */
1047836SJohn.Forte@Sun.COM static char fc_trans[] = "SUNW,ifp"; /* fibre channel transport */
1057836SJohn.Forte@Sun.COM static char fp_trans[] = "SUNW,qlc"; /* fca layer driver */
1067836SJohn.Forte@Sun.COM static char fp_trans_id[] = "fp@"; /* transport layer id */
1077836SJohn.Forte@Sun.COM static char qlgc2100[] = "FC100/P"; /* product name for 2100 */
1087836SJohn.Forte@Sun.COM static char qlgc2200[] = "ISP2200"; /* product name for 2200 */
1097836SJohn.Forte@Sun.COM static char qlgc2300[] = "ISP2300"; /* product name for 2300 */
1107836SJohn.Forte@Sun.COM static char qlgc2312[] = "ISP2312"; /* product name for 2312 */
1117836SJohn.Forte@Sun.COM /*
1127836SJohn.Forte@Sun.COM * The variable qlgc2200Sbus represents the string which is always the
1137836SJohn.Forte@Sun.COM * starting string of the version information in an ISP2200 Sbus Fcode.
1147836SJohn.Forte@Sun.COM */
1157836SJohn.Forte@Sun.COM static char qlgc2200Sbus[] = "ISP2200 Sbus FC-AL Host Adapter Driver";
1167836SJohn.Forte@Sun.COM static char pcibus_list[HBA_MAX][PATH_MAX];
1177836SJohn.Forte@Sun.COM /* Internal functions */
1187836SJohn.Forte@Sun.COM static int q_load_file(int, char *);
1197836SJohn.Forte@Sun.COM static int q_getbootdev(uchar_t *);
1207836SJohn.Forte@Sun.COM static int q_getdevctlpath(char *, int *);
1217836SJohn.Forte@Sun.COM static int q_warn(int);
1227836SJohn.Forte@Sun.COM static int q_findversion(int, int, uchar_t *, uint16_t *);
123*8538SReed.Liu@Sun.COM static int q_findfileversion(char *, uchar_t *, uint16_t *, int, int *);
124*8538SReed.Liu@Sun.COM static int q_findSbusfile(int, int *);
1257836SJohn.Forte@Sun.COM static int memstrstr(char *, char *, int, int);
1267836SJohn.Forte@Sun.COM static int fcode_load_file(int, char *, int *);
1277836SJohn.Forte@Sun.COM
1287836SJohn.Forte@Sun.COM /*
1297836SJohn.Forte@Sun.COM * Functions to support Fcode download for Emulex HBAs
1307836SJohn.Forte@Sun.COM */
1317836SJohn.Forte@Sun.COM static int emulex_fcodeversion(di_node_t, uchar_t *);
1327836SJohn.Forte@Sun.COM static void handle_emulex_error(int, char *);
1337836SJohn.Forte@Sun.COM
1347836SJohn.Forte@Sun.COM /*
135*8538SReed.Liu@Sun.COM * Searches for and updates the cards. This is the "main" function
1367836SJohn.Forte@Sun.COM * and will give the output to the user by calling the subfunctions.
1377836SJohn.Forte@Sun.COM * args: FCode file; if NULL only the current FCode version is printed
1387836SJohn.Forte@Sun.COM */
1397836SJohn.Forte@Sun.COM int
q_qlgc_update(unsigned int verbose,char * file)1407836SJohn.Forte@Sun.COM q_qlgc_update(unsigned int verbose, char *file)
1417836SJohn.Forte@Sun.COM /*ARGSUSED*/
1427836SJohn.Forte@Sun.COM {
1437836SJohn.Forte@Sun.COM int fd, fcode_fd = -1, errnum = 0, devcnt = 0, retval = 0, isSbus = 0;
1447836SJohn.Forte@Sun.COM int sbus_off;
1457836SJohn.Forte@Sun.COM uint_t i, fflag = 0;
1467836SJohn.Forte@Sun.COM uint16_t chip_id = 0, file_id = 0;
1477836SJohn.Forte@Sun.COM uchar_t fcode_buf[FCODE_HDR];
1487836SJohn.Forte@Sun.COM static uchar_t bootpath[PATH_MAX];
1497836SJohn.Forte@Sun.COM static uchar_t version[MAXNAMELEN], version_file[MAXNAMELEN];
1507836SJohn.Forte@Sun.COM char devpath[PATH_MAX], tmppath[PATH_MAX];
1517836SJohn.Forte@Sun.COM void (*sigint)(); /* to store default SIGTERM setting */
1527836SJohn.Forte@Sun.COM static struct utmpx *utmpp = NULL; /* pointer for getutxent() */
1537836SJohn.Forte@Sun.COM char *ptr1, *ptr2;
1547836SJohn.Forte@Sun.COM char phys_path[PATH_MAX];
1557836SJohn.Forte@Sun.COM /*
1567836SJohn.Forte@Sun.COM * The variables port1 and port2 are used to store the bus id
1577836SJohn.Forte@Sun.COM * e.g. the bus id for this path:
1587836SJohn.Forte@Sun.COM * /devices/sbus@12,0/SUNW,qlc@2,30000/fp@0,0:devctl
1597836SJohn.Forte@Sun.COM * is "sbus@12". They are initialized to a random value and are
1607836SJohn.Forte@Sun.COM * set such that they are not equal initially.
1617836SJohn.Forte@Sun.COM */
1627836SJohn.Forte@Sun.COM static char port1[MAXNAMELEN] = {NULL};
1637836SJohn.Forte@Sun.COM static char port2[MAXNAMELEN] = {NULL};
1647836SJohn.Forte@Sun.COM
1657836SJohn.Forte@Sun.COM if (file) {
1667836SJohn.Forte@Sun.COM fflag++;
1677836SJohn.Forte@Sun.COM
1687836SJohn.Forte@Sun.COM /* check for a valid file */
1697836SJohn.Forte@Sun.COM if ((fcode_fd = open(file, O_RDONLY)) < 0) {
1707836SJohn.Forte@Sun.COM (void) fprintf(stderr,
1717836SJohn.Forte@Sun.COM MSGSTR(21000, "Error: Could not open %s\n"), file);
1727836SJohn.Forte@Sun.COM return (1);
1737836SJohn.Forte@Sun.COM }
1747836SJohn.Forte@Sun.COM if (read(fcode_fd, fcode_buf, FCODE_HDR) != FCODE_HDR) {
1757836SJohn.Forte@Sun.COM perror(MSGSTR(21001, "read"));
1767836SJohn.Forte@Sun.COM (void) close(fcode_fd);
1777836SJohn.Forte@Sun.COM return (1);
1787836SJohn.Forte@Sun.COM }
1797836SJohn.Forte@Sun.COM
1807836SJohn.Forte@Sun.COM /*
1817836SJohn.Forte@Sun.COM * Check if it's SBUS FCode by calling q_findSbusfile
1827836SJohn.Forte@Sun.COM * if it is then isSbus will be 1, if not it will be 0
1837836SJohn.Forte@Sun.COM * in case of an error, it will be -1
1847836SJohn.Forte@Sun.COM */
1857836SJohn.Forte@Sun.COM isSbus = q_findSbusfile(fcode_fd, &sbus_off);
1867836SJohn.Forte@Sun.COM if (isSbus == -1) {
1877836SJohn.Forte@Sun.COM (void) close(fcode_fd);
1887836SJohn.Forte@Sun.COM return (1);
1897836SJohn.Forte@Sun.COM }
1907836SJohn.Forte@Sun.COM
1917836SJohn.Forte@Sun.COM /*
1927836SJohn.Forte@Sun.COM * FCode header check - make sure it's PCI FCode
1937836SJohn.Forte@Sun.COM * Structure of FCode header (byte# refers to byte numbering
1947836SJohn.Forte@Sun.COM * in FCode spec, not the byte# of our fcode_buf buffer):
195*8538SReed.Liu@Sun.COM * header byte 00 0x55 prom signature byte one
196*8538SReed.Liu@Sun.COM * byte 01 0xaa prom signature byte two
1977836SJohn.Forte@Sun.COM * data byte 00-03 P C I R
1987836SJohn.Forte@Sun.COM * OR
199*8538SReed.Liu@Sun.COM * header byte 32 0x55
200*8538SReed.Liu@Sun.COM * byte 33 0xaa
2017836SJohn.Forte@Sun.COM * data byte 60-63 P C I R
2027836SJohn.Forte@Sun.COM * The second format with an offset of 32 is used for ifp prom
2037836SJohn.Forte@Sun.COM */
2047836SJohn.Forte@Sun.COM if (!(((fcode_buf[0x00] == 0x55) &&
2057836SJohn.Forte@Sun.COM (fcode_buf[0x01] == 0xaa) &&
2067836SJohn.Forte@Sun.COM (fcode_buf[0x1c] == 'P') &&
2077836SJohn.Forte@Sun.COM (fcode_buf[0x1d] == 'C') &&
2087836SJohn.Forte@Sun.COM (fcode_buf[0x1e] == 'I') &&
2097836SJohn.Forte@Sun.COM (fcode_buf[0x1f] == 'R')) ||
2107836SJohn.Forte@Sun.COM
2117836SJohn.Forte@Sun.COM ((fcode_buf[0x20] == 0x55) &&
2127836SJohn.Forte@Sun.COM (fcode_buf[0x21] == 0xaa) &&
2137836SJohn.Forte@Sun.COM (fcode_buf[0x3c] == 'P') &&
2147836SJohn.Forte@Sun.COM (fcode_buf[0x3d] == 'C') &&
2157836SJohn.Forte@Sun.COM (fcode_buf[0x3e] == 'I') &&
2167836SJohn.Forte@Sun.COM (fcode_buf[0x3f] == 'R')) ||
2177836SJohn.Forte@Sun.COM
2187836SJohn.Forte@Sun.COM (isSbus))) {
2197836SJohn.Forte@Sun.COM (void) fprintf(stderr, MSGSTR(21002,
2207836SJohn.Forte@Sun.COM "Error: %s is not a valid FC100/P, "
2217836SJohn.Forte@Sun.COM "ISP2200, ISP23xx FCode file.\n"),
2227836SJohn.Forte@Sun.COM file);
2237836SJohn.Forte@Sun.COM (void) close(fcode_fd);
2247836SJohn.Forte@Sun.COM return (1);
2257836SJohn.Forte@Sun.COM }
2267836SJohn.Forte@Sun.COM
2277836SJohn.Forte@Sun.COM /* check for single user mode */
2287836SJohn.Forte@Sun.COM while ((utmpp = getutxent()) != NULL) {
2297836SJohn.Forte@Sun.COM if (strstr(utmpp->ut_line, "run-level") &&
2307836SJohn.Forte@Sun.COM (strcmp(utmpp->ut_line, "run-level S") &&
2317836SJohn.Forte@Sun.COM strcmp(utmpp->ut_line, "run-level 1"))) {
2327836SJohn.Forte@Sun.COM if (q_warn(1)) {
2337836SJohn.Forte@Sun.COM (void) endutxent();
2347836SJohn.Forte@Sun.COM (void) close(fcode_fd);
2357836SJohn.Forte@Sun.COM return (1);
2367836SJohn.Forte@Sun.COM }
2377836SJohn.Forte@Sun.COM break;
2387836SJohn.Forte@Sun.COM }
2397836SJohn.Forte@Sun.COM }
2407836SJohn.Forte@Sun.COM (void) endutxent();
2417836SJohn.Forte@Sun.COM
2427836SJohn.Forte@Sun.COM /* get bootpath */
2437836SJohn.Forte@Sun.COM if (!q_getbootdev((uchar_t *)&bootpath[0]) &&
2447836SJohn.Forte@Sun.COM getenv("_LUX_D_DEBUG") != NULL) {
2457836SJohn.Forte@Sun.COM (void) fprintf(stdout, " Bootpath: %s\n", bootpath);
2467836SJohn.Forte@Sun.COM }
2477836SJohn.Forte@Sun.COM }
2487836SJohn.Forte@Sun.COM /*
2497836SJohn.Forte@Sun.COM * Get count of, and names of PCI slots with ifp device control
2507836SJohn.Forte@Sun.COM * (devctl) nodes. Search /devices.
2517836SJohn.Forte@Sun.COM */
2527836SJohn.Forte@Sun.COM (void) strcpy(devpath, "/devices");
2537836SJohn.Forte@Sun.COM if (q_getdevctlpath(devpath, (int *)&devcnt) == 0) {
2547836SJohn.Forte@Sun.COM (void) fprintf(stdout, MSGSTR(21003,
2557836SJohn.Forte@Sun.COM "\n Found Path to %d FC100/P, ISP2200, ISP23xx Devices\n"),
2567836SJohn.Forte@Sun.COM devcnt);
2577836SJohn.Forte@Sun.COM } else {
2587836SJohn.Forte@Sun.COM (void) fprintf(stderr, MSGSTR(21004,
2597836SJohn.Forte@Sun.COM "Error: Could not get /devices path to FC100/P,"
2607836SJohn.Forte@Sun.COM "ISP2200, ISP23xx Cards.\n"));
2617836SJohn.Forte@Sun.COM retval++;
2627836SJohn.Forte@Sun.COM }
2637836SJohn.Forte@Sun.COM
2647836SJohn.Forte@Sun.COM for (i = 0; i < devcnt; i++) {
2657836SJohn.Forte@Sun.COM
2667836SJohn.Forte@Sun.COM (void) strncpy((char *)phys_path, &pcibus_list[i][0],
2677836SJohn.Forte@Sun.COM strlen(&pcibus_list[i][0]));
2687836SJohn.Forte@Sun.COM if (fflag && (strstr((char *)bootpath,
2697836SJohn.Forte@Sun.COM strtok((char *)phys_path, ":")) != NULL)) {
2707836SJohn.Forte@Sun.COM (void) fprintf(stderr,
2717836SJohn.Forte@Sun.COM MSGSTR(21005, "Ignoring %s (bootpath)\n"),
2727836SJohn.Forte@Sun.COM &pcibus_list[i][0]);
2737836SJohn.Forte@Sun.COM continue;
2747836SJohn.Forte@Sun.COM }
2757836SJohn.Forte@Sun.COM
2767836SJohn.Forte@Sun.COM (void) fprintf(stdout,
2777836SJohn.Forte@Sun.COM MSGSTR(21006, "\n Opening Device: %s\n"), &pcibus_list[i][0]);
2787836SJohn.Forte@Sun.COM /* Check if the device is valid */
2797836SJohn.Forte@Sun.COM if ((fd = open(&pcibus_list[i][0], O_RDWR)) < 0) {
2807836SJohn.Forte@Sun.COM (void) fprintf(stderr,
2817836SJohn.Forte@Sun.COM MSGSTR(21000, "Error: Could not open %s\n"),
2827836SJohn.Forte@Sun.COM &pcibus_list[i][0]);
2837836SJohn.Forte@Sun.COM retval++;
2847836SJohn.Forte@Sun.COM continue;
2857836SJohn.Forte@Sun.COM }
2867836SJohn.Forte@Sun.COM (void) close(fd);
2877836SJohn.Forte@Sun.COM /*
2887836SJohn.Forte@Sun.COM * Check FCode version present on the adapter (at last boot)
2897836SJohn.Forte@Sun.COM */
2907836SJohn.Forte@Sun.COM if (q_findversion(verbose, i, (uchar_t *)&version[0],
2917836SJohn.Forte@Sun.COM &chip_id) == 0) {
2927836SJohn.Forte@Sun.COM if (strlen((char *)version) == 0) {
2937836SJohn.Forte@Sun.COM (void) fprintf(stdout, MSGSTR(21007,
2947836SJohn.Forte@Sun.COM " Detected FCode Version:\tNo version available for this FCode\n"));
2957836SJohn.Forte@Sun.COM } else {
2967836SJohn.Forte@Sun.COM (void) fprintf(stdout, MSGSTR(21008,
2977836SJohn.Forte@Sun.COM " Detected FCode Version:\t%s\n"), version);
2987836SJohn.Forte@Sun.COM }
2997836SJohn.Forte@Sun.COM } else {
3007836SJohn.Forte@Sun.COM chip_id = 0x0;
3017836SJohn.Forte@Sun.COM }
3027836SJohn.Forte@Sun.COM
3037836SJohn.Forte@Sun.COM if (fflag) {
3047836SJohn.Forte@Sun.COM /*
3057836SJohn.Forte@Sun.COM * For ISP2200, Sbus HBA, do just 1 download
3067836SJohn.Forte@Sun.COM * for both the ports (dual port HBA)
3077836SJohn.Forte@Sun.COM * Here it is assumed that readdir() always
3087836SJohn.Forte@Sun.COM * returns the paths in pcibus_list[] in the
3097836SJohn.Forte@Sun.COM * sorted order.
3107836SJohn.Forte@Sun.COM */
3117836SJohn.Forte@Sun.COM (void) strcpy(tmppath, pcibus_list[i]);
3127836SJohn.Forte@Sun.COM if (ptr1 = strstr(tmppath, IVORY_BUS)) {
3137836SJohn.Forte@Sun.COM if (ptr2 = strstr(ptr1, IVORY_DRVR)) {
3147836SJohn.Forte@Sun.COM ptr2 = strchr(ptr2, ',');
3157836SJohn.Forte@Sun.COM if (ptr2 = strchr(++ptr2, ',')) {
3167836SJohn.Forte@Sun.COM *ptr2 = '\0';
3177836SJohn.Forte@Sun.COM }
3187836SJohn.Forte@Sun.COM }
3197836SJohn.Forte@Sun.COM (void) strcpy(port2, ptr1);
3207836SJohn.Forte@Sun.COM if (strcmp(port1, port2) == 0) {
3217836SJohn.Forte@Sun.COM (void) fprintf(stdout, MSGSTR(21037,
3227836SJohn.Forte@Sun.COM "/n New FCode has already been downloaded "
3237836SJohn.Forte@Sun.COM "to this ISP2200 SBus HBA Card.\n"
3247836SJohn.Forte@Sun.COM "It is sufficient to download to one "
3257836SJohn.Forte@Sun.COM "port of the ISP2200 SBus HBA Card. "
3267836SJohn.Forte@Sun.COM "Moving on...\n"));
3277836SJohn.Forte@Sun.COM continue;
3287836SJohn.Forte@Sun.COM }
3297836SJohn.Forte@Sun.COM }
3307836SJohn.Forte@Sun.COM /*
3317836SJohn.Forte@Sun.COM * Check version of the supplied FCode file (once)
3327836SJohn.Forte@Sun.COM */
3337836SJohn.Forte@Sun.COM if ((file_id != 0 && version_file != NULL) ||
3347836SJohn.Forte@Sun.COM (q_findfileversion((char *)
3357836SJohn.Forte@Sun.COM &fcode_buf[0], (uchar_t *)&version_file[0],
3367836SJohn.Forte@Sun.COM &file_id, isSbus, &sbus_off) == 0)) {
3377836SJohn.Forte@Sun.COM (void) fprintf(stdout, MSGSTR(21009,
3387836SJohn.Forte@Sun.COM " New FCode Version:\t\t%s\n"),
3397836SJohn.Forte@Sun.COM version_file);
3407836SJohn.Forte@Sun.COM } else {
3417836SJohn.Forte@Sun.COM (void) close(fcode_fd);
3427836SJohn.Forte@Sun.COM return (1);
3437836SJohn.Forte@Sun.COM }
3447836SJohn.Forte@Sun.COM
3457836SJohn.Forte@Sun.COM /*
3467836SJohn.Forte@Sun.COM * Load the New FCode
3477836SJohn.Forte@Sun.COM * Give warning if file doesn't appear to be correct
3487836SJohn.Forte@Sun.COM *
3497836SJohn.Forte@Sun.COM */
3507836SJohn.Forte@Sun.COM if (chip_id == 0) {
3517836SJohn.Forte@Sun.COM errnum = 2; /* can't get chip_id */
3527836SJohn.Forte@Sun.COM retval++;
3537836SJohn.Forte@Sun.COM } else if (chip_id - file_id != 0) {
3547836SJohn.Forte@Sun.COM errnum = 3; /* file/card mismatch */
3557836SJohn.Forte@Sun.COM retval++;
3567836SJohn.Forte@Sun.COM } else {
3577836SJohn.Forte@Sun.COM errnum = 0; /* everything is ok */
3587836SJohn.Forte@Sun.COM }
3597836SJohn.Forte@Sun.COM
3607836SJohn.Forte@Sun.COM if (!q_warn(errnum)) {
3617836SJohn.Forte@Sun.COM /* Disable user-interrupt Control-C */
3627836SJohn.Forte@Sun.COM sigint =
3637836SJohn.Forte@Sun.COM (void (*)(int)) signal(SIGINT, SIG_IGN);
3647836SJohn.Forte@Sun.COM
3657836SJohn.Forte@Sun.COM /* Load FCode */
3667836SJohn.Forte@Sun.COM (void) fprintf(stdout, MSGSTR(21010,
3677836SJohn.Forte@Sun.COM " Loading FCode: %s\n"), file);
3687836SJohn.Forte@Sun.COM
3697836SJohn.Forte@Sun.COM if (q_load_file(fcode_fd,
3707836SJohn.Forte@Sun.COM &pcibus_list[i][0]) == 0) {
3717836SJohn.Forte@Sun.COM (void) fprintf(stdout, MSGSTR(21011,
3727836SJohn.Forte@Sun.COM " Successful FCode download: %s\n"),
3737836SJohn.Forte@Sun.COM &pcibus_list[i][0]);
3747836SJohn.Forte@Sun.COM (void) strcpy(port1, port2);
3757836SJohn.Forte@Sun.COM } else {
3767836SJohn.Forte@Sun.COM (void) fprintf(stderr, MSGSTR(21012,
3777836SJohn.Forte@Sun.COM "Error: FCode download failed: %s\n"),
3787836SJohn.Forte@Sun.COM &pcibus_list[i][0]);
3797836SJohn.Forte@Sun.COM retval++;
3807836SJohn.Forte@Sun.COM }
3817836SJohn.Forte@Sun.COM /* Restore SIGINT (user interrupt) setting */
3827836SJohn.Forte@Sun.COM (void) signal(SIGINT, sigint);
3837836SJohn.Forte@Sun.COM }
3847836SJohn.Forte@Sun.COM }
3857836SJohn.Forte@Sun.COM }
3867836SJohn.Forte@Sun.COM (void) fprintf(stdout, " ");
3877836SJohn.Forte@Sun.COM (void) fprintf(stdout, MSGSTR(125, "Complete\n"));
3887836SJohn.Forte@Sun.COM if (fcode_fd != -1)
3897836SJohn.Forte@Sun.COM (void) close(fcode_fd);
3907836SJohn.Forte@Sun.COM return (retval);
3917836SJohn.Forte@Sun.COM }
3927836SJohn.Forte@Sun.COM
3937836SJohn.Forte@Sun.COM
3947836SJohn.Forte@Sun.COM /*
3957836SJohn.Forte@Sun.COM * Retrieve the version banner from the card
396*8538SReed.Liu@Sun.COM * uses ioctl: FCIO_FCODE_MCODE_VERSION FCode revision
3977836SJohn.Forte@Sun.COM */
3987836SJohn.Forte@Sun.COM static int
q_findversion(int verbose,int index,uchar_t * version,uint16_t * chip_id)3997836SJohn.Forte@Sun.COM q_findversion(int verbose, int index, uchar_t *version, uint16_t *chip_id)
4007836SJohn.Forte@Sun.COM /*ARGSUSED*/
4017836SJohn.Forte@Sun.COM {
4027836SJohn.Forte@Sun.COM int fd, ntries;
403*8538SReed.Liu@Sun.COM struct ifp_fm_version *version_buffer = NULL;
4047836SJohn.Forte@Sun.COM char prom_ver[100] = {NULL};
4057836SJohn.Forte@Sun.COM char mcode_ver[100] = {NULL};
4067836SJohn.Forte@Sun.COM fcio_t fcio;
4077836SJohn.Forte@Sun.COM
4087836SJohn.Forte@Sun.COM if (strstr(&pcibus_list[index][0], fc_trans)) {
4097836SJohn.Forte@Sun.COM
4107836SJohn.Forte@Sun.COM if ((fd = open(&pcibus_list[index][0], O_RDWR)) < 0) {
4117836SJohn.Forte@Sun.COM (void) fprintf(stderr,
4127836SJohn.Forte@Sun.COM MSGSTR(21000, "Error: Could not open %s\n"),
4137836SJohn.Forte@Sun.COM &pcibus_list[index][0]);
4147836SJohn.Forte@Sun.COM return (1);
4157836SJohn.Forte@Sun.COM }
4167836SJohn.Forte@Sun.COM
4177836SJohn.Forte@Sun.COM if ((version_buffer = (struct ifp_fm_version *)malloc(
4187836SJohn.Forte@Sun.COM sizeof (struct ifp_fm_version))) == NULL) {
4197836SJohn.Forte@Sun.COM (void) fprintf(stderr,
4207836SJohn.Forte@Sun.COM MSGSTR(21013, "Error: Memory allocation failed\n"));
4217836SJohn.Forte@Sun.COM (void) close(fd);
4227836SJohn.Forte@Sun.COM return (1);
4237836SJohn.Forte@Sun.COM }
4247836SJohn.Forte@Sun.COM
4257836SJohn.Forte@Sun.COM version_buffer->fcode_ver = (char *)version;
4267836SJohn.Forte@Sun.COM version_buffer->mcode_ver = mcode_ver;
4277836SJohn.Forte@Sun.COM version_buffer->prom_ver = prom_ver;
4287836SJohn.Forte@Sun.COM version_buffer->fcode_ver_len = MAXNAMELEN - 1;
4297836SJohn.Forte@Sun.COM version_buffer->mcode_ver_len = 100;
4307836SJohn.Forte@Sun.COM version_buffer->prom_ver_len = 100;
4317836SJohn.Forte@Sun.COM
4327836SJohn.Forte@Sun.COM if (ioctl(fd, FCIO_FCODE_MCODE_VERSION, version_buffer) < 0) {
4337836SJohn.Forte@Sun.COM (void) fprintf(stderr, MSGSTR(21014,
4347836SJohn.Forte@Sun.COM "Error: Driver interface FCIO_FCODE_MCODE_VERSION failed\n"));
4357836SJohn.Forte@Sun.COM free(version_buffer);
4367836SJohn.Forte@Sun.COM (void) close(fd);
4377836SJohn.Forte@Sun.COM return (1);
4387836SJohn.Forte@Sun.COM }
4397836SJohn.Forte@Sun.COM version[version_buffer->fcode_ver_len] = '\0';
4407836SJohn.Forte@Sun.COM
4417836SJohn.Forte@Sun.COM /* Need a way to get card MCODE (firmware) to track certain HW bugs */
4427836SJohn.Forte@Sun.COM if (getenv("_LUX_D_DEBUG") != NULL) {
4437836SJohn.Forte@Sun.COM (void) fprintf(stdout, " Device %i: QLGC chip_id %x\n",
4447836SJohn.Forte@Sun.COM index+1, *chip_id);
4457836SJohn.Forte@Sun.COM (void) fprintf(stdout, " FCode:%s\n MCODE:%s\n PROM:%s\n",
4467836SJohn.Forte@Sun.COM (char *)version, mcode_ver, prom_ver);
4477836SJohn.Forte@Sun.COM }
4487836SJohn.Forte@Sun.COM free(version_buffer);
4497836SJohn.Forte@Sun.COM
4507836SJohn.Forte@Sun.COM } else if (strstr(&pcibus_list[index][0], fp_trans)) {
4517836SJohn.Forte@Sun.COM /*
4527836SJohn.Forte@Sun.COM * Get the fcode and prom's fw version
4537836SJohn.Forte@Sun.COM * using the fp ioctls. Currently, we pass
4547836SJohn.Forte@Sun.COM * only the fcode version to the calling function
4557836SJohn.Forte@Sun.COM * and ignore the FW version (using the existing
4567836SJohn.Forte@Sun.COM * implementation).
4577836SJohn.Forte@Sun.COM */
4587836SJohn.Forte@Sun.COM
4597836SJohn.Forte@Sun.COM if ((fd = open(&pcibus_list[index][0], O_RDWR)) < 0) {
4607836SJohn.Forte@Sun.COM (void) fprintf(stderr,
4617836SJohn.Forte@Sun.COM MSGSTR(4511, "Could not open %s\n"),
4627836SJohn.Forte@Sun.COM &pcibus_list[index][0]);
4637836SJohn.Forte@Sun.COM (void) close(fd);
4647836SJohn.Forte@Sun.COM return (1);
4657836SJohn.Forte@Sun.COM }
4667836SJohn.Forte@Sun.COM /* Get the fcode version */
4677836SJohn.Forte@Sun.COM bzero(version, sizeof (version));
4687836SJohn.Forte@Sun.COM fcio.fcio_cmd = FCIO_GET_FCODE_REV;
4697836SJohn.Forte@Sun.COM /* Information read operation */
4707836SJohn.Forte@Sun.COM fcio.fcio_xfer = FCIO_XFER_READ;
4717836SJohn.Forte@Sun.COM fcio.fcio_obuf = (caddr_t)version;
4727836SJohn.Forte@Sun.COM fcio.fcio_olen = MAXNAMELEN;
4737836SJohn.Forte@Sun.COM
4747836SJohn.Forte@Sun.COM for (ntries = 0; ntries < MAX_RETRIES; ntries++) {
4757836SJohn.Forte@Sun.COM if (ioctl(fd, FCIO_CMD, &fcio) != 0) {
4767836SJohn.Forte@Sun.COM if ((errno == EAGAIN) &&
4777836SJohn.Forte@Sun.COM (ntries+1 < MAX_RETRIES)) {
4787836SJohn.Forte@Sun.COM /* wait 30 secs */
4797836SJohn.Forte@Sun.COM (void) sleep(MAX_WAIT_TIME);
4807836SJohn.Forte@Sun.COM continue;
4817836SJohn.Forte@Sun.COM }
4827836SJohn.Forte@Sun.COM (void) close(fd);
4837836SJohn.Forte@Sun.COM return (L_FCIO_GET_FCODE_REV_FAIL);
4847836SJohn.Forte@Sun.COM }
4857836SJohn.Forte@Sun.COM break;
4867836SJohn.Forte@Sun.COM }
4877836SJohn.Forte@Sun.COM version[MAXNAMELEN-1] = '\0';
4887836SJohn.Forte@Sun.COM }
4897836SJohn.Forte@Sun.COM
4907836SJohn.Forte@Sun.COM /* Get type of card from product name in FCode version banner */
4917836SJohn.Forte@Sun.COM if (strstr((char *)version, qlgc2100)) {
4927836SJohn.Forte@Sun.COM *chip_id = 0x2100;
4937836SJohn.Forte@Sun.COM } else if (strstr((char *)version, qlgc2200)) {
4947836SJohn.Forte@Sun.COM *chip_id = 0x2200;
4957836SJohn.Forte@Sun.COM if (strstr((char *)version, "Sbus")) {
4967836SJohn.Forte@Sun.COM *chip_id = SBUS_CHIP_ID;
4977836SJohn.Forte@Sun.COM }
4987836SJohn.Forte@Sun.COM } else if (strstr((char *)version, qlgc2300)) {
4997836SJohn.Forte@Sun.COM *chip_id = 0x2300;
5007836SJohn.Forte@Sun.COM } else if (strstr((char *)version, qlgc2312)) {
5017836SJohn.Forte@Sun.COM *chip_id = 0x2312;
5027836SJohn.Forte@Sun.COM } else {
5037836SJohn.Forte@Sun.COM *chip_id = 0x0;
5047836SJohn.Forte@Sun.COM }
5057836SJohn.Forte@Sun.COM
5067836SJohn.Forte@Sun.COM (void) close(fd);
5077836SJohn.Forte@Sun.COM return (0);
5087836SJohn.Forte@Sun.COM }
5097836SJohn.Forte@Sun.COM
5107836SJohn.Forte@Sun.COM /*
5117836SJohn.Forte@Sun.COM * Retrieve the version banner and file type (2100 or 2200) from the file
5127836SJohn.Forte@Sun.COM */
5137836SJohn.Forte@Sun.COM static int
q_findfileversion(char * dl_fcode,uchar_t * version_file,uint16_t * file_id,int isSbus,int * sbus_offset)5147836SJohn.Forte@Sun.COM q_findfileversion(char *dl_fcode, uchar_t *version_file, uint16_t *file_id,
5157836SJohn.Forte@Sun.COM int isSbus, int *sbus_offset)
5167836SJohn.Forte@Sun.COM {
5177836SJohn.Forte@Sun.COM int mark;
5187836SJohn.Forte@Sun.COM int qlc_offset = 0;
5197836SJohn.Forte@Sun.COM char temp[4] = {NULL};
5207836SJohn.Forte@Sun.COM
5217836SJohn.Forte@Sun.COM
5227836SJohn.Forte@Sun.COM /*
5237836SJohn.Forte@Sun.COM * Get file version from FCode for 2100 or 2202
5247836SJohn.Forte@Sun.COM */
5257836SJohn.Forte@Sun.COM if (isSbus) {
5267836SJohn.Forte@Sun.COM *file_id = SBUS_CHIP_ID;
5277836SJohn.Forte@Sun.COM } else {
5287836SJohn.Forte@Sun.COM if ((dl_fcode[0x23] == 0x22) ||
5297836SJohn.Forte@Sun.COM (dl_fcode[0x23] == 0x23)) {
5307836SJohn.Forte@Sun.COM *file_id = dl_fcode[0x22] & 0xff;
5317836SJohn.Forte@Sun.COM *file_id |= (dl_fcode[0x23] << 8) & 0xff00;
5327836SJohn.Forte@Sun.COM } else {
5337836SJohn.Forte@Sun.COM *file_id = dl_fcode[0x42] & 0xff;
5347836SJohn.Forte@Sun.COM *file_id |= (dl_fcode[0x43] << 8) & 0xff00;
5357836SJohn.Forte@Sun.COM }
5367836SJohn.Forte@Sun.COM }
5377836SJohn.Forte@Sun.COM
5387836SJohn.Forte@Sun.COM /*
5397836SJohn.Forte@Sun.COM * Ok, we're just checking for 2200 here. If it is we need
5407836SJohn.Forte@Sun.COM * to offset to find the banner.
5417836SJohn.Forte@Sun.COM */
5427836SJohn.Forte@Sun.COM if ((*file_id == 0x2200) ||
5437836SJohn.Forte@Sun.COM (*file_id == 0x2300) ||
5447836SJohn.Forte@Sun.COM (*file_id == 0x2312)) {
5457836SJohn.Forte@Sun.COM qlc_offset = -32;
5467836SJohn.Forte@Sun.COM }
5477836SJohn.Forte@Sun.COM
5487836SJohn.Forte@Sun.COM /*
5497836SJohn.Forte@Sun.COM * If this is an ISP2200 Sbus Fcode file, then search for the string
5507836SJohn.Forte@Sun.COM * "ISP2200 FC-AL Host Adapter Driver" in the whole fcode file
5517836SJohn.Forte@Sun.COM */
5527836SJohn.Forte@Sun.COM if (isSbus) {
5537836SJohn.Forte@Sun.COM *file_id = SBUS_CHIP_ID;
5547836SJohn.Forte@Sun.COM qlc_offset = *sbus_offset;
5557836SJohn.Forte@Sun.COM /* Subtract 111 from the offset we add below for PCI Fcodes */
5567836SJohn.Forte@Sun.COM qlc_offset -= 111;
5577836SJohn.Forte@Sun.COM }
5587836SJohn.Forte@Sun.COM
5597836SJohn.Forte@Sun.COM /* Banner length varies; grab banner to end of date marker yr/mo/da */
5607836SJohn.Forte@Sun.COM version_file[0] = '\0';
5617836SJohn.Forte@Sun.COM for (mark = (111 + qlc_offset); mark < (191 + qlc_offset); mark++) {
5627836SJohn.Forte@Sun.COM (void) strncpy(temp, (char *)&dl_fcode[mark], 4);
5637836SJohn.Forte@Sun.COM if ((strncmp(&temp[0], "/", 1) == 0) &&
5647836SJohn.Forte@Sun.COM (strncmp(&temp[3], "/", 1) == 0)) {
5657836SJohn.Forte@Sun.COM (void) strncat((char *)version_file,
5667836SJohn.Forte@Sun.COM (char *)&dl_fcode[mark], 6);
5677836SJohn.Forte@Sun.COM break;
5687836SJohn.Forte@Sun.COM }
5697836SJohn.Forte@Sun.COM (void) strncat((char *)version_file, temp, 1);
5707836SJohn.Forte@Sun.COM }
5717836SJohn.Forte@Sun.COM return (0);
5727836SJohn.Forte@Sun.COM }
5737836SJohn.Forte@Sun.COM
5747836SJohn.Forte@Sun.COM /*
5757836SJohn.Forte@Sun.COM * Find if the FCode file is a ISP2200 SBUS Fcode file
5767836SJohn.Forte@Sun.COM */
5777836SJohn.Forte@Sun.COM static int
q_findSbusfile(int fd,int * sbus_offset)5787836SJohn.Forte@Sun.COM q_findSbusfile(int fd, int *sbus_offset)
5797836SJohn.Forte@Sun.COM {
5807836SJohn.Forte@Sun.COM static int file_size;
5817836SJohn.Forte@Sun.COM char *sbus_info;
5827836SJohn.Forte@Sun.COM struct stat statinfo;
5837836SJohn.Forte@Sun.COM
5847836SJohn.Forte@Sun.COM if (lseek(fd, 0, SEEK_SET) == -1) {
5857836SJohn.Forte@Sun.COM perror(MSGSTR(21022, "seek"));
5867836SJohn.Forte@Sun.COM return (-1);
5877836SJohn.Forte@Sun.COM }
5887836SJohn.Forte@Sun.COM if (fstat(fd, &statinfo)) {
5897836SJohn.Forte@Sun.COM perror(MSGSTR(21023, "fstat"));
5907836SJohn.Forte@Sun.COM return (-1);
5917836SJohn.Forte@Sun.COM }
5927836SJohn.Forte@Sun.COM file_size = statinfo.st_size;
5937836SJohn.Forte@Sun.COM
5947836SJohn.Forte@Sun.COM if ((sbus_info = (char *)malloc(file_size)) == NULL) {
5957836SJohn.Forte@Sun.COM (void) fprintf(stderr,
5967836SJohn.Forte@Sun.COM MSGSTR(21013, "Error: Memory allocation failed\n"));
5977836SJohn.Forte@Sun.COM return (-1);
5987836SJohn.Forte@Sun.COM }
5997836SJohn.Forte@Sun.COM
6007836SJohn.Forte@Sun.COM if (read(fd, sbus_info, file_size) < 0) {
6017836SJohn.Forte@Sun.COM perror(MSGSTR(21001, "read"));
6027836SJohn.Forte@Sun.COM free(sbus_info);
6037836SJohn.Forte@Sun.COM return (-1);
6047836SJohn.Forte@Sun.COM }
6057836SJohn.Forte@Sun.COM
6067836SJohn.Forte@Sun.COM /*
6077836SJohn.Forte@Sun.COM * Search for the version string in the whole file
6087836SJohn.Forte@Sun.COM */
6097836SJohn.Forte@Sun.COM if ((*sbus_offset = memstrstr((char *)sbus_info, qlgc2200Sbus,
6107836SJohn.Forte@Sun.COM file_size, strlen(qlgc2200Sbus))) != -1) {
6117836SJohn.Forte@Sun.COM free(sbus_info);
6127836SJohn.Forte@Sun.COM return (1);
6137836SJohn.Forte@Sun.COM } else {
6147836SJohn.Forte@Sun.COM free(sbus_info);
6157836SJohn.Forte@Sun.COM return (0);
6167836SJohn.Forte@Sun.COM }
6177836SJohn.Forte@Sun.COM }
6187836SJohn.Forte@Sun.COM
6197836SJohn.Forte@Sun.COM
6207836SJohn.Forte@Sun.COM /*
6217836SJohn.Forte@Sun.COM * Build a list of all the devctl entries for all the 2100/2200 based adapters
6227836SJohn.Forte@Sun.COM */
6237836SJohn.Forte@Sun.COM static int
q_getdevctlpath(char * devpath,int * devcnt)6247836SJohn.Forte@Sun.COM q_getdevctlpath(char *devpath, int *devcnt)
6257836SJohn.Forte@Sun.COM {
6267836SJohn.Forte@Sun.COM struct stat statbuf;
6277836SJohn.Forte@Sun.COM struct dirent *dirp = NULL;
6287836SJohn.Forte@Sun.COM DIR *dp = NULL;
6297836SJohn.Forte@Sun.COM char *ptr = NULL;
6308288SBing.Hu@Sun.COM int err = 0;
6317836SJohn.Forte@Sun.COM int testopen;
6327836SJohn.Forte@Sun.COM
6337836SJohn.Forte@Sun.COM if (lstat(devpath, &statbuf) < 0) {
6347836SJohn.Forte@Sun.COM (void) fprintf(stderr,
6357836SJohn.Forte@Sun.COM MSGSTR(21016, "Error: %s lstat() error\n"), devpath);
6367836SJohn.Forte@Sun.COM return (1);
6377836SJohn.Forte@Sun.COM }
6387836SJohn.Forte@Sun.COM
6397836SJohn.Forte@Sun.COM if ((strstr(devpath, fc_trans) ||
6407836SJohn.Forte@Sun.COM (strstr(devpath, fp_trans_id) && strstr(devpath, fp_trans))) &&
6417836SJohn.Forte@Sun.COM strstr(devpath, "devctl")) {
6427836SJohn.Forte@Sun.COM /* Verify the path is valid */
6437836SJohn.Forte@Sun.COM if ((testopen = open(devpath, O_RDONLY)) >= 0) {
6447836SJohn.Forte@Sun.COM (void) close(testopen);
6457836SJohn.Forte@Sun.COM (void) strcpy(pcibus_list[*devcnt], devpath);
6467836SJohn.Forte@Sun.COM *devcnt += 1;
6477836SJohn.Forte@Sun.COM return (0);
6487836SJohn.Forte@Sun.COM }
6497836SJohn.Forte@Sun.COM }
6507836SJohn.Forte@Sun.COM
6517836SJohn.Forte@Sun.COM if (S_ISDIR(statbuf.st_mode) == 0) {
6527836SJohn.Forte@Sun.COM /*
6537836SJohn.Forte@Sun.COM * not a directory so
6547836SJohn.Forte@Sun.COM * we don't care about it - return
6557836SJohn.Forte@Sun.COM */
6567836SJohn.Forte@Sun.COM return (0);
6577836SJohn.Forte@Sun.COM }
6587836SJohn.Forte@Sun.COM
6597836SJohn.Forte@Sun.COM /*
6607836SJohn.Forte@Sun.COM * It's a directory. Call ourself to
6617836SJohn.Forte@Sun.COM * traverse the path(s)
6627836SJohn.Forte@Sun.COM */
6637836SJohn.Forte@Sun.COM ptr = devpath + strlen(devpath);
6647836SJohn.Forte@Sun.COM *ptr++ = '/';
6657836SJohn.Forte@Sun.COM *ptr = 0;
6667836SJohn.Forte@Sun.COM
6677836SJohn.Forte@Sun.COM /* Forget the /devices/pseudo/ directory */
6687836SJohn.Forte@Sun.COM if (strcmp(devpath, "/devices/pseudo/") == 0) {
6697836SJohn.Forte@Sun.COM return (0);
6707836SJohn.Forte@Sun.COM }
6717836SJohn.Forte@Sun.COM
6727836SJohn.Forte@Sun.COM if ((dp = opendir(devpath)) == NULL) {
6737836SJohn.Forte@Sun.COM (void) fprintf(stderr,
6747836SJohn.Forte@Sun.COM MSGSTR(21017, "Error: %s Can't read directory\n"), devpath);
6757836SJohn.Forte@Sun.COM return (1);
6767836SJohn.Forte@Sun.COM }
6777836SJohn.Forte@Sun.COM
6787836SJohn.Forte@Sun.COM while ((dirp = readdir(dp)) != NULL) {
6797836SJohn.Forte@Sun.COM
6807836SJohn.Forte@Sun.COM if (strcmp(dirp->d_name, ".") == 0 ||
6817836SJohn.Forte@Sun.COM strcmp(dirp->d_name, "..") == 0) {
6827836SJohn.Forte@Sun.COM continue;
6837836SJohn.Forte@Sun.COM }
6847836SJohn.Forte@Sun.COM (void) strcpy(ptr, dirp->d_name); /* append name */
6857836SJohn.Forte@Sun.COM err = q_getdevctlpath(devpath, devcnt);
6867836SJohn.Forte@Sun.COM }
6877836SJohn.Forte@Sun.COM
6887836SJohn.Forte@Sun.COM if (closedir(dp) < 0) {
6897836SJohn.Forte@Sun.COM (void) fprintf(stderr,
6907836SJohn.Forte@Sun.COM MSGSTR(21018, "Error: Can't close directory %s\n"), devpath);
6917836SJohn.Forte@Sun.COM return (1);
6927836SJohn.Forte@Sun.COM }
6937836SJohn.Forte@Sun.COM return (err);
6947836SJohn.Forte@Sun.COM }
6957836SJohn.Forte@Sun.COM
6967836SJohn.Forte@Sun.COM /*
697*8538SReed.Liu@Sun.COM * Get the boot device. Cannot load FCode to current boot device.
6987836SJohn.Forte@Sun.COM * Boot devices under volume management will prompt a warning.
6997836SJohn.Forte@Sun.COM */
7007836SJohn.Forte@Sun.COM static int
q_getbootdev(uchar_t * bootpath)7017836SJohn.Forte@Sun.COM q_getbootdev(uchar_t *bootpath)
7027836SJohn.Forte@Sun.COM {
7037836SJohn.Forte@Sun.COM struct mnttab mp;
7047836SJohn.Forte@Sun.COM struct mnttab mpref;
7057836SJohn.Forte@Sun.COM FILE *fp = NULL;
7067836SJohn.Forte@Sun.COM static char buf[BUFSIZ];
7077836SJohn.Forte@Sun.COM char *p = NULL, *p1 = NULL; /* p = full device, p1 = chunk to rm */
7087836SJohn.Forte@Sun.COM char *slot = ":devctl";
7097836SJohn.Forte@Sun.COM char *root = "/";
7107836SJohn.Forte@Sun.COM
7117836SJohn.Forte@Sun.COM if ((fp = fopen(MNTTAB, "r")) == NULL) {
7127836SJohn.Forte@Sun.COM (void) fprintf(stderr,
7137836SJohn.Forte@Sun.COM MSGSTR(21000, "Error: Could not open %s\n"), MNTTAB);
7147836SJohn.Forte@Sun.COM return (1);
7157836SJohn.Forte@Sun.COM }
7167836SJohn.Forte@Sun.COM
7177836SJohn.Forte@Sun.COM mntnull(&mpref);
7187836SJohn.Forte@Sun.COM mpref.mnt_mountp = (char *)root;
7197836SJohn.Forte@Sun.COM
7207836SJohn.Forte@Sun.COM if (getmntany(fp, &mp, &mpref) != 0 ||
7217836SJohn.Forte@Sun.COM mpref.mnt_mountp == NULL) {
7227836SJohn.Forte@Sun.COM (void) fprintf(stderr, MSGSTR(21019,
7237836SJohn.Forte@Sun.COM "Error: Cannot get boot device, check %s.\n"), MNTTAB);
7247836SJohn.Forte@Sun.COM (void) fclose(fp);
7257836SJohn.Forte@Sun.COM return (1);
7267836SJohn.Forte@Sun.COM }
7277836SJohn.Forte@Sun.COM (void) fclose(fp);
7287836SJohn.Forte@Sun.COM
7297836SJohn.Forte@Sun.COM /*
7307836SJohn.Forte@Sun.COM * If we can't get a link, we may be dealing with a volume mgr
7317836SJohn.Forte@Sun.COM * so give a warning. If a colon is present, we likely have a
7327836SJohn.Forte@Sun.COM * non-local disk or cd-rom, so no warning is necessary.
7337836SJohn.Forte@Sun.COM * e.g. /devices/pci@1f,4000/scsi@3/sd@6,0:b (cdrom, no link) or
734*8538SReed.Liu@Sun.COM * storage-e4:/blah/blah remote boot server
7357836SJohn.Forte@Sun.COM */
7367836SJohn.Forte@Sun.COM if (readlink(mp.mnt_special, buf, BUFSIZ) < 0) {
7377836SJohn.Forte@Sun.COM if (strstr(mp.mnt_special, ":") == NULL) {
7387836SJohn.Forte@Sun.COM (void) fprintf(stderr, MSGSTR(21020,
7397836SJohn.Forte@Sun.COM "\nWarning: Cannot read boot device link, check %s.\n"), MNTTAB);
7407836SJohn.Forte@Sun.COM (void) fprintf(stderr, MSGSTR(21021,
7417836SJohn.Forte@Sun.COM "Do not upgrade FCode on adapters controlling the boot device.\n"));
7427836SJohn.Forte@Sun.COM }
7437836SJohn.Forte@Sun.COM return (1);
7447836SJohn.Forte@Sun.COM }
7457836SJohn.Forte@Sun.COM /*
7467836SJohn.Forte@Sun.COM * Copy boot device path to bootpath. First remove leading
7477836SJohn.Forte@Sun.COM * path junk (../../..) then if it's an ifp device, chop off
7487836SJohn.Forte@Sun.COM * the disk and add the devctl to the end of the path.
7497836SJohn.Forte@Sun.COM */
7507836SJohn.Forte@Sun.COM if (p = strstr(buf, "/devices")) {
7517836SJohn.Forte@Sun.COM if (strstr(buf, fc_trans) != NULL) {
7527836SJohn.Forte@Sun.COM p1 = strrchr(p, '/');
7537836SJohn.Forte@Sun.COM *p1 = '\0';
7547836SJohn.Forte@Sun.COM }
7557836SJohn.Forte@Sun.COM }
7567836SJohn.Forte@Sun.COM (void) strcpy((char *)bootpath, (char *)p);
7577836SJohn.Forte@Sun.COM if (p1) {
7587836SJohn.Forte@Sun.COM (void) strcat((char *)bootpath, slot);
7597836SJohn.Forte@Sun.COM }
7607836SJohn.Forte@Sun.COM return (0);
7617836SJohn.Forte@Sun.COM }
7627836SJohn.Forte@Sun.COM
7637836SJohn.Forte@Sun.COM /*
7647836SJohn.Forte@Sun.COM * Load FCode to card.
7657836SJohn.Forte@Sun.COM * uses ioctl: IFPIO_FCODE_DOWNLOAD
7667836SJohn.Forte@Sun.COM */
7677836SJohn.Forte@Sun.COM static int
q_load_file(int fcode_fd,char * device)7687836SJohn.Forte@Sun.COM q_load_file(int fcode_fd, char *device)
7697836SJohn.Forte@Sun.COM {
7707836SJohn.Forte@Sun.COM static int dev_fd, fcode_size;
7717836SJohn.Forte@Sun.COM struct stat stat;
7727836SJohn.Forte@Sun.COM ifp_download_t *download_p = NULL;
7737836SJohn.Forte@Sun.COM fcio_t fcio;
7747836SJohn.Forte@Sun.COM uint16_t file_id = 0;
7757836SJohn.Forte@Sun.COM uchar_t *bin;
7767836SJohn.Forte@Sun.COM
7777836SJohn.Forte@Sun.COM if (lseek(fcode_fd, 0, SEEK_SET) == -1) {
7787836SJohn.Forte@Sun.COM perror(MSGSTR(21022, "seek"));
7797836SJohn.Forte@Sun.COM (void) close(fcode_fd);
7807836SJohn.Forte@Sun.COM return (1);
7817836SJohn.Forte@Sun.COM }
7827836SJohn.Forte@Sun.COM if (fstat(fcode_fd, &stat) == -1) {
7837836SJohn.Forte@Sun.COM perror(MSGSTR(21023, "fstat"));
7847836SJohn.Forte@Sun.COM (void) close(fcode_fd);
7857836SJohn.Forte@Sun.COM return (1);
7867836SJohn.Forte@Sun.COM }
7877836SJohn.Forte@Sun.COM
7887836SJohn.Forte@Sun.COM fcode_size = stat.st_size;
7897836SJohn.Forte@Sun.COM
7907836SJohn.Forte@Sun.COM if (strstr(device, fc_trans)) {
7917836SJohn.Forte@Sun.COM if ((download_p = (ifp_download_t *)malloc(
7927836SJohn.Forte@Sun.COM sizeof (ifp_download_t) + fcode_size)) == NULL) {
7937836SJohn.Forte@Sun.COM (void) fprintf(stderr,
7947836SJohn.Forte@Sun.COM MSGSTR(21013, "Error: Memory allocation failed\n"));
7957836SJohn.Forte@Sun.COM (void) close(fcode_fd);
7967836SJohn.Forte@Sun.COM return (1);
7977836SJohn.Forte@Sun.COM }
7987836SJohn.Forte@Sun.COM } else {
7997836SJohn.Forte@Sun.COM if ((bin = (uchar_t *)malloc(fcode_size)) == NULL) {
8007836SJohn.Forte@Sun.COM (void) fprintf(stderr,
8017836SJohn.Forte@Sun.COM MSGSTR(21013, "Error: Memory allocation failed\n"));
8027836SJohn.Forte@Sun.COM (void) close(fcode_fd);
8037836SJohn.Forte@Sun.COM return (1);
8047836SJohn.Forte@Sun.COM }
8057836SJohn.Forte@Sun.COM }
8067836SJohn.Forte@Sun.COM
8077836SJohn.Forte@Sun.COM if (strstr(device, fc_trans)) {
8087836SJohn.Forte@Sun.COM if (read(fcode_fd, download_p->dl_fcode, fcode_size)
8097836SJohn.Forte@Sun.COM != fcode_size) {
8107836SJohn.Forte@Sun.COM perror(MSGSTR(21001, "read"));
8117836SJohn.Forte@Sun.COM free(download_p);
8127836SJohn.Forte@Sun.COM (void) close(fcode_fd);
8137836SJohn.Forte@Sun.COM return (1);
8147836SJohn.Forte@Sun.COM }
8157836SJohn.Forte@Sun.COM } else {
8167836SJohn.Forte@Sun.COM if (read(fcode_fd, bin, fcode_size)
8177836SJohn.Forte@Sun.COM != fcode_size) {
8187836SJohn.Forte@Sun.COM perror(MSGSTR(21001, "read"));
8197836SJohn.Forte@Sun.COM free(bin);
8207836SJohn.Forte@Sun.COM (void) close(fcode_fd);
8217836SJohn.Forte@Sun.COM return (1);
8227836SJohn.Forte@Sun.COM }
8237836SJohn.Forte@Sun.COM }
8247836SJohn.Forte@Sun.COM
8257836SJohn.Forte@Sun.COM
8267836SJohn.Forte@Sun.COM if ((dev_fd = open(device, O_RDWR|O_EXCL)) < 0) {
8277836SJohn.Forte@Sun.COM (void) fprintf(stderr,
8287836SJohn.Forte@Sun.COM MSGSTR(21000, "Error: Could not open %s\n"), device);
8297836SJohn.Forte@Sun.COM free(download_p);
8307836SJohn.Forte@Sun.COM return (1);
8317836SJohn.Forte@Sun.COM }
8327836SJohn.Forte@Sun.COM if (strstr(device, fc_trans)) {
8337836SJohn.Forte@Sun.COM download_p->dl_fcode_len = fcode_size;
8347836SJohn.Forte@Sun.COM file_id = download_p->dl_fcode[0x42] & 0xff;
8357836SJohn.Forte@Sun.COM file_id |= (download_p->dl_fcode[0x43] << 8) & 0xff00;
8367836SJohn.Forte@Sun.COM download_p->dl_chip_id = file_id;
8377836SJohn.Forte@Sun.COM if (ioctl(dev_fd, IFPIO_FCODE_DOWNLOAD, download_p) < 0) {
8387836SJohn.Forte@Sun.COM (void) fprintf(stderr, MSGSTR(21024,
8397836SJohn.Forte@Sun.COM "Error: Driver interface IFPIO_FCODE_DOWNLOAD failed\n"));
8407836SJohn.Forte@Sun.COM free(download_p);
8417836SJohn.Forte@Sun.COM (void) close(dev_fd);
8427836SJohn.Forte@Sun.COM return (1);
8437836SJohn.Forte@Sun.COM }
8447836SJohn.Forte@Sun.COM free(download_p);
8457836SJohn.Forte@Sun.COM } else if (strstr(device, fp_trans)) {
8467836SJohn.Forte@Sun.COM fcio.fcio_cmd = FCIO_DOWNLOAD_FCODE;
8477836SJohn.Forte@Sun.COM /* Information read operation */
8487836SJohn.Forte@Sun.COM fcio.fcio_xfer = FCIO_XFER_WRITE;
8497836SJohn.Forte@Sun.COM fcio.fcio_ibuf = (caddr_t)bin;
8507836SJohn.Forte@Sun.COM fcio.fcio_ilen = fcode_size;
8517836SJohn.Forte@Sun.COM
8527836SJohn.Forte@Sun.COM if (ioctl(dev_fd, FCIO_CMD, &fcio) != 0) {
8537836SJohn.Forte@Sun.COM (void) fprintf(stderr, MSGSTR(21036,
8547836SJohn.Forte@Sun.COM "Error: Driver interface FCIO_DOWNLOAD_FCODE failed\n"));
8557836SJohn.Forte@Sun.COM free(download_p);
8567836SJohn.Forte@Sun.COM (void) close(dev_fd);
8577836SJohn.Forte@Sun.COM return (1);
8587836SJohn.Forte@Sun.COM }
8597836SJohn.Forte@Sun.COM free(bin);
8607836SJohn.Forte@Sun.COM }
8617836SJohn.Forte@Sun.COM (void) close(dev_fd);
8627836SJohn.Forte@Sun.COM return (0);
8637836SJohn.Forte@Sun.COM }
8647836SJohn.Forte@Sun.COM
8657836SJohn.Forte@Sun.COM /*
8667836SJohn.Forte@Sun.COM * Issue warning strings and loop for Yes/No user interaction
8677836SJohn.Forte@Sun.COM * err# 0 -- we're ok, warn for pending FCode load
868*8538SReed.Liu@Sun.COM * 1 -- not in single user mode
869*8538SReed.Liu@Sun.COM * 2 -- can't get chip_id
870*8538SReed.Liu@Sun.COM * 3 -- card and file do not have same type (2100/2200)
8717836SJohn.Forte@Sun.COM */
8727836SJohn.Forte@Sun.COM static int
q_warn(int errnum)8737836SJohn.Forte@Sun.COM q_warn(int errnum)
8747836SJohn.Forte@Sun.COM {
8757836SJohn.Forte@Sun.COM char input[1024];
8767836SJohn.Forte@Sun.COM input[0] = '\0';
8777836SJohn.Forte@Sun.COM
8787836SJohn.Forte@Sun.COM if (errnum == 1) {
8797836SJohn.Forte@Sun.COM (void) fprintf(stderr, MSGSTR(21025,
8807836SJohn.Forte@Sun.COM "\nWarning: System is not in single-user mode.\n"));
8817836SJohn.Forte@Sun.COM (void) fprintf(stderr, MSGSTR(21026,
8827836SJohn.Forte@Sun.COM "Loading FCode will reset the adapter and terminate I/O activity\n"));
8837836SJohn.Forte@Sun.COM } else {
8847836SJohn.Forte@Sun.COM if (errnum == 2) {
8857836SJohn.Forte@Sun.COM (void) fprintf(stderr, MSGSTR(21027,
8867836SJohn.Forte@Sun.COM " Warning: FCode is missing or existing FCode has"
8877836SJohn.Forte@Sun.COM " unrecognized version.\n"));
8887836SJohn.Forte@Sun.COM return (1);
8897836SJohn.Forte@Sun.COM } else if (errnum == 3) {
8907836SJohn.Forte@Sun.COM (void) fprintf(stderr, MSGSTR(21028,
8917836SJohn.Forte@Sun.COM " Warning: New FCode file version does not match this"
8927836SJohn.Forte@Sun.COM " board type. Skipping...\n"));
8937836SJohn.Forte@Sun.COM return (1);
8947836SJohn.Forte@Sun.COM }
8957836SJohn.Forte@Sun.COM (void) fprintf(stderr, MSGSTR(21029,
8967836SJohn.Forte@Sun.COM "\nWARNING!! This program will update the FCode in this"
8977836SJohn.Forte@Sun.COM " FC100/PCI, ISP2200/PCI, ISP23xx/PCI "
8987836SJohn.Forte@Sun.COM " and Emulex devices.\n"));
8997836SJohn.Forte@Sun.COM (void) fprintf(stderr, MSGSTR(21030,
9007836SJohn.Forte@Sun.COM "This may take a few (5) minutes. Please be patient.\n"));
9017836SJohn.Forte@Sun.COM }
9027836SJohn.Forte@Sun.COM
9037836SJohn.Forte@Sun.COM loop1:
9047836SJohn.Forte@Sun.COM (void) fprintf(stderr, MSGSTR(21031,
9057836SJohn.Forte@Sun.COM "Do you wish to continue ? (y/n) "));
9067836SJohn.Forte@Sun.COM
9077836SJohn.Forte@Sun.COM (void) gets(input);
9087836SJohn.Forte@Sun.COM
9097836SJohn.Forte@Sun.COM if ((strcmp(input, MSGSTR(21032, "y")) == 0) ||
9107836SJohn.Forte@Sun.COM (strcmp(input, MSGSTR(40, "yes")) == 0)) {
9117836SJohn.Forte@Sun.COM return (0);
9127836SJohn.Forte@Sun.COM } else if ((strcmp(input, MSGSTR(21033, "n")) == 0) ||
9137836SJohn.Forte@Sun.COM (strcmp(input, MSGSTR(45, "no")) == 0)) {
9147836SJohn.Forte@Sun.COM (void) fprintf(stderr,
9157836SJohn.Forte@Sun.COM MSGSTR(21034, "Not Downloading FCode\n"));
9167836SJohn.Forte@Sun.COM return (1);
9177836SJohn.Forte@Sun.COM } else {
9187836SJohn.Forte@Sun.COM (void) fprintf(stderr, MSGSTR(21035, "Invalid input\n"));
9197836SJohn.Forte@Sun.COM goto loop1;
9207836SJohn.Forte@Sun.COM }
9217836SJohn.Forte@Sun.COM }
9227836SJohn.Forte@Sun.COM
9237836SJohn.Forte@Sun.COM /*
924*8538SReed.Liu@Sun.COM * Name : memstrstr
9257836SJohn.Forte@Sun.COM * Input : pointer to buf1, pointer to buf2, size of buf1, size of buf2
9267836SJohn.Forte@Sun.COM * Returns :
927*8538SReed.Liu@Sun.COM * Offset of the start of contents-of-buf2 in buf1 if it is found
928*8538SReed.Liu@Sun.COM * -1 if buf1 does not contain contents of buf2
9297836SJohn.Forte@Sun.COM * Synopsis:
9307836SJohn.Forte@Sun.COM * This function works similar to strstr(). The difference is that null
9317836SJohn.Forte@Sun.COM * characters in the buffer are treated like any other character. So, buf1
9327836SJohn.Forte@Sun.COM * and buf2 can have embedded null characters in them.
9337836SJohn.Forte@Sun.COM */
9347836SJohn.Forte@Sun.COM static int
memstrstr(char * s1,char * s2,int size1,int size2)9357836SJohn.Forte@Sun.COM memstrstr(char *s1, char *s2, int size1, int size2)
9367836SJohn.Forte@Sun.COM {
9377836SJohn.Forte@Sun.COM int count1, count2;
9387836SJohn.Forte@Sun.COM char *s1_ptr, *s2_ptr;
9397836SJohn.Forte@Sun.COM
9407836SJohn.Forte@Sun.COM count1 = size1; count2 = size2;
9417836SJohn.Forte@Sun.COM s1_ptr = s1; s2_ptr = s2;
9427836SJohn.Forte@Sun.COM
9437836SJohn.Forte@Sun.COM if ((size2 == 0)||(size1 == 0))
9447836SJohn.Forte@Sun.COM return (-1);
9457836SJohn.Forte@Sun.COM
9467836SJohn.Forte@Sun.COM for (count1 = 0; count1 < (size1 - size2 + 1); count1++) {
9477836SJohn.Forte@Sun.COM if (*s1_ptr++ == *s2_ptr++) {
9487836SJohn.Forte@Sun.COM if (--count2 == 0) {
9497836SJohn.Forte@Sun.COM return (count1 - size2 + 1);
9507836SJohn.Forte@Sun.COM }
9517836SJohn.Forte@Sun.COM continue;
9527836SJohn.Forte@Sun.COM }
9537836SJohn.Forte@Sun.COM count2 = size2;
9547836SJohn.Forte@Sun.COM s2_ptr = s2;
9557836SJohn.Forte@Sun.COM }
9567836SJohn.Forte@Sun.COM
9577836SJohn.Forte@Sun.COM return (-1);
9587836SJohn.Forte@Sun.COM }
9597836SJohn.Forte@Sun.COM
9607836SJohn.Forte@Sun.COM /*
9617836SJohn.Forte@Sun.COM * generic fcode load file routine. given a file descriptor to a fcode file
9627836SJohn.Forte@Sun.COM * this routine will issue the FCIO_DOWNLOAD_FCODE ioctl to the given
9637836SJohn.Forte@Sun.COM * device. Any ioctl errors will be returned in fcio_errno
9647836SJohn.Forte@Sun.COM *
9657836SJohn.Forte@Sun.COM * Arguments:
9667836SJohn.Forte@Sun.COM * fcode_fd file descriptor to a fcode file
9677836SJohn.Forte@Sun.COM * device path to the device we will be downloading the fcode onto
9687836SJohn.Forte@Sun.COM * fcio_errno pointer to an int that will be used to return any errors
9697836SJohn.Forte@Sun.COM * back to the caller
9707836SJohn.Forte@Sun.COM * Retrurn Values:
9717836SJohn.Forte@Sun.COM * 0 successful download
9727836SJohn.Forte@Sun.COM * >0 otherwise
9737836SJohn.Forte@Sun.COM */
9747836SJohn.Forte@Sun.COM static int
fcode_load_file(int fcode_fd,char * device,int * fcio_errno)9757836SJohn.Forte@Sun.COM fcode_load_file(int fcode_fd, char *device, int *fcio_errno)
9767836SJohn.Forte@Sun.COM {
9777836SJohn.Forte@Sun.COM
9787836SJohn.Forte@Sun.COM fcio_t fcio;
9797836SJohn.Forte@Sun.COM static int dev_fd, fcode_size;
9807836SJohn.Forte@Sun.COM uchar_t *bin;
9817836SJohn.Forte@Sun.COM struct stat stat;
9827836SJohn.Forte@Sun.COM
9837836SJohn.Forte@Sun.COM if (device == NULL || fcio_errno == NULL) {
9847836SJohn.Forte@Sun.COM return (FCODE_LOAD_FAILURE);
9857836SJohn.Forte@Sun.COM }
9867836SJohn.Forte@Sun.COM
9877836SJohn.Forte@Sun.COM *fcio_errno = 0;
9887836SJohn.Forte@Sun.COM if (lseek(fcode_fd, 0, SEEK_SET) == -1) {
9897836SJohn.Forte@Sun.COM perror(MSGSTR(21022, "seek"));
9907836SJohn.Forte@Sun.COM return (FCODE_LOAD_FAILURE);
9917836SJohn.Forte@Sun.COM }
9927836SJohn.Forte@Sun.COM
9937836SJohn.Forte@Sun.COM if (fstat(fcode_fd, &stat) == -1) {
9947836SJohn.Forte@Sun.COM perror(MSGSTR(21023, "fstat"));
9957836SJohn.Forte@Sun.COM return (FCODE_LOAD_FAILURE);
9967836SJohn.Forte@Sun.COM }
9977836SJohn.Forte@Sun.COM
9987836SJohn.Forte@Sun.COM fcode_size = stat.st_size;
9997836SJohn.Forte@Sun.COM
10007836SJohn.Forte@Sun.COM if ((bin = (uchar_t *)malloc(fcode_size)) == NULL) {
10017836SJohn.Forte@Sun.COM (void) fprintf(stderr,
10027836SJohn.Forte@Sun.COM MSGSTR(21013, "Error: Memory allocation failed\n"));
10037836SJohn.Forte@Sun.COM return (FCODE_LOAD_FAILURE);
10047836SJohn.Forte@Sun.COM }
10057836SJohn.Forte@Sun.COM
10067836SJohn.Forte@Sun.COM if (read(fcode_fd, bin, fcode_size)
10077836SJohn.Forte@Sun.COM != fcode_size) {
10087836SJohn.Forte@Sun.COM perror(MSGSTR(21001, "read"));
10097836SJohn.Forte@Sun.COM free(bin);
10107836SJohn.Forte@Sun.COM return (FCODE_LOAD_FAILURE);
10117836SJohn.Forte@Sun.COM }
10127836SJohn.Forte@Sun.COM
10137836SJohn.Forte@Sun.COM if ((dev_fd = open(device, O_RDWR|O_EXCL)) < 0) {
10147836SJohn.Forte@Sun.COM (void) fprintf(stderr,
10157836SJohn.Forte@Sun.COM MSGSTR(21122, "Error: Could not open %s, failed "
10167836SJohn.Forte@Sun.COM "with errno %d\n"), device, errno);
10177836SJohn.Forte@Sun.COM free(bin);
10187836SJohn.Forte@Sun.COM return (FCODE_LOAD_FAILURE);
10197836SJohn.Forte@Sun.COM }
10207836SJohn.Forte@Sun.COM
10217836SJohn.Forte@Sun.COM fcio.fcio_cmd = FCIO_DOWNLOAD_FCODE;
10227836SJohn.Forte@Sun.COM fcio.fcio_xfer = FCIO_XFER_WRITE;
10237836SJohn.Forte@Sun.COM fcio.fcio_ibuf = (caddr_t)bin;
10247836SJohn.Forte@Sun.COM fcio.fcio_ilen = fcode_size;
10257836SJohn.Forte@Sun.COM
10267836SJohn.Forte@Sun.COM if (ioctl(dev_fd, FCIO_CMD, &fcio) != 0) {
10277836SJohn.Forte@Sun.COM (void) close(dev_fd);
10287836SJohn.Forte@Sun.COM *fcio_errno = fcio.fcio_errno;
10297836SJohn.Forte@Sun.COM free(bin);
10307836SJohn.Forte@Sun.COM return (FCODE_IOCTL_FAILURE);
10317836SJohn.Forte@Sun.COM }
10327836SJohn.Forte@Sun.COM
10337836SJohn.Forte@Sun.COM free(bin);
10347836SJohn.Forte@Sun.COM (void) close(dev_fd);
10357836SJohn.Forte@Sun.COM return (FCODE_SUCCESS);
10367836SJohn.Forte@Sun.COM }
10377836SJohn.Forte@Sun.COM
10387836SJohn.Forte@Sun.COM /*
10397836SJohn.Forte@Sun.COM * Searches for and updates the fcode for Emulex HBA cards
10407836SJohn.Forte@Sun.COM * args: FCode file; if NULL only the current FCode
10417836SJohn.Forte@Sun.COM * version is printed
10427836SJohn.Forte@Sun.COM */
10437836SJohn.Forte@Sun.COM
10447836SJohn.Forte@Sun.COM int
emulex_update(char * file)10457836SJohn.Forte@Sun.COM emulex_update(char *file)
10467836SJohn.Forte@Sun.COM {
10477836SJohn.Forte@Sun.COM
1048*8538SReed.Liu@Sun.COM int fd, retval = 0;
1049*8538SReed.Liu@Sun.COM int devcnt = 0;
1050*8538SReed.Liu@Sun.COM uint_t state = 0, fflag = 0;
1051*8538SReed.Liu@Sun.COM static uchar_t bootpath[PATH_MAX];
1052*8538SReed.Liu@Sun.COM int fcode_fd = -1;
10537836SJohn.Forte@Sun.COM static struct utmpx *utmpp = NULL;
1054*8538SReed.Liu@Sun.COM di_node_t root;
1055*8538SReed.Liu@Sun.COM di_node_t node, sib_node, count_node;
1056*8538SReed.Liu@Sun.COM di_minor_t minor_node;
1057*8538SReed.Liu@Sun.COM char phys_path[PATH_MAX], *path;
1058*8538SReed.Liu@Sun.COM int errnum = 0, fcio_errno = 0;
10597836SJohn.Forte@Sun.COM static uchar_t prom_ver_data[MAXNAMELEN];
10607836SJohn.Forte@Sun.COM static char ver_file[EMULEX_FCODE_VERSION_LENGTH];
10617836SJohn.Forte@Sun.COM void (*sigint)();
10627836SJohn.Forte@Sun.COM int prop_entries = -1;
1063*8538SReed.Liu@Sun.COM int *port_data = NULL;
10647836SJohn.Forte@Sun.COM
10657836SJohn.Forte@Sun.COM if (file) {
10667836SJohn.Forte@Sun.COM /* set the fcode download flag */
10677836SJohn.Forte@Sun.COM fflag++;
10687836SJohn.Forte@Sun.COM
10697836SJohn.Forte@Sun.COM /* check for a valid file */
10707836SJohn.Forte@Sun.COM if ((fcode_fd = open(file, O_RDONLY)) < 0) {
10717836SJohn.Forte@Sun.COM (void) fprintf(stderr,
10727836SJohn.Forte@Sun.COM MSGSTR(21118, "Error: Could not open %s, failed "
10737836SJohn.Forte@Sun.COM "with errno %d\n"), file, errno);
10747836SJohn.Forte@Sun.COM return (1);
10757836SJohn.Forte@Sun.COM }
10767836SJohn.Forte@Sun.COM
10777836SJohn.Forte@Sun.COM /* check for single user mode */
10787836SJohn.Forte@Sun.COM while ((utmpp = getutxent()) != NULL) {
10797836SJohn.Forte@Sun.COM if (strstr(utmpp->ut_line, "run-level") &&
10807836SJohn.Forte@Sun.COM (strcmp(utmpp->ut_line, "run-level S") &&
10817836SJohn.Forte@Sun.COM strcmp(utmpp->ut_line, "run-level 1"))) {
10827836SJohn.Forte@Sun.COM if (q_warn(1)) {
10837836SJohn.Forte@Sun.COM (void) endutxent();
10847836SJohn.Forte@Sun.COM (void) close(fcode_fd);
10857836SJohn.Forte@Sun.COM return (1);
10867836SJohn.Forte@Sun.COM }
10877836SJohn.Forte@Sun.COM break;
10887836SJohn.Forte@Sun.COM }
10897836SJohn.Forte@Sun.COM }
10907836SJohn.Forte@Sun.COM (void) endutxent();
10917836SJohn.Forte@Sun.COM
10927836SJohn.Forte@Sun.COM /* get bootpath */
10937836SJohn.Forte@Sun.COM if (!q_getbootdev((uchar_t *)&bootpath[0]) &&
10947836SJohn.Forte@Sun.COM getenv("_LUX_D_DEBUG") != NULL) {
10957836SJohn.Forte@Sun.COM (void) fprintf(stdout, " Bootpath: %s\n", bootpath);
10967836SJohn.Forte@Sun.COM }
10977836SJohn.Forte@Sun.COM }
10987836SJohn.Forte@Sun.COM
10997836SJohn.Forte@Sun.COM /*
11007836SJohn.Forte@Sun.COM * Download the Fcode to all the emulex cards found
11017836SJohn.Forte@Sun.COM */
11027836SJohn.Forte@Sun.COM
11037836SJohn.Forte@Sun.COM /* Create a snapshot of the kernel device tree */
11047836SJohn.Forte@Sun.COM if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) {
11057836SJohn.Forte@Sun.COM (void) fprintf(stderr, MSGSTR(21114,
11067836SJohn.Forte@Sun.COM "Error: Could not get /devices path to "
11077836SJohn.Forte@Sun.COM "Emulex Devices.\n"));
11087836SJohn.Forte@Sun.COM retval++;
11097836SJohn.Forte@Sun.COM }
11107836SJohn.Forte@Sun.COM
11117836SJohn.Forte@Sun.COM /* point to first node which matches emulex driver */
11127836SJohn.Forte@Sun.COM node = di_drv_first_node("emlxs", root);
11137836SJohn.Forte@Sun.COM
11147836SJohn.Forte@Sun.COM if (node == DI_NODE_NIL) {
11157836SJohn.Forte@Sun.COM /*
11167836SJohn.Forte@Sun.COM * Could not find any emulex cards
11177836SJohn.Forte@Sun.COM */
11187836SJohn.Forte@Sun.COM (void) di_fini(root);
11197836SJohn.Forte@Sun.COM (void) fprintf(stderr, MSGSTR(21115,
11207836SJohn.Forte@Sun.COM "\n Found Path to %d Emulex Devices.\n"), devcnt);
11217836SJohn.Forte@Sun.COM retval++;
11227836SJohn.Forte@Sun.COM } else {
11237836SJohn.Forte@Sun.COM count_node = node;
11247836SJohn.Forte@Sun.COM while (count_node != DI_NODE_NIL) {
11257836SJohn.Forte@Sun.COM state = di_state(count_node);
11267836SJohn.Forte@Sun.COM if ((state & DI_DRIVER_DETACHED)
11277836SJohn.Forte@Sun.COM != DI_DRIVER_DETACHED) {
1128*8538SReed.Liu@Sun.COM sib_node = di_child_node(count_node);
1129*8538SReed.Liu@Sun.COM while (sib_node != DI_NODE_NIL) {
1130*8538SReed.Liu@Sun.COM state = di_state(sib_node);
1131*8538SReed.Liu@Sun.COM if ((state & DI_DRIVER_DETACHED) !=
1132*8538SReed.Liu@Sun.COM DI_DRIVER_DETACHED) {
1133*8538SReed.Liu@Sun.COM /* Found an attached node */
1134*8538SReed.Liu@Sun.COM prop_entries =
1135*8538SReed.Liu@Sun.COM di_prop_lookup_ints(
1136*8538SReed.Liu@Sun.COM DDI_DEV_T_ANY, sib_node,
1137*8538SReed.Liu@Sun.COM "port", &port_data);
1138*8538SReed.Liu@Sun.COM if (prop_entries != -1) {
1139*8538SReed.Liu@Sun.COM devcnt++;
1140*8538SReed.Liu@Sun.COM break;
1141*8538SReed.Liu@Sun.COM }
1142*8538SReed.Liu@Sun.COM }
1143*8538SReed.Liu@Sun.COM
1144*8538SReed.Liu@Sun.COM sib_node = di_sibling_node(sib_node);
1145*8538SReed.Liu@Sun.COM }
11467836SJohn.Forte@Sun.COM }
11477836SJohn.Forte@Sun.COM count_node = di_drv_next_node(count_node);
11487836SJohn.Forte@Sun.COM }
11497836SJohn.Forte@Sun.COM (void) fprintf(stdout, MSGSTR(21116,
11507836SJohn.Forte@Sun.COM "\n Found Path to %d Emulex Devices.\n"), devcnt);
11517836SJohn.Forte@Sun.COM }
11527836SJohn.Forte@Sun.COM
11537836SJohn.Forte@Sun.COM
11547836SJohn.Forte@Sun.COM /*
11557836SJohn.Forte@Sun.COM * Traverse device tree to find all emulex cards
11567836SJohn.Forte@Sun.COM */
11577836SJohn.Forte@Sun.COM while (node != DI_NODE_NIL) {
11587836SJohn.Forte@Sun.COM
11597836SJohn.Forte@Sun.COM state = di_state(node);
11607836SJohn.Forte@Sun.COM if ((state & DI_DRIVER_DETACHED) == DI_DRIVER_DETACHED) {
11617836SJohn.Forte@Sun.COM node = di_drv_next_node(node);
11627836SJohn.Forte@Sun.COM continue;
11637836SJohn.Forte@Sun.COM }
11647836SJohn.Forte@Sun.COM
11657836SJohn.Forte@Sun.COM sib_node = di_child_node(node);
11667836SJohn.Forte@Sun.COM while (sib_node != DI_NODE_NIL) {
11677836SJohn.Forte@Sun.COM state = di_state(sib_node);
11687836SJohn.Forte@Sun.COM if ((state & DI_DRIVER_DETACHED) !=
11697836SJohn.Forte@Sun.COM DI_DRIVER_DETACHED) {
11707836SJohn.Forte@Sun.COM
11717836SJohn.Forte@Sun.COM /* Found an attached node */
11727836SJohn.Forte@Sun.COM prop_entries = di_prop_lookup_ints(
11737836SJohn.Forte@Sun.COM DDI_DEV_T_ANY, sib_node,
11747836SJohn.Forte@Sun.COM "port", &port_data);
11757836SJohn.Forte@Sun.COM if (prop_entries != -1) {
11767836SJohn.Forte@Sun.COM
11777836SJohn.Forte@Sun.COM /* Found a node with "port" property */
11787836SJohn.Forte@Sun.COM minor_node = di_minor_next(sib_node,
11797836SJohn.Forte@Sun.COM DI_MINOR_NIL);
11807836SJohn.Forte@Sun.COM break;
11817836SJohn.Forte@Sun.COM }
11827836SJohn.Forte@Sun.COM }
11837836SJohn.Forte@Sun.COM sib_node = di_sibling_node(sib_node);
11847836SJohn.Forte@Sun.COM }
11857836SJohn.Forte@Sun.COM
11867836SJohn.Forte@Sun.COM if (sib_node == DI_NODE_NIL) {
1187*8538SReed.Liu@Sun.COM goto try_next;
11887836SJohn.Forte@Sun.COM }
1189*8538SReed.Liu@Sun.COM
11907836SJohn.Forte@Sun.COM path = di_devfs_path(sib_node);
11917836SJohn.Forte@Sun.COM (void) strcpy(phys_path, "/devices");
11927836SJohn.Forte@Sun.COM (void) strncat(phys_path, path, strlen(path));
11937836SJohn.Forte@Sun.COM di_devfs_path_free(path);
11947836SJohn.Forte@Sun.COM
11957836SJohn.Forte@Sun.COM if (fflag && (strstr((char *)bootpath,
11967836SJohn.Forte@Sun.COM (char *)phys_path) != NULL)) {
11977836SJohn.Forte@Sun.COM (void) fprintf(stderr,
11987836SJohn.Forte@Sun.COM MSGSTR(21117, "Ignoring %s (bootpath)\n"),
11997836SJohn.Forte@Sun.COM phys_path);
12007836SJohn.Forte@Sun.COM node = di_drv_next_node(node);
12017836SJohn.Forte@Sun.COM continue;
12027836SJohn.Forte@Sun.COM }
12037836SJohn.Forte@Sun.COM
12047836SJohn.Forte@Sun.COM if (minor_node) {
12057836SJohn.Forte@Sun.COM (void) strncat(phys_path, ":", 1);
12067836SJohn.Forte@Sun.COM (void) strncat(phys_path,
12077836SJohn.Forte@Sun.COM di_minor_name(minor_node),
12087836SJohn.Forte@Sun.COM strlen(di_minor_name(minor_node)));
12097836SJohn.Forte@Sun.COM }
12107836SJohn.Forte@Sun.COM
12117836SJohn.Forte@Sun.COM (void) fprintf(stdout,
12127836SJohn.Forte@Sun.COM MSGSTR(21107, "\n Opening Device: %s\n"),
12137836SJohn.Forte@Sun.COM phys_path);
12147836SJohn.Forte@Sun.COM
12157836SJohn.Forte@Sun.COM /* Check if the device is valid */
12167836SJohn.Forte@Sun.COM if ((fd = open(phys_path, O_RDWR)) < 0) {
12177836SJohn.Forte@Sun.COM (void) fprintf(stderr,
12187836SJohn.Forte@Sun.COM MSGSTR(21121, "Error: Could not open %s, failed "
12197836SJohn.Forte@Sun.COM "with errno %d\n"), phys_path, errno);
12207836SJohn.Forte@Sun.COM retval++;
12217836SJohn.Forte@Sun.COM node = di_drv_next_node(node);
12227836SJohn.Forte@Sun.COM continue;
12237836SJohn.Forte@Sun.COM }
12247836SJohn.Forte@Sun.COM
12257836SJohn.Forte@Sun.COM (void) close(fd);
12267836SJohn.Forte@Sun.COM
12277836SJohn.Forte@Sun.COM /*
12287836SJohn.Forte@Sun.COM * Check FCode version present on the adapter
12297836SJohn.Forte@Sun.COM * (at last boot)
12307836SJohn.Forte@Sun.COM */
12317836SJohn.Forte@Sun.COM memset(prom_ver_data, 0, sizeof (prom_ver_data));
12327836SJohn.Forte@Sun.COM if (emulex_fcodeversion(node, (uchar_t *)&prom_ver_data[0])
12337836SJohn.Forte@Sun.COM == 0) {
12347836SJohn.Forte@Sun.COM errnum = 0;
12357836SJohn.Forte@Sun.COM if (strlen((char *)prom_ver_data) == 0) {
12367836SJohn.Forte@Sun.COM (void) fprintf(stdout, MSGSTR(21108,
12377836SJohn.Forte@Sun.COM " Detected FCode Version:\tNo version available for this FCode\n"));
12387836SJohn.Forte@Sun.COM } else {
12397836SJohn.Forte@Sun.COM (void) fprintf(stdout, MSGSTR(21109,
12407836SJohn.Forte@Sun.COM " Detected FCode Version:\t%s\n"),
12417836SJohn.Forte@Sun.COM prom_ver_data);
12427836SJohn.Forte@Sun.COM }
12437836SJohn.Forte@Sun.COM } else {
12447836SJohn.Forte@Sun.COM errnum = 2; /* can't get prom properties */
12457836SJohn.Forte@Sun.COM retval++;
12467836SJohn.Forte@Sun.COM }
12477836SJohn.Forte@Sun.COM
12487836SJohn.Forte@Sun.COM if (fflag) {
12497836SJohn.Forte@Sun.COM
12507836SJohn.Forte@Sun.COM memset(ver_file, 0, sizeof (ver_file));
12517836SJohn.Forte@Sun.COM if (emulex_fcode_reader(fcode_fd, "fcode-version",
12527836SJohn.Forte@Sun.COM ver_file, sizeof (ver_file)) == 0) {
12537836SJohn.Forte@Sun.COM (void) fprintf(stdout, MSGSTR(21110,
12547836SJohn.Forte@Sun.COM " New FCode Version:\t\t%s\n"),
12557836SJohn.Forte@Sun.COM ver_file);
12567836SJohn.Forte@Sun.COM } else {
12577836SJohn.Forte@Sun.COM di_fini(root);
12587836SJohn.Forte@Sun.COM (void) close(fcode_fd);
12597836SJohn.Forte@Sun.COM return (1);
12607836SJohn.Forte@Sun.COM }
12617836SJohn.Forte@Sun.COM
12627836SJohn.Forte@Sun.COM /*
12637836SJohn.Forte@Sun.COM * Load the New FCode
12647836SJohn.Forte@Sun.COM * Give warning if file doesn't appear to be correct
12657836SJohn.Forte@Sun.COM */
12667836SJohn.Forte@Sun.COM if (!q_warn(errnum)) {
12677836SJohn.Forte@Sun.COM /* Disable user-interrupt Control-C */
12687836SJohn.Forte@Sun.COM sigint =
12697836SJohn.Forte@Sun.COM (void (*)(int)) signal(SIGINT, SIG_IGN);
12707836SJohn.Forte@Sun.COM /* Load FCode */
12717836SJohn.Forte@Sun.COM (void) fprintf(stdout, MSGSTR(21111,
12727836SJohn.Forte@Sun.COM " Loading FCode: %s\n"), file);
12737836SJohn.Forte@Sun.COM if (fcode_load_file(fcode_fd, phys_path,
12747836SJohn.Forte@Sun.COM &fcio_errno) == FCODE_SUCCESS) {
12757836SJohn.Forte@Sun.COM (void) fprintf(stdout, MSGSTR(21112,
12767836SJohn.Forte@Sun.COM " Successful FCode download: %s\n"),
12777836SJohn.Forte@Sun.COM phys_path);
12787836SJohn.Forte@Sun.COM } else {
12797836SJohn.Forte@Sun.COM handle_emulex_error(fcio_errno,
12807836SJohn.Forte@Sun.COM phys_path);
12817836SJohn.Forte@Sun.COM retval++;
12827836SJohn.Forte@Sun.COM }
12837836SJohn.Forte@Sun.COM
12847836SJohn.Forte@Sun.COM /* Restore SIGINT (user interrupt) setting */
12857836SJohn.Forte@Sun.COM (void) signal(SIGINT, sigint);
12867836SJohn.Forte@Sun.COM }
12877836SJohn.Forte@Sun.COM }
12887836SJohn.Forte@Sun.COM
1289*8538SReed.Liu@Sun.COM try_next:
12907836SJohn.Forte@Sun.COM node = di_drv_next_node(node);
12917836SJohn.Forte@Sun.COM }
12927836SJohn.Forte@Sun.COM
12937836SJohn.Forte@Sun.COM di_fini(root);
12947836SJohn.Forte@Sun.COM (void) fprintf(stdout, " ");
12957836SJohn.Forte@Sun.COM (void) fprintf(stdout, MSGSTR(125, "Complete\n"));
12967836SJohn.Forte@Sun.COM if (fcode_fd != -1)
12977836SJohn.Forte@Sun.COM (void) close(fcode_fd);
12987836SJohn.Forte@Sun.COM return (retval);
12997836SJohn.Forte@Sun.COM
13007836SJohn.Forte@Sun.COM }
13017836SJohn.Forte@Sun.COM
13027836SJohn.Forte@Sun.COM /*
13037836SJohn.Forte@Sun.COM * Retrieve the version from the card.
13047836SJohn.Forte@Sun.COM * uses PROM properties
13057836SJohn.Forte@Sun.COM */
13067836SJohn.Forte@Sun.COM static int
emulex_fcodeversion(di_node_t node,uchar_t * ver)13077836SJohn.Forte@Sun.COM emulex_fcodeversion(di_node_t node, uchar_t *ver) {
13087836SJohn.Forte@Sun.COM di_prom_prop_t promprop;
13097836SJohn.Forte@Sun.COM di_prom_handle_t ph;
13107836SJohn.Forte@Sun.COM char *promname;
13117836SJohn.Forte@Sun.COM uchar_t *ver_data = NULL;
13127836SJohn.Forte@Sun.COM int size, found = 0;
13137836SJohn.Forte@Sun.COM
13147836SJohn.Forte@Sun.COM /* check to make sure ver is not NULL */
13157836SJohn.Forte@Sun.COM if (ver == NULL) {
13167836SJohn.Forte@Sun.COM return (1);
13177836SJohn.Forte@Sun.COM }
13187836SJohn.Forte@Sun.COM
13197836SJohn.Forte@Sun.COM if ((ph = di_prom_init()) == DI_PROM_HANDLE_NIL) {
13207836SJohn.Forte@Sun.COM return (1);
13217836SJohn.Forte@Sun.COM }
13227836SJohn.Forte@Sun.COM
13237836SJohn.Forte@Sun.COM for (promprop = di_prom_prop_next(ph, node,
13247836SJohn.Forte@Sun.COM DI_PROM_PROP_NIL);
13257836SJohn.Forte@Sun.COM promprop != DI_PROM_PROP_NIL;
13267836SJohn.Forte@Sun.COM promprop = di_prom_prop_next(ph, node, promprop)) {
13277836SJohn.Forte@Sun.COM if (((promname = di_prom_prop_name(
13287836SJohn.Forte@Sun.COM promprop)) != NULL) &&
13297836SJohn.Forte@Sun.COM (strcmp(promname, "fcode-version") == 0)) {
13307836SJohn.Forte@Sun.COM size = di_prom_prop_data(promprop, &ver_data);
13317836SJohn.Forte@Sun.COM (void) memset(ver, NULL, size);
13327836SJohn.Forte@Sun.COM (void) memcpy(ver, ver_data, size);
13337836SJohn.Forte@Sun.COM found = 1;
13347836SJohn.Forte@Sun.COM }
13357836SJohn.Forte@Sun.COM }
13367836SJohn.Forte@Sun.COM
13377836SJohn.Forte@Sun.COM if (found) {
13387836SJohn.Forte@Sun.COM return (0);
13397836SJohn.Forte@Sun.COM } else {
13407836SJohn.Forte@Sun.COM return (1);
13417836SJohn.Forte@Sun.COM }
13427836SJohn.Forte@Sun.COM }
13437836SJohn.Forte@Sun.COM
13447836SJohn.Forte@Sun.COM /*
13457836SJohn.Forte@Sun.COM * Retrieves information from the Emulex fcode
13467836SJohn.Forte@Sun.COM *
13477836SJohn.Forte@Sun.COM * Given a pattern, this routine will look for this pattern in the fcode
13487836SJohn.Forte@Sun.COM * file and if found will return the pattern value
13497836SJohn.Forte@Sun.COM *
13507836SJohn.Forte@Sun.COM * possible patterns are manufacturer and fcode-version
13517836SJohn.Forte@Sun.COM */
13527836SJohn.Forte@Sun.COM int
emulex_fcode_reader(int fcode_fd,char * pattern,char * pattern_value,uint32_t pattern_value_size)13537836SJohn.Forte@Sun.COM emulex_fcode_reader(int fcode_fd, char *pattern, char *pattern_value,
13547836SJohn.Forte@Sun.COM uint32_t pattern_value_size) {
13557836SJohn.Forte@Sun.COM int32_t i = 0;
13567836SJohn.Forte@Sun.COM uint32_t n = 0;
13577836SJohn.Forte@Sun.COM uint32_t b = 0;
13587836SJohn.Forte@Sun.COM char byte1;
13597836SJohn.Forte@Sun.COM char byte2;
13607836SJohn.Forte@Sun.COM char byte3;
13617836SJohn.Forte@Sun.COM char byte4;
13627836SJohn.Forte@Sun.COM char buffer1[EMULEX_READ_BUFFER_SIZE];
13637836SJohn.Forte@Sun.COM char buffer2[EMULEX_READ_BUFFER_SIZE];
13647836SJohn.Forte@Sun.COM uint32_t plen, image_size;
13657836SJohn.Forte@Sun.COM struct stat stat;
13667836SJohn.Forte@Sun.COM uchar_t *image;
13677836SJohn.Forte@Sun.COM
13687836SJohn.Forte@Sun.COM /* Check the arguments */
13697836SJohn.Forte@Sun.COM if (!fcode_fd || !pattern_value || pattern_value_size < 8) {
13707836SJohn.Forte@Sun.COM return (1);
13717836SJohn.Forte@Sun.COM }
13727836SJohn.Forte@Sun.COM
13737836SJohn.Forte@Sun.COM if (fstat(fcode_fd, &stat) == -1) {
13747836SJohn.Forte@Sun.COM perror(MSGSTR(21023, "fstat"));
13757836SJohn.Forte@Sun.COM return (1);
13767836SJohn.Forte@Sun.COM }
13777836SJohn.Forte@Sun.COM image_size = stat.st_size;
13787836SJohn.Forte@Sun.COM if (image_size < 2) {
13797836SJohn.Forte@Sun.COM return (1);
13807836SJohn.Forte@Sun.COM }
13817836SJohn.Forte@Sun.COM if ((image = (uchar_t *)calloc(image_size, 1)) == NULL) {
13827836SJohn.Forte@Sun.COM (void) fprintf(stderr,
13837836SJohn.Forte@Sun.COM MSGSTR(21013, "Error: Memory allocation failed\n"));
13847836SJohn.Forte@Sun.COM return (1);
13857836SJohn.Forte@Sun.COM }
13867836SJohn.Forte@Sun.COM
13877836SJohn.Forte@Sun.COM /* Read the fcode image file */
13887836SJohn.Forte@Sun.COM lseek(fcode_fd, 0, SEEK_SET);
13897836SJohn.Forte@Sun.COM read(fcode_fd, image, image_size);
13907836SJohn.Forte@Sun.COM
13917836SJohn.Forte@Sun.COM /* Initialize */
13927836SJohn.Forte@Sun.COM bzero(buffer1, sizeof (buffer1));
13937836SJohn.Forte@Sun.COM bzero(buffer2, sizeof (buffer2));
13947836SJohn.Forte@Sun.COM /* Default pattern_value string */
13957836SJohn.Forte@Sun.COM strcpy((char *)pattern_value, "<unknown>");
13967836SJohn.Forte@Sun.COM plen = strlen(pattern);
13977836SJohn.Forte@Sun.COM n = 0;
13987836SJohn.Forte@Sun.COM b = 0;
13997836SJohn.Forte@Sun.COM i = 0;
14007836SJohn.Forte@Sun.COM
14017836SJohn.Forte@Sun.COM /* Search entire image for pattern string */
14027836SJohn.Forte@Sun.COM while (i <= (image_size - 2)) {
14037836SJohn.Forte@Sun.COM /* Read next two bytes */
14047836SJohn.Forte@Sun.COM byte1 = image[i++];
14057836SJohn.Forte@Sun.COM byte2 = image[i++];
14067836SJohn.Forte@Sun.COM
14077836SJohn.Forte@Sun.COM /* Check second byte first due to endianness */
14087836SJohn.Forte@Sun.COM
14097836SJohn.Forte@Sun.COM /* Save byte in circular buffer */
14107836SJohn.Forte@Sun.COM buffer1[b++] = byte2;
14117836SJohn.Forte@Sun.COM if (b == sizeof (buffer1)) {
14127836SJohn.Forte@Sun.COM b = 0;
14137836SJohn.Forte@Sun.COM }
14147836SJohn.Forte@Sun.COM
14157836SJohn.Forte@Sun.COM /* Check byte for pattern match */
14167836SJohn.Forte@Sun.COM if (pattern[n++] != byte2) {
14177836SJohn.Forte@Sun.COM /* If no match, then reset pattern */
14187836SJohn.Forte@Sun.COM n = 0;
14197836SJohn.Forte@Sun.COM } else {
14207836SJohn.Forte@Sun.COM /*
14217836SJohn.Forte@Sun.COM * If complete pattern has been matched then
14227836SJohn.Forte@Sun.COM * exit loop
14237836SJohn.Forte@Sun.COM */
14247836SJohn.Forte@Sun.COM if (n == plen) {
14257836SJohn.Forte@Sun.COM goto found;
14267836SJohn.Forte@Sun.COM }
14277836SJohn.Forte@Sun.COM }
14287836SJohn.Forte@Sun.COM
14297836SJohn.Forte@Sun.COM
14307836SJohn.Forte@Sun.COM /* Check first byte second due to endianness */
14317836SJohn.Forte@Sun.COM /* Save byte in circular buffer */
14327836SJohn.Forte@Sun.COM buffer1[b++] = byte1;
14337836SJohn.Forte@Sun.COM if (b == sizeof (buffer1)) {
14347836SJohn.Forte@Sun.COM b = 0;
14357836SJohn.Forte@Sun.COM }
14367836SJohn.Forte@Sun.COM /* Check byte for pattern match */
14377836SJohn.Forte@Sun.COM if (pattern[n++] != byte1) {
14387836SJohn.Forte@Sun.COM /* If no match, then reset pattern */
14397836SJohn.Forte@Sun.COM n = 0;
14407836SJohn.Forte@Sun.COM } else {
14417836SJohn.Forte@Sun.COM /*
14427836SJohn.Forte@Sun.COM * If complete pattern has been matched
14437836SJohn.Forte@Sun.COM * then exit loop
14447836SJohn.Forte@Sun.COM */
14457836SJohn.Forte@Sun.COM if (n == plen) {
14467836SJohn.Forte@Sun.COM goto found;
14477836SJohn.Forte@Sun.COM }
14487836SJohn.Forte@Sun.COM }
14497836SJohn.Forte@Sun.COM }
14507836SJohn.Forte@Sun.COM
14517836SJohn.Forte@Sun.COM /* Not found. Try again with different endianess */
14527836SJohn.Forte@Sun.COM
14537836SJohn.Forte@Sun.COM /* Initialize */
14547836SJohn.Forte@Sun.COM bzero(buffer1, sizeof (buffer1));
14557836SJohn.Forte@Sun.COM bzero(buffer2, sizeof (buffer2));
14567836SJohn.Forte@Sun.COM n = 0;
14577836SJohn.Forte@Sun.COM b = 0;
14587836SJohn.Forte@Sun.COM i = 0;
14597836SJohn.Forte@Sun.COM
14607836SJohn.Forte@Sun.COM /* Search entire 32bit endian image for pattern string */
14617836SJohn.Forte@Sun.COM while (i <= (image_size - 4)) {
14627836SJohn.Forte@Sun.COM /* Read next four bytes */
14637836SJohn.Forte@Sun.COM byte1 = image[i++];
14647836SJohn.Forte@Sun.COM byte2 = image[i++];
14657836SJohn.Forte@Sun.COM byte3 = image[i++];
14667836SJohn.Forte@Sun.COM byte4 = image[i++];
14677836SJohn.Forte@Sun.COM
14687836SJohn.Forte@Sun.COM /* Save byte in circular buffer */
14697836SJohn.Forte@Sun.COM buffer1[b++] = byte4;
14707836SJohn.Forte@Sun.COM if (b == sizeof (buffer1)) {
14717836SJohn.Forte@Sun.COM b = 0;
14727836SJohn.Forte@Sun.COM }
14737836SJohn.Forte@Sun.COM
14747836SJohn.Forte@Sun.COM /* Check byte for pattern match */
14757836SJohn.Forte@Sun.COM if (pattern[n++] != byte4) {
14767836SJohn.Forte@Sun.COM /* If no match, then reset pattern */
14777836SJohn.Forte@Sun.COM n = 0;
14787836SJohn.Forte@Sun.COM } else {
14797836SJohn.Forte@Sun.COM /*
14807836SJohn.Forte@Sun.COM * If complete pattern has been matched then exit loop
14817836SJohn.Forte@Sun.COM */
14827836SJohn.Forte@Sun.COM if (n == plen) {
14837836SJohn.Forte@Sun.COM goto found;
14847836SJohn.Forte@Sun.COM }
14857836SJohn.Forte@Sun.COM }
14867836SJohn.Forte@Sun.COM
14877836SJohn.Forte@Sun.COM /* Save byte in circular buffer */
14887836SJohn.Forte@Sun.COM buffer1[b++] = byte3;
14897836SJohn.Forte@Sun.COM if (b == sizeof (buffer1)) {
14907836SJohn.Forte@Sun.COM b = 0;
14917836SJohn.Forte@Sun.COM }
14927836SJohn.Forte@Sun.COM
14937836SJohn.Forte@Sun.COM /* Check byte for pattern match */
14947836SJohn.Forte@Sun.COM if (pattern[n++] != byte3) {
14957836SJohn.Forte@Sun.COM /* If no match, then reset pattern */
14967836SJohn.Forte@Sun.COM n = 0;
14977836SJohn.Forte@Sun.COM } else {
14987836SJohn.Forte@Sun.COM /*
14997836SJohn.Forte@Sun.COM * If complete pattern has been matched then exit loop
15007836SJohn.Forte@Sun.COM */
15017836SJohn.Forte@Sun.COM if (n == plen) {
15027836SJohn.Forte@Sun.COM goto found;
15037836SJohn.Forte@Sun.COM }
15047836SJohn.Forte@Sun.COM }
15057836SJohn.Forte@Sun.COM
15067836SJohn.Forte@Sun.COM /* Save byte in circular buffer */
15077836SJohn.Forte@Sun.COM buffer1[b++] = byte2;
15087836SJohn.Forte@Sun.COM if (b == sizeof (buffer1)) {
15097836SJohn.Forte@Sun.COM b = 0;
15107836SJohn.Forte@Sun.COM }
15117836SJohn.Forte@Sun.COM
15127836SJohn.Forte@Sun.COM /* Check byte for pattern match */
15137836SJohn.Forte@Sun.COM if (pattern[n++] != byte2) {
15147836SJohn.Forte@Sun.COM /* If no match, then reset pattern */
15157836SJohn.Forte@Sun.COM n = 0;
15167836SJohn.Forte@Sun.COM } else {
15177836SJohn.Forte@Sun.COM /*
15187836SJohn.Forte@Sun.COM * If complete pattern has been matched then exit loop
15197836SJohn.Forte@Sun.COM */
15207836SJohn.Forte@Sun.COM if (n == plen) {
15217836SJohn.Forte@Sun.COM goto found;
15227836SJohn.Forte@Sun.COM }
15237836SJohn.Forte@Sun.COM }
15247836SJohn.Forte@Sun.COM
15257836SJohn.Forte@Sun.COM /* Save byte in circular buffer */
15267836SJohn.Forte@Sun.COM buffer1[b++] = byte1;
15277836SJohn.Forte@Sun.COM if (b == sizeof (buffer1)) {
15287836SJohn.Forte@Sun.COM b = 0;
15297836SJohn.Forte@Sun.COM }
15307836SJohn.Forte@Sun.COM
15317836SJohn.Forte@Sun.COM /* Check byte for pattern match */
15327836SJohn.Forte@Sun.COM if (pattern[n++] != byte1) {
15337836SJohn.Forte@Sun.COM /* If no match, then reset pattern */
15347836SJohn.Forte@Sun.COM n = 0;
15357836SJohn.Forte@Sun.COM } else {
15367836SJohn.Forte@Sun.COM /*
15377836SJohn.Forte@Sun.COM * If complete pattern has been matched then exit loop
15387836SJohn.Forte@Sun.COM */
15397836SJohn.Forte@Sun.COM if (n == plen) {
15407836SJohn.Forte@Sun.COM goto found;
15417836SJohn.Forte@Sun.COM }
15427836SJohn.Forte@Sun.COM }
15437836SJohn.Forte@Sun.COM }
15447836SJohn.Forte@Sun.COM
15457836SJohn.Forte@Sun.COM free(image);
15467836SJohn.Forte@Sun.COM return (1);
15477836SJohn.Forte@Sun.COM
15487836SJohn.Forte@Sun.COM found:
15497836SJohn.Forte@Sun.COM free(image);
15507836SJohn.Forte@Sun.COM
15517836SJohn.Forte@Sun.COM /* Align buffer and eliminate non-printable characters */
15527836SJohn.Forte@Sun.COM for (i = 0; i < (sizeof (buffer1)-plen); i++) {
15537836SJohn.Forte@Sun.COM byte1 = buffer1[b++];
15547836SJohn.Forte@Sun.COM if (b == sizeof (buffer1)) {
15557836SJohn.Forte@Sun.COM b = 0;
15567836SJohn.Forte@Sun.COM }
15577836SJohn.Forte@Sun.COM /* Zero any non-printable characters */
15587836SJohn.Forte@Sun.COM if (byte1 >= 33 && byte1 <= 126) {
15597836SJohn.Forte@Sun.COM buffer2[i] = byte1;
15607836SJohn.Forte@Sun.COM } else {
15617836SJohn.Forte@Sun.COM buffer2[i] = 0;
15627836SJohn.Forte@Sun.COM }
15637836SJohn.Forte@Sun.COM }
15647836SJohn.Forte@Sun.COM
15657836SJohn.Forte@Sun.COM /*
15667836SJohn.Forte@Sun.COM * Scan backwards for first non-zero string. This will be the
15677836SJohn.Forte@Sun.COM * version string
15687836SJohn.Forte@Sun.COM */
15697836SJohn.Forte@Sun.COM for (i = sizeof (buffer1)-plen-1; i >= 0; i--) {
15707836SJohn.Forte@Sun.COM if (buffer2[i] != 0) {
15717836SJohn.Forte@Sun.COM for (; i >= 0; i--) {
15727836SJohn.Forte@Sun.COM if (buffer2[i] == 0) {
15737836SJohn.Forte@Sun.COM i++;
15747836SJohn.Forte@Sun.COM strncpy((char *)pattern_value,
15757836SJohn.Forte@Sun.COM &buffer2[i], pattern_value_size);
15767836SJohn.Forte@Sun.COM break;
15777836SJohn.Forte@Sun.COM }
15787836SJohn.Forte@Sun.COM }
15797836SJohn.Forte@Sun.COM break;
15807836SJohn.Forte@Sun.COM }
15817836SJohn.Forte@Sun.COM }
15827836SJohn.Forte@Sun.COM return (0);
15837836SJohn.Forte@Sun.COM }
15847836SJohn.Forte@Sun.COM
15857836SJohn.Forte@Sun.COM /*
15867836SJohn.Forte@Sun.COM * error handling routine to handle emulex error conditions
15877836SJohn.Forte@Sun.COM */
15887836SJohn.Forte@Sun.COM static void
handle_emulex_error(int fcio_errno,char * phys_path)15897836SJohn.Forte@Sun.COM handle_emulex_error(int fcio_errno, char *phys_path) {
15907836SJohn.Forte@Sun.COM if (fcio_errno == EMLX_IMAGE_BAD) {
15917836SJohn.Forte@Sun.COM fprintf(stderr, MSGSTR(21119,
15927836SJohn.Forte@Sun.COM "Error: Fcode download failed. "
15937836SJohn.Forte@Sun.COM "Bad fcode image.\n"));
15947836SJohn.Forte@Sun.COM } else if (fcio_errno == EMLX_IMAGE_INCOMPATIBLE) {
15957836SJohn.Forte@Sun.COM fprintf(stderr, MSGSTR(21120,
15967836SJohn.Forte@Sun.COM "Error: Fcode download failed. Fcode is not "
15977836SJohn.Forte@Sun.COM "compatible with card.\n"));
15987836SJohn.Forte@Sun.COM } else {
15997836SJohn.Forte@Sun.COM (void) fprintf(stderr, MSGSTR(21036,
16007836SJohn.Forte@Sun.COM "Error: Driver interface FCIO_DOWNLOAD_FCODE failed\n"));
16017836SJohn.Forte@Sun.COM (void) fprintf(stderr,
16027836SJohn.Forte@Sun.COM MSGSTR(21113,
16037836SJohn.Forte@Sun.COM "Error: FCode download failed: %s\n"),
16047836SJohn.Forte@Sun.COM phys_path);
16057836SJohn.Forte@Sun.COM }
16067836SJohn.Forte@Sun.COM }
1607