# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright (c) 2018, Joyent, Inc. PROG = luxadm COBJS = adm.o fchba.o lux_util.o fabric_conf.o OBJS_sparc= g_adm.o diag.o fcalupdate.o hotplug.o qlgcupdate.o setboot.o OBJS_i386 = x86_adm.o errormsgs.o OBJS = $(OBJS_$(MACH)) $(COBJS) SRCS = $(OBJS:%.o=%.c) POFILES = $(OBJS:%.o=%.po) POFILE = luxadm.po include ../Makefile.cmd CERRWARN += -Wno-parentheses CERRWARN += -Wno-address # not linted SMATCH=off sparc_LDLIBS = -la5k -lg_fc -ldevid -lkstat -ldevinfo i386_LDLIBS = LDLIBS += $($(MACH)_LDLIBS) LDLIBS += -lnvpair LDLIBS += -ldevice LDLIBS += -lHBAAPI INCS += -I$(SRC)/lib/sun_fc/common CPPFLAGS += -D_LARGEFILE64_SOURCE=1 -D_REENTRANT $(INCS) ROOTUSRSBINLINKS = $(PROG:%=$(ROOTUSRSBIN)/%) .KEEP_STATE: all: $(PROG) $(PROG): $(OBJS) $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(POST_PROCESS) GENCAT_PROG=a5k_g_fc_i18n_cat GENMSG_LUX= $(PROG).msg LUXFIRMWARED= $(ROOTLIB)/locale/C/LC_MESSAGES LUXIBFIRMWARE_sparc= $(LUXFIRMWARED)/ibfirmware LUXIBFIRMWARE= $(LUXIBFIRMWARE_$(MACH)) LUXGENCAT_PROG_sparc= $(LUXFIRMWARED)/$(GENCAT_PROG) LUXGENCAT_PROG= $(LUXGENCAT_PROG_$(MACH)) $(LUXIBFIRMWARE): FILEMODE= 0644 $(LUXGENCAT_PROG): FILEMODE= 0644 $(LUXFIRMWARED): $(INS.dir) $(LUXIBFIRMWARE): $(LUXFIRMWARED) ibfirmware $(INS.file) ibfirmware $(GENMSG_LUX): $(SRCS) /usr/bin/genmsg -d -p '$(COMPILE.cpp)' -o $@ $(SRCS) $(GENCAT_PROG): $(GENMSG_LUX) /usr/bin/gencat $@ $(GENMSG_LUX) $(LUXGENCAT_PROG): $(LUXFIRMWARED) $(GENCAT_PROG) $(INS.file) $(GENCAT_PROG) install: all $(ROOTUSRSBINPROG) $(LUXIBFIRMWARE) $(LUXGENCAT_PROG) $(POFILE): $(POFILES) $(RM) $@ $(CAT) $(POFILES) > $@ clean: $(RM) $(OBJS) $(PROG) $(GENCAT_PROG) $(GENMSG_LUX) include ../Makefile.targ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * Administration program for SENA * subsystems and individual FC_AL devices. */ /* * I18N message number ranges * This file: 2000 - 2999 * Shared common messages: 1 - 1999 */ /* #define _POSIX_SOURCE 1 */ /* * These defines are used to map instance number from sf minor node. * They are copied from SF_INST_SHIFT4MINOR and SF_MINOR2INST in sfvar.h. * sfvar.h is not clean for userland use. * When it is cleaned up, these defines will be removed and sfvar.h * will be included in luxadm.h header file. */ #define LUX_SF_INST_SHIFT4MINOR 6 #define LUX_SF_MINOR2INST(x) (x >> LUX_SF_INST_SHIFT4MINOR) /* Includes */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* For password */ #include #include "common.h" #include "luxadm.h" /* Global variables */ char *dtype[16]; /* setting a global for later use. */ char *whoami; int Options; const int OPTION_A = 0x00000001; const int OPTION_B = 0x00000002; const int OPTION_C = 0x00000004; const int OPTION_D = 0x00000008; const int OPTION_E = 0x00000010; const int OPTION_F = 0x00000020; const int OPTION_L = 0x00000040; const int OPTION_P = 0x00000080; const int OPTION_R = 0x00000100; const int OPTION_T = 0x00000200; const int OPTION_V = 0x00000400; const int OPTION_Z = 0x00001000; const int OPTION_Y = 0x00002000; const int OPTION_CAPF = 0x00004000; const int PVERBOSE = 0x00008000; const int SAVE = 0x00010000; const int EXPERT = 0x00020000; /* * Given a pointer to a character array, print the character array. * the character array will not necesarily be NULL terminated. * * Inputs: * size - the max number of characters to print * fill_flag - flag when set fills all NULL characters with spaces * Returns: * N/A */ void print_chars(uchar_t *buffer, int size, int fill_flag) { int i; for (i = 0; i < size; i++) { if (buffer[i]) (void) fprintf(stdout, "%c", buffer[i]); else if (fill_flag) (void) fprintf(stdout, " "); else return; } } /* * Name : memstrstr * Input : pointer to buf1, pointer to buf2, size of buf1, size of buf2 * Returns : * Pointer to start of contents-of-buf2 in buf1 if it is found * NULL if buf1 does not contain contents of buf2 * Synopsis: * This function works similar to strstr(). The difference is that null * characters in the buffer are treated like any other character. So, buf1 * and buf2 can have embedded null characters in them. */ static char * memstrstr(char *s1, char *s2, int size1, int size2) { int count1, count2; char *s1_ptr, *s2_ptr; count1 = size1; count2 = size2; s1_ptr = s1; s2_ptr = s2; if (size2 == 0) return (s1); while (count1--) { if (*s1_ptr++ == *s2_ptr++) { if (--count2 == 0) return (s1_ptr - size2); continue; } count2 = size2; s2_ptr = s2; } return (NULL); } /* * Download host bus adapter FCode to all supported cards. * * Specify a directory that holds the FCode files, or * it will use the default dir. Each file is dealt to * the appropriate function. * * -p prints current versions only, -d specifies a directory to load */ static int adm_fcode(int verbose, char *dir) { struct stat statbuf; struct dirent *dirp; DIR *dp; int fp; char fbuf[BUFSIZ]; char file[MAXPATHLEN]; int retval = 0, strfound = 0; char manf[BUFSIZ]; /* Find all adapters and print the current FCode version */ if (Options & OPTION_P) { /* SOCAL (SBus) adapters are not supported on x86 */ #ifndef __x86 if (verbose) { (void) fprintf(stdout, MSGSTR(2215, "\n Searching for FC100/S cards:\n")); } retval += fcal_update(Options & PVERBOSE, NULL); #endif if (verbose) { (void) fprintf(stdout, MSGSTR(2216, "\n Searching for FC100/P, FC100/2P cards:\n")); } retval += q_qlgc_update(Options & PVERBOSE, NULL); if (verbose) { (void) fprintf(stdout, MSGSTR(2503, "\n Searching for Emulex cards:\n")); } retval += emulex_update(NULL); /* Send files to the correct function for loading to the HBA */ } else { if (!dir) { (void) fprintf(stdout, MSGSTR(2251, " Location of Fcode not specified.\n")); return (1); } else if (verbose) { (void) fprintf(stdout, MSGSTR(2217, " Using directory %s"), dir); } if (lstat(dir, &statbuf) < 0) { (void) fprintf(stderr, MSGSTR(134, "%s: lstat() failed - %s\n"), dir, strerror(errno)); return (1); } if (S_ISDIR(statbuf.st_mode) == 0) { (void) fprintf(stderr, MSGSTR(2218, "Error: %s is not a directory.\n"), dir); return (1); } if ((dp = opendir(dir)) == NULL) { (void) fprintf(stderr, MSGSTR(2219, " Error Cannot open directory %s\n"), dir); return (1); } while ((dirp = readdir(dp)) != NULL) { if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0) { continue; } sprintf(file, "%s/%s", dir, dirp->d_name); if ((fp = open(file, O_RDONLY)) < 0) { (void) fprintf(stderr, MSGSTR(2220, "Error: open() failed to open file " "%s\n"), file); /* * We should just issue an error message and * make an attempt on the next file, * and the open error is still an error * so the retval should be incremented */ retval++; continue; } while ((read(fp, fbuf, BUFSIZ)) > 0) { if (memstrstr(fbuf, "SUNW,socal", BUFSIZ, strlen("SUNW,socal")) != NULL) { (void) fprintf(stdout, MSGSTR(2221, "\n Using file: %s\n"), file); retval += fcal_update( Options & PVERBOSE, file); strfound++; break; } else if ((memstrstr(fbuf, "SUNW,ifp", BUFSIZ, strlen("SUNW,ifp")) != NULL) || (memstrstr(fbuf, "SUNW,qlc", BUFSIZ, strlen("SUNW,qlc")) != NULL)) { (void) fprintf(stdout, MSGSTR(2221, "\n Using file: %s\n"), file); retval += q_qlgc_update( Options & PVERBOSE, file); strfound++; break; } } if (!strfound) { /* check to see if this is an emulex fcode */ memset(manf, 0, sizeof (manf)); if ((emulex_fcode_reader(fp, "manufacturer", manf, sizeof (manf)) == 0) && (strncmp(manf, "Emulex", sizeof (manf)) == 0)) { retval += emulex_update(file); strfound = 0; } else { (void) fprintf(stderr, MSGSTR(2222, "\nError: %s is not a valid Fcode " "file.\n"), file); retval++; } } else { strfound = 0; } close(fp); } closedir(dp); } return (retval); } /* * Definition of getaction() routine which does keyword parsing * * Operation: A character string containing the ascii cmd to be * parsed is passed in along with an array of structures. * The 1st struct element is a recognizable cmd string, the second * is the minimum number of characters from the start of this string * to succeed on a match. For example, { "offline", 3, ONLINE } * will match "off", "offli", "offline", but not "of" nor "offlinebarf" * The third element is the {usually but not necessarily unique} * integer to return on a successful match. Note: compares are cAsE insensitive. * * To change, extend or use this utility, just add or remove appropriate * lines in the structure initializer below and in the #define s for the * return values. * * N O T E * Do not change the minimum number of characters to produce * a match as someone may be building scripts that use this * feature. */ struct keyword { char *match; /* Character String to match against */ int num_match; /* Minimum chars to produce a match */ int ret_code; /* Value to return on a match */ }; static struct keyword Keywords[] = { {"display", 2, DISPLAY}, {"download", 3, DOWNLOAD}, {"enclosure_names", 2, ENCLOSURE_NAMES}, {"failover", 3, FAILOVER}, {"fcal_s_download", 4, FCAL_UPDATE}, {"fcode_download", 4, FCODE_UPDATE}, {"inquiry", 2, INQUIRY}, {"insert_device", 3, INSERT_DEVICE}, {"led", 3, LED}, {"led_on", 5, LED_ON}, {"led_off", 5, LED_OFF}, {"led_blink", 5, LED_BLINK}, {"password", 2, PASSWORD}, {"power_on", 8, POWER_ON}, {"power_off", 9, POWER_OFF}, {"probe", 2, PROBE}, {"qlgc_s_download", 4, QLGC_UPDATE}, {"remove_device", 3, REMOVE_DEVICE}, {"reserve", 5, RESERVE}, {"release", 3, RELEASE}, {"set_boot_dev", 5, SET_BOOT_DEV}, {"start", 3, START}, {"stop", 3, STOP}, {"rdls", 2, RDLS}, {"bypass", 3, BYPASS}, {"enable", 3, ENABLE}, {"p_offline", 4, LUX_P_OFFLINE}, {"p_online", 4, LUX_P_ONLINE}, {"forcelip", 2, FORCELIP}, {"dump", 2, DUMP}, {"check_file", 2, CHECK_FILE}, {"dump_map", 2, DUMP_MAP}, {"sysdump", 5, SYSDUMP}, {"port", 4, PORT}, {"external_loopback", 12, EXT_LOOPBACK}, {"internal_loopback", 12, INT_LOOPBACK}, {"no_loopback", 11, NO_LOOPBACK}, {"version", 2, VERSION}, {"create_fabric_device", 2, CREATE_FAB}, /* hotplugging device operations */ {"online", 2, DEV_ONLINE}, {"offline", 2, DEV_OFFLINE}, {"dev_getstate", 5, DEV_GETSTATE}, {"dev_reset", 5, DEV_RESET}, /* hotplugging bus operations */ {"bus_quiesce", 5, BUS_QUIESCE}, {"bus_unquiesce", 5, BUS_UNQUIESCE}, {"bus_getstate", 5, BUS_GETSTATE}, {"bus_reset", 9, BUS_RESET}, {"bus_resetall", 12, BUS_RESETALL}, /* hotplugging "helper" subcommands */ { NULL, 0, 0} }; #ifndef EOK static const int EOK = 0; /* errno.h type success return code */ #endif /* * function getaction() takes a character string, cmd, and * tries to match it against a passed structure of known cmd * character strings. If a match is found, corresponding code * is returned in retval. Status returns as follows: * EOK = Match found, look for cmd's code in retval * EFAULT = One of passed parameters was bad * EINVAL = cmd did not match any in list */ static int getaction(char *cmd, struct keyword *matches, int *retval) { int actlen; /* Idiot checking of pointers */ if (! cmd || ! matches || ! retval || ! (actlen = strlen(cmd))) /* Is there an cmd ? */ return (EFAULT); /* Keep looping until NULL match string (end of list) */ while (matches->match) { /* * Precedence: Make sure target is no longer than * current match string * and target is at least as long as * minimum # match chars, * then do case insensitive match * based on actual target size */ if ((((int)strlen(matches->match)) >= actlen) && (actlen >= matches->num_match) && /* can't get strncasecmp to work on SCR4 */ /* (strncasecmp(matches->match, cmd, actlen) == 0) */ (strncmp(matches->match, cmd, actlen) == 0)) { *retval = matches->ret_code; /* Found our match */ return (EOK); } else { matches++; /* Next match string/struct */ } } /* End of matches loop */ return (EINVAL); } /* End of getaction() */ /* main functions. */ int main(int argc, char **argv) { register int c; /* getopt varbs */ extern char *optarg; char *optstring = NULL; int path_index, err = 0; int cmd = 0; /* Cmd verb from cmd line */ int exit_code = 0; /* exit code for program */ int temp_fd; /* For -f option */ char *file_name = NULL; int option_t_input = 0; char *path_phys = NULL; int USE_FCHBA = 0; whoami = argv[0]; /* * Enable locale announcement */ i18n_catopen(); while ((c = getopt(argc, argv, "ve")) != EOF) { switch (c) { case 'v': Options |= PVERBOSE; break; case 'e': Options |= EXPERT; break; default: /* Note: getopt prints an error if invalid option */ USEAGE() exit(-1); } /* End of switch(c) */ } setbuf(stdout, NULL); /* set stdout unbuffered. */ /* * Build any i18n global variables */ dtype[0] = MSGSTR(2192, "Disk device"); dtype[1] = MSGSTR(2193, "Tape device"); dtype[2] = MSGSTR(2194, "Printer device"); dtype[3] = MSGSTR(2195, "Processor device"); dtype[4] = MSGSTR(2196, "WORM device"); dtype[5] = MSGSTR(2197, "CD-ROM device"); dtype[6] = MSGSTR(2198, "Scanner device"); dtype[7] = MSGSTR(2199, "Optical memory device"); dtype[8] = MSGSTR(2200, "Medium changer device"); dtype[9] = MSGSTR(2201, "Communications device"); dtype[10] = MSGSTR(107, "Graphic arts device"); dtype[11] = MSGSTR(107, "Graphic arts device"); dtype[12] = MSGSTR(2202, "Array controller device"); dtype[13] = MSGSTR(2203, "SES device"); dtype[14] = MSGSTR(71, "Reserved"); dtype[15] = MSGSTR(71, "Reserved"); /* * Get subcommand. */ if ((getaction(argv[optind], Keywords, &cmd)) == EOK) { optind++; if ((cmd != PROBE) && (cmd != FCAL_UPDATE) && (cmd != QLGC_UPDATE) && (cmd != FCODE_UPDATE) && (cmd != INSERT_DEVICE) && (cmd != SYSDUMP) && (cmd != AU) && (cmd != PORT) && (cmd != CREATE_FAB) && (optind >= argc)) { (void) fprintf(stderr, MSGSTR(2204, "Error: enclosure or pathname not specified.\n")); USEAGE(); exit(-1); } } else { (void) fprintf(stderr, MSGSTR(2205, "%s: subcommand not specified.\n"), whoami); USEAGE(); exit(-1); } /* Extract & Save subcommand options */ if ((cmd == ENABLE) || (cmd == BYPASS)) { optstring = "Ffrab"; } else if (cmd == FCODE_UPDATE) { optstring = "pd:"; } else if (cmd == REMOVE_DEVICE) { optstring = "F"; } else if (cmd == CREATE_FAB) { optstring = "f:"; } else { optstring = "Fryszabepcdlvt:f:w:"; } while ((c = getopt(argc, argv, optstring)) != EOF) { switch (c) { case 'a': Options |= OPTION_A; break; case 'b': Options |= OPTION_B; break; case 'c': Options |= OPTION_C; break; case 'd': Options |= OPTION_D; if (cmd == FCODE_UPDATE) { file_name = optarg; } break; case 'e': Options |= OPTION_E; break; case 'f': Options |= OPTION_F; if (!((cmd == ENABLE) || (cmd == BYPASS))) { file_name = optarg; } break; case 'F': Options |= OPTION_CAPF; break; case 'l': Options |= OPTION_L; break; case 'p': Options |= OPTION_P; break; case 'r': Options |= OPTION_R; break; case 's': Options |= SAVE; break; case 't': Options |= OPTION_T; option_t_input = atoi(optarg); break; case 'v': Options |= OPTION_V; break; case 'z': Options |= OPTION_Z; break; case 'y': Options |= OPTION_Y; break; default: /* Note: getopt prints an error if invalid option */ USEAGE() exit(-1); } /* End of switch(c) */ } if ((cmd != PROBE) && (cmd != FCAL_UPDATE) && (cmd != QLGC_UPDATE) && (cmd != FCODE_UPDATE) && (cmd != INSERT_DEVICE) && (cmd != SYSDUMP) && (cmd != AU) && (cmd != PORT) && (cmd != CREATE_FAB) && (optind >= argc)) { (void) fprintf(stderr, MSGSTR(2206, "Error: enclosure or pathname not specified.\n")); USEAGE(); exit(-1); } path_index = optind; /* * Check if the file supplied with the -f option is valid * Some sub commands (bypass for example) use the -f option * for other reasons. In such cases, "file_name" should be * NULL. */ if ((file_name != NULL) && (Options & OPTION_F)) { if ((temp_fd = open(file_name, O_RDONLY)) == -1) { perror(file_name); exit(-1); } else { close(temp_fd); } } /* Determine which mode to operate in (FC-HBA or original) */ USE_FCHBA = use_fchba(); switch (cmd) { case DISPLAY: if (Options & ~(PVERBOSE | OPTION_A | OPTION_Z | OPTION_R | OPTION_P | OPTION_V | OPTION_L | OPTION_E | OPTION_T)) { USEAGE(); exit(-1); } /* Display object(s) */ if (USE_FCHBA) { exit_code = fchba_display_config(&argv[path_index], option_t_input, argc - path_index); } else { exit_code = adm_display_config(&argv[path_index]); } break; case DOWNLOAD: if (Options & ~(PVERBOSE | OPTION_F | SAVE)) { USEAGE(); exit(-1); } adm_download(&argv[path_index], file_name); break; case ENCLOSURE_NAMES: if (Options & ~PVERBOSE) { USEAGE(); exit(-1); } up_encl_name(&argv[path_index], argc); break; case FAILOVER: if (Options & ~PVERBOSE) { USEAGE(); exit(-1); } adm_failover(&argv[path_index]); break; case INQUIRY: if (Options & ~(PVERBOSE)) { USEAGE(); exit(-1); } if (USE_FCHBA) { exit_code = fchba_inquiry(&argv[path_index]); } else { exit_code = adm_inquiry(&argv[path_index]); } break; case PROBE: if (Options & ~(PVERBOSE | OPTION_P)) { USEAGE(); exit(-1); } /* * A special check just in case someone entered * any characters after the -p or the probe. * * (I know, a nit.) */ if (((Options & PVERBOSE) && (Options & OPTION_P) && (argc != 4)) || (!(Options & PVERBOSE) && (Options & OPTION_P) && (argc != 3)) || ((Options & PVERBOSE) && (!(Options & OPTION_P)) && (argc != 3)) || (!(Options & PVERBOSE) && (!(Options & OPTION_P)) && (argc != 2))) { (void) fprintf(stderr, MSGSTR(114, "Error: Incorrect number of arguments.\n")); (void) fprintf(stderr, MSGSTR(2208, "Usage: %s [-v] subcommand [option]\n"), whoami); exit(-1); } if (USE_FCHBA) { exit_code = fchba_non_encl_probe(); } else { pho_probe(); non_encl_probe(); } break; case FCODE_UPDATE: /* Update Fcode in all cards */ if ((Options & ~(PVERBOSE)) & ~(OPTION_P | OPTION_D) || argv[path_index]) { USEAGE(); exit(-1); } if (!((Options & (OPTION_P | OPTION_D)) && !((Options & OPTION_P) && (Options & OPTION_D)))) { USEAGE(); exit(-1); } if (adm_fcode(Options & PVERBOSE, file_name) != 0) { exit(-1); } break; case QLGC_UPDATE: /* Update Fcode in PCI HBA card(s) */ if ((Options & ~(PVERBOSE)) & ~(OPTION_F) || argv[path_index]) { USEAGE(); exit(-1); } if (q_qlgc_update(Options & PVERBOSE, file_name) != 0) { exit(-1); } break; case FCAL_UPDATE: /* Update Fcode in Sbus soc+ card */ if ((Options & ~(PVERBOSE)) & ~(OPTION_F) || argv[path_index]) { USEAGE(); exit(-1); } exit_code = fcal_update(Options & PVERBOSE, file_name); break; case SET_BOOT_DEV: /* Set boot-device variable in nvram */ exit_code = setboot(Options & OPTION_Y, Options & PVERBOSE, argv[path_index]); break; case LED: if (Options & ~(PVERBOSE)) { USEAGE(); exit(-1); } adm_led(&argv[path_index], L_LED_STATUS); break; case LED_ON: if (Options & ~(PVERBOSE)) { USEAGE(); exit(-1); } adm_led(&argv[path_index], L_LED_ON); break; case LED_OFF: if (Options & ~(PVERBOSE)) { USEAGE(); exit(-1); } adm_led(&argv[path_index], L_LED_OFF); break; case LED_BLINK: if (Options & ~(PVERBOSE)) { USEAGE(); exit(-1); } adm_led(&argv[path_index], L_LED_RQST_IDENTIFY); break; case PASSWORD: if (Options & ~(PVERBOSE)) { USEAGE(); exit(-1); } up_password(&argv[path_index]); break; case RESERVE: if (Options & (~PVERBOSE)) { USEAGE(); exit(-1); } VERBPRINT(MSGSTR(2209, " Reserving: \n %s\n"), argv[path_index]); if (USE_FCHBA) { struct stat sbuf; /* Just stat the argument and make sure it exists */ if (stat(argv[path_index], &sbuf) < 0) { (void) fprintf(stderr, "%s: ", whoami); (void) fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), argv[path_index]); (void) fprintf(stderr, "\n"); exit(-1); } path_phys = argv[path_index]; if (err = scsi_reserve(path_phys)) { (void) print_errString(err, argv[path_index]); exit(-1); } } else { exit_code = adm_reserve(argv[path_index]); } break; case RELEASE: if (Options & (~PVERBOSE)) { USEAGE(); exit(-1); } VERBPRINT(MSGSTR(2210, " Canceling Reservation for:\n %s\n"), argv[path_index]); if (USE_FCHBA) { struct stat sbuf; /* Just stat the argument and make sure it exists */ if (stat(argv[path_index], &sbuf) < 0) { (void) fprintf(stderr, "%s: ", whoami); (void) fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), argv[path_index]); (void) fprintf(stderr, "\n"); exit(-1); } path_phys = argv[path_index]; if (err = scsi_release(path_phys)) { (void) print_errString(err, argv[path_index]); exit(-1); } } else { exit_code = adm_release(argv[path_index]); } break; case START: if (Options & ~(PVERBOSE)) { USEAGE(); exit(-1); } exit_code = adm_start(&argv[path_index]); break; case STOP: if (Options & ~(PVERBOSE)) { USEAGE(); exit(-1); } exit_code = adm_stop(&argv[path_index]); break; case POWER_OFF: if (Options & ~(PVERBOSE | OPTION_CAPF)) { USEAGE(); exit(-1); } exit_code = adm_power_off(&argv[path_index], 1); break; case POWER_ON: if (Options & (~PVERBOSE)) { USEAGE(); exit(-1); } exit_code = adm_power_off(&argv[path_index], 0); break; /* * EXPERT commands. */ case FORCELIP: if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) { E_USEAGE(); exit(-1); } exit_code = adm_forcelip(&argv[path_index]); break; case BYPASS: if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT | OPTION_CAPF | OPTION_A | OPTION_B | OPTION_F | OPTION_R)) || !(Options & (OPTION_A | OPTION_B)) || ((Options & OPTION_A) && (Options & OPTION_B))) { E_USEAGE(); exit(-1); } adm_bypass_enable(&argv[path_index], 1); break; case ENABLE: if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT | OPTION_CAPF | OPTION_A | OPTION_B | OPTION_F | OPTION_R)) || !(Options & (OPTION_A | OPTION_B)) || ((Options & OPTION_A) && (Options & OPTION_B))) { E_USEAGE(); exit(-1); } adm_bypass_enable(&argv[path_index], 0); break; case LUX_P_OFFLINE: /* Offline a port */ if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) { E_USEAGE(); exit(-1); } exit_code = adm_port_offline_online(&argv[path_index], LUX_P_OFFLINE); break; case LUX_P_ONLINE: /* Online a port */ if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) { E_USEAGE(); exit(-1); } exit_code = adm_port_offline_online(&argv[path_index], LUX_P_ONLINE); break; case RDLS: if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) { E_USEAGE(); exit(-1); } if (USE_FCHBA) { exit_code = fchba_display_link_status(&argv[path_index]); } else { display_link_status(&argv[path_index]); } break; case CREATE_FAB: if (!(Options & (EXPERT | OPTION_F)) || (Options & ~(PVERBOSE | EXPERT | OPTION_F))) { E_USEAGE(); exit(-1); } if (read_repos_file(file_name) != 0) { exit(-1); } break; /* * Undocumented commands. */ case CHECK_FILE: /* Undocumented Cmd */ if (Options & ~(PVERBOSE)) { USEAGE(); exit(-1); } exit_code = adm_check_file(&argv[path_index], (Options & PVERBOSE)); break; case DUMP: /* Undocumented Cmd */ if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) { USEAGE(); exit(-1); } dump(&argv[path_index]); break; case DUMP_MAP: /* Undocumented Cmd */ if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) { USEAGE(); exit(-1); } if (USE_FCHBA) { exit_code = fchba_dump_map(&argv[path_index]); } else { dump_map(&argv[path_index]); } break; case SYSDUMP: if (Options & ~(PVERBOSE)) { USEAGE(); exit(-1); } if (err = sysdump(Options & PVERBOSE)) { (void) print_errString(err, NULL); exit(-1); } break; case PORT: /* Undocumented command */ if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) { USEAGE(); exit(-1); } if (USE_FCHBA) { exit_code = fchba_display_port(Options & PVERBOSE); } else { exit_code = adm_display_port(Options & PVERBOSE); } break; case EXT_LOOPBACK: if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) { USEAGE(); exit(-1); } if (adm_port_loopback(argv[path_index], EXT_LOOPBACK) < 0) { exit(-1); } break; case INT_LOOPBACK: if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) { USEAGE(); exit(-1); } if (adm_port_loopback(argv[path_index], INT_LOOPBACK) < 0) { exit(-1); } break; case NO_LOOPBACK: if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) { USEAGE(); exit(-1); } if (adm_port_loopback(argv[path_index], NO_LOOPBACK) < 0) { exit(-1); } break; case VERSION: break; case INSERT_DEVICE: if (argv[path_index] == NULL) { if ((err = h_insertSena_fcdev()) != 0) { (void) print_errString(err, NULL); exit(-1); } } else if ((err = hotplug(INSERT_DEVICE, &argv[path_index], Options & PVERBOSE, Options & OPTION_CAPF)) != 0) { (void) print_errString(err, argv[path_index]); exit(-1); } break; case REMOVE_DEVICE: if (err = hotplug(REMOVE_DEVICE, &argv[path_index], Options & PVERBOSE, Options & OPTION_CAPF)) { (void) print_errString(err, argv[path_index]); exit(-1); } break; /* for hotplug device operations */ case DEV_ONLINE: case DEV_OFFLINE: case DEV_GETSTATE: case DEV_RESET: case BUS_QUIESCE: case BUS_UNQUIESCE: case BUS_GETSTATE: case BUS_RESET: case BUS_RESETALL: if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) { E_USEAGE(); exit(-1); } if (USE_FCHBA) { if (fchba_hotplug_e(cmd, &argv[path_index], Options & PVERBOSE, Options & OPTION_CAPF) != 0) { exit(-1); } } else { if (hotplug_e(cmd, &argv[path_index], Options & PVERBOSE, Options & OPTION_CAPF) != 0) { exit(-1); } } break; default: (void) fprintf(stderr, MSGSTR(2213, "%s: subcommand decode failed.\n"), whoami); USEAGE(); exit(-1); } return (exit_code); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * PHOTON CONFIGURATION MANAGER * Common definitions */ /* * I18N message number ranges * This file: 12500 - 12999 * Shared common messages: 1 - 1999 */ #ifndef _COMMON_H #define _COMMON_H /* * Include any headers you depend on. */ #include #include #ifdef __cplusplus extern "C" { #endif /*#ifdef _BIG_ENDIAN #define htonll(x) (x) #define ntohll(x) (x) #else #define htonll(x) ((((unsigned long long)htonl(x)) << 32) + htonl(x >> 32)) #define ntohll(x) ((((unsigned long long)ntohl(x)) << 32) + ntohl(x >> 32)) #endif*/ extern char *p_error_msg_ptr; #ifdef __x86 #include extern nl_catd l_catd; #define L_SET1 1 /* catalog set number */ #define MSGSTR(Num, Str) catgets(l_catd, L_SET1, Num, Str) #endif /* Defines */ #define USEAGE() {(void) fprintf(stderr, MSGSTR(12500, \ "Usage: %s [-v] subcommand [option...]" \ " {enclosure[,dev]... | pathname...}\n"), \ whoami); \ (void) fflush(stderr); } #define E_USEAGE() {(void) fprintf(stderr, MSGSTR(12501, \ "Usage: %s [-v] -e subcommand [option...]" \ " {enclosure[,dev]... | pathname...}\n"), \ whoami); \ (void) fflush(stderr); } #define VERBPRINT if (Options & PVERBOSE) (void) printf #define L_ERR_PRINT \ if (p_error_msg_ptr == NULL) { \ perror(MSGSTR(12502, "Error")); \ } else { \ (void) fprintf(stderr, MSGSTR(12503, "Error: %s"), p_error_msg_ptr); \ } \ p_error_msg_ptr = NULL; #define P_ERR_PRINT if (p_error_msg_ptr == NULL) { \ perror(whoami); \ } else { \ (void) fprintf(stderr, MSGSTR(12504, "Error: %s"), p_error_msg_ptr); \ } \ p_error_msg_ptr = NULL; /* Display extended mode page information. */ #ifndef MODEPAGE_CACHING #undef MODEPAGE_CACHING #define MODEPAGE_CACHING 0x08 #endif /* Primary commands */ #define ENCLOSURE_NAMES 100 #define DISPLAY 101 #define DOWNLOAD 102 #define FAST_WRITE 400 /* SSA */ #define FAILOVER 500 #define FC_UPDATE 401 /* SSA */ #define FCAL_UPDATE 103 /* Update the Fcode on Sbus soc card */ #define FCODE_UPDATE 117 /* Update the Fcode on all cards */ #define QLGC_UPDATE 116 /* Update the Fcode on PCI card(s) */ #define INQUIRY 105 #define LED 107 #define LED_ON 108 #define LED_OFF 109 #define LED_BLINK 110 #define NVRAM_DATA 402 /* SSA */ #define POWER_OFF 403 /* SSA */ #define POWER_ON 111 #define PASSWORD 112 #define PURGE 404 /* SSA */ #define PERF_STATISTICS 405 /* SSA */ #define PROBE 113 #define RELEASE 210 #define RESERVE 211 #define START 213 #define STOP 214 #define SYNC_CACHE 406 /* SSA */ #define SET_BOOT_DEV 115 /* Set the boot-device variable in nvram */ #define INSERT_DEVICE 106 /* Hot plug */ #define REMOVE_DEVICE 114 /* hot plug */ /* Device hotplugging */ #define REPLACE_DEVICE 150 #define DEV_ONLINE 155 #define DEV_OFFLINE 156 #define DEV_GETSTATE 157 #define DEV_RESET 158 #define BUS_QUIESCE 160 #define BUS_UNQUIESCE 161 #define BUS_GETSTATE 162 #define BUS_RESET 163 #define BUS_RESETALL 164 #define SKIP 111 #define QUIT 222 #define L_LED_STATUS 0x00 #define L_LED_RQST_IDENTIFY 0x01 #define L_LED_ON 0x02 #define L_LED_OFF 0x04 /* Enclosure Specific */ #define ALARM 407 /* SSA */ #define ALARM_OFF 408 /* SSA */ #define ALARM_ON 409 /* SSA */ #define ALARM_SET 410 /* SSA */ #define ENV_DISPLAY 411 /* SSA */ /* Expert commands */ #define RDLS 215 #define P_BYPASS 218 #define P_ENABLE 219 #define BYPASS 220 #define ENABLE 221 #define FORCELIP 222 #define LUX_P_OFFLINE 223 #define LUX_P_ONLINE 224 #define EXT_LOOPBACK 225 #define INT_LOOPBACK 226 #define NO_LOOPBACK 227 #define CREATE_FAB 228 /* Undocumented commands */ #define DUMP 300 #define CHECK_FILE 301 /* Undocumented - Check download file */ #define DUMP_MAP 302 /* Dump map of loop */ #define VERSION 303 /* undocumented */ #define AU 304 /* undocumented */ #define PORT 305 /* undocumented */ /* Undocumented diagnostic subcommands */ #define SYSDUMP 350 /* SSA - for adm_download */ /* #define SSAFIRMWARE_FILE "/usr/lib/firmware/ssa/ssafirmware" */ /* Global variables */ extern char *whoami; extern int Options; extern const int OPTION_A; extern const int OPTION_B; extern const int OPTION_C; extern const int OPTION_D; extern const int OPTION_E; extern const int OPTION_F; extern const int OPTION_L; extern const int OPTION_P; extern const int OPTION_R; extern const int OPTION_T; extern const int OPTION_V; extern const int OPTION_Z; extern const int OPTION_Y; extern const int OPTION_CAPF; extern const int PVERBOSE; extern const int SAVE; extern const int EXPERT; #define TARGET_ID(box_id, f_r, slot) \ ((box_id | ((f_r == 'f' ? 0 : 1) << 4)) | (slot + 2)) #define NEWER(time1, time2) (time1.tv_sec > time2.tv_sec) /* used to set the behavior of get_slash_devices_from_osDevName. */ #define STANDARD_DEVNAME_HANDLING 1 #define NOT_IGNORE_DANGLING_LINK 2 #include #ifndef __x86 #include #include #include #include #include #include #else typedef struct l_inquiry_inq_2 { #if defined(_BIT_FIELDS_HTOL) uchar_t inq_2_reladdr : 1, /* relative addressing */ inq_wbus32 : 1, /* 32 bit wide data xfers */ inq_wbus16 : 1, /* 16 bit wide data xfers */ inq_sync : 1, /* synchronous data xfers */ inq_linked : 1, /* linked commands */ inq_res1 : 1, /* reserved */ inq_cmdque : 1, /* command queueing */ inq_sftre : 1; /* Soft Reset option */ #else uchar_t inq_sftre : 1, /* Soft Reset option */ inq_cmdque : 1, /* command queueing */ inq_res1 : 1, /* reserved */ inq_linked : 1, /* linked commands */ inq_sync : 1, /* synchronous data xfers */ inq_wbus16 : 1, /* 16 bit wide data xfers */ inq_wbus32 : 1, /* 32 bit wide data xfers */ inq_2_reladdr : 1; /* relative addressing */ #endif /* _BIT_FIELDS_HTOL */ } L_inq_2; typedef struct l_inquiry_inq_3 { #if defined(_BIT_FIELDS_HTOL) uchar_t inq_3_reladdr : 1, /* relative addressing */ inq_SIP_2 : 3, /* Interlocked Protocol */ inq_3_linked : 1, /* linked commands */ inq_trandis : 1, /* Transfer Disable */ inq_3_cmdque : 1, /* command queueing */ inq_SIP_3 : 1; /* Interlocked Protocol */ #else uchar_t inq_SIP_3 : 1, /* Interlocked Protocol */ inq_3_cmdque : 1, /* command queueing */ inq_trandis : 1, /* Transfer Disable */ inq_3_linked : 1, /* linked commands */ inq_SIP_2 : 3, /* Interlocked Protocol */ inq_3_reladdr : 1; /* relative addressing */ #endif /* _BIT_FIELDS_HTOL */ } L_inq_3; typedef struct l_inquiry_struct { /* * byte 0 * * Bits 7-5 are the Peripheral Device Qualifier * Bits 4-0 are the Peripheral Device Type * */ uchar_t inq_dtype; /* byte 1 */ #if defined(_BIT_FIELDS_HTOL) uchar_t inq_rmb : 1, /* removable media */ inq_qual : 7; /* device type qualifier */ #else uchar_t inq_qual : 7, /* device type qualifier */ inq_rmb : 1; /* removable media */ #endif /* _BIT_FIELDS_HTOL */ /* byte 2 */ #if defined(_BIT_FIELDS_HTOL) uchar_t inq_iso : 2, /* ISO version */ inq_ecma : 3, /* ECMA version */ inq_ansi : 3; /* ANSI version */ #else uchar_t inq_ansi : 3, /* ANSI version */ inq_ecma : 3, /* ECMA version */ inq_iso : 2; /* ISO version */ #endif /* _BIT_FIELDS_HTOL */ /* byte 3 */ #define inq_aerc inq_aenc /* SCSI-3 */ #if defined(_BIT_FIELDS_HTOL) uchar_t inq_aenc : 1, /* async event notification cap. */ inq_trmiop : 1, /* supports TERMINATE I/O PROC msg */ inq_normaca : 1, /* Normal ACA Supported */ : 1, /* reserved */ inq_rdf : 4; /* response data format */ #else uchar_t inq_rdf : 4, /* response data format */ : 1, /* reserved */ inq_normaca : 1, /* Normal ACA Supported */ inq_trmiop : 1, /* supports TERMINATE I/O PROC msg */ inq_aenc : 1; /* async event notification cap. */ #endif /* _BIT_FIELDS_HTOL */ /* bytes 4-7 */ uchar_t inq_len; /* additional length */ uchar_t : 8; /* reserved */ #if defined(_BIT_FIELDS_HTOL) uchar_t : 2, /* reserved */ inq_port : 1, /* Only defined when dual_p set */ inq_dual_p : 1, /* Dual Port */ inq_mchngr : 1, /* Medium Changer */ inq_SIP_1 : 3; /* Interlocked Protocol */ #else uchar_t inq_SIP_1 : 3, /* Interlocked Protocol */ inq_mchngr : 1, /* Medium Changer */ inq_dual_p : 1, /* Dual Port */ inq_port : 1, /* Only defined when dual_p set */ : 2; /* reserved */ #endif /* _BIT_FIELDS_HTOL */ union { L_inq_2 inq_2; L_inq_3 inq_3; } ui; /* bytes 8-35 */ uchar_t inq_vid[8]; /* vendor ID */ uchar_t inq_pid[16]; /* product ID */ uchar_t inq_revision[4]; /* product revision level */ /* * Bytes 36-55 are vendor-specific parameter bytes */ /* SSA specific definitions */ /* bytes 36 - 39 */ #define inq_ven_specific_1 inq_firmware_rev uchar_t inq_firmware_rev[4]; /* firmware revision level */ /* bytes 40 - 51 */ uchar_t inq_serial[12]; /* serial number, not used any more */ /* bytes 52-53 */ uchar_t inq_res2[2]; /* byte 54, 55 */ uchar_t inq_ssa_ports; /* number of ports */ uchar_t inq_ssa_tgts; /* number of targets */ /* * Bytes 56-95 are reserved. */ uchar_t inq_res3[40]; /* * 96 to 'n' are vendor-specific parameter bytes */ uchar_t inq_box_name[32]; uchar_t inq_avu[256]; } L_inquiry; #define HEX_ONLY 0 /* Print Hex only */ #define HEX_ASCII 1 /* Print Hex and Ascii */ #define WWN_SIZE 8 /* # of bytes to dump per line */ /* NOTE: These command op codes are not defined in commands.h */ #define SCMD_SYNC_CACHE 0x35 #define SCMD_LOG_SENSE 0x4d #define SCMD_PERS_RESERV_IN 0x5e #define SCMD_PERS_RESERV_OUT 0x5f typedef struct rls_payload { uint_t rls_portno; uint_t rls_linkfail; uint_t rls_syncfail; uint_t rls_sigfail; uint_t rls_primitiverr; uint_t rls_invalidword; uint_t rls_invalidcrc; } rls_payload_t; typedef struct l_inquiry00_struct { #if defined(_BIT_FIELDS_LTOH) uchar_t qual :3, dtype :5; #else uchar_t dtype :5, qual :3; #endif /* _BIT_FIELDS_LTOH */ uchar_t page_code; uchar_t reserved; uchar_t len; uchar_t page_list[251]; } L_inquiry00; #define MIN(a, b) (a < b ? a : b) #define ER_DPRINTF if (getenv("_LUX_ER_DEBUG") != NULL) (void) printf #define O_DPRINTF if (getenv("_LUX_O_DEBUG") != NULL) (void) printf #define P_DPRINTF if (getenv("_LUX_P_DEBUG") != NULL) (void) printf #define R_DPRINTF if (getenv("_LUX_R_DEBUG") != NULL) (void) printf #define I_DPRINTF if (getenv("_LUX_I_DEBUG") != NULL) (void) printf #define S_DPRINTF if (getenv("_LUX_S_DEBUG") != NULL) (void) printf #define RETRY_FCIO_IOCTL 360 #define WAIT_FCIO_IOCTL 250000 /* 1/4 of a second */ #endif /* __x86 */ int adm_display_config(char **argv); void adm_download(char **argv, char *file_name); void up_encl_name(char **argv, int argc); void adm_failover(char **argv); void pho_probe(); void non_encl_probe(); void adm_led(char **argv, int led_action); void up_password(char **argv); int adm_start(char **argv); int adm_stop(char **argv); int adm_power_off(char **argv, int off_flag); int adm_forcelip(char **argv); void adm_bypass_enable(char **argv, int bypass_flag); int adm_port_offline_online(char *argv[], int flag); void display_link_status(char **argv); int read_repos_file(char *repos_filename); int adm_check_file(char **argv, int flag); void dump(char **argv); void dump_map(char **argv); int adm_port_loopback(char *portpath, int flag); int adm_inquiry(char **argv); int adm_display_port(int verbose); int adm_reserve(char *path); int adm_release(char *path); void i18n_catopen(); void dump_hex_data(char *, uchar_t *, int, int); void print_errString(int, char *); void print_chars(uchar_t *, int, int); void print_inq_data(char *, char *, L_inquiry, uchar_t *, size_t); void print_fabric_dtype_prop(uchar_t *hba_port_wwn, uchar_t *port_wwn, uchar_t dtype_prop); void print_private_loop_dtype_prop(uchar_t *hba_port_wwn, uchar_t *port_wwn, uchar_t dtype_prop); char *get_errString(int errornum); int cmp_raw_wwn(uchar_t *wwn_1, uchar_t *wwn_2); /* routines in fchba*.c files */ int fchba_display_port(int verbose); int fchba_display_config(char **argv, int option_t_input, int argc); char *get_slash_devices_from_osDevName(char *osDevName, int flag); int get_scsi_vhci_pathinfo(char *dev_path, sv_iocdata_t *ioc, int *path_count); int get_mode_page(char *path, uchar_t **pg_buf); int scsi_mode_sense_cmd(int fd, uchar_t *buf_ptr, int buf_len, uchar_t pc, uchar_t page_code); int scsi_release(char *path); int scsi_reserve(char *path); int is_path(char *arg); int is_wwn(char *arg); int loadLibrary(); uint32_t getNumberOfAdapters(); int getAdapterAttrs(HBA_HANDLE handle, char *name, HBA_ADAPTERATTRIBUTES *attrs); int getAdapterPortAttrs(HBA_HANDLE handle, char *name, int portIndex, HBA_PORTATTRIBUTES *attrs); HBA_STATUS fetch_mappings(HBA_HANDLE handle, HBA_WWN pwwn, HBA_FCPTARGETMAPPINGV2 **map); int match_mappings(char *compare, HBA_FCPTARGETMAPPINGV2 *map); uint64_t wwnConversion(uchar_t *wwn); #ifdef __cplusplus } #endif #endif /* _COMMON_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /*LINTLIBRARY*/ /* * This module is part of the photon library */ /* * I18N message number ranges * This file: 3500 - 3999 * Shared common messages: 1 - 1999 */ /* Includes */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for max */ #include #include #define _SYS_FC4_FCAL_LINKAPP_H #include #include #include #include #include #include #include #include #include "luxadm.h" /* Defines */ #define VERBPRINT if (verbose) (void) printf static int print_ssd_in_box(char *ses_path, uchar_t *box_name, int verbose) { L_state l_state; int err, i; struct dlist *ml; WWN_list *wwn_list, *wwn_list_ptr; char *s; L_inquiry inq; int enc_type = 0; wwn_list = wwn_list_ptr = NULL; if (err = l_get_status(ses_path, &l_state, verbose)) { return (err); } if (err = g_get_wwn_list(&wwn_list, verbose)) { return (err); } /* Need to find out whether this device is a daktari */ if (g_get_inquiry(ses_path, &inq)) { return (L_SCSI_ERROR); } if ((strncmp((char *)&inq.inq_pid[0], DAK_OFF_NAME, strlen(DAK_OFF_NAME)) == 0) || (strncmp((char *)&inq.inq_pid[0], DAK_PROD_STR, strlen(DAK_PROD_STR)) == 0)) { enc_type = DAK_ENC_TYPE; } for (i = 0; i < (int)l_state.total_num_drv/2; i++) { if (l_state.drv_front[i].ib_status.code != S_NOT_INSTALLED) { ml = l_state.drv_front[i].g_disk_state.multipath_list; while (ml) { for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL; wwn_list_ptr = wwn_list_ptr->wwn_next) { s = wwn_list_ptr->physical_path; if (strcmp((char *)s, ml->dev_path) == 0) { (void) fprintf(stdout, MSGSTR(3500, "%-80.80s %-17.17s %-17.17s %-22.22s "), wwn_list_ptr->physical_path, wwn_list_ptr->node_wwn_s, wwn_list_ptr->port_wwn_s, wwn_list_ptr->logical_path); if (enc_type == DAK_ENC_TYPE) { (void) fprintf(stdout, MSGSTR(3513, "%s,s%d\n"), box_name, i); } else { (void) fprintf(stdout, MSGSTR(3501, "%s,f%d\n"), box_name, i); } } } ml = ml->next; } } } for (i = 0; i < (int)l_state.total_num_drv/2; i++) { if (l_state.drv_rear[i].ib_status.code != S_NOT_INSTALLED) { ml = l_state.drv_rear[i].g_disk_state.multipath_list; while (ml) { wwn_list_ptr = wwn_list; for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL; wwn_list_ptr = wwn_list_ptr->wwn_next) { s = wwn_list_ptr->physical_path; if (strcmp((char *)s, ml->dev_path) == 0) { (void) fprintf(stdout, MSGSTR(3502, "%-80.80s %-17.17s %-17.17s %-22.22s "), wwn_list_ptr->physical_path, wwn_list_ptr->node_wwn_s, wwn_list_ptr->port_wwn_s, wwn_list_ptr->logical_path); if (enc_type == DAK_ENC_TYPE) { (void) fprintf(stdout, MSGSTR(3513, "%s,s%d\n"), box_name, (int)l_state.total_num_drv/2+i); } else { (void) fprintf(stdout, MSGSTR(3503, "%s,r%d\n"), box_name, i); } } } ml = ml->next; } } } g_free_wwn_list(&wwn_list); return (0); } int sysdump(int verbose) { int err; Box_list *b_list = NULL; Box_list *o_list = NULL; Box_list *c_list = NULL; int multi_print_flag; if (err = l_get_box_list(&b_list, verbose)) { return (err); } if (b_list == NULL) { (void) fprintf(stdout, MSGSTR(93, "No %s enclosures found " "in /dev/es\n"), ENCLOSURE_PROD_NAME); } else { o_list = b_list; while (b_list != NULL) { /* Don't re-print multiple paths */ c_list = o_list; multi_print_flag = 0; while (c_list != b_list) { if (strcmp(c_list->b_node_wwn_s, b_list->b_node_wwn_s) == 0) { multi_print_flag = 1; break; } c_list = c_list->box_next; } if (multi_print_flag) { b_list = b_list->box_next; continue; } /* Found enclosure */ (void) fprintf(stdout, MSGSTR(3504, "Enclosure name:%s Node WWN:%s\n"), b_list->b_name, b_list->b_node_wwn_s); (void) fprintf(stdout, MSGSTR(3505, "%-80.80s %-17.17s %-17.17s %-22.22s %-20.20s \n"), MSGSTR(3506, "Physical"), MSGSTR(3507, "Node_WWN"), MSGSTR(3508, "Port_WWN"), MSGSTR(3509, "Logical"), MSGSTR(3510, "Name")); (void) fprintf(stdout, MSGSTR(3511, "%-80.80s %-17.17s %-17.17s %-22.22s %-20.20s\n"), b_list->b_physical_path, b_list->b_node_wwn_s, b_list->b_port_wwn_s, b_list->logical_path, b_list->b_name); c_list = o_list; while (c_list != NULL) { if ((c_list != b_list) && (strcmp(c_list->b_node_wwn_s, b_list->b_node_wwn_s) == 0)) { (void) fprintf(stdout, MSGSTR(3512, "%-80.80s %-17.17s %-17.17s %-22.22s %-20.20s\n"), c_list->b_physical_path, c_list->b_node_wwn_s, c_list->b_port_wwn_s, c_list->logical_path, c_list->b_name); } c_list = c_list->box_next; } /* * Print the individual disk information for each box. */ if (err = print_ssd_in_box(b_list->b_physical_path, b_list->b_name, verbose)) { return (err); } b_list = b_list->box_next; } } (void) l_free_box_list(&b_list); return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _ERRORCODES_H #define _ERRORCODES_H /* * Include any headers you depend on. */ #ifdef __cplusplus extern "C" { #endif /* On the sparc platform, error codes come from stgcom.h */ #ifdef __x86 /* * All error numbers below this base value * are assumed to be UNIX error codes. */ #define L_BASE L_SCSI_ERROR /* * SCSI Errors * */ /* SCSI error */ #define L_SCSI_ERROR 0x10000 /* Receive Diagnostics: Transfer length is not word aligned */ #define L_RD_INVLD_TRNSFR_LEN 0x11002 /* No disk element found in Receive diag. page */ #define L_RD_NO_DISK_ELEM 0x11003 /* Illegal mode sense page length */ #define L_ILLEGAL_MODE_SENSE_PAGE 0x11004 /* Invalid number of ENV. SENSE pages */ #define L_INVALID_NO_OF_ENVSEN_PAGES 0x11005 /* Buffer is *too* small to hold more than 8 pages */ #define L_INVALID_BUF_LEN 0x11006 /* Scsi_vhci errors */ #define L_SCSI_VHCI_ERROR 0x11007 #define L_SCSI_VHCI_ALREADY_ACTIVE 0x11008 #define L_SCSI_VHCI_NO_STANDBY 0x11009 #define L_SCSI_VHCI_FAILOVER_NOTSUP 0x1100a #define L_SCSI_VHCI_FAILOVER_BUSY 0x1100b /* * Error definitions * for Format Errors. */ #define L_INVALID_PATH 0x20200 /* Failed to open a given path */ #define L_OPEN_PATH_FAIL 0x20001 /* Invalid password length. */ #define L_INVALID_PASSWORD_LEN 0x20002 /* Given disk physical path is not valid. */ #define L_INVLD_PHYS_PATH_TO_DISK 0x20004 /* Invalid name id found in the physical path */ #define L_INVLD_ID_FOUND 0x20005 /* Invalid WWN format found */ #define L_INVLD_WWN_FORMAT 0x20006 /* No WWN found in the disk's physical path */ #define L_NO_WWN_FOUND_IN_PATH 0x20007 /* No Loop address found in the phys path */ #define L_NO_LOOP_ADDRS_FOUND 0x20008 /* Invalid port number found in the phys path */ #define L_INVLD_PORT_IN_PATH 0x20009 /* Invalid LED request */ #define L_INVALID_LED_RQST 0x20010 /* Invalid path format */ #define L_INVALID_PATH_FORMAT 0x20011 /* failed to get the physical path */ #define L_NO_PHYS_PATH 0x20012 /* failed to get the ses path */ #define L_NO_SES_PATH 0x20015 /* No "/" found in the physical path */ #define L_INVLD_PATH_NO_SLASH_FND 0x20100 /* No "@" found in the physical path */ #define L_INVLD_PATH_NO_ATSIGN_FND 0x20101 /* Invalid slot (slot < 0 or slot > 10). */ #define L_INVALID_SLOT 0x20102 /* No valid path to a device */ #define L_NO_VALID_PATH 0x20103 /* No disk devices found in /dev/rdsk directory */ #define L_NO_DISK_DEV_FOUND 0x20104 /* No tape devices found in /dev/rmt directory */ #define L_NO_TAPE_DEV_FOUND 0x20105 /* Device's Node WWN not found in the WWN list. */ #define L_NO_NODE_WWN_IN_WWNLIST 0x20106 /* Device's Node WWN not found in the Box list. */ #define L_NO_NODE_WWN_IN_BOXLIST 0x20107 /* Null WWN list found. */ #define L_NULL_WWN_LIST 0x20108 /* No devices found. */ #define L_NO_DEVICES_FOUND 0x20109 /* function arg error in wwn_list process */ #define L_PROC_WWN_ARG_ERROR 0x20110 /* WWN property not found */ #define L_NO_WWN_PROP_FOUND 0x20111 /* No driver nodes found for requested driver */ #define L_NO_DRIVER_NODES_FOUND 0x20112 /* ULP error on device(s) */ #define L_GET_DEV_LIST_ULP_FAILURE 0x20150 /* * Error definitions * for FC Loop (FC4 devices). */ /* Invalid loop map found */ #define L_INVALID_LOOP_MAP 0x20202 /* SFIOCGMAP ioctl failed */ #define L_SFIOCGMAP_IOCTL_FAIL 0x20203 /* FCIO_GETMAP ioctl failed */ #define L_FCIO_GETMAP_IOCTL_FAIL 0x20204 /* FCIO_LINKSTATUS ioctl failed */ #define L_FCIO_LINKSTATUS_FAILED 0x20205 /* FCIO_GETMAP: Invalid # of entries */ #define L_FCIOGETMAP_INVLD_LEN 0x20206 /* FCIO_FORCE_LIP ioctl failed. */ #define L_FCIO_FORCE_LIP_FAIL 0x20207 /* Error definitions for FC devices */ /* FCIO_RESET_LINK ioctl failed */ #define L_FCIO_RESET_LINK_FAIL 0x20208 /* FCIO_GET_FCODE_REV_FAIL ioctl failed */ #define L_FCIO_GET_FCODE_REV_FAIL 0x20209 /* FCIO_GET_FW_REV_FAIL ioctl failed */ #define L_FCIO_GET_FW_REV_FAIL 0x20210 /* FCIO_GET_DEV_LIST returns invalid dev. counts */ #define L_INVALID_DEVICE_COUNT 0x20211 /* L_FCIO_GET_NUM_DEVS_FAIL ioctl failed */ #define L_FCIO_GET_NUM_DEVS_FAIL 0x20212 /* L_FCIO_GET_DEV_LIST_FAIL ioctl failed */ #define L_FCIO_GET_DEV_LIST_FAIL 0x20213 /* L_FCIO_GET_LINK_STATUS ioctl failed */ #define L_FCIO_GET_LINK_STATUS_FAIL 0x20214 /* L_FCIO_LOOPBACK_INTERNAL or FCIO_CMD/FCIO_LASER_OFF ioctl failed */ #define L_PORT_OFFLINE_FAIL 0x20215 /* Internal Loopback or laser off ioctls not supported */ #define L_PORT_OFFLINE_UNSUPPORTED 0x20216 /* L_FCIO_NO_LOOPBACK or FCIO_CMD/FCIO_LASER_ON ioctl failed */ #define L_PORT_ONLINE_FAIL 0x20217 /* No-Loopback or laser on ioctls not supported */ #define L_PORT_ONLINE_UNSUPPORTED 0x20218 /* L_FCIO_GET_HOST_PARAMS ioctl failed */ #define L_FCIO_GET_HOST_PARAMS_FAIL 0x20219 /* Loopback mode failure */ #define L_LOOPBACK_FAILED 0x20220 /* Loopback unsupported */ #define L_LOOPBACK_UNSUPPORTED 0x20221 /* FCIO_FORCE_LIP ioctl failed on one of the paths, say, of an MPXIO device */ #define L_FCIO_FORCE_LIP_PARTIAL_FAIL 0x20222 /* * Error definitions * for Fabric FC driver ioctls */ /* FCP_TGT_INQUIRY ioctl failed */ #define L_FCP_TGT_INQUIRY_FAIL 0x20250 /* * Error definitions * for 24-bit address handling */ /* Private loop address > 0xFF found */ #define L_INVALID_PRIVATE_LOOP_ADDRESS 0x20401 /* Encountered an unexpected fibre channel topology value */ #define L_UNEXPECTED_FC_TOPOLOGY 0x20402 /* Fabric address was not found */ #define L_NO_FABRIC_ADDR_FOUND 0x20403 /* The FCIO_GET_TOPOLOGY ioctl failed */ #define L_FCIO_GET_TOPOLOGY_FAIL 0x20404 /* Invalid fabric or public loop address */ #define L_INVALID_FABRIC_ADDRESS 0x20405 /* Point to Point fibre channel topology not supported */ #define L_PT_PT_FC_TOP_NOT_SUPPORTED 0x20406 /* * Error definitions for Tapestry SAN support. */ /* The FCIO_DEV_LOGIN ioctl failed */ #define L_FCIO_DEV_LOGIN_FAIL 0x20407 /* The FCIO_DEV_LOGOUT ioctl failed */ #define L_FCIO_DEV_LOGOUT_FAIL 0x20408 /* Operation not supported on connected topology */ #define L_OPNOSUPP_ON_TOPOLOGY 0x20409 /* Operation not supported on the path */ #define L_INVALID_PATH_TYPE 0x20410 /* FCIO_GET_STATE ioctl failed */ #define L_FCIO_GET_STATE_FAIL 0x20411 /* input WWN not found in dev list */ #define L_WWN_NOT_FOUND_IN_DEV_LIST 0x20412 /* * Error definitions for * g_dev_map_init related routines. */ /* input addr invalid */ #define L_INVALID_MAP_DEV_ADDR 0x20430 /* input property invalid */ #define L_INVALID_MAP_DEV_PROP_NAME 0x20431 /* input property invalid */ #define L_INVALID_MAP_DEV_PROP_TYPE 0x20432 /* input property name invalid */ #define L_INVALID_MAP_DEV_PROP 0x20433 /* device not found */ #define L_NO_SUCH_DEV_FOUND 0x20434 /* prop not found */ #define L_NO_SUCH_PROP_FOUND 0x20435 /* invalid arg found */ #define L_INVALID_ARG 0x20436 /* * Error definitions * for Downloading IB FW. */ /* Invalid download file checksum */ #define L_DWNLD_CHKSUM_FAILED 0x20301 /* Unable to read download exec header */ #define L_DWNLD_READ_HEADER_FAIL 0x20302 /* Number of bytes read from download file is not correct */ #define L_DWNLD_READ_INCORRECT_BYTES 0x20303 /* Wrong text segment size */ #define L_DWNLD_INVALID_TEXT_SIZE 0x20304 /* Error reading the download file */ #define L_DWNLD_READ_ERROR 0x20305 /* Bad firmware magic found in the download file */ #define L_DWNLD_BAD_FRMWARE 0x20306 /* Timeout message for the IB to be available */ #define L_DWNLD_TIMED_OUT 0x20307 /* Error with Rec Diag page 1 */ #define L_REC_DIAG_PG1 0x20600 /* Invalid transfer Length */ #define L_TRANSFER_LEN 0x20601 /* A firmware file must be specified on the command line */ #define L_REQUIRE_FILE 0x20602 /* * Error definitions * for System Errors */ #define L_MALLOC_FAILED 0x30000 #define L_MEMCPY_FAILED 0x30001 /* Cannot get status for the given path */ #define L_LSTAT_ERROR 0x30020 /* Error reading the symbolic link */ #define L_SYMLINK_ERROR 0x30021 /* Could not convert std. time to hrs/min/sec */ #define L_LOCALTIME_ERROR 0x30022 /* select() system call failed to wait for specified time */ #define L_SELECT_ERROR 0x30023 /* uname() system call failed to get the system info. */ #define L_UNAME_FAILED 0x30024 /* Cannot get status for the given path */ #define L_FSTAT_ERROR 0x30025 /* Cannot get status for the given path */ #define L_STAT_ERROR 0x30026 /* di_init() failed to return snapshot of device tree */ #define L_DEV_SNAPSHOT_FAILED 0x30027 /* di_drv_first_node() failed to find a valid driver */ #define L_PORT_DRIVER_NOT_FOUND 0x30029 /* failed to find any device paths */ #define L_PHYS_PATH_NOT_FOUND 0x30030 /* No device identifier found */ #define L_NO_DEVID 0x30031 /* Driver not supported */ #define L_DRIVER_NOTSUPP 0x30032 /* di_prom_init failure */ #define L_PROM_INIT_FAILED 0x30033 /* * Error definitions * for individual * devices. */ /* Device busy */ #define L_DEV_BUSY 0x40000 /* Disk reserved */ #define L_DEVICE_RESERVED 0x40001 /* One or more disks in enclosure are reserved */ #define L_DISKS_RESERVED 0x40002 /* Exclusive open to a device failed. May be busy */ #define L_EXCL_OPEN_FAILED 0x40003 /* Empty slot: Device not installed */ #define L_SLOT_EMPTY 0x40100 /* * Error definitions * for Devctl functions. */ /* Devctl acquire fails */ #define L_ACQUIRE_FAIL 0x40200 /* Power off fails. Device may be busy */ #define L_POWER_OFF_FAIL_BUSY 0x40300 /* * Error definitions * specific to Enclosure. */ /* Failed to change the enclosure name */ #define L_ENCL_NAME_CHANGE_FAIL 0x40400 /* Duplicate enclosure names found */ #define L_DUPLICATE_ENCLOSURES 0x40401 /* Invalid no. of dsks in SENA enclosure */ #define L_INVALID_NUM_DISKS_ENCL 0x40402 /* Path is not to a SENA ecnlosure. */ #define L_ENCL_INVALID_PATH 0x40403 /* Cannot get the box list */ #define L_NO_ENCL_LIST_FOUND 0x40404 /* * Error definitions * specific to IB. */ /* No element returned from the enclosure */ #define L_IB_NO_ELEM_FOUND 0x40500 /* Invalid page code found in Receive Diag. page. */ #define L_RD_PG_INVLD_CODE 0x40501 /* Reading Receive Diag. page failed: small buffer. */ #define L_RD_PG_MIN_BUFF 0x40502 /* Get status failed */ #define L_GET_STATUS_FAILED 0x40600 /* Warning define. */ #define L_WARNING 0x90000 /* Persistant Rservation: Invalid transfer length */ #define L_PR_INVLD_TRNSFR_LEN 0x10001 /* * Error definitions * for Format Errors. */ /* box name conflicts with the SSA name */ #define L_SSA_CONFLICT 0x20013 /* * Error definitions * for System Errors */ /* drvconfig fail */ #define L_DRVCONFIG_ERROR 0x31001 /* disks program failed */ #define L_DISKS_ERROR 0x31002 /* devlinks program failed */ #define L_DEVLINKS_ERROR 0x31003 /* fail to read /dev/rdsk directory. */ #define L_READ_DEV_DIR_ERROR 0x31004 /* Failed to open /dev/es/ directory. */ #define L_OPEN_ES_DIR_FAILED 0x31005 /* fail to get status from /dev/es directory. */ #define L_LSTAT_ES_DIR_ERROR 0x31006 /* disks program failed */ #define L_TAPES_ERROR 0x31007 /* fail to get status from /dev/rmt/directory. */ #define L_STAT_RMT_DIR_ERROR 0x31008 /* fail to get status from /dev/rmt/directory. */ #define L_STAT_DEV_DIR_ERROR 0x31009 /* * Error definitions * specific to Back plane. */ /* Backplane: Busy or reserved disks found */ #define L_BP_BUSY_RESERVED 0x50000 /* Backplane: one or more busy disks found */ #define L_BP_BUSY 0x50001 /* Backplane: one or more reserved disks found */ #define L_BP_RESERVED 0x50002 /* No BP element found in the enclosure */ #define L_NO_BP_ELEM_FOUND 0x50003 /* * Thread errors. */ #define L_TH_CREATE 0x60000 #define L_TH_JOIN 0x60001 #endif /* __x86 */ #ifdef __cplusplus } #endif #endif /* _ERRORCODES_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * I18N message number ranges * This file: 10000 - 10499 * Shared common messages: 1 - 1999 */ /* #define _POSIX_SOURCE 1 */ /* Includes */ #include #include #include #include #include #include #include #include "common.h" #include "errorcodes.h" /* Defines */ #define MAXLEN 1000 /* * Allocate space for and return a pointer to a string * on the stack. If the string is null, create * an empty string. */ char * alloc_string(char *s) { char *ns; if (s == (char *)NULL) { ns = (char *)calloc(1, 1); } else { ns = (char *)calloc(1, strlen(s) + 1); if (ns != NULL) { (void) strncpy(ns, s, (strlen(s) + 1)); } } return (ns); } /* * Decodes the SCSI sense byte to a string. * * RETURNS: * character string */ static char * decode_sense_byte(uchar_t status) { switch (status & STATUS_MASK) { case STATUS_GOOD: return (MSGSTR(10000, "Good status")); case STATUS_CHECK: return (MSGSTR(128, "Check condition")); case STATUS_MET: return (MSGSTR(124, "Condition met")); case STATUS_BUSY: return (MSGSTR(37, "Busy")); case STATUS_INTERMEDIATE: return (MSGSTR(10001, "Intermediate")); case STATUS_INTERMEDIATE_MET: return (MSGSTR(10002, "Intermediate - condition met")); case STATUS_RESERVATION_CONFLICT: return (MSGSTR(10003, "Reservation_conflict")); case STATUS_TERMINATED: return (MSGSTR(126, "Command terminated")); case STATUS_QFULL: return (MSGSTR(83, "Queue full")); default: return (MSGSTR(4, "Unknown status")); } } /* * This function finds a predefined error string to a given * error number (errornum), allocates memory for the string * and returns the corresponding error message to the caller. * * RETURNS * error string if O.K. * NULL otherwise */ char *get_errString(int errornum) { char err_msg[MAXLEN], *errStrg; err_msg[0] = '\0'; /* Just in case */ if (errornum < L_BASE) { /* Some sort of random system error most likely */ errStrg = strerror(errno); if (errStrg != NULL) { (void) strcpy(err_msg, errStrg); } else { /* Something's _really_ messed up */ (void) sprintf(err_msg, MSGSTR(10081, " Error: could not decode the" " error message.\n" " The given error message is not" " defined in the library.\n" " Message number: %d.\n"), errornum); } /* Make sure ALL CASES set err_msg to something */ } else switch (errornum) { case L_SCSI_ERROR: (void) sprintf(err_msg, MSGSTR(10096, " Error: SCSI failure.")); break; case L_PR_INVLD_TRNSFR_LEN: (void) sprintf(err_msg, MSGSTR(10005, " Error: Persistant Reserve command" " transfer length not word aligned.")); break; case L_RD_NO_DISK_ELEM: (void) sprintf(err_msg, MSGSTR(10006, " Error: Could not find the disk elements" " in the Receive Diagnostic pages.")); break; case L_RD_INVLD_TRNSFR_LEN: (void) sprintf(err_msg, MSGSTR(10007, " Error: Receive Diagnostic command" " transfer length not word aligned.")); break; case L_ILLEGAL_MODE_SENSE_PAGE: (void) sprintf(err_msg, MSGSTR(10008, " Error: Programming error - " "illegal Mode Sense parameter.")); break; case L_INVALID_NO_OF_ENVSEN_PAGES: (void) sprintf(err_msg, MSGSTR(10009, " Error: Invalid no. of sense pages.\n" " Could not get valid sense page" " information from the device.")); break; case L_INVALID_BUF_LEN: (void) sprintf(err_msg, MSGSTR(10010, " Error: Invalid buffer length.\n" " Could not get diagnostic " " information from the device.")); break; case L_INVALID_PATH: (void) sprintf(err_msg, MSGSTR(113, " Error: Invalid pathname")); break; case L_NO_PHYS_PATH: (void) sprintf(err_msg, MSGSTR(10011, " Error: Could not get" " physical path to the device.")); break; case L_NO_SES_PATH: (void) sprintf(err_msg, MSGSTR(10098, " Error: No SES found" " for the device path.")); break; case L_INVLD_PATH_NO_SLASH_FND: (void) sprintf(err_msg, MSGSTR(10012, "Error in the device physical path.")); break; case L_INVLD_PATH_NO_ATSIGN_FND: (void) sprintf(err_msg, MSGSTR(10013, " Error in the device physical path:" " no @ found.")); break; case L_INVALID_SLOT: (void) sprintf(err_msg, MSGSTR(10014, " Error: Invalid path format." " Invalid slot.")); break; case L_INVALID_LED_RQST: (void) sprintf(err_msg, MSGSTR(10015, " Error: Invalid LED request.")); break; case L_INVALID_PATH_FORMAT: (void) sprintf(err_msg, MSGSTR(10016, " Error: Invalid path format.")); break; case L_OPEN_PATH_FAIL: (void) sprintf(err_msg, MSGSTR(10017, " Error opening the path.")); break; case L_INVALID_PASSWORD_LEN: (void) sprintf(err_msg, MSGSTR(10018, "Error: Invalid password length.")); break; case L_INVLD_PHYS_PATH_TO_DISK: (void) sprintf(err_msg, MSGSTR(10019, " Error: Physical path not of a disk.")); break; case L_INVLD_ID_FOUND: (void) sprintf(err_msg, MSGSTR(10020, " Error in the device physical path:" " Invalid ID found in the path.")); break; case L_INVLD_WWN_FORMAT: (void) sprintf(err_msg, MSGSTR(10021, " Error in the device physical path:" " Invalid wwn format.")); break; case L_NO_VALID_PATH: (void) sprintf(err_msg, MSGSTR(10022, " Error: Could not find valid path to" " the device.")); break; case L_NO_WWN_FOUND_IN_PATH: (void) sprintf(err_msg, MSGSTR(10023, " Error in the device physical path:" " No WWN found.")); break; case L_NO_NODE_WWN_IN_WWNLIST: (void) sprintf(err_msg, MSGSTR(10024, " Error: Device's Node WWN is not" " found in the WWN list.\n")); break; case L_NO_NODE_WWN_IN_BOXLIST: (void) sprintf(err_msg, MSGSTR(10025, " Error: Device's Node WWN is not" " found in the Box list.\n")); break; case L_NULL_WWN_LIST: (void) sprintf(err_msg, MSGSTR(10026, " Error: Null WWN list found.")); break; case L_NO_LOOP_ADDRS_FOUND: (void) sprintf(err_msg, MSGSTR(10027, " Error: Could not find the loop address for " " the device at physical path.")); break; case L_INVLD_PORT_IN_PATH: (void) sprintf(err_msg, MSGSTR(10028, "Error in the device physical path:" " Invalid port number found." " (Should be 0 or 1).")); break; case L_INVALID_LOOP_MAP: (void) sprintf(err_msg, MSGSTR(10029, "Error: Invalid loop map found.")); break; case L_SFIOCGMAP_IOCTL_FAIL: (void) sprintf(err_msg, MSGSTR(10030, " Error: SFIOCGMAP ioctl failed." " Cannot read loop map.")); break; case L_FCIO_GETMAP_IOCTL_FAIL: (void) sprintf(err_msg, MSGSTR(10031, " Error: FCIO_GETMAP ioctl failed." " Cannot read loop map.")); break; case L_FCIO_LINKSTATUS_FAILED: (void) sprintf(err_msg, MSGSTR(10032, " Error: FCIO_LINKSTATUS ioctl failed." " Cannot read loop map.")); break; case L_FCIOGETMAP_INVLD_LEN: (void) sprintf(err_msg, MSGSTR(10033, " Error: FCIO_GETMAP ioctl returned" " an invalid parameter:" " # entries to large.")); break; case L_FCIO_FORCE_LIP_FAIL: (void) sprintf(err_msg, MSGSTR(10034, " Error: FCIO_FORCE_LIP ioctl failed.")); break; case L_FCIO_FORCE_LIP_PARTIAL_FAIL: (void) sprintf(err_msg, MSGSTR(10115, " Error: FCIO_FORCE_LIP ioctl failed on one" " or more (but not all) of the paths.")); break; case L_DWNLD_CHKSUM_FAILED: (void) sprintf(err_msg, MSGSTR(10035, "Error: Download file checksum failed.")); break; case L_DWNLD_READ_HEADER_FAIL: (void) sprintf(err_msg, MSGSTR(10036, " Error: Reading download file exec" " header failed.")); break; case L_DWNLD_READ_INCORRECT_BYTES: (void) sprintf(err_msg, MSGSTR(10037, " Error: Incorrect number of bytes read.")); break; case L_DWNLD_INVALID_TEXT_SIZE: (void) sprintf(err_msg, MSGSTR(10038, " Error: Reading text segment: " " Found wrong size.")); break; case L_DWNLD_READ_ERROR: (void) sprintf(err_msg, MSGSTR(10039, " Error: Failed to read download file.")); break; case L_DWNLD_BAD_FRMWARE: (void) sprintf(err_msg, MSGSTR(10040, " Error: Bad Firmware MAGIC.")); break; case L_DWNLD_TIMED_OUT: (void) sprintf(err_msg, MSGSTR(10041, " Error: Timed out in 5 minutes" " waiting for the" " IB to become available.")); break; case L_REC_DIAG_PG1: (void) sprintf(err_msg, MSGSTR(10042, " Error parsing the Receive" " diagnostic page.")); break; case L_TRANSFER_LEN: (void) sprintf(err_msg, MSGSTR(10043, " ")); break; case L_REQUIRE_FILE: (void) sprintf(err_msg, MSGSTR(10109, " Error: No default file. You must specify" " the filename path.")); break; case L_MALLOC_FAILED: (void) sprintf(err_msg, MSGSTR(10, " Error: Unable to allocate memory.")); break; case L_LOCALTIME_ERROR: (void) sprintf(err_msg, MSGSTR(10044, " Error: Could not convert time" " to broken-down time: Hrs/Mins/Secs.")); break; case L_SELECT_ERROR: (void) sprintf(err_msg, MSGSTR(10045, " select() error during retry:" " Could not wait for" " specified time.")); break; case L_NO_DISK_DEV_FOUND: (void) sprintf(err_msg, MSGSTR(10046, " Error: No disk devices found" " in the /dev/rdsk" " directory.")); break; case L_NO_TAPE_DEV_FOUND: (void) sprintf(err_msg, MSGSTR(10047, " Error: No tape devices found" " in the /dev/rmt" " directory.")); break; case L_LSTAT_ERROR: (void) sprintf(err_msg, MSGSTR(10048, " lstat() error: Cannot obtain status" " for the device.")); break; case L_SYMLINK_ERROR: (void) sprintf(err_msg, MSGSTR(10049, " Error: Could not read the symbolic link.")); break; case L_UNAME_FAILED: (void) sprintf(err_msg, MSGSTR(10050, " uname() error: Could not obtain the" " architeture of the host machine.")); break; case L_DRVCONFIG_ERROR: (void) sprintf(err_msg, MSGSTR(10051, " Error: Could not run drvconfig.")); break; case L_DISKS_ERROR: (void) sprintf(err_msg, MSGSTR(10052, " Error: Could not run disks.")); break; case L_DEVLINKS_ERROR: (void) sprintf(err_msg, MSGSTR(10053, " Error: Could not run devlinks.")); break; case L_READ_DEV_DIR_ERROR: (void) sprintf(err_msg, MSGSTR(10054, " Error: Could not read /dev/rdsk" " directory.")); break; case L_OPEN_ES_DIR_FAILED: (void) sprintf(err_msg, MSGSTR(10055, " Error: Could not open /dev/es" " directory.")); break; case L_LSTAT_ES_DIR_ERROR: (void) sprintf(err_msg, MSGSTR(10056, " lstat() error: Could not get status" " for /dev/es directory.")); break; case L_DEV_BUSY: (void) sprintf(err_msg, MSGSTR(10057, " Error: Could not offline the device\n" " May be Busy.")); break; case L_EXCL_OPEN_FAILED: (void) sprintf(err_msg, MSGSTR(10058, " Error: Could not open device in" " exclusive mode." " May already be open.")); break; case L_DEVICE_RESERVED: (void) sprintf(err_msg, MSGSTR(10059, " Error: Disk is reserved.")); break; case L_DISKS_RESERVED: (void) sprintf(err_msg, MSGSTR(10060, " Error: One or more disks in" " SENA are reserved.")); break; case L_SLOT_EMPTY: (void) sprintf(err_msg, MSGSTR(10061, " Error: Slot is empty.")); break; case L_ACQUIRE_FAIL: (void) sprintf(err_msg, MSGSTR(10062, " Error: Could not acquire" " the device.")); break; case L_POWER_OFF_FAIL_BUSY: (void) sprintf(err_msg, MSGSTR(10063, " Error: Could not power off the device.\n" " May be Busy.")); break; case L_ENCL_NAME_CHANGE_FAIL: (void) sprintf(err_msg, MSGSTR(10064, " Error: The Enclosure name change failed.")); break; case L_DUPLICATE_ENCLOSURES: (void) sprintf(err_msg, MSGSTR(10065, " Error: There are two or more enclosures" " with the same name." " Please use a logical or physical" " pathname.")); break; case L_INVALID_NUM_DISKS_ENCL: (void) sprintf(err_msg, MSGSTR(10066, " Error: The number of disks in the" " front & rear of the enclosure are" " different." " This is not a supported configuration.")); break; case L_ENCL_INVALID_PATH: (void) sprintf(err_msg, MSGSTR(10067, " Error: Invalid path." " Device is not a SENA subsystem.")); break; case L_NO_ENCL_LIST_FOUND: (void) sprintf(err_msg, MSGSTR(10068, " Error: Cannot get the Box list.")); break; case L_IB_NO_ELEM_FOUND: (void) sprintf(err_msg, MSGSTR(10069, " Error: No elements returned from" " enclosure (IB).")); break; case L_GET_STATUS_FAILED: (void) sprintf(err_msg, MSGSTR(10070, " Error: Get status failed.")); break; case L_RD_PG_MIN_BUFF: (void) sprintf(err_msg, MSGSTR(10071, " Error: Reading page from IB.\n" " Buffer size too small.")); break; case L_RD_PG_INVLD_CODE: (void) sprintf(err_msg, MSGSTR(10072, " Error: Reading page from IB\n" " Invalid page code or page len found.")); break; case L_BP_BUSY_RESERVED: (void) sprintf(err_msg, MSGSTR(10073, " Error: There is a busy or reserved disk" " attached to this backplane.\n" " You must close the disk,\n" " or release the disk,\n" " or resubmit the command using" " the Force option.")); break; case L_BP_BUSY: (void) sprintf(err_msg, MSGSTR(10074, " Error: There is a busy disk" " attached to this backplane.\n" " You must close the disk,\n" " or resubmit the command using" " the Force option.")); break; case L_BP_RESERVED: (void) sprintf(err_msg, MSGSTR(10075, " Error: There is a reserved disk" " attached to this backplane.\n" " You must release the disk,\n" " or resubmit the subcommand using" " the Force option.")); break; case L_NO_BP_ELEM_FOUND: (void) sprintf(err_msg, MSGSTR(10076, " Error: No Back plane elements found" " in the enclosure.")); break; case L_SSA_CONFLICT: (void) sprintf(err_msg, MSGSTR(10077, " There is a conflict between the " "enclosure name and an SSA name of " "same form, cN.\n" " Please use a logical or physical " "pathname.")); break; case L_WARNING: (void) sprintf(err_msg, MSGSTR(10078, " Warning:")); break; case L_TH_JOIN: (void) sprintf(err_msg, MSGSTR(10079, " Error: Thread join failed.")); break; case L_FCIO_RESET_LINK_FAIL: (void) sprintf(err_msg, MSGSTR(10082, " Error: FCIO_RESET_LINK ioctl failed.\n" " Could not reset the loop.")); break; case L_FCIO_GET_FCODE_REV_FAIL: (void) sprintf(err_msg, MSGSTR(10083, " Error: FCIO_GET_FCODE_REV ioctl failed.\n" " Could not get the fcode version.")); break; case L_FCIO_GET_FW_REV_FAIL: (void) sprintf(err_msg, MSGSTR(10084, " Error: FCIO_GET_FW_REV ioctl failed.\n" " Could not get the firmware revision.")); break; case L_NO_DEVICES_FOUND: (void) sprintf(err_msg, MSGSTR(10085, " No FC devices found.")); break; case L_INVALID_DEVICE_COUNT: (void) sprintf(err_msg, MSGSTR(10086, " Error: FCIO_GET_DEV_LIST ioctl returned" " an invalid device count.")); break; case L_FCIO_GET_NUM_DEVS_FAIL: (void) sprintf(err_msg, MSGSTR(10087, " Error: FCIO_GET_NUM_DEVS ioctl failed.\n" " Could not get the number of devices.")); break; case L_FCIO_GET_DEV_LIST_FAIL: (void) sprintf(err_msg, MSGSTR(10088, " Error: FCIO_GET_DEV_LIST ioctl failed.\n" " Could not get the device list.")); break; case L_FCIO_GET_LINK_STATUS_FAIL: (void) sprintf(err_msg, MSGSTR(10089, " Error: FCIO_GET_LINK_STATUS ioctl failed.\n" " Could not get the link status.")); break; case L_PORT_OFFLINE_FAIL: (void) sprintf(err_msg, MSGSTR(10090, " Error: ioctl to offline the port failed.")); break; case L_PORT_OFFLINE_UNSUPPORTED: (void) sprintf(err_msg, MSGSTR(10091, " Error: The driver does not support ioctl to" " disable the FCA port.")); break; case L_PORT_ONLINE_FAIL: (void) sprintf(err_msg, MSGSTR(10092, " Error: ioctl to online the port failed.")); break; case L_PORT_ONLINE_UNSUPPORTED: (void) sprintf(err_msg, MSGSTR(10093, " Error: The driver does not support ioctl to" " enable the FCA port.")); break; case L_FCP_TGT_INQUIRY_FAIL: (void) sprintf(err_msg, MSGSTR(10094, " Error: FCP_TGT_INQUIRY ioctl failed.\n" " Could not get the target inquiry data" " from FCP.")); break; case L_FSTAT_ERROR: (void) sprintf(err_msg, MSGSTR(10095, " fstat() error: Cannot obtain status" " for the device.")); break; case L_FCIO_GET_HOST_PARAMS_FAIL: (void) sprintf(err_msg, MSGSTR(10097, " Error: FCIO_GET_HOST_PARAMS ioctl failed.\n" " Could not get the host parameters.")); break; case L_STAT_ERROR: (void) sprintf(err_msg, MSGSTR(10099, " stat() error: Cannot obtain status" " for the device.")); break; case L_DEV_SNAPSHOT_FAILED: (void) sprintf(err_msg, MSGSTR(10100, " Error: Could not retrieve device tree" " snapshot.")); break; case L_LOOPBACK_UNSUPPORTED: (void) sprintf(err_msg, MSGSTR(10101, " Error: Loopback mode is unsupported for this" " device.")); break; case L_LOOPBACK_FAILED: (void) sprintf(err_msg, MSGSTR(10102, " Error: Error occurred during loopback mode" " set.")); break; case L_FCIO_GET_TOPOLOGY_FAIL: (void) sprintf(err_msg, MSGSTR(10103, " Error: FCIO_GET_TOPOLOGY ioctl failed.\n" " Could not get the fca port topology.")); break; case L_UNEXPECTED_FC_TOPOLOGY: (void) sprintf(err_msg, MSGSTR(10104, " Error: Unexpected Fibre Channel topology" " found.")); break; case L_INVALID_PRIVATE_LOOP_ADDRESS: (void) sprintf(err_msg, MSGSTR(10105, " Error: AL_PA is not a valid private loop" " address.")); break; case L_NO_FABRIC_ADDR_FOUND: (void) sprintf(err_msg, MSGSTR(10106, " Error: Could not find the fabric address" " for the device at physical path.")); break; case L_INVALID_FABRIC_ADDRESS: (void) sprintf(err_msg, MSGSTR(10107, " Error: Device port address on the Fabric" " topology is not valid.")); break; case L_PT_PT_FC_TOP_NOT_SUPPORTED: (void) sprintf(err_msg, MSGSTR(10108, " Error: Point to Point Fibre Channel " "topology is currently not supported.")); break; case L_FCIO_DEV_LOGIN_FAIL: (void) sprintf(err_msg, MSGSTR(10310, " Error: FCIO_DEV_LOGIN ioctl failed.")); break; case L_FCIO_DEV_LOGOUT_FAIL: (void) sprintf(err_msg, MSGSTR(10311, " Error: FCIO_DEV_LOGOUT ioctl failed.")); break; case L_OPNOSUPP_ON_TOPOLOGY: (void) sprintf(err_msg, MSGSTR(10312, " Error: operation not supported " "on connected topology.")); break; case L_INVALID_PATH_TYPE: (void) sprintf(err_msg, MSGSTR(10313, " Error: operation not supported " "on the path.")); break; case L_FCIO_GET_STATE_FAIL: (void) sprintf(err_msg, MSGSTR(10314, " Error: FCIO_GET_STATE ioctl failed.")); break; case L_WWN_NOT_FOUND_IN_DEV_LIST: (void) sprintf(err_msg, MSGSTR(10315, " Error: device WWN not found in " "device list.")); break; case L_STAT_RMT_DIR_ERROR: (void) sprintf(err_msg, MSGSTR(10110, " stat() error: Could not get status" " for /dev/rmt directory.")); break; case L_STAT_DEV_DIR_ERROR: (void) sprintf(err_msg, MSGSTR(10111, " stat() error: Could not get status" " for /dev/dsk directory.")); break; case L_PROM_INIT_FAILED: (void) sprintf(err_msg, MSGSTR(10234, " Error: di_prom_init failure")); break; case L_PORT_DRIVER_NOT_FOUND: (void) sprintf(err_msg, MSGSTR(10113, " Error: requested port driver" " does not exist")); break; case L_PHYS_PATH_NOT_FOUND: (void) sprintf(err_msg, MSGSTR(10114, " Error: requested phys path does not exist")); break; case L_GET_DEV_LIST_ULP_FAILURE: (void) sprintf(err_msg, MSGSTR(10150, " Error: g_get_dev_list failed on ULP " "processing of target device(s)")); break; case L_SCSI_VHCI_ERROR: (void) sprintf(err_msg, MSGSTR(10230, " Error: Unable to perform failover")); break; case L_SCSI_VHCI_ALREADY_ACTIVE: (void) sprintf(err_msg, MSGSTR(10231, " Error: Pathclass already active")); break; case L_NO_DEVID: (void) sprintf(err_msg, MSGSTR(10232, " Error: No device identifier found")); break; case L_DRIVER_NOTSUPP: (void) sprintf(err_msg, MSGSTR(10233, " Error: Driver not supported")); break; case L_PROC_WWN_ARG_ERROR: (void) sprintf(err_msg, MSGSTR(10235, " Error: process WWN argument")); break; case L_NO_WWN_PROP_FOUND: (void) sprintf(err_msg, MSGSTR(10236, " Error: WWN prop not found")); break; case L_NO_DRIVER_NODES_FOUND: (void) sprintf(err_msg, MSGSTR(10237, " Error: Requested driver nodes not found")); break; case L_INVALID_MAP_DEV_ADDR: (void) sprintf(err_msg, MSGSTR(10330, " Error: Invalid map device handle found")); break; case L_INVALID_MAP_DEV_PROP_TYPE: (void) sprintf(err_msg, MSGSTR(10331, " Error: Invalid device property type found")); break; case L_INVALID_MAP_DEV_PROP_NAME: (void) sprintf(err_msg, MSGSTR(10332, " Error: Invalid device property name found")); break; case L_INVALID_MAP_DEV_PROP: (void) sprintf(err_msg, MSGSTR(10333, " Error: Invalid device property handle " "found")); break; case L_SCSI_VHCI_NO_STANDBY: (void) sprintf(err_msg, MSGSTR(10334, " Error: Unable to perform failover, " "standby path unavailable")); break; case L_SCSI_VHCI_FAILOVER_NOTSUP: (void) sprintf(err_msg, MSGSTR(10335, " Error: Device does not support failover")); break; case L_SCSI_VHCI_FAILOVER_BUSY: (void) sprintf(err_msg, MSGSTR(10336, " Error: Failover currently in progress")); break; case L_NO_SUCH_DEV_FOUND: (void) sprintf(err_msg, MSGSTR(10337, " Error: No such device found")); break; case L_NO_SUCH_PROP_FOUND: (void) sprintf(err_msg, MSGSTR(10338, " Error: No such property found")); break; case L_INVALID_ARG: (void) sprintf(err_msg, MSGSTR(10339, " Error: Invalid argument found")); break; default: if (((L_SCSI_ERROR ^ errornum) == STATUS_GOOD) || ((L_SCSI_ERROR ^ errornum) == STATUS_BUSY) || ((L_SCSI_ERROR ^ errornum) == STATUS_CHECK) || ((L_SCSI_ERROR ^ errornum) == STATUS_MET) || ((L_SCSI_ERROR ^ errornum) == STATUS_INTERMEDIATE) || ((L_SCSI_ERROR ^ errornum) == STATUS_INTERMEDIATE_MET) || ((L_SCSI_ERROR ^ errornum) == STATUS_RESERVATION_CONFLICT) || ((L_SCSI_ERROR ^ errornum) == STATUS_TERMINATED) || ((L_SCSI_ERROR ^ errornum) == STATUS_QFULL)) { (void) sprintf(err_msg, MSGSTR(10080, " SCSI Error - Sense Byte:(0x%x) %s \n" " Error: Retry failed."), (L_SCSI_ERROR ^ errornum) & STATUS_MASK, decode_sense_byte((uchar_t)L_SCSI_ERROR ^ errornum)); } else { (void) sprintf(err_msg, MSGSTR(10081, " Error: could not decode the" " error message.\n" " The given error message is not" " defined in the library.\n" " Message number: %d.\n"), errornum); } } /* end of switch */ errStrg = alloc_string(err_msg); return (errStrg); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "common.h" static int parse_line(char *line, char *path, char *wwn, char *filename); static int create_ap_instance(char *ap_id, char *wwn_string, char *filename, char *line); static void log_error(char *msg_id, char *input_tmplt, ...); static char ctoi(char c); /* * Simple wrapper for syslog error messages. * Allows easy addition of syserr output if desired. */ static void log_error(char *msg_id, char *input_tmplt, ...) { va_list ap; char input_merged_msg[200]; char *msg_template = "ID[luxadm.create_fabric_device.%s] %s"; /* * First %s for msg_id in merged msg. * Second %s is for input merged_msg */ char *merged_msg; va_start(ap, input_tmplt); /* insert caller's args */ (void) vsprintf(input_merged_msg, input_tmplt, ap); va_end(ap); merged_msg = (char *)malloc(strlen(msg_template) + strlen(input_merged_msg) + strlen(msg_id) + 1); if (merged_msg == NULL) { syslog(LOG_ERR, "ID[luxadm.create_fabric_device.2317] " "malloc failure, %s", strerror(errno)); } else { sprintf(merged_msg, msg_template, msg_id, input_merged_msg); /* first insert msg_id */ syslog(LOG_ERR, merged_msg, ""); (void) puts(merged_msg); /* also print message */ free(merged_msg); } } /* * Routines for reading tapestry repository file */ #define COMMENT_CHAR '#' int read_repos_file(char *repos_filename) { int fd; char *line; char *tmp_ptr, *mmap_ptr; char path[MAXPATHLEN]; int ret; char wwn[FC_WWN_SIZE*2+1]; struct stat stbuf; unsigned int filesize; unsigned int bytes_read; if (repos_filename == NULL || *repos_filename == '\0') { log_error("2310", "filename missing for -f option of " "luxadm -e create_fabric_device"); return (-1); } fd = open(repos_filename, O_RDONLY); if (fd == -1) { log_error("2311", "fopen failed: cannot open repository file %s. %d", repos_filename, strerror(errno)); return (-1); } if (fstat(fd, &stbuf) == -1) { close(fd); log_error("2312", "stat failed on file %s. %s", repos_filename, strerror(errno)); return (-1); } filesize = stbuf.st_size; tmp_ptr = mmap_ptr = mmap((caddr_t)0, filesize, (PROT_READ | PROT_WRITE), MAP_PRIVATE, fd, 0); if (mmap_ptr == MAP_FAILED) { log_error("2315", "Failed to mmap file %s. %s", repos_filename, strerror(errno)); return (-1); } bytes_read = 0; while (bytes_read < filesize) { line = tmp_ptr; while (bytes_read < filesize && *tmp_ptr != '\n') { bytes_read++; tmp_ptr++; } if (*tmp_ptr == '\n') { *tmp_ptr = '\0'; tmp_ptr++; bytes_read++; } /* If the line is a comment, read another line */ if (*line == COMMENT_CHAR) { continue; } ret = parse_line(line, path, wwn, repos_filename); if (ret == 0) { ret = create_ap_instance(path, wwn, repos_filename, line); } } ret = close(fd); ret = munmap(mmap_ptr, filesize); return (ret); } /* * Input is paramater 1 - a line from repository * Output is other parameters, the path to the attachment point, * and the port wwn are parsed from the repository * Format is * "/devices/pci..../fp@1,0:fc::wwn" * If controller name is missing, that's okay. Other fields * must be present * * Return 0 on success or -1 on failure; all failures logged to syslog. */ #define WWN_DELIM "::" static int parse_line(char *line, char *path, char *wwn, char *filename) { char *p_path, *p_wwn, *p_delim; char *line_copy; line_copy = strdup(line); if (line_copy == NULL) { log_error("2317", "malloc failure, %s", strerror(errno)); } p_path = line_copy; p_delim = strstr(p_path, WWN_DELIM); if (p_delim == NULL) { log_error("2313", "Invalid line (%s) in file %s.", line, filename); free(line_copy); return (-1); } *p_delim = '\0'; /* NULL terminate path */ if (strlcpy(path, p_path, MAXPATHLEN) >= MAXPATHLEN) { log_error("2318", "Path too long (%s) in file %s.", p_path, filename); free(line_copy); return (-1); } p_wwn = p_delim + strlen(WWN_DELIM); /* * Now look for the blank delimiter before the controller * * This is just the case when there may be a controller # * after the attachment point and WWN. For example - * /devices/pci@b,2000/pci@2/SUNW,qlc@4/fp@0,0:fc::220000203707f4f1 c4 */ p_delim = strchr(p_wwn, ' '); if (p_delim != NULL) { /* now p_delim points to blank */ *p_delim = '\0'; /* terminate wwn at delim */ } else { char *p_last_char; p_last_char = p_wwn+strlen(p_wwn)-1; if (*p_last_char == '\n') { *p_last_char = '\0'; } } strcpy(wwn, p_wwn); free(line_copy); return (0); } static char ctoi(char c) { if ((c >= '0') && (c <= '9')) c -= '0'; else if ((c >= 'A') && (c <= 'F')) c = c - 'A' + 10; else if ((c >= 'a') && (c <= 'f')) c = c - 'a' + 10; else c = -1; return (c); } /* * "string" is Input and "port_wwn" has the output * * This function converts a string to WWN. * For example a string like * "220000203707F4F1" gets converted to 0x220000203707F4F1 ... * where * port_wwn[0] = 0x22, * port_wwn[1] = 0x00, * port_wwn[2] = 0x00, * port_wwn[3] = 0x20, * port_wwn[4] = 0x37, * port_wwn[5] = 0x07, * port_wwn[6] = 0xF4, and * port_wwn[7] = 0xF1 */ static int string_to_wwn(const uchar_t *string, uchar_t *port_wwn) { int i; char c, c1; uchar_t *wwnp; wwnp = port_wwn; for (i = 0; i < WWN_SIZE; i++, wwnp++) { c = ctoi(*string++); c1 = ctoi(*string++); if (c == -1 || c1 == -1) return (-1); *wwnp = ((c << 4) + c1); } return (0); } static int create_ap_instance(char *ap_id, char *wwn_string, char *filename, char *line) { devctl_hdl_t bus_handle, dev_handle; devctl_ddef_t ddef_handle; int ret; uchar_t wwn_array[FC_WWN_SIZE]; ddef_handle = devctl_ddef_alloc("dummy", 0); if (ddef_handle == NULL) { log_error("2314", "Internal error to process line (%s) in file: %s. %s", line, filename, strerror(errno)); return (-1); } /* * g_string_to_wwn() has not been used here because it * prepends 2 NULLs. */ if (string_to_wwn((uchar_t *)wwn_string, wwn_array) != 0) { log_error("2314", "Internal error to process line (%s) in file: %s. %s", line, filename, strerror(errno)); devctl_ddef_free(ddef_handle); return (-1); } (void) devctl_ddef_byte_array(ddef_handle, "port-wwn", FC_WWN_SIZE, wwn_array); if ((bus_handle = devctl_bus_acquire(ap_id, 0)) == NULL) { devctl_ddef_free(ddef_handle); log_error("2314", "Internal error to process line (%s) in file: %s. %s", line, filename, strerror(errno)); return (-1); } if (ret = devctl_bus_dev_create(bus_handle, ddef_handle, 0, &dev_handle)) { devctl_ddef_free(ddef_handle); devctl_release(bus_handle); log_error("2316", "configuration failed for line (%s) in file: %s. %s", line, filename, strerror(errno)); return (-1); } devctl_release(dev_handle); devctl_ddef_free(ddef_handle); devctl_release(bus_handle); return (ret); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * I18N message number ranges * This file: 4500 - 4999 * Shared common messages: 1 - 1999 */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* * The following define is not to * include sys/fc4/fcal_linkapp.h * file from sys/socalio.h, since it * has same structure defines as in * sys/fibre-channel/fcio.h. */ #define _SYS_FC4_FCAL_LINKAPP_H #include #include #include #include #include #include #include #include "luxadm.h" /* Defines */ #define FEPROM_SIZE 256*1024 #define FEPROM_MAX_PROGRAM 25 #define FEPROM_MAX_ERASE 1000 #define FEPROM_READ_MEMORY 0x00 #define FEPROM_ERASE 0x20 #define FEPROM_ERASE_VERIFY 0xa0 #define FEPROM_PROGRAM 0x40 #define FEPROM_PROGRAM_VERIFY 0xc0 #define FEPROM_RESET 0xff #define HBA_MAX 128 #define FOUND 0 #define NOT_FOUND 1 #define PROM_SIZ 0x20010 #define MAX_RETRIES 3 #define MAX_WAIT_TIME 30 /* * The next define is to work around a problem with sbusmem driver not * able to round up mmap() requests that are not around page boundaries. */ #define PROM_SIZ_ROUNDED 0x22000 #define SAMPLE_SIZ 0x100 #define REG_OFFSET 0x20000 #define FEPROM_WWN_OFFSET 0x3fe00 #define FEPROM_SUN_WWN 0x50200200 /* * We'll leave this on leadville, as the onboard * isn't allowed to be zapped by luxadm */ #define ONBOARD_SOCAL "SUNW,socal@d" #define SOCAL_STR "SUNW,socal" #define SOCAL_STR_LEN 10 static uchar_t buffer[FEPROM_SIZE]; static char sbus_list[HBA_MAX][PATH_MAX]; static char sbussoc_list[HBA_MAX][PATH_MAX]; static char bootpath[PATH_MAX]; static char version[MAXNAMELEN]; static uint_t getsbuslist(void); static int load_file(char *, caddr_t, volatile socal_reg_t *); static void usec_delay(int); static void getbootdev(unsigned int); static void getsocpath(char *, int *); static int loadsocpath(const char *, int *); static int warn(void); static int findversion(int, uchar_t *); static int write_feprom(uchar_t *, uchar_t *, volatile socal_reg_t *); static int feprom_erase(volatile uchar_t *, volatile socal_reg_t *); static struct exec exec; int fcal_update(unsigned int verbose, char *file) /*ARGSUSED*/ { int fd, strfound = 0, retval = 0; int fbuf_idx, fd1, bytes_read; caddr_t addr; uint_t i; uint_t fflag = 0; uint_t vflag = 0; uint_t numslots; volatile socal_reg_t *regs; char *slotname, socal[MAXNAMELEN]; char fbuf[BUFSIZ]; if (!file) vflag++; else { fflag++; if ((fd1 = open(file, O_RDONLY)) == -1) { (void) fprintf(stderr, MSGSTR(4500, "Error: open() failed on file " "%s\n"), file); return (1); } /* * We will just make a check to see if it the file * has the "SUNW,socal" strings in it * We cannot use strstr() here because we are operating on * binary data and so is very likely to have embedded NULLs */ while (!strfound && ((bytes_read = read(fd1, fbuf, BUFSIZ)) > 0)) { for (fbuf_idx = 0; fbuf_idx < bytes_read; fbuf_idx++) { /* First check for the SUNW,socal string */ if (strncmp((fbuf + fbuf_idx), SOCAL_STR, SOCAL_STR_LEN) == 0) { strfound = 1; break; } } } (void) close(fd1); if (!strfound) { (void) fprintf(stderr, MSGSTR(4501, "Error: %s is not a " "FC100/S Fcode file\n"), file); return (1); } } /* * Get count of, and names of SBus slots using the SBus memory * interface. */ (void) getbootdev(verbose); if (getenv("_LUX_D_DEBUG") != NULL) { (void) fprintf(stdout, " Bootpath: %s\n", bootpath); } numslots = getsbuslist(); (void) fprintf(stdout, MSGSTR(4503, "\n Found Path to %d FC100/S Cards\n"), numslots); for (i = 0; i < numslots; i++) { /* * Open SBus memory for this slot. */ slotname = &sbus_list[i][0]; if (fflag && (strcmp(slotname, bootpath) == 0)) { (void) fprintf(stderr, MSGSTR(4504, " Ignoring %s (bootpath)\n"), slotname); continue; } (void) sprintf(socal, "%s:0", &sbussoc_list[i][0]); if ((fd = open(socal, O_RDWR)) < 0) { (void) sprintf(socal, "%s:1", &sbussoc_list[i][0]); if ((fd = open(socal, O_RDWR)) < 0) { (void) fprintf(stderr, MSGSTR(4505, "Could not open %s\n"), &sbussoc_list[i][0]); (void) fprintf(stderr, MSGSTR(4506, "Ignoring %s\n"), &sbussoc_list[i][0]); retval++; continue; } } (void) close(fd); if (verbose) { (void) fprintf(stdout, "\n "); (void) fprintf(stdout, MSGSTR(85, "Opening %s\n"), slotname); } fd = open(slotname, O_RDWR); if (fd < 0) { perror(MSGSTR(4507, "open of slotname")); retval++; continue; } /* * Mmap that SBus memory into my memory space. */ addr = mmap((caddr_t)0, PROM_SIZ_ROUNDED, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0); if (addr == MAP_FAILED) { perror(MSGSTR(46, "mmap")); (void) close(fd); retval++; continue; } if ((int)addr == -1) { perror(MSGSTR(46, "mmap")); (void) close(fd); retval++; continue; } regs = (socal_reg_t *)((int)addr + REG_OFFSET); (void) fprintf(stdout, MSGSTR(4508, "\n Device: %s\n"), &sbussoc_list[i][0]); /* * Load the New FCode */ if (fflag) { if (!warn()) retval += load_file(file, addr, regs); } else if (vflag) { if (findversion(i, (uchar_t *)&version[0]) == FOUND) { (void) fprintf(stdout, MSGSTR(4509, " Detected FC100/S Version: %s\n"), version); } } if (munmap(addr, PROM_SIZ) == -1) { perror(MSGSTR(4510, "munmap")); retval++; } (void) close(fd); } (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(125, "Complete\n")); return (retval); } static int findversion(int index, uchar_t *version) /*ARGSUSED*/ { int fd = 0, ntries; struct socal_fm_version *buffer; char socal[MAXNAMELEN]; char fp[MAXNAMELEN]; char prom_ver[100]; char mcode_ver[100]; uint_t dev_type; fcio_t fcio; char fw_rev[FC_FW_REV_SIZE + 1]; if ((dev_type = g_get_path_type(&sbussoc_list[index][0])) == 0) { return (L_INVALID_PATH); } if (dev_type & FC4_FCA_MASK) { P_DPRINTF("findversion: found an FC4 path\n"); (void) sprintf(socal, "%s:0", &sbussoc_list[index][0]); if ((fd = open(socal, O_RDWR)) < 0) { (void) sprintf(socal, "%s:1", &sbussoc_list[index][0]); if ((fd = open(socal, O_RDWR)) < 0) { (void) fprintf(stderr, MSGSTR(4511, "Could not open %s\n"), &sbussoc_list[index][0]); (void) close(fd); return (NOT_FOUND); } } if ((buffer = (struct socal_fm_version *)malloc( sizeof (struct socal_fm_version))) == NULL) { (void) fprintf(stderr, MSGSTR(10, " Error: Unable to allocate memory.")); (void) fprintf(stderr, "\n"); (void) close(fd); return (NOT_FOUND); } buffer->fcode_ver = (char *)version; buffer->mcode_ver = mcode_ver; buffer->prom_ver = prom_ver; buffer->fcode_ver_len = MAXNAMELEN - 1; buffer->mcode_ver_len = 100; buffer->prom_ver_len = 100; if (ioctl(fd, FCIO_FCODE_MCODE_VERSION, buffer) < 0) { (void) fprintf(stderr, MSGSTR(4512, "fcal_s_download: could not get" " fcode version.\n")); (void) close(fd); (void) free(buffer); return (NOT_FOUND); } version[buffer->fcode_ver_len] = '\0'; free(buffer); } else if (dev_type & FC_FCA_MASK) { /* * Get the fcode and prom's fw version * using new ioctls. Currently, we pass * only the fcode version to the calling function * and ignore the FW version (using the existing * implementation). The function definition * might be changed in future to pass both the * fcode and FW revisions to the calling function, if * needed by the calling function. */ P_DPRINTF("findversion: found an FC path\n"); (void) sprintf(fp, "%s/fp@0,0:devctl", &sbussoc_list[index][0]); if ((fd = open(fp, O_RDWR)) < 0) { (void) sprintf(fp, "%s/fp@1,0:devctl", &sbussoc_list[index][0]); if ((fd = open(fp, O_RDWR)) < 0) { (void) fprintf(stderr, MSGSTR(4511, "Could not open %s\n"), &sbussoc_list[index][0]); (void) close(fd); return (NOT_FOUND); } } /* Get the fcode version */ bzero(version, sizeof (version)); fcio.fcio_cmd = FCIO_GET_FCODE_REV; /* Information read operation */ fcio.fcio_xfer = FCIO_XFER_READ; fcio.fcio_obuf = (caddr_t)version; fcio.fcio_olen = MAXNAMELEN; for (ntries = 0; ntries < MAX_RETRIES; ntries++) { if (ioctl(fd, FCIO_CMD, &fcio) != 0) { if ((errno == EAGAIN) && (ntries+1 < MAX_RETRIES)) { /* wait 30 secs */ (void) sleep(MAX_WAIT_TIME); continue; } I_DPRINTF("ioctl FCIO_GET_FCODE_REV failed.\n" "Error: %s\n", strerror(errno)); (void) close(fd); return (L_FCIO_GET_FCODE_REV_FAIL); } break; } version[MAXNAMELEN-1] = '\0'; /* Get the FW revision */ bzero(fw_rev, sizeof (fw_rev)); fcio.fcio_cmd = FCIO_GET_FW_REV; /* Information read operation */ fcio.fcio_xfer = FCIO_XFER_READ; fcio.fcio_obuf = (caddr_t)fw_rev; fcio.fcio_olen = FC_FW_REV_SIZE; for (ntries = 0; ntries < MAX_RETRIES; ntries++) { if (ioctl(fd, FCIO_CMD, &fcio) != 0) { if ((errno == EAGAIN) && (ntries+1 < MAX_RETRIES)) { /* wait 30 secs */ (void) sleep(MAX_WAIT_TIME); continue; } I_DPRINTF(" FCIO_GET_FW_REV ioctl failed.\n" " Error: %s\n", strerror(errno)); (void) close(fd); return (L_FCIO_GET_FW_REV_FAIL); } break; } } (void) close(fd); return (FOUND); } /* * program an FEprom with data from 'source_address'. * program the FEprom with zeroes, * erase it, * program it with the real data. */ static int feprom_program(uchar_t *source_address, uchar_t *dest_address, volatile socal_reg_t *regs) { int i; (void) fprintf(stdout, MSGSTR(4513, "Filling with zeroes...\n")); if (!write_feprom((uchar_t *)0, dest_address, regs)) { (void) fprintf(stderr, MSGSTR(4514, "FEprom at 0x%x: zero fill failed\n"), (int)dest_address); return (0); } (void) fprintf(stdout, MSGSTR(4515, "Erasing...\n")); for (i = 0; i < FEPROM_MAX_ERASE; i++) { if (feprom_erase(dest_address, regs)) break; } if (i >= FEPROM_MAX_ERASE) { (void) fprintf(stderr, MSGSTR(4516, "FEprom at 0x%x: failed to erase\n"), (int)dest_address); return (0); } else if (i > 0) { if (i == 1) { (void) fprintf(stderr, MSGSTR(4517, "FEprom erased after %d attempt\n"), i); } else { (void) fprintf(stderr, MSGSTR(4518, "FEprom erased after %d attempts\n"), i); } } (void) fprintf(stdout, MSGSTR(4519, "Programming...\n")); if (!(write_feprom(source_address, dest_address, regs))) { (void) fprintf(stderr, MSGSTR(4520, "FEprom at 0x%x: write failed\n"), (int)dest_address); return (0); } /* select the zeroth bank at end so we can read it */ regs->socal_cr.w &= ~(0x30000); (void) fprintf(stdout, MSGSTR(4521, "Programming done\n")); return (1); } /* * program an FEprom one byte at a time using hot electron injection. */ static int write_feprom(uchar_t *source_address, uchar_t *dest_address, volatile socal_reg_t *regs) { int pulse, i; uchar_t *s = source_address; volatile uchar_t *d; for (i = 0; i < FEPROM_SIZE; i++, s++) { if ((i & 0xffff) == 0) { (void) fprintf(stdout, MSGSTR(4522, "selecting bank %d\n"), i>>16); regs->socal_cr.w &= ~(0x30000); regs->socal_cr.w |= i & 0x30000; } d = dest_address + (i & 0xffff); for (pulse = 0; pulse < FEPROM_MAX_PROGRAM; pulse++) { *d = FEPROM_PROGRAM; *d = source_address ? *s : 0; usec_delay(50); *d = FEPROM_PROGRAM_VERIFY; usec_delay(30); if (*d == (source_address ? *s : 0)) break; } if (pulse >= FEPROM_MAX_PROGRAM) { *dest_address = FEPROM_RESET; return (0); } } *dest_address = FEPROM_RESET; return (1); } /* * erase an FEprom using Fowler-Nordheim tunneling. */ static int feprom_erase(volatile uchar_t *dest_address, volatile socal_reg_t *regs) { int i; volatile uchar_t *d = dest_address; *d = FEPROM_ERASE; usec_delay(50); *d = FEPROM_ERASE; usec_delay(10000); /* wait 10ms while FEprom erases */ for (i = 0; i < FEPROM_SIZE; i++) { if ((i & 0xffff) == 0) { regs->socal_cr.w &= ~(0x30000); regs->socal_cr.w |= i & 0x30000; } d = dest_address + (i & 0xffff); *d = FEPROM_ERASE_VERIFY; usec_delay(50); if (*d != 0xff) { *dest_address = FEPROM_RESET; return (0); } } *dest_address = FEPROM_RESET; return (1); } static void usec_delay(int s) { hrtime_t now, then; now = gethrtime(); then = now + s*1000; do { now = gethrtime(); } while (now < then); } static uint_t getsbuslist(void) { int devcnt = 0; char devpath[PATH_MAX]; /* We're searching the /devices directory, so... */ (void) strcpy(devpath, "/devices"); /* get the directory entries under /devices for socal sbusmem */ (void) getsocpath(devpath, (int *)&devcnt); return (devcnt); } static void getbootdev(unsigned int verbose) { char *df = "df /"; FILE *ptr; char *p = NULL, *p1; char bootdev[PATH_MAX]; char buf[BUFSIZ]; int foundroot = 0; if ((ptr = popen(df, "r")) != NULL) { while (fgets(buf, BUFSIZ, ptr) != NULL) { if (p = strstr(buf, "/dev/dsk/")) { (void) memset((char *)&bootdev[0], 0, PATH_MAX); p1 = p; while (*p1 != '\0') { if (!isalnum(*p1) && (*p1 != '/')) *p1 = ' '; p1++; } (void) sscanf(p, "%s", bootdev); foundroot = 1; } } if (!foundroot) { if (verbose) (void) fprintf(stderr, MSGSTR(44, "root is not on a local disk!\n")); (void) memset((char *)&bootpath[0], 0, PATH_MAX); return; } (void) pclose(ptr); if (bootdev[0]) { char *ls; char *p1; char *p2 = NULL; char *sbusmem = "/sbusmem@"; char *slot = ",0:slot"; ls = (char *)malloc(PATH_MAX); (void) memset((char *)ls, 0, PATH_MAX); (void) strcpy(ls, "ls -l "); (void) strcat(ls, bootdev); if ((ptr = popen(ls, "r")) != NULL) { while (fgets(buf, BUFSIZ, ptr) != NULL) { if (p = strstr(buf, "/devices")) { if (p1 = strstr(buf, "sbus")) { while (*p1 != '/') p1++; p2 = strstr(p1, "@"); ++p2; *p1 = '\0'; } else { if (p1 = strstr(buf, SOCAL_STR)) { p2 = strstr(p1, "@"); ++p2; --p1; *p1 = '\0'; } } } } (void) pclose(ptr); } (void) memset((char *)&bootdev[0], 0, PATH_MAX); (void) sscanf(p, "%s", bootdev); (void) memset((char *)&bootpath[0], 0, PATH_MAX); (void) strcat(bootpath, bootdev); (void) strcat(bootpath, sbusmem); if (p2) { (void) strncat(bootpath, p2, 1); (void) strcat(bootpath, slot); (void) strncat(bootpath, p2, 1); } } } } /* * This function reads "size" bytes from the FC100/S PROM. * source_address: PROM address * dest_address: local memeory * offset: Location in PROM to start reading from. */ static void feprom_read(uchar_t *source_address, uchar_t *dest_address, int offset, int size, volatile socal_reg_t *regs) { uchar_t *s = source_address; uchar_t *d = dest_address; int i = offset; if (getenv("_LUX_D_DEBUG") != NULL) { (void) fprintf(stdout, " feprom_read: selecting bank %d\n", (i&0xf0000)>>16); if (size <= 8) { (void) fprintf(stdout, " Data read: "); } } regs->socal_cr.w = i & 0xf0000; s = source_address + (i & 0xffff); *s = FEPROM_READ_MEMORY; usec_delay(6); for (; s < source_address + (i & 0xffff) + size; d++, s++) { *d = *s; if ((getenv("_LUX_D_DEBUG") != NULL) && (size <= 8)) { (void) fprintf(stdout, "0x%x ", *d); } } if ((getenv("_LUX_D_DEBUG") != NULL) && (size <= 8)) { (void) fprintf(stdout, "\n From offset: 0x%x\n", offset); } } static int load_file(char *file, caddr_t prom, volatile socal_reg_t *regs) { uint_t wwn_d8, wwn_lo; uint_t wwn_hi; int ffd = open(file, 0); wwn_hi = FEPROM_SUN_WWN; if (ffd < 0) { perror(MSGSTR(4524, "open of file")); exit(1); } (void) fprintf(stdout, MSGSTR(4525, "Loading FCode: %s\n"), file); if (read(ffd, &exec, sizeof (exec)) != sizeof (exec)) { perror(MSGSTR(4526, "read exec")); exit(1); } if (exec.a_trsize || exec.a_drsize) { (void) fprintf(stderr, MSGSTR(4527, "%s: is relocatable\n"), file); exit(1); } if (exec.a_data || exec.a_bss) { (void) fprintf(stderr, MSGSTR(4528, "%s: has data or bss\n"), file); exit(1); } if (exec.a_machtype != M_SPARC) { (void) fprintf(stderr, MSGSTR(4529, "%s: not for SPARC\n"), file); exit(1); } (void) fprintf(stdout, MSGSTR(4530, "Loading 0x%x bytes from %s at offset 0x%x\n"), (int)exec.a_text, file, 0); if (read(ffd, &buffer, exec.a_text) != exec.a_text) { perror(MSGSTR(4531, "read")); exit(1); } (void) close(ffd); feprom_read((uchar_t *)prom, (uchar_t *)&wwn_d8, FEPROM_WWN_OFFSET, 4, regs); feprom_read((uchar_t *)prom, (uchar_t *)&wwn_lo, FEPROM_WWN_OFFSET + 4, 4, regs); wwn_hi |= wwn_d8 & 0x0f; /* only last digit is interesting */ if (getenv("_LUX_D_DEBUG") != NULL) { (void) fprintf(stdout, " load_file: Writing WWN hi:0x%x lo:0x%x " "to the FC100/S PROM\n", wwn_hi, wwn_lo); } /* put wwn into buffer location */ bcopy((const void *)&wwn_hi, (void *)&buffer[FEPROM_WWN_OFFSET], sizeof (wwn_hi)); bcopy((const void *)&wwn_lo, (void *)&buffer[FEPROM_WWN_OFFSET + 4], sizeof (wwn_lo)); bcopy((const void *)&wwn_hi, (void *)&buffer[FEPROM_WWN_OFFSET + 8], sizeof (wwn_hi)); bcopy((const void *)&wwn_lo, (void *)&buffer[FEPROM_WWN_OFFSET + 0xc], sizeof (wwn_lo)); if (feprom_program((uchar_t *)buffer, (uchar_t *)prom, regs) == 0) { /* here 0 means failure */ return (1); } return (0); } static int warn(void) { char input[1024]; input[0] = '\0'; (void) fprintf(stderr, MSGSTR(4532, "\nWARNING!! This program will update the FCode in this FC100/S Sbus Card.\n")); (void) fprintf(stderr, MSGSTR(4533, "This may take a few (5) minutes. Please be patient.\n")); loop1: (void) fprintf(stderr, MSGSTR(4534, "Do you wish to continue ? (y/n) ")); (void) gets(input); if ((strcmp(input, MSGSTR(4535, "y")) == 0) || (strcmp(input, MSGSTR(40, "yes")) == 0)) { return (FOUND); } else if ((strcmp(input, MSGSTR(4536, "n")) == 0) || (strcmp(input, MSGSTR(45, "no")) == 0)) { (void) fprintf(stderr, MSGSTR(4537, "Not Downloading FCode\n")); return (NOT_FOUND); } else { (void) fprintf(stderr, MSGSTR(4538, "Invalid input\n")); goto loop1; } } /* * getsocpath(): * Searches the /devices directory recursively returning all soc_name * entries in sbussoc_list (global). This excludes port entries and * onboard socal (which leaves only directory entries with * soc_name included). devcnt is updated to reflect number of soc_name * devices found. */ static void getsocpath(char *devpath, int *devcnt) { struct stat statbuf; struct dirent *dirp; DIR *dp; char *ptr; if (lstat(devpath, &statbuf) < 0) { (void) fprintf(stderr, MSGSTR(4539, "Error: %s lstat() error\n"), devpath); exit(1); } if (S_ISDIR(statbuf.st_mode) == 0) /* * not a directory so * we don't care about it - return */ return; else { if (strstr(devpath, ONBOARD_SOCAL)) return; if (strstr(devpath, SOCAL_STR)) { /* It's a keeper - call the load function */ if ((loadsocpath(devpath, devcnt)) < 0) { (void) fprintf(stderr, MSGSTR(4540, "Error: Cannot set device list\n"), devpath); exit(1); } /* * if socal directory - return, * nothing else to see here */ return; } } /* * It's a directory. Call ourself to * traverse the path(s) */ ptr = devpath + strlen(devpath); *ptr++ = '/'; *ptr = 0; /* Forget the /devices/pseudo/ directory */ if (strcmp(devpath, "/devices/pseudo/") == 0) return; if ((dp = opendir(devpath)) == NULL) { (void) fprintf(stderr, MSGSTR(4541, "Error: %s Can't read directory\n"), devpath); exit(1); } while ((dirp = readdir(dp)) != NULL) { if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0) continue; (void) strcpy(ptr, dirp->d_name); /* append name */ getsocpath(devpath, devcnt); } if (closedir(dp) < 0) { (void) fprintf(stderr, MSGSTR(4542, "Error: %s Can't close directory\n"), devpath); exit(1); } } static int loadsocpath(const char *pathname, int *devcnt) { int ret = 0; int len; int len_tmp; char *sp = NULL; char *sp_tmp; char buffer[PATH_MAX]; /* * Okay we found a device, now let's load it in to sbussoc_list * and load the sbusmem file into sbus_list */ if (pathname != NULL && *devcnt < HBA_MAX) { (void) strcpy(sbussoc_list[*devcnt], pathname); if (sp_tmp = strstr(sbussoc_list[*devcnt], SOCAL_STR)) { sp = sp_tmp; /* len_tmp will be len of "SUNW,socal@" */ len_tmp = SOCAL_STR_LEN + 1; } len = strlen(sbussoc_list[*devcnt]) - strlen(sp); (void) strncpy(buffer, sbussoc_list[*devcnt], len); buffer[len] = '\0'; sp += len_tmp; (void) sprintf(sbus_list[*devcnt], "%ssbusmem@%c,0:slot%c", buffer, sp[0], sp[0]); *devcnt += 1; } else ret = -1; return (ret); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common.h" #include "sun_fc_version.h" #define DEFAULT_LUN_COUNT 1024 #define LUN_SIZE 8 #define LUN_HEADER_SIZE 8 #define DEFAULT_LUN_LENGTH DEFAULT_LUN_COUNT * \ LUN_SIZE + \ LUN_HEADER_SIZE struct lun_val { uchar_t val[8]; }; struct rep_luns_rsp { uint32_t length; uint32_t rsrvd; struct lun_val lun[1]; }; /* Extracted from the old scsi.h file */ struct capacity_data_struct { uint_t last_block_addr; uint_t block_size; }; /* Structure to handle the inq. page 0x80 serial number */ struct page80 { uchar_t inq_dtype; uchar_t inq_page_code; uchar_t reserved; uchar_t inq_page_len; uchar_t inq_serial[251]; }; extern char *dtype[]; extern int Options; extern const int OPTION_P; int skip_hba(int i); int find_supported_inq_page(HBA_HANDLE handle, HBA_WWN hwwn, HBA_WWN pwwn, uint64_t lun, int page_num); /* * The routines within this file operate against the T11 * HBA API interface. In some cases, proprietary Sun driver * interface are also called to add additional information * above what the standard library supports. */ uint64_t wwnConversion(uchar_t *wwn) { uint64_t tmp; (void) memcpy(&tmp, wwn, sizeof (uint64_t)); return (ntohll(tmp)); } void printStatus(HBA_STATUS status) { switch (status) { case HBA_STATUS_OK: printf(MSGSTR(2410, "OK")); return; case HBA_STATUS_ERROR: printf(MSGSTR(2411, "ERROR")); return; case HBA_STATUS_ERROR_NOT_SUPPORTED: printf(MSGSTR(2412, "NOT SUPPORTED")); return; case HBA_STATUS_ERROR_INVALID_HANDLE: printf(MSGSTR(2413, "INVALID HANDLE")); return; case HBA_STATUS_ERROR_ARG: printf(MSGSTR(2414, "ERROR ARG")); return; case HBA_STATUS_ERROR_ILLEGAL_WWN: printf(MSGSTR(2415, "ILLEGAL WWN")); return; case HBA_STATUS_ERROR_ILLEGAL_INDEX: printf(MSGSTR(2416, "ILLEGAL INDEX")); return; case HBA_STATUS_ERROR_MORE_DATA: printf(MSGSTR(2417, "MORE DATA")); return; case HBA_STATUS_ERROR_STALE_DATA: printf(MSGSTR(2418, "STALE DATA")); return; case HBA_STATUS_SCSI_CHECK_CONDITION: printf(MSGSTR(2419, "SCSI CHECK CONDITION")); return; case HBA_STATUS_ERROR_BUSY: printf(MSGSTR(2420, "BUSY")); return; case HBA_STATUS_ERROR_TRY_AGAIN: printf(MSGSTR(2421, "TRY AGAIN")); return; case HBA_STATUS_ERROR_UNAVAILABLE: printf(MSGSTR(2422, "UNAVAILABLE")); return; default: printf(MSGSTR(2423, "UNKNOWN ERROR TYPE %d"), status); return; } } uint32_t getNumberOfAdapters() { uint32_t count = HBA_GetNumberOfAdapters(); if (count == 0) { fprintf(stderr, MSGSTR(2405, "\nERROR: No Fibre Channel Adapters found.\n")); } return (count); } #define MAX_RETRIES 10 /* * Returns non-zero on failure (aka, HBA_STATUS_ERROR_* * Will handle retries if applicable. */ int getAdapterAttrs(HBA_HANDLE handle, char *name, HBA_ADAPTERATTRIBUTES *attrs) { int count = 0; HBA_STATUS status = HBA_STATUS_ERROR_TRY_AGAIN; /* force first pass */ /* Loop as long as we have a retryable error */ while ((status == HBA_STATUS_ERROR_TRY_AGAIN || status == HBA_STATUS_ERROR_BUSY) && count++ < MAX_RETRIES) { status = HBA_GetAdapterAttributes(handle, attrs); if (status == HBA_STATUS_OK) { break; } (void) sleep(1); } if (status != HBA_STATUS_OK) { /* We encountered a non-retryable error */ fprintf(stderr, MSGSTR(2501, "\nERROR: Unable to retrieve adapter port details (%s)"), name); printStatus(status); fprintf(stderr, "\n"); } return (status); } /* * Returns non-zero on failure (aka, HBA_STATUS_ERROR_* * Will handle retries if applicable. */ int getAdapterPortAttrs(HBA_HANDLE handle, char *name, int portIndex, HBA_PORTATTRIBUTES *attrs) { int count = 0; HBA_STATUS status = HBA_STATUS_ERROR_TRY_AGAIN; /* force first pass */ /* Loop as long as we have a retryable error */ while ((status == HBA_STATUS_ERROR_TRY_AGAIN || status == HBA_STATUS_ERROR_BUSY) && count++ < MAX_RETRIES) { status = HBA_GetAdapterPortAttributes(handle, portIndex, attrs); if (status == HBA_STATUS_OK) { break; } /* The odds of this occuring are very slim, but possible. */ if (status == HBA_STATUS_ERROR_STALE_DATA) { /* * If we hit a stale data scenario, * we'll just tell the user to try again. */ status = HBA_STATUS_ERROR_TRY_AGAIN; break; } sleep(1); } if (status != HBA_STATUS_OK) { /* We encountered a non-retryable error */ fprintf(stderr, MSGSTR(2501, "\nERROR: Unable to retrieve adapter port details (%s)"), name); printStatus(status); fprintf(stderr, "\n"); } return (status); } /* * Returns non-zero on failure (aka, HBA_STATUS_ERROR_* * Will handle retries if applicable. */ int getDiscPortAttrs(HBA_HANDLE handle, char *name, int portIndex, int discIndex, HBA_PORTATTRIBUTES *attrs) { int count = 0; HBA_STATUS status = HBA_STATUS_ERROR_TRY_AGAIN; /* force first pass */ /* Loop as long as we have a retryable error */ while ((status == HBA_STATUS_ERROR_TRY_AGAIN || status == HBA_STATUS_ERROR_BUSY) && count++ < MAX_RETRIES) { status = HBA_GetDiscoveredPortAttributes(handle, portIndex, discIndex, attrs); if (status == HBA_STATUS_OK) { break; } /* The odds of this occuring are very slim, but possible. */ if (status == HBA_STATUS_ERROR_STALE_DATA) { /* * If we hit a stale data scenario, we'll just tell the * user to try again. */ status = HBA_STATUS_ERROR_TRY_AGAIN; break; } sleep(1); } if (status != HBA_STATUS_OK) { /* We encountered a non-retryable error */ fprintf(stderr, MSGSTR(2504, "\nERROR: Unable to retrieve target port details (%s)"), name); printStatus(status); fprintf(stderr, "\n"); } return (status); } /*ARGSUSED*/ int fchba_display_port(int verbose) { int retval = 0; HBA_HANDLE handle; HBA_ADAPTERATTRIBUTES hbaAttrs; HBA_PORTATTRIBUTES portAttrs; HBA_STATUS status; int count, adapterIndex, portIndex; char name[256]; char *physical = NULL; char path[MAXPATHLEN]; if ((retval = loadLibrary())) { return (retval); } count = getNumberOfAdapters(); for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) { if (skip_hba(adapterIndex)) { continue; } status = HBA_GetAdapterName(adapterIndex, (char *)&name); if (status != HBA_STATUS_OK) { /* Just skip it, maybe it was DR'd */ continue; } handle = HBA_OpenAdapter(name); if (handle == 0) { /* Just skip it, maybe it was DR'd */ continue; } if (getAdapterAttrs(handle, name, &hbaAttrs)) { /* This should never happen, we'll just skip the adapter */ HBA_CloseAdapter(handle); continue; } for (portIndex = 0; portIndex < hbaAttrs.NumberOfPorts; portIndex++) { if (getAdapterPortAttrs(handle, name, portIndex, &portAttrs)) { continue; } physical = get_slash_devices_from_osDevName( portAttrs.OSDeviceName, STANDARD_DEVNAME_HANDLING); if (physical) { char *tmp = strstr(physical, ":fc"); if (tmp) { *tmp = '\0'; (void) snprintf(path, MAXPATHLEN, "%s:devctl", physical); } else { (void) snprintf(path, MAXPATHLEN, "%s", physical); } free(physical); physical = NULL; (void) printf("%-65s ", path); } else { (void) printf("%-65s ", portAttrs.OSDeviceName); } if (portAttrs.NumberofDiscoveredPorts > 0) { printf(MSGSTR(2233, "CONNECTED\n")); } else { printf(MSGSTR(2234, "NOT CONNECTED\n")); } } } (void) HBA_FreeLibrary(); return (retval); } /* * Internal routines/structure to deal with a path list * so we can ensure uniqueness */ struct path_entry { char path[MAXPATHLEN]; HBA_UINT8 wwn[8]; uchar_t dtype; struct path_entry *next; }; void add_path(struct path_entry *head, struct path_entry *cur) { struct path_entry *tmp; for (tmp = head; tmp->next != NULL; tmp = tmp->next) { } tmp->next = cur; } struct path_entry *is_duplicate_path(struct path_entry *head, char *path) { struct path_entry *tmp; for (tmp = head; tmp != NULL; tmp = tmp->next) { if (strncmp(tmp->path, path, sizeof (tmp->path)) == 0) { return (tmp); } } return (NULL); } void free_path_list(struct path_entry *head) { struct path_entry *tmp; struct path_entry *tmp2; for (tmp = head; tmp != NULL; ) { tmp2 = tmp->next; free(tmp); tmp = tmp2; } } int is_wwn(char *arg) { int i; if (strlen(arg) == 16) { for (i = 0; i < 16; i++) { if (!isxdigit(arg[i])) { return (0); } } return (1); } return (0); } int is_path(char *arg) { struct stat buf; if (stat(arg, &buf)) { return (0); } return (1); } /* We take a wild guess for our first get target mappings call */ #define MAP_GUESS 50 HBA_STATUS fetch_mappings(HBA_HANDLE handle, HBA_WWN pwwn, HBA_FCPTARGETMAPPINGV2 **map) { int loop = 0; int count = 0; HBA_STATUS status = HBA_STATUS_ERROR_TRY_AGAIN; /* force first pass */ *map = (HBA_FCPTARGETMAPPINGV2 *) calloc(1, (sizeof (HBA_FCPSCSIENTRYV2)* (MAP_GUESS-1)) + sizeof (HBA_FCPTARGETMAPPINGV2)); /* Loop as long as we have a retryable error */ while ((status == HBA_STATUS_ERROR_TRY_AGAIN || status == HBA_STATUS_ERROR_BUSY || status == HBA_STATUS_ERROR_MORE_DATA) && loop++ < MAX_RETRIES) { status = HBA_GetFcpTargetMappingV2(handle, pwwn, *map); if (status == HBA_STATUS_OK) { break; } else if (status == HBA_STATUS_ERROR_MORE_DATA) { count = (*map)->NumberOfEntries; free(*map); *map = (HBA_FCPTARGETMAPPINGV2 *) calloc(1, (sizeof (HBA_FCPSCSIENTRYV2)* (count-1)) + sizeof (HBA_FCPTARGETMAPPINGV2)); (*map)->NumberOfEntries = count; continue; } sleep(1); } if (status != HBA_STATUS_OK) { /* We encountered a non-retryable error */ fprintf(stderr, MSGSTR(2502, "\nERROR: Unable to retrieve SCSI device paths " "(HBA Port WWN %016llx)"), wwnConversion(pwwn.wwn)); printStatus(status); fprintf(stderr, "\n"); } return (status); } /* * Returns the index of the first match, or -1 if no match */ int match_mappings(char *compare, HBA_FCPTARGETMAPPINGV2 *map) { int mapIndex; char *physical = NULL; char *tmp; int wwnCompare = 0; uint64_t wwn; if (map == NULL || compare == NULL) { return (-1); } if (is_wwn(compare)) { wwnCompare = 1; (void) sscanf(compare, "%016llx", &wwn); } else { /* Convert the paths to phsyical paths */ physical = get_slash_devices_from_osDevName(compare, STANDARD_DEVNAME_HANDLING); } for (mapIndex = 0; mapIndex < map->NumberOfEntries; mapIndex ++) { if (wwnCompare) { if (wwn == wwnConversion( map->entry[mapIndex].FcpId.NodeWWN.wwn) || wwn == wwnConversion( map->entry[mapIndex].FcpId.PortWWN.wwn)) { return (mapIndex); } } else { if (physical != NULL) { tmp = get_slash_devices_from_osDevName( map->entry[mapIndex].ScsiId.OSDeviceName, STANDARD_DEVNAME_HANDLING); if ((tmp != NULL) && strncmp(physical, tmp, MAXPATHLEN) == 0) { free(physical); return (mapIndex); } } } } if (physical) { free(physical); } return (-1); } /* * returns non-zero on failure (aka HBA_STATUS_ERROR_* */ int loadLibrary() { int status = HBA_LoadLibrary(); if (status != HBA_STATUS_OK) { fprintf(stderr, MSGSTR(2505, "ERROR: Unable to load HBA API library: ")); printStatus(status); fprintf(stderr, "\n"); } return (status); } int fchba_non_encl_probe() { HBA_HANDLE handle; HBA_ADAPTERATTRIBUTES hbaAttrs; HBA_PORTATTRIBUTES portAttrs; HBA_FCPTARGETMAPPINGV2 *map; HBA_STATUS status; int count, adapterIndex, portIndex, mapIndex; char name[256]; struct path_entry *head = NULL; uint64_t lun = 0; L_inquiry inq; struct scsi_extended_sense sense; HBA_UINT8 scsiStatus; uint32_t inquirySize = sizeof (inq), senseSize = sizeof (sense); if (loadLibrary()) { return (-1); } count = getNumberOfAdapters(); /* Loop over all HBAs */ for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) { if (skip_hba(adapterIndex)) { continue; } status = HBA_GetAdapterName(adapterIndex, (char *)&name); if (status != HBA_STATUS_OK) { /* May have been DR'd */ continue; } handle = HBA_OpenAdapter(name); if (handle == 0) { /* May have been DR'd */ continue; } if (getAdapterAttrs(handle, name, &hbaAttrs)) { /* Should not happen, just skip it */ HBA_CloseAdapter(handle); continue; } /* Loop over all HBA Ports */ for (portIndex = 0; portIndex < hbaAttrs.NumberOfPorts; portIndex++) { if (getAdapterPortAttrs(handle, name, portIndex, &portAttrs)) { continue; } if (fetch_mappings(handle, portAttrs.PortWWN, &map)) { continue; } /* Loop over all target Mapping entries */ for (mapIndex = 0; mapIndex < map->NumberOfEntries; mapIndex ++) { struct path_entry *tmpPath = NULL; int doInquiry = 0; if (!head) { head = (struct path_entry *)calloc(1, sizeof (struct path_entry)); tmpPath = head; strncpy(head->path, map->entry[mapIndex].ScsiId.OSDeviceName, sizeof (map->entry[mapIndex].ScsiId.OSDeviceName)); (void) memcpy(tmpPath->wwn, map->entry[mapIndex].FcpId.NodeWWN.wwn, sizeof (HBA_UINT8) * 8); doInquiry = 1; } else if (tmpPath = is_duplicate_path(head, map->entry[mapIndex].ScsiId.OSDeviceName)) { if (tmpPath->dtype != 0x1f) { doInquiry = 0; } else { doInquiry = 1; } } else { tmpPath = (struct path_entry *) calloc(1, sizeof (struct path_entry)); strncpy(tmpPath->path, map->entry[mapIndex].ScsiId.OSDeviceName, sizeof (map->entry[mapIndex].ScsiId.OSDeviceName)); (void) memcpy(tmpPath->wwn, map->entry[mapIndex].FcpId.NodeWWN.wwn, sizeof (HBA_UINT8) * 8); add_path(head, tmpPath); doInquiry = 1; } if (doInquiry) { lun = map->entry[mapIndex].FcpId.FcpLun; memset(&inq, 0, sizeof (inq)); memset(&sense, 0, sizeof (sense)); status = HBA_ScsiInquiryV2(handle, portAttrs.PortWWN, map->entry[mapIndex].FcpId.PortWWN, lun, 0, 0, &inq, &inquirySize, &scsiStatus, &sense, &senseSize); if (status != HBA_STATUS_OK) { inq.inq_dtype = 0x1f; } tmpPath->dtype = inq.inq_dtype; } } } } if (head) { struct path_entry *tmp; printf(MSGSTR(2098, "\nFound Fibre Channel device(s):\n")); for (tmp = head; tmp != NULL; tmp = tmp->next) { printf(" "); printf(MSGSTR(90, "Node WWN:")); printf("%016llx ", wwnConversion(tmp->wwn)); fprintf(stdout, MSGSTR(35, "Device Type:")); (void) fflush(stdout); if ((tmp->dtype & DTYPE_MASK) < 0x10) { fprintf(stdout, "%s", dtype[tmp->dtype & DTYPE_MASK]); } else if ((tmp->dtype & DTYPE_MASK) < 0x1f) { fprintf(stdout, MSGSTR(2406, "Reserved")); } else { fprintf(stdout, MSGSTR(2407, "Unknown")); } printf("\n "); printf(MSGSTR(31, "Logical Path:%s"), tmp->path); printf("\n"); /* We probably shouldn't be using a g_fc interface here */ if (Options & OPTION_P) { char *phys_path = get_slash_devices_from_osDevName( tmp->path, STANDARD_DEVNAME_HANDLING); if (phys_path != NULL) { fprintf(stdout, " "); fprintf(stdout, MSGSTR(5, "Physical Path:")); fprintf(stdout, "\n %s\n", phys_path); free(phys_path); } } } free_path_list(head); } HBA_FreeLibrary(); return (0); } int fchba_inquiry(char **argv) { int path_index = 0, found = 0; uint64_t wwn; uint64_t lun = 0; HBA_HANDLE handle; HBA_ADAPTERATTRIBUTES hbaAttrs; HBA_PORTATTRIBUTES portAttrs; HBA_FCPTARGETMAPPINGV2 *map; HBA_STATUS status; int count, adapterIndex, portIndex, mapIndex; char name[256]; L_inquiry inq; struct page80 serial; uint32_t serialSize = sizeof (serial); struct scsi_extended_sense sense; HBA_UINT8 scsiStatus; uint32_t inquirySize = sizeof (inq), senseSize = sizeof (sense); boolean_t goodPath = B_FALSE; int matched = 0, wwnCompare = 0; char *tmp, *physical = NULL; int ret = 0; if (loadLibrary()) { return (-1); } for (path_index = 0; argv[path_index] != NULL; path_index++) { goodPath = B_FALSE; found = 0; if (is_wwn(argv[path_index])) { (void) sscanf(argv[path_index], "%016llx", &wwn); wwnCompare = 1; } else if (!is_path(argv[path_index])) { fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), argv[path_index]); fprintf(stderr, "\n"); ret = -1; continue; } if (!wwnCompare) { /* Convert the paths to phsyical paths */ physical = get_slash_devices_from_osDevName(argv[path_index], STANDARD_DEVNAME_HANDLING); if (!physical) { fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), argv[path_index]); fprintf(stderr, "\n"); ret = -1; continue; } } count = getNumberOfAdapters(); /* Loop over all HBAs */ for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) { if (skip_hba(adapterIndex)) { continue; } status = HBA_GetAdapterName(adapterIndex, (char *)&name); if (status != HBA_STATUS_OK) { /* May have been DR'd */ continue; } handle = HBA_OpenAdapter(name); if (handle == 0) { /* May have been DR'd */ continue; } if (getAdapterAttrs(handle, name, &hbaAttrs)) { /* Should never happen */ HBA_CloseAdapter(handle); continue; } /* Loop over all HBA Ports */ for (portIndex = 0; portIndex < hbaAttrs.NumberOfPorts; portIndex++) { if (getAdapterPortAttrs(handle, name, portIndex, &portAttrs)) { continue; } if (fetch_mappings(handle, portAttrs.PortWWN, &map)) { continue; } for (mapIndex = 0; mapIndex < map->NumberOfEntries; mapIndex ++) { matched = 0; if (wwnCompare) { if (wwn == wwnConversion( map->entry[mapIndex].FcpId.NodeWWN.wwn) || wwn == wwnConversion( map->entry[mapIndex].FcpId.PortWWN.wwn)) { lun = map->entry[mapIndex].FcpId.FcpLun; matched = 1; } } else { tmp = get_slash_devices_from_osDevName( map->entry[mapIndex].ScsiId.OSDeviceName, STANDARD_DEVNAME_HANDLING); if ((tmp != NULL) && (strncmp(physical, tmp, MAXPATHLEN) == 0)) { lun = map->entry[mapIndex].FcpId.FcpLun; matched = 1; free(tmp); } } if (matched) { memset(&inq, 0, sizeof (inq)); memset(&sense, 0, sizeof (sense)); status = HBA_ScsiInquiryV2(handle, portAttrs.PortWWN, map->entry[mapIndex].FcpId.PortWWN, lun, 0, 0, &inq, &inquirySize, &scsiStatus, &sense, &senseSize); if (status == HBA_STATUS_OK) { goodPath = B_TRUE; /* * Call the inquiry cmd on page 0x80 only if * the vendor supports page 0x80 */ memset(&serial, 0, sizeof (serial)); if ((find_supported_inq_page(handle, portAttrs.PortWWN, map->entry[mapIndex].FcpId.PortWWN, lun, 0x80))) { status = HBA_ScsiInquiryV2(handle, portAttrs.PortWWN, map->entry[mapIndex].FcpId.PortWWN, lun, 1, 0x80, &serial, &serialSize, &scsiStatus, &sense, &senseSize); if (status != HBA_STATUS_OK) { strncpy( (char *)serial.inq_serial, "Unavailable", sizeof (serial.inq_serial)); } } else { strncpy((char *)serial.inq_serial, "Unsupported", sizeof (serial.inq_serial)); } /* * we are adding serial number information * from 0x80. If length is less than 39, * then we want to increase length to 52 to * reflect the fact that we have serial number * information */ if (inq.inq_len < 39) { inq.inq_len = 52; } print_inq_data(argv[path_index], map->entry[mapIndex].ScsiId.OSDeviceName, inq, serial.inq_serial, sizeof (serial.inq_serial)); if (! wwnCompare) { found = 1; break; } } else { fprintf(stderr, MSGSTR(2430, "Error: I/O failure communicating with %s "), map->entry[mapIndex].ScsiId.OSDeviceName); printStatus(status); fprintf(stderr, "\n"); } } } if (found == 1) { break; } } if (found == 1) { break; } } if (physical) { free(physical); } if (!goodPath) { fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), argv[path_index]); fprintf(stderr, "\n"); ret = -1; } } return (ret); } int fchba_dump_map(char **argv) { int path_index = 0; uint64_t wwn; uint64_t lun = 0; HBA_HANDLE handle; HBA_ADAPTERATTRIBUTES hbaAttrs; HBA_PORTATTRIBUTES portAttrs; HBA_PORTATTRIBUTES discPortAttrs; HBA_FCPTARGETMAPPINGV2 *map; HBA_STATUS status; int count, adapterIndex, portIndex, mapIndex, discIndex; char name[256], *physical = NULL, *comp_phys = NULL; L_inquiry inq; struct scsi_extended_sense sense; HBA_UINT8 scsiStatus; int matched; int done; uint32_t inquirySize = sizeof (inq), senseSize = sizeof (sense); boolean_t goodPath = B_FALSE; int ret = 0; uint32_t responseSize = DEFAULT_LUN_LENGTH; uchar_t raw_luns[DEFAULT_LUN_LENGTH]; struct rep_luns_rsp *lun_resp; if (loadLibrary()) { return (-1); } for (path_index = 0; argv[path_index] != NULL; path_index++) { goodPath = B_FALSE; if (is_wwn(argv[path_index])) { (void) sscanf(argv[path_index], "%016llx", &wwn); } else if (!is_path(argv[path_index])) { fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), argv[path_index]); fprintf(stderr, "\n"); ret = -1; continue; } count = getNumberOfAdapters(); done = 0; /* Loop over all HBAs */ for (adapterIndex = 0; adapterIndex < count && !done; adapterIndex ++) { if (skip_hba(adapterIndex)) { continue; } status = HBA_GetAdapterName(adapterIndex, (char *)&name); if (status != HBA_STATUS_OK) { /* May have been DR'd */ continue; } handle = HBA_OpenAdapter(name); if (handle == 0) { /* May have been DR'd */ continue; } if (getAdapterAttrs(handle, name, &hbaAttrs)) { /* Should never happen */ HBA_CloseAdapter(handle); continue; } /* Loop over all HBA Ports */ for (portIndex = 0; portIndex < hbaAttrs.NumberOfPorts && !done; portIndex++) { if (getAdapterPortAttrs(handle, name, portIndex, &portAttrs)) { continue; } matched = 0; if (is_wwn(argv[path_index])) { if (wwn == wwnConversion( portAttrs.NodeWWN.wwn) || wwn == wwnConversion( portAttrs.PortWWN.wwn)) { matched = 1; } } else { if (is_path(argv[path_index]) && ((physical = get_slash_devices_from_osDevName( argv[path_index], STANDARD_DEVNAME_HANDLING)) != NULL) && ((comp_phys = get_slash_devices_from_osDevName( portAttrs.OSDeviceName, STANDARD_DEVNAME_HANDLING)) != NULL)) { char *tmp = strstr(physical, ":devctl"); if (tmp) { *tmp = '\0'; } else { tmp = strstr(physical, ":fc"); if (tmp) { *tmp = '\0'; } } if (strstr(comp_phys, physical)) { matched = 1; } } if (physical) { free(physical); physical = NULL; } if (comp_phys) { free(comp_phys); comp_phys = NULL; } } if (!fetch_mappings(handle, portAttrs.PortWWN, &map)) { mapIndex = match_mappings(argv[path_index], map); if (mapIndex >= 0) { matched = 1; } } else { continue; } if (matched) { goodPath = B_TRUE; printf(MSGSTR(2095, "Pos Port_ID Hard_Addr Port WWN" " Node WWN Type\n")); for (discIndex = 0; discIndex < portAttrs.NumberofDiscoveredPorts; discIndex++) { if (getDiscPortAttrs(handle, name, portIndex, discIndex, &discPortAttrs)) { /* Move on to the next target */ continue; } printf("%-4d %-6x %-6x %016llx %016llx", discIndex, discPortAttrs.PortFcId, 0, wwnConversion(discPortAttrs.PortWWN.wwn), wwnConversion(discPortAttrs.NodeWWN.wwn)); /* * devices are not all required to respond to * Scsi Inquiry calls sent to LUN 0. We must * fisrt issue a ReportLUN and then send the * SCSI Inquiry call to the first LUN Returned * from the ReportLUN call */ memset(&sense, 0, sizeof (sense)); status = HBA_ScsiReportLUNsV2(handle, portAttrs.PortWWN, discPortAttrs.PortWWN, (void *)raw_luns, &responseSize, &scsiStatus, (void *)&sense, &senseSize); if (status == HBA_STATUS_OK) { lun_resp = (struct rep_luns_rsp *) (unsigned long)raw_luns; lun = ntohll( wwnConversion(lun_resp->lun[0].val)); } else { /* * in case we are unable to retrieve report * LUN data, we will blindly try sending the * INQUIRY to lun 0. */ lun = 0; } memset(&sense, 0, sizeof (sense)); status = HBA_ScsiInquiryV2(handle, portAttrs.PortWWN, discPortAttrs.PortWWN, lun, 0, 0, &inq, &inquirySize, &scsiStatus, &sense, &senseSize); if (status != HBA_STATUS_OK) { inq.inq_dtype = 0x1f; } print_fabric_dtype_prop(portAttrs.PortWWN.wwn, map->entry[mapIndex].FcpId.PortWWN.wwn, inq.inq_dtype); } /* Now dump this HBA's stats */ printf("%-4d %-6x %-6x %016llx %016llx", discIndex, portAttrs.PortFcId, 0, wwnConversion(portAttrs.PortWWN.wwn), wwnConversion(portAttrs.NodeWWN.wwn)); print_fabric_dtype_prop(portAttrs.PortWWN.wwn, portAttrs.PortWWN.wwn, 0x1f); done = 1; } } } if (!goodPath) { fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), argv[path_index]); fprintf(stderr, "\n"); ret = -1; } } return (ret); } int fchba_display_link_status(char **argv) { int path_index = 0; uint64_t wwn; HBA_HANDLE handle; HBA_ADAPTERATTRIBUTES hbaAttrs; HBA_PORTATTRIBUTES portAttrs; HBA_PORTATTRIBUTES discPortAttrs; HBA_FCPTARGETMAPPINGV2 *map; HBA_STATUS status; int count, adapterIndex, portIndex, discIndex; char name[256], *physical = NULL, *comp_phys = NULL; int matched; struct fc_rls_acc_params rls; uint32_t rls_size = sizeof (rls); boolean_t goodPath = B_FALSE; int ret = 0; if (loadLibrary()) { return (-1); } for (path_index = 0; argv[path_index] != NULL; path_index++) { goodPath = B_FALSE; if (is_wwn(argv[path_index])) { (void) sscanf(argv[path_index], "%016llx", &wwn); } else if (!is_path(argv[path_index])) { fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), argv[path_index]); fprintf(stderr, "\n"); ret = -1; continue; } count = getNumberOfAdapters(); /* Loop over all HBAs */ for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) { if (skip_hba(adapterIndex)) { continue; } status = HBA_GetAdapterName(adapterIndex, (char *)&name); if (status != HBA_STATUS_OK) { /* May have been DR'd */ continue; } handle = HBA_OpenAdapter(name); if (handle == 0) { /* May have been DR'd */ continue; } if (getAdapterAttrs(handle, name, &hbaAttrs)) { /* Should never happen */ HBA_CloseAdapter(handle); continue; } /* Loop over all HBA Ports */ for (portIndex = 0; portIndex < hbaAttrs.NumberOfPorts; portIndex++) { if (getAdapterPortAttrs(handle, name, portIndex, &portAttrs)) { continue; } matched = 0; if (is_wwn(argv[path_index])) { if (wwn == wwnConversion( portAttrs.NodeWWN.wwn) || wwn == wwnConversion( portAttrs.PortWWN.wwn)) { matched = 1; } } else { if (is_path(argv[path_index]) && ((physical = get_slash_devices_from_osDevName( argv[path_index], STANDARD_DEVNAME_HANDLING)) != NULL) && ((comp_phys = get_slash_devices_from_osDevName( portAttrs.OSDeviceName, STANDARD_DEVNAME_HANDLING)) != NULL)) { char *tmp = strstr(physical, ":devctl"); if (tmp) { *tmp = '\0'; } else { tmp = strstr(physical, ":fc"); if (tmp) { *tmp = '\0'; } } if (strstr(comp_phys, physical)) { matched = 1; } } if (physical) { free(physical); physical = NULL; } if (comp_phys) { free(comp_phys); comp_phys = NULL; } } if (!matched) { if (fetch_mappings(handle, portAttrs.PortWWN, &map)) { continue; } } if (matched || match_mappings(argv[path_index], map) >= 0) { goodPath = B_TRUE; fprintf(stdout, MSGSTR(2007, "\nLink Error Status " "information for loop:%s\n"), argv[path_index]); fprintf(stdout, MSGSTR(2008, "al_pa lnk fail " " sync loss signal loss sequence err" " invalid word CRC\n")); for (discIndex = 0; discIndex < portAttrs.NumberofDiscoveredPorts; discIndex++) { if (getDiscPortAttrs(handle, name, portIndex, discIndex, &discPortAttrs)) { continue; } status = HBA_SendRLS(handle, portAttrs.PortWWN, discPortAttrs.PortWWN, &rls, &rls_size); if (status != HBA_STATUS_OK) { memset(&rls, 0xff, sizeof (rls)); } if ((rls.rls_link_fail == 0xffffffff) && (rls.rls_sync_loss == 0xffffffff) && (rls.rls_sig_loss == 0xffffffff) && (rls.rls_prim_seq_err == 0xffffffff) && (rls.rls_invalid_word == 0xffffffff) && (rls.rls_invalid_crc == 0xffffffff)) { fprintf(stdout, "%x\t%-12d%-12d%-14d%-15d%-15d%-12d\n", discPortAttrs.PortFcId, rls.rls_link_fail, rls.rls_sync_loss, rls.rls_sig_loss, rls.rls_prim_seq_err, rls.rls_invalid_word, rls.rls_invalid_crc); } else { fprintf(stdout, "%x\t%-12u%-12u%-14u%-15u%-15u%-12u\n", discPortAttrs.PortFcId, rls.rls_link_fail, rls.rls_sync_loss, rls.rls_sig_loss, rls.rls_prim_seq_err, rls.rls_invalid_word, rls.rls_invalid_crc); } } /* Now dump this HBA's stats */ status = HBA_SendRLS(handle, portAttrs.PortWWN, portAttrs.PortWWN, &rls, &rls_size); if (status != HBA_STATUS_OK) { memset(&rls, 0xff, sizeof (rls)); } if ((rls.rls_link_fail == 0xffffffff) && (rls.rls_sync_loss == 0xffffffff) && (rls.rls_sig_loss == 0xffffffff) && (rls.rls_prim_seq_err == 0xffffffff) && (rls.rls_invalid_word == 0xffffffff) && (rls.rls_invalid_crc == 0xffffffff)) { fprintf(stdout, "%x\t%-12d%-12d%-14d%-15d%-15d%-12d\n", portAttrs.PortFcId, rls.rls_link_fail, rls.rls_sync_loss, rls.rls_sig_loss, rls.rls_prim_seq_err, rls.rls_invalid_word, rls.rls_invalid_crc); } else { fprintf(stdout, "%x\t%-12u%-12u%-14u%-15u%-15u%-12u\n", portAttrs.PortFcId, rls.rls_link_fail, rls.rls_sync_loss, rls.rls_sig_loss, rls.rls_prim_seq_err, rls.rls_invalid_word, rls.rls_invalid_crc); } } } } if (!goodPath) { fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), argv[path_index]); fprintf(stderr, "\n"); ret = -1; } } (void) fprintf(stdout, MSGSTR(2009, "NOTE: These LESB counts are not" " cleared by a reset, only power cycles.\n" "These counts must be compared" " to previously read counts.\n")); return (ret); } typedef struct _PathInformation { char pathClass[MAXPATHLEN]; char pathState[MAXPATHLEN]; int32_t pathInfoState; int32_t pathInfoExternalState; } PathInformation; struct lun_tracking { HBA_FCPSCSIENTRYV2 map; HBA_WWN hba_pwwn; char hba_path[MAXPATHLEN]; PathInformation info; /* Points to another lun_tracking instance with the same map->LUID */ struct lun_tracking *next_path; /* Points to next lun_tracking with a different map->LUID */ struct lun_tracking *next_lun; }; static const char VHCI_COMPONENT[] = "scsi_vhci"; static void scsi_vhci_details(struct lun_tracking *lun) { HBA_FCPSCSIENTRYV2 entry = lun->map; int retval = 0; int pathcnt, i, count, found = 0; char temppath[MAXPATHLEN]; char buf[MAXPATHLEN]; char *path_state[5]; char *phys_path = get_slash_devices_from_osDevName( entry.ScsiId.OSDeviceName, STANDARD_DEVNAME_HANDLING); char *devPath = NULL; char *trailingCruft = NULL; char devaddr[MAXPATHLEN]; sv_iocdata_t ioc; int prop_buf_size = SV_PROP_MAX_BUF_SIZE; char *path_class_val = NULL; char client_path[MAXPATHLEN]; char phci_path[MAXPATHLEN]; /* Only proceed if we are an mpxio path */ if (phys_path == NULL || strstr(phys_path, VHCI_COMPONENT) == NULL) { return; } path_state[0] = MSGSTR(2400, "INIT"); path_state[1] = MSGSTR(2401, "ONLINE"); path_state[2] = MSGSTR(2402, "STANDBY"); path_state[3] = MSGSTR(2403, "FAULT"); path_state[4] = MSGSTR(2404, "OFFLINE"); sprintf(devaddr, "%016llx,%x", wwnConversion( entry.FcpId.PortWWN.wwn), entry.ScsiId.ScsiOSLun); /* First get the controller path */ sprintf(temppath, "/dev/cfg/c%d", entry.ScsiId.ScsiBusNumber); if ((count = readlink(temppath, buf, sizeof (buf)))) { buf[count] = '\0'; /* Now skip over the leading "../.." */ devPath = strstr(buf, "/devices/"); if (devPath == NULL) { strcpy(lun->info.pathClass, "Unavailable"); strcpy(lun->info.pathState, "Unavailable"); free(phys_path); return; } /* Now chop off the trailing ":xxx" portion if present */ trailingCruft = strrchr(buf, ':'); if (trailingCruft) { trailingCruft[0] = '\0'; } } else { strcpy(lun->info.pathClass, "Unavailable"); strcpy(lun->info.pathState, "Unavailable"); free(phys_path); return; } ioc.client = client_path; ioc.phci = phci_path; retval = get_scsi_vhci_pathinfo(phys_path, &ioc, &pathcnt); if (retval != 0) { print_errString(retval, NULL); exit(-1); } for (i = 0; i < pathcnt; i++) { nvlist_t *nvl; if (strstr(devPath, ioc.ret_buf[i].device.ret_phci)) { /* This could break someday if MPxIO changes devaddr */ if (strstr(ioc.ret_buf[i].ret_addr, devaddr)) { retval = nvlist_unpack(ioc.ret_buf[i].ret_prop.buf, prop_buf_size, &nvl, 0); if (retval != 0) { strcpy(lun->info.pathClass, "UNKNOWN PROB"); } else { strcpy(lun->info.pathState, path_state[ioc.ret_buf[i].ret_state]); lun->info.pathInfoState = ioc.ret_buf[i].ret_state; lun->info.pathInfoExternalState = ioc.ret_buf[i].ret_ext_state; if (nvlist_lookup_string(nvl, "path-class", &path_class_val) == 0) { strcpy(lun->info.pathClass, path_class_val); } else { strcpy(lun->info.pathClass, "UNKNOWN"); } } nvlist_free(nvl); found++; break; } } } if (!found) { strcpy(lun->info.pathClass, "Unavailable"); strcpy(lun->info.pathState, "Unavailable"); } free(phys_path); /* free everything we alloced */ for (i = 0; i < ioc.buf_elem; i++) { free(ioc.ret_buf[i].ret_prop.buf); free(ioc.ret_buf[i].ret_prop.ret_buf_size); } free(ioc.ret_buf); } /* Utility routine to add new entries to the list (ignores dups) */ static void add_lun_path(struct lun_tracking *head, HBA_FCPSCSIENTRYV2 *map, HBA_WWN pwwn, char *path) { struct lun_tracking *tmp = NULL, *cmp = NULL; for (tmp = head; tmp != NULL; tmp = tmp->next_lun) { if (memcmp(&tmp->map.LUID, &map->LUID, sizeof (HBA_LUID)) == 0) { /* Ensure this isn't a duplicate */ for (cmp = tmp; cmp->next_path != NULL; cmp = cmp->next_path) { if (memcmp(&cmp->map, map, sizeof (cmp->map)) == 0) { return; } } if (memcmp(&cmp->map, map, sizeof (cmp->map)) == 0) { return; } /* We have a new entry to add */ cmp->next_path = (struct lun_tracking *)calloc(1, sizeof (struct lun_tracking)); cmp = cmp->next_path; (void) memcpy(&cmp->map, map, sizeof (cmp->map)); (void) memcpy(&cmp->hba_pwwn, &pwwn, sizeof (cmp->hba_pwwn)); (void) snprintf(cmp->hba_path, MAXPATHLEN, path); scsi_vhci_details(cmp); return; } } /* Append a new LUN at the end of the list */ for (tmp = head; tmp->next_lun != NULL; tmp = tmp->next_lun) {} tmp->next_lun = (struct lun_tracking *)calloc(1, sizeof (struct lun_tracking)); tmp = tmp->next_lun; (void) memcpy(&tmp->map, map, sizeof (tmp->map)); (void) memcpy(&tmp->hba_pwwn, &pwwn, sizeof (tmp->hba_pwwn)); (void) snprintf(tmp->hba_path, MAXPATHLEN, path); scsi_vhci_details(tmp); } /*ARGSUSED*/ int fchba_display_config(char **argv, int option_t_input, int argc) { int path_index = 0; uint64_t wwn; uint64_t lun = 0; HBA_HANDLE handle; HBA_ADAPTERATTRIBUTES hbaAttrs; HBA_PORTATTRIBUTES portAttrs; HBA_FCPTARGETMAPPINGV2 *map; HBA_STATUS status; int count, adapterIndex, portIndex; char name[256]; L_inquiry inq; struct scsi_extended_sense sense; struct page80 serial; HBA_UINT8 scsiStatus; uint32_t inquirySize = sizeof (inq), senseSize = sizeof (sense); uint32_t serialSize = sizeof (serial); struct mode_page *pg_hdr; uchar_t *pg_buf; float lunMbytes; struct capacity_data_struct cap_data; uint32_t cap_data_size = sizeof (cap_data); struct mode_header_g1 *mode_header_ptr; int offset; char *phys_path = NULL; int mpxio = 0; int wwnCompare = 0; char *physical = NULL; struct lun_tracking *head = NULL; boolean_t goodPath = B_FALSE; int ret = 0; if ((status = loadLibrary())) { return (-1); } for (path_index = 0; argv[path_index] != NULL; path_index++) { goodPath = B_FALSE; if (is_wwn(argv[path_index])) { (void) sscanf(argv[path_index], "%016llx", &wwn); wwnCompare = 1; } else if (!is_path(argv[path_index])) { fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), argv[path_index]); fprintf(stderr, "\n"); ret = -1; continue; } if (!wwnCompare) { /* Convert the paths to phsyical paths */ physical = get_slash_devices_from_osDevName(argv[path_index], STANDARD_DEVNAME_HANDLING); if (!physical) { fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), argv[path_index]); fprintf(stderr, "\n"); ret = -1; continue; } } count = getNumberOfAdapters(); /* * We have to loop twice to ensure we don't miss any * extra paths for other targets in a multi-target device */ /* First check WWN/path comparisons */ for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) { if (skip_hba(adapterIndex)) { continue; } status = HBA_GetAdapterName(adapterIndex, (char *)&name); if (status != HBA_STATUS_OK) { /* May have been DR'd */ continue; } handle = HBA_OpenAdapter(name); if (handle == 0) { /* May have been DR'd */ continue; } if (getAdapterAttrs(handle, name, &hbaAttrs)) { /* Should never happen */ HBA_CloseAdapter(handle); continue; } /* Loop over all HBA Ports */ for (portIndex = 0; portIndex < hbaAttrs.NumberOfPorts; portIndex++) { int matched = 0; int mapIndex; char *tmp; if (getAdapterPortAttrs(handle, name, portIndex, &portAttrs)) { continue; } if (fetch_mappings(handle, portAttrs.PortWWN, &map)) { continue; } for (mapIndex = 0; mapIndex < map->NumberOfEntries; mapIndex ++) { matched = 0; if (wwnCompare) { if (wwn == wwnConversion( map->entry[mapIndex].FcpId.NodeWWN.wwn) || wwn == wwnConversion( map->entry[mapIndex].FcpId.PortWWN.wwn)) { matched = 1; } } else { tmp = get_slash_devices_from_osDevName( map->entry[mapIndex].ScsiId.OSDeviceName, STANDARD_DEVNAME_HANDLING); if ((tmp != NULL) && (strncmp(physical, tmp, MAXPATHLEN) == 0)) { matched = 1; free(tmp); } } if (matched && head == NULL) { goodPath = B_TRUE; head = (struct lun_tracking *)calloc(1, sizeof (struct lun_tracking)); (void) memcpy(&head->map, &map->entry[mapIndex], sizeof (head->map)); (void) memcpy(&head->hba_pwwn, &portAttrs.PortWWN, sizeof (head->hba_pwwn)); (void) snprintf(head->hba_path, MAXPATHLEN, portAttrs.OSDeviceName); scsi_vhci_details(head); } else if (matched) { goodPath = B_TRUE; add_lun_path(head, &map->entry[mapIndex], portAttrs.PortWWN, portAttrs.OSDeviceName); } } } } if (physical) { free(physical); } /* Now do it again and look for matching LUIDs (aka GUIDs) */ for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) { if (skip_hba(adapterIndex)) { continue; } status = HBA_GetAdapterName(adapterIndex, (char *)&name); if (status != HBA_STATUS_OK) { /* May have been DR'd */ continue; } handle = HBA_OpenAdapter(name); if (handle == 0) { /* May have been DR'd */ continue; } if (getAdapterAttrs(handle, name, &hbaAttrs)) { /* Should never happen */ HBA_CloseAdapter(handle); continue; } /* Loop over all HBA Ports */ for (portIndex = 0; portIndex < hbaAttrs.NumberOfPorts; portIndex++) { int matched = 0; int mapIndex; if (getAdapterPortAttrs(handle, name, portIndex, &portAttrs)) { continue; } if (fetch_mappings(handle, portAttrs.PortWWN, &map)) { continue; } for (mapIndex = 0; mapIndex < map->NumberOfEntries; mapIndex ++) { struct lun_tracking *outer; matched = 0; for (outer = head; outer != NULL; outer = outer->next_lun) { struct lun_tracking *inner; for (inner = outer; inner != NULL; inner = inner->next_path) { if (memcmp(&inner->map.LUID, &map->entry[mapIndex].LUID, sizeof (HBA_LUID)) == 0) { matched = 1; break; } } if (matched) { break; } } if (matched && head == NULL) { goodPath = B_TRUE; head = (struct lun_tracking *)calloc(1, sizeof (struct lun_tracking)); (void) memcpy(&head->map, &map->entry[mapIndex], sizeof (head->map)); (void) memcpy(&head->hba_pwwn, &portAttrs.PortWWN, sizeof (head->hba_pwwn)); (void) snprintf(head->hba_path, MAXPATHLEN, portAttrs.OSDeviceName); scsi_vhci_details(head); } else if (matched) { goodPath = B_TRUE; add_lun_path(head, &map->entry[mapIndex], portAttrs.PortWWN, portAttrs.OSDeviceName); } } } } if (!goodPath) { fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), argv[path_index]); fprintf(stderr, "\n"); ret = -1; /* Just bomb out instead of going on */ return (ret); } } /* Now display all the LUNs that we found that matched */ { struct lun_tracking *first_time; struct lun_tracking *tmp_path; for (first_time = head; first_time != NULL; first_time = first_time->next_lun) { struct lun_tracking *path; phys_path = get_slash_devices_from_osDevName( first_time->map.ScsiId.OSDeviceName, STANDARD_DEVNAME_HANDLING); /* Change behavior if this is an MPxIO device */ if (phys_path != NULL) { if (strstr(phys_path, VHCI_COMPONENT) != NULL) { mpxio = 1; } } for (tmp_path = first_time; tmp_path != NULL; tmp_path = tmp_path->next_path) { if (mpxio && (strncmp(tmp_path->info.pathState, "ONLINE", strlen(tmp_path->info.pathState)))) { /* continue to next online path */ continue; } status = HBA_OpenAdapterByWWN(&handle, tmp_path->hba_pwwn); if (status != HBA_STATUS_OK) { fprintf(stderr, MSGSTR(2431, "Error: Failed to get handle for %s "), tmp_path->hba_path); printStatus(status); fprintf(stderr, "\n"); /* continue to next path */ continue; } lun = tmp_path->map.FcpId.FcpLun; memset(&inq, 0, sizeof (inq)); memset(&sense, 0, sizeof (sense)); status = HBA_ScsiInquiryV2(handle, tmp_path->hba_pwwn, tmp_path->map.FcpId.PortWWN, lun, 0, 0, &inq, &inquirySize, &scsiStatus, &sense, &senseSize); if (status == HBA_STATUS_OK) { break; } HBA_CloseAdapter(handle); } if (tmp_path == NULL) { fprintf(stderr, MSGSTR(2430, "Error: I/O failure communicating with %s "), first_time->map.ScsiId.OSDeviceName); printStatus(status); fprintf(stderr, "\n"); continue; } switch ((inq.inq_dtype & DTYPE_MASK)) { case DTYPE_DIRECT: fprintf(stdout, MSGSTR(121, "DEVICE PROPERTIES for disk: %s\n"), first_time->map.ScsiId.OSDeviceName); break; case DTYPE_SEQUENTIAL: /* Tape */ fprintf(stdout, MSGSTR(2249, "DEVICE PROPERTIES for tape: %s\n"), first_time->map.ScsiId.OSDeviceName); break; default: fprintf(stdout, MSGSTR(2250, "DEVICE PROPERTIES for: %s\n"), first_time->map.ScsiId.OSDeviceName); break; } fprintf(stdout, " "); fprintf(stdout, MSGSTR(3, "Vendor:")); fprintf(stdout, "\t\t"); print_chars(inq.inq_vid, sizeof (inq.inq_vid), 0); fprintf(stdout, MSGSTR(2115, "\n Product ID:\t\t")); print_chars(inq.inq_pid, sizeof (inq.inq_pid), 0); fprintf(stdout, "\n "); fprintf(stdout, MSGSTR(2119, "Revision:")); fprintf(stdout, "\t\t"); print_chars(inq.inq_revision, sizeof (inq.inq_revision), 0); fprintf(stdout, "\n "); fprintf(stdout, MSGSTR(17, "Serial Num:")); fprintf(stdout, "\t\t"); (void) fflush(stdout); /* * Call the inquiry cmd on page 0x80 only if the vendor * supports page 0x80. */ if ((find_supported_inq_page(handle, first_time->hba_pwwn, first_time->map.FcpId.PortWWN, lun, 0x80))) { memset(&serial, 0, sizeof (serial)); status = HBA_ScsiInquiryV2(handle, first_time->hba_pwwn, first_time->map.FcpId.PortWWN, lun, 1, 0x80, &serial, &serialSize, &scsiStatus, &sense, &senseSize); if (status == HBA_STATUS_OK) { print_chars(serial.inq_serial, sizeof (serial.inq_serial), 0); } else { fprintf(stdout, MSGSTR(2506, "Unsupported")); } } else { fprintf(stdout, MSGSTR(2506, "Unsupported")); } HBA_CloseAdapter(handle); if ((inq.inq_dtype & DTYPE_MASK) == DTYPE_DIRECT) { /* Read capacity wont work on standby paths, so try till OK */ for (tmp_path = first_time; tmp_path != NULL; tmp_path = tmp_path->next_path) { if (mpxio && (strncmp(tmp_path->info.pathState, "ONLINE", strlen(tmp_path->info.pathState)))) { /* continue to next online path */ continue; } status = HBA_OpenAdapterByWWN(&handle, tmp_path->hba_pwwn); if (status != HBA_STATUS_OK) { /* continue to next path */ continue; } status = HBA_ScsiReadCapacityV2(handle, tmp_path->hba_pwwn, tmp_path->map.FcpId.PortWWN, tmp_path->map.FcpId.FcpLun, &cap_data, &cap_data_size, &scsiStatus, &sense, &senseSize); if (status == HBA_STATUS_OK) { break; } else if (status == HBA_STATUS_SCSI_CHECK_CONDITION && sense.es_key == KEY_UNIT_ATTENTION) { /* * retry for check-condition state when unit attention * condition has been established */ status = HBA_ScsiReadCapacityV2(handle, tmp_path->hba_pwwn, tmp_path->map.FcpId.PortWWN, tmp_path->map.FcpId.FcpLun, &cap_data, &cap_data_size, &scsiStatus, &sense, &senseSize); if (status == HBA_STATUS_OK) { break; } } HBA_CloseAdapter(handle); } } if (handle != HBA_HANDLE_INVALID) { HBA_CloseAdapter(handle); } if (status != HBA_STATUS_OK) { /* Make sure we don't display garbage */ cap_data.block_size = 0; cap_data.last_block_addr = 0; } if (cap_data.block_size > 0 && cap_data.last_block_addr > 0) { lunMbytes = ntohl(cap_data.last_block_addr) + 1; lunMbytes *= ntohl(cap_data.block_size); lunMbytes /= (float)(1024*1024); fprintf(stdout, "\n "); fprintf(stdout, MSGSTR(60, "Unformatted capacity:\t%6.3f MBytes"), lunMbytes); } fprintf(stdout, "\n"); /* * get mode page information for FC device. * do not do mode sense if this is a tape device. * mode sense will rewind the tape */ if ((inq.inq_dtype & DTYPE_MASK) != DTYPE_SEQUENTIAL) { if (get_mode_page(first_time->map.ScsiId.OSDeviceName, &pg_buf) == 0) { mode_header_ptr = (struct mode_header_g1 *) (void *)pg_buf; offset = sizeof (struct mode_header_g1) + ntohs(mode_header_ptr->bdesc_length); pg_hdr = (struct mode_page *)&pg_buf[offset]; while (offset < (ntohs(mode_header_ptr->length) + sizeof (mode_header_ptr->length))) { if (pg_hdr->code == MODEPAGE_CACHING) { struct mode_caching *pg8_buf; pg8_buf = (struct mode_caching *) (void *)pg_hdr; if (pg8_buf->wce) { fprintf(stdout, MSGSTR(2122, " Write Cache:\t\t" "Enabled\n")); } if (pg8_buf->rcd == 0) { fprintf(stdout, MSGSTR(2123, " Read Cache:\t\t" "Enabled\n")); fprintf(stdout, MSGSTR(2509, " Minimum prefetch:\t0x%x\n" " Maximum prefetch:\t0x%x\n"), pg8_buf->min_prefetch, pg8_buf->max_prefetch); } break; } offset += pg_hdr->length + sizeof (struct mode_page); pg_hdr = (struct mode_page *)&pg_buf[offset]; } } } fprintf(stdout, " %s\t\t", MSGSTR(35, "Device Type:")); if ((inq.inq_dtype & DTYPE_MASK) < 0x10) { fprintf(stdout, "%s\n", dtype[inq.inq_dtype & DTYPE_MASK]); } else if ((inq.inq_dtype & DTYPE_MASK) < 0x1f) { fprintf(stdout, MSGSTR(2432, "Reserved")); } else { /* dtype of 0x1f is returned */ fprintf(stdout, MSGSTR(2433, "Unknown")); } fprintf(stdout, MSGSTR(2128, " Path(s):\n")); fprintf(stdout, "\n"); fprintf(stdout, " %s\n", first_time->map.ScsiId.OSDeviceName); if (phys_path != NULL) { fprintf(stdout, " %s\n", phys_path); } /* Now display all paths to this LUN */ for (path = first_time; path != NULL; path = path->next_path) { /* Display the controller information */ fprintf(stdout, MSGSTR(2303, " Controller \t%s\n"), path->hba_path); fprintf(stdout, MSGSTR(2507, " Device Address\t\t%016llx,%x\n"), wwnConversion( path->map.FcpId.PortWWN.wwn), path->map.ScsiId.ScsiOSLun); fprintf(stdout, MSGSTR(2508, " Host controller port WWN\t%016llx\n"), wwnConversion(path->hba_pwwn.wwn)); if (mpxio) { fprintf(stdout, MSGSTR(2305, " Class\t\t\t%s\n"), path->info.pathClass); fprintf(stdout, MSGSTR(2306, " State\t\t\t%s\n"), path->info.pathState); } if (phys_path != NULL) { free(phys_path); phys_path = NULL; } } printf("\n"); } } return (ret); } /* * handle expert-mode hotplug commands * * return 0 iff all is okay */ int fchba_hotplug_e(int todo, char **argv, int verbose_flag, int force_flag) { char *path_phys = NULL; int exit_code; devctl_hdl_t dcp; if (todo != DEV_ONLINE && todo != DEV_OFFLINE) { fprintf(stderr, "%s\n", strerror(ENOTSUP)); return (-1); } /* Convert the paths to phsyical paths */ path_phys = get_slash_devices_from_osDevName(argv[0], NOT_IGNORE_DANGLING_LINK); if (!path_phys) { fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), argv[0]); fprintf(stderr, "\n"); return (-1); } if (verbose_flag) { (void) fprintf(stdout, MSGSTR(5516, "phys path = \"%s\"\n"), path_phys); } /* acquire rights to hack on device */ if ((dcp = devctl_device_acquire(path_phys, force_flag ? 0 : DC_EXCL)) == NULL) { (void) fprintf(stderr, MSGSTR(5517, "Error: can't acquire \"%s\": %s\n"), path_phys, strerror(errno)); return (1); } switch (todo) { case DEV_ONLINE: exit_code = devctl_device_online(dcp); break; case DEV_OFFLINE: exit_code = devctl_device_offline(dcp); break; default: exit_code = 0; } if (exit_code != 0) { perror(MSGSTR(5518, "devctl")); } /* all done now -- release device */ devctl_release(dcp); if (path_phys) { free(path_phys); } return (exit_code); } /* * Returns non zero if we should use FC-HBA. * For x86, luxadm uses FC-HBA. */ int use_fchba() { #ifdef __x86 return (1); #else return (0); #endif } /* * Returns non-zero if we should skip the HBA at index "i" */ int skip_hba(int i) { HBA_LIBRARYATTRIBUTES lib_attrs; (void) HBA_GetVendorLibraryAttributes(i, &lib_attrs); if (strncmp(lib_attrs.VName, VSL_NAME, sizeof (lib_attrs.VName)) == 0) { return (0); } return (1); } /* * Function to determine if the given page is supported by vendor. */ int find_supported_inq_page(HBA_HANDLE handle, HBA_WWN hwwn, HBA_WWN pwwn, uint64_t lun, int page_num) { struct scsi_extended_sense sense; L_inquiry00 inq00; uchar_t *data; HBA_STATUS status = HBA_STATUS_ERROR; int index; HBA_UINT8 scsiStatus; uint32_t inqSize = sizeof (inq00); uint32_t senseSize = sizeof (sense); status = HBA_ScsiInquiryV2(handle, hwwn, pwwn, lun, 1, 0x00, &inq00, &inqSize, &scsiStatus, &sense, &senseSize); if (status == HBA_STATUS_OK) { data = (uchar_t *)&inq00; for (index = 4; (index <= inq00.len+3)&& (data[index] <= page_num); index ++) { if (data[index] == page_num) { return (1); } } } return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #define LUX_SF_INST_SHIFT4MINOR 6 #define LUX_SF_MINOR2INST(x) (x >> LUX_SF_INST_SHIFT4MINOR) #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* For password */ #include #include #include #include #include #include #include #include #include #include "common.h" extern char *dtype[]; extern char *whoami; extern int Options; extern const int OPTION_A; extern const int OPTION_B; extern const int OPTION_C; extern const int OPTION_D; extern const int OPTION_E; extern const int OPTION_F; extern const int OPTION_L; extern const int OPTION_P; extern const int OPTION_R; extern const int OPTION_T; extern const int OPTION_V; extern const int OPTION_Z; extern const int OPTION_Y; extern const int OPTION_CAPF; extern const int PVERBOSE; extern const int SAVE; extern const int EXPERT; static struct termios termios; static int termio_fd; static void pho_display_config(char *); static void dpm_display_config(char *); static void n_rem_list_entry(uchar_t, struct gfc_map *, WWN_list **); static void n_rem_list_entry_fabric(int, struct gfc_map *, WWN_list **); static void n_rem_wwn_entry(uchar_t *, WWN_list **); static void display_disk_info(L_inquiry, L_disk_state, Path_struct *, struct mode_page *, int, char *, int); static void display_lun_info(L_disk_state, Path_struct *, struct mode_page *, int, WWN_list *, char *); static void display_fc_disk(struct path_struct *, char *, gfc_map_t *, L_inquiry, int); static void adm_display_err(char *, int); static void temperature_messages(struct l_state_struct *, int); static void ctlr_messages(struct l_state_struct *, int, int); static void fan_messages(struct l_state_struct *, int, int); static void ps_messages(struct l_state_struct *, int, int); static void abnormal_condition_display(struct l_state_struct *); static void loop_messages(struct l_state_struct *, int, int); static void revision_msg(struct l_state_struct *, int); static void mb_messages(struct l_state_struct *, int, int); static void back_plane_messages(struct l_state_struct *, int, int); static void dpm_SSC100_messages(struct l_state_struct *, int, int); static void mb_messages(struct l_state_struct *, int, int); static void back_plane_messages(struct l_state_struct *, int, int); static void dpm_SSC100_messages(struct l_state_struct *, int, int); static void trans_decode(Trans_elem_st *trans); static void trans_messages(struct l_state_struct *, int); static void adm_print_pathlist(char *); static void display_path_info(char *, char *, WWN_list *); static void copy_wwn_data_to_str(char *, const uchar_t *); static void adm_mplist_free(struct mplist_struct *); static int lun_display(Path_struct *path_struct, L_inquiry inq_struct, int verbose); static int non_encl_fc_disk_display(Path_struct *path_struct, L_inquiry inq_struct, int verbose); static int get_enclStatus(char *phys_path, char *encl_name, int off_flag); static int get_host_controller_pwwn(char *hba_path, uchar_t *pwwn); static int get_lun_capacity(char *devpath, struct scsi_capacity_16 *cap_data); static int get_path_status(char *devpath, int *status); static int get_FC4_host_controller_pwwn(char *hba_path, uchar_t *pwwn); /* * Gets the device's state from the SENA IB and * checks whether device is offlined, bypassed * or if the slot is empty and prints it to the * stdout. * * RETURNS: * 0 O.K. * non-zero otherwise */ int print_devState(char *devname, char *ppath, int fr_flag, int slot, int verbose_flag) { L_state l_state; int err; int i, elem_index = 0; uchar_t device_off, ib_status_code, bypass_a_en, bypass_b_en; Bp_elem_st bpf, bpr; if ((err = l_get_status(ppath, &l_state, verbose_flag)) != 0) { (void) print_errString(err, ppath); return (err); } for (i = 0; i < (int)l_state.ib_tbl.config.enc_num_elem; i++) { elem_index++; if (l_state.ib_tbl.config.type_hdr[i].type == ELM_TYP_BP) { break; } elem_index += l_state.ib_tbl.config.type_hdr[i].num; } (void) bcopy((const void *) &(l_state.ib_tbl.p2_s.element[elem_index]), (void *)&bpf, sizeof (bpf)); (void) bcopy((const void *) &(l_state.ib_tbl.p2_s.element[elem_index + 1]), (void *)&bpr, sizeof (bpr)); if (fr_flag) { device_off = l_state.drv_front[slot].ib_status.dev_off; bypass_a_en = l_state.drv_front[slot].ib_status.bypass_a_en; bypass_b_en = l_state.drv_front[slot].ib_status.bypass_b_en; ib_status_code = l_state.drv_front[slot].ib_status.code; } else { device_off = l_state.drv_rear[slot].ib_status.dev_off; bypass_a_en = l_state.drv_rear[slot].ib_status.bypass_a_en; bypass_b_en = l_state.drv_rear[slot].ib_status.bypass_b_en; ib_status_code = l_state.drv_rear[slot].ib_status.code; } if (device_off) { (void) fprintf(stdout, MSGSTR(2000, "%s is offlined and bypassed.\n" " Could not get device specific" " information.\n\n"), devname); } else if (bypass_a_en && bypass_b_en) { (void) fprintf(stdout, MSGSTR(2001, "%s is bypassed (Port:AB).\n" " Could not get device specific" " information.\n\n"), devname); } else if (ib_status_code == S_NOT_INSTALLED) { (void) fprintf(stdout, MSGSTR(2002, "Slot %s is empty.\n\n"), devname); } else if (((bpf.code != S_NOT_INSTALLED) && ((bpf.byp_a_enabled || bpf.en_bypass_a) && (bpf.byp_b_enabled || bpf.en_bypass_b))) || ((bpr.code != S_NOT_INSTALLED) && ((bpr.byp_a_enabled || bpr.en_bypass_a) && (bpr.byp_b_enabled || bpr.en_bypass_b)))) { (void) fprintf(stdout, MSGSTR(2003, "Backplane(Port:AB) is bypassed.\n" " Could not get device specific" " information for" " %s.\n\n"), devname); } else { (void) fprintf(stderr, MSGSTR(33, " Error: converting" " %s to physical path.\n" " Invalid pathname.\n"), devname); } return (-1); } /* * Given an error number, this functions * calls the get_errString() to print a * corresponding error message to the stderr. * get_errString() always returns an error * message, even in case of undefined error number. * So, there is no need to check for a NULL pointer * while printing the error message to the stdout. * * RETURNS: N/A * */ void print_errString(int errnum, char *devpath) { char *errStr; errStr = g_get_errString(errnum); if (devpath == NULL) { (void) fprintf(stderr, "%s \n\n", errStr); } else { (void) fprintf(stderr, "%s - %s.\n\n", errStr, devpath); } /* free the allocated memory for error string */ if (errStr != NULL) (void) free(errStr); } /* * adm_inquiry() Display the inquiry information for * a SENA enclosure(s) or disk(s). * * RETURNS: * none. */ int adm_inquiry(char **argv) { L_inquiry inq; L_inquiry80 inq80; size_t serial_len; int path_index = 0, retval = 0; int slot, f_r, err = 0, argpwwn, argnwwn; char inq_path[MAXNAMELEN]; char *path_phys = NULL, *ptr; Path_struct *path_struct; WWN_list *wwn_list, *wwn_list_ptr, *list_start; char last_logical_path[MAXPATHLEN]; while (argv[path_index] != NULL) { if ((err = l_convert_name(argv[path_index], &path_phys, &path_struct, Options & PVERBOSE)) != 0) { (void) strcpy(inq_path, argv[path_index]); if (((ptr = strstr(inq_path, ",")) != NULL) && ((*(ptr + 1) == 'f') || (*(ptr + 1) == 'r') || (*(ptr +1) == 's'))) { if (err != -1) { (void) print_errString(err, argv[path_index]); path_index++; retval++; continue; } *ptr = '\0'; slot = path_struct->slot; f_r = path_struct->f_flag; path_phys = NULL; if ((err = l_convert_name(inq_path, &path_phys, &path_struct, Options & PVERBOSE)) != 0) { (void) fprintf(stderr, MSGSTR(33, " Error: converting" " %s to physical path.\n" " Invalid pathname.\n"), argv[path_index]); if (err != -1) { (void) print_errString(err, argv[path_index]); } path_index++; retval++; continue; } if ((err = print_devState(argv[path_index], path_struct->p_physical_path, f_r, slot, Options & PVERBOSE)) != 0) { path_index++; retval++; continue; } } else { if (err != -1) { (void) print_errString(err, argv[path_index]); } else { (void) fprintf(stderr, "\n "); (void) fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), argv[path_index]); (void) fprintf(stderr, "\n"); } } path_index++; retval++; continue; } if (strstr(argv[path_index], "/") != NULL) { if (err = g_get_inquiry(path_phys, &inq)) { (void) fprintf(stderr, "\n"); (void) print_errString(err, argv[path_index]); (void) fprintf(stderr, "\n"); path_index++; retval++; continue; } serial_len = sizeof (inq80.inq_serial); if (err = g_get_serial_number(path_phys, inq80.inq_serial, &serial_len)) { (void) fprintf(stderr, "\n"); (void) print_errString(err, argv[path_index]); (void) fprintf(stderr, "\n"); path_index++; retval++; continue; } print_inq_data(argv[path_index], path_phys, inq, inq80.inq_serial, serial_len); path_index++; continue; } if ((err = g_get_wwn_list(&wwn_list, 0)) != 0) { return (err); } g_sort_wwn_list(&wwn_list); list_start = wwn_list; argpwwn = argnwwn = 0; (void) strcpy(last_logical_path, path_phys); for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL; wwn_list_ptr = wwn_list_ptr->wwn_next) { if (strcasecmp(wwn_list_ptr->port_wwn_s, path_struct->argv) == 0) { list_start = wwn_list_ptr; argpwwn = 1; break; } else if (strcasecmp(wwn_list_ptr->node_wwn_s, path_struct->argv) == 0) { list_start = wwn_list_ptr; argnwwn = 1; break; } } if (!(argpwwn || argnwwn)) { /* * if the wwn list is null or the arg device not found * from the wwn list, still go ahead to issue inquiry. */ if (err = g_get_inquiry(path_phys, &inq)) { (void) fprintf(stderr, "\n"); (void) print_errString(err, argv[path_index]); (void) fprintf(stderr, "\n"); path_index++; retval++; continue; } serial_len = sizeof (inq80.inq_serial); if (err = g_get_serial_number(path_phys, inq80.inq_serial, &serial_len)) { (void) fprintf(stderr, "\n"); (void) print_errString(err, argv[path_index]); (void) fprintf(stderr, "\n"); path_index++; retval++; continue; } print_inq_data(argv[path_index], path_phys, inq, inq80.inq_serial, serial_len); (void) g_free_wwn_list(&wwn_list); path_index++; continue; } for (wwn_list_ptr = list_start; wwn_list_ptr != NULL; wwn_list_ptr = wwn_list_ptr->wwn_next) { if (argpwwn) { if (strcasecmp(wwn_list_ptr->port_wwn_s, path_struct->argv) != 0) { continue; } (void) strcpy(path_phys, wwn_list_ptr->physical_path); } else if (argnwwn) { if (strcasecmp(wwn_list_ptr->node_wwn_s, path_struct->argv) != 0) { continue; } if (strstr(wwn_list_ptr->logical_path, last_logical_path) != NULL) { continue; } (void) strcpy(path_phys, wwn_list_ptr->physical_path); (void) strcpy(last_logical_path, wwn_list_ptr->logical_path); } if (err = g_get_inquiry(path_phys, &inq)) { (void) fprintf(stderr, "\n"); (void) print_errString(err, argv[path_index]); (void) fprintf(stderr, "\n"); retval++; break; } serial_len = sizeof (inq80.inq_serial); if (err = g_get_serial_number(path_phys, inq80.inq_serial, &serial_len)) { (void) fprintf(stderr, "\n"); (void) print_errString(err, argv[path_index]); (void) fprintf(stderr, "\n"); retval++; break; } print_inq_data(argv[path_index], path_phys, inq, inq80.inq_serial, serial_len); } (void) g_free_wwn_list(&wwn_list); path_index++; } return (retval); } /* * FORCELIP expert function */ int adm_forcelip(char **argv) { int slot, f_r, path_index = 0, err = 0, retval = 0; Path_struct *path_struct = NULL; char *path_phys = NULL, *ptr; char err_path[MAXNAMELEN]; while (argv[path_index] != NULL) { if ((err = l_convert_name(argv[path_index], &path_phys, &path_struct, Options & PVERBOSE)) != 0) { (void) strcpy(err_path, argv[path_index]); if (err != -1) { (void) print_errString(err, argv[path_index]); path_index++; retval++; continue; } if (((ptr = strstr(err_path, ", ")) != NULL) && ((*(ptr + 1) == 'f') || (*(ptr + 1) == 'r') || (*(ptr +1) == 's'))) { *ptr = '\0'; slot = path_struct->slot; f_r = path_struct->f_flag; path_phys = NULL; if ((err = l_convert_name(err_path, &path_phys, &path_struct, Options & PVERBOSE)) != 0) { (void) fprintf(stderr, MSGSTR(33, " Error: converting" " %s to physical path.\n" " Invalid pathname.\n"), argv[path_index]); if (err != -1) { (void) print_errString(err, argv[path_index]); } path_index++; retval++; continue; } if ((err = print_devState(argv[path_index], path_struct->p_physical_path, f_r, slot, Options & PVERBOSE)) != 0) { path_index++; retval++; continue; } } else { (void) fprintf(stderr, "\n "); (void) fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), argv[path_index]); (void) fprintf(stderr, "\n"); } path_index++; retval++; continue; } if (err = g_force_lip(path_phys, Options & PVERBOSE)) { (void) print_errString(err, argv[path_index]); path_index++; retval++; continue; } path_index++; if (path_struct != NULL) { (void) free(path_struct); } } return (retval); } /* * DISPLAY function * * RETURNS: * 0 O.K. */ int adm_display_config(char **argv) { L_inquiry inq, ses_inq; int i, slot, f_r, path_index = 0, err = 0, opnerr = 0; int retval = 0; gfc_map_t map; Path_struct *path_struct; char *path_phys = NULL, *ptr; char ses_path[MAXPATHLEN], inq_path[MAXNAMELEN]; while (argv[path_index] != NULL) { VERBPRINT(MSGSTR(2108, " Displaying information for: %s\n"), argv[path_index]); map.dev_addr = (gfc_port_dev_info_t *)NULL; if ((err = l_convert_name(argv[path_index], &path_phys, &path_struct, Options & PVERBOSE)) != 0) { if (strstr(argv[path_index], SCSI_VHCI) == NULL) { (void) strcpy(inq_path, argv[path_index]); if (((ptr = strstr(inq_path, ",")) != NULL) && ((*(ptr + 1) == 'f') || (*(ptr + 1) == 'r') || (*(ptr +1) == 's'))) { if (err != -1) { (void) print_errString(err, argv[path_index]); path_index++; retval++; continue; } *ptr = '\0'; slot = path_struct->slot; f_r = path_struct->f_flag; if ((err = l_convert_name(inq_path, &path_phys, &path_struct, Options & PVERBOSE)) != 0) { (void) fprintf(stderr, MSGSTR(33, " Error: converting" " %s to physical path.\n" " Invalid pathname.\n"), argv[path_index]); if (err != -1) { (void) print_errString(err, argv[path_index]); } path_index++; retval++; continue; } if ((err = print_devState(argv[path_index], path_struct->p_physical_path, f_r, slot, Options & PVERBOSE)) != 0) { path_index++; retval++; continue; } } else { if (err != -1) { (void) print_errString(err, argv[path_index]); } else { (void) fprintf(stderr, "\n "); (void) fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), argv[path_index]); (void) fprintf(stderr, "\n"); } } } else { if (err != -1) { (void) print_errString(err, argv[path_index]); } else { (void) fprintf(stderr, "\n "); (void) fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), argv[path_index]); (void) fprintf(stderr, "\n"); } } path_index++; retval++; continue; } /* * See what kind of device we are talking to. */ if ((opnerr = g_get_inquiry(path_phys, &inq)) != 0) { if (opnerr == L_OPEN_PATH_FAIL) { /* * We check only for L_OPEN_PATH_FAIL because * that is the only error code returned by * g_get_inquiry() which is not got from the ioctl * call itself. So, we are dependent, in a way, on the * implementation of g_get_inquiry(). * */ (void) print_errString(errno, argv[path_index]); path_index++; retval++; continue; } } else if (!g_enclDiskChk((char *)inq.inq_vid, (char *)inq.inq_pid)) { if ((err = lun_display(path_struct, inq, Options & PVERBOSE)) != 0) { (void) print_errString(err, path_phys); exit(1); } } else if (strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) != NULL) { /* * Display SENA enclosure. */ (void) fprintf(stdout, "\n\t\t\t\t "); print_chars(inq.inq_pid, sizeof (inq.inq_pid), 0); (void) fprintf(stdout, "\n"); if (Options & OPTION_R) { adm_display_err(path_phys, (inq.inq_dtype & DTYPE_MASK)); } else { pho_display_config(path_phys); } } else if ((((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)) && (l_get_enc_type(inq) == DAK_ENC_TYPE)) { /* * Display for the Daktari/DPM */ (void) fprintf(stdout, "\n\t\t"); for (i = 0; i < sizeof (inq.inq_pid); i++) { (void) fprintf(stdout, "%c", inq.inq_pid[i]); } (void) fprintf(stdout, "\n"); if (Options & OPTION_R) { adm_display_err(path_phys, (inq.inq_dtype & DTYPE_MASK)); } else { dpm_display_config(path_phys); } /* * if device is in SENA enclosure * * if the slot is valid, then I know this is a SENA enclosure * and can continue * otherwise: * I first get the ses_path, if this doesn't fail * I retrieve the inquiry data from the ses node * and check teh PID to make sure this is a SENA */ } else if (((inq.inq_dtype & DTYPE_MASK) == DTYPE_DIRECT) && ((path_struct->slot_valid == 1) || ((g_get_dev_map(path_phys, &map, (Options & PVERBOSE)) == 0) && (l_get_ses_path(path_phys, ses_path, &map, Options & PVERBOSE) == 0) && (g_get_inquiry(ses_path, &ses_inq) == 0) && ((strstr((char *)ses_inq.inq_pid, ENCLOSURE_PROD_ID) != NULL))))) { if (Options & OPTION_R) { adm_display_err(path_phys, (inq.inq_dtype & DTYPE_MASK)); } else { display_fc_disk(path_struct, ses_path, &map, inq, Options & PVERBOSE); } } else if (strstr((char *)inq.inq_pid, "SUN_SEN") != 0) { if (strcmp(argv[path_index], path_phys) != 0) { (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(5, "Physical Path:")); (void) fprintf(stdout, "\n %s\n", path_phys); } (void) fprintf(stdout, MSGSTR(2109, "DEVICE is a ")); print_chars(inq.inq_vid, sizeof (inq.inq_vid), 1); (void) fprintf(stdout, " "); print_chars(inq.inq_pid, sizeof (inq.inq_pid), 1); (void) fprintf(stdout, MSGSTR(2110, " card.")); if (inq.inq_len > 31) { (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(26, "Revision:")); (void) fprintf(stdout, " "); print_chars(inq.inq_revision, sizeof (inq.inq_revision), 0); } (void) fprintf(stdout, "\n"); /* if device is not in SENA or SSA enclosures. */ } else if ((inq.inq_dtype & DTYPE_MASK) < 0x10) { switch ((inq.inq_dtype & DTYPE_MASK)) { case DTYPE_DIRECT: case DTYPE_SEQUENTIAL: /* Tape */ if (Options & OPTION_R) { adm_display_err(path_phys, (inq.inq_dtype & DTYPE_MASK)); } else if (non_encl_fc_disk_display(path_struct, inq, Options & PVERBOSE) != 0) { (void) fprintf(stderr, MSGSTR(2111, "Error: getting the device" " information.\n")); retval++; } break; /* case 0x01: same as default */ default: (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(35, "Device Type:")); (void) fprintf(stdout, "%s\n", dtype[inq.inq_dtype & DTYPE_MASK]); break; } } else if ((inq.inq_dtype & DTYPE_MASK) < 0x1f) { (void) fprintf(stdout, MSGSTR(2112, " Device type: Reserved")); (void) fprintf(stdout, "\n"); } else { (void) fprintf(stdout, MSGSTR(2113, " Device type: Unknown device")); (void) fprintf(stdout, "\n"); } path_index++; if (map.dev_addr != NULL) { free((void *)map.dev_addr); } (void) free(path_struct); } return (retval); } /* * Powers off a list of SENA enclosure(s) * and disk(s) which is provided by the user. * * RETURNS: * none. */ int adm_power_off(char **argv, int off_flag) { int path_index = 0, err = 0, retval = 0; L_inquiry inq; char *path_phys = NULL; Path_struct *path_struct; while (argv[path_index] != NULL) { if ((err = l_convert_name(argv[path_index], &path_phys, &path_struct, Options & PVERBOSE)) != 0) { /* * In case we did not find the device * in the /devices directory. * * Only valid for pathnames like box,f1 */ if (path_struct->ib_path_flag) { path_phys = path_struct->p_physical_path; } else { (void) fprintf(stderr, MSGSTR(33, " Error: converting" " %s to physical path.\n" " Invalid pathname.\n"), argv[path_index]); if (err != -1) { (void) print_errString(err, argv[path_index]); } path_index++; retval++; continue; } } if (path_struct->ib_path_flag) { /* * We are addressing a disk using a path * format type box,f1. */ if (err = l_dev_pwr_up_down(path_phys, path_struct, off_flag, Options & PVERBOSE, Options & OPTION_CAPF)) { /* * Is it Bypassed... try to give more * informtaion. */ print_devState(argv[path_index], path_struct->p_physical_path, path_struct->f_flag, path_struct->slot, Options & PVERBOSE); retval++; } path_index++; continue; } if (err = g_get_inquiry(path_phys, &inq)) { (void) print_errString(err, argv[path_index]); path_index++; retval++; continue; } if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) != 0) || (strncmp((char *)inq.inq_vid, "SUN ", sizeof (inq.inq_vid)) && ((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI))) { if (get_enclStatus(path_phys, argv[path_index], off_flag) != 0) { path_index++; retval++; continue; } /* power off SENA enclosure. */ if (err = l_pho_pwr_up_down(argv[path_index], path_phys, off_flag, Options & PVERBOSE, Options & OPTION_CAPF)) { (void) print_errString(err, argv[path_index]); retval++; } } else if ((inq.inq_dtype & DTYPE_MASK) == DTYPE_DIRECT) { if (err = l_dev_pwr_up_down(path_phys, path_struct, off_flag, Options & PVERBOSE, Options & OPTION_CAPF)) { (void) print_errString(err, argv[path_index]); retval++; } } else { /* * SSA section: */ (void) print_errString(L_INVALID_PATH, argv[path_index]); } path_index++; } return (retval); } void adm_bypass_enable(char **argv, int bypass_flag) { int path_index = 0, err = 0; L_inquiry inq; char *path_phys = NULL; Path_struct *path_struct; if ((err = l_convert_name(argv[path_index], &path_phys, &path_struct, Options & PVERBOSE)) != 0) { /* * In case we did not find the device * in the /devices directory. * * Only valid for pathnames like box,f1 */ if (path_struct->ib_path_flag) { path_phys = path_struct->p_physical_path; } else { (void) fprintf(stderr, MSGSTR(33, " Error: converting" " %s to physical path.\n" " Invalid pathname.\n"), argv[path_index]); if (err != -1) { (void) print_errString(err, argv[path_index]); } exit(-1); } } if (path_struct->ib_path_flag) { if (Options & OPTION_F) { E_USEAGE(); exit(-1); } /* * We are addressing a disk using a path * format type box,f1 and no disk * path was found. * So set the Force flag so no reserved/busy * check is performed. */ if (err = l_dev_bypass_enable(path_struct, bypass_flag, OPTION_CAPF, Options & OPTION_A, Options & PVERBOSE)) { (void) print_errString(err, argv[path_index]); exit(-1); } return; } if (err = g_get_inquiry(path_phys, &inq)) { (void) print_errString(err, argv[path_index]); exit(-1); } if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) != 0) || (strncmp((char *)inq.inq_vid, "SUN ", sizeof (inq.inq_vid)) && ((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI))) { if ((!((Options & OPTION_F) || (Options & OPTION_R))) || ((Options & OPTION_R) && (Options & OPTION_F))) { E_USEAGE(); exit(-1); } if (err = l_bp_bypass_enable(path_phys, bypass_flag, Options & OPTION_A, Options & OPTION_F, Options & OPTION_CAPF, Options & PVERBOSE)) { (void) print_errString(err, argv[path_index]); exit(-1); } } else if ((inq.inq_dtype & DTYPE_MASK) == DTYPE_DIRECT) { if (Options & OPTION_F) { E_USEAGE(); exit(-1); } if (err = l_dev_bypass_enable(path_struct, bypass_flag, Options & OPTION_CAPF, Options & OPTION_A, Options & PVERBOSE)) { (void) print_errString(err, argv[path_index]); exit(-1); } } } /* * adm_download() Download subsystem microcode. * Path must point to a LUX IB. * * RETURNS: * None. */ void adm_download(char **argv, char *file_name) { int path_index = 0, err = 0; char *path_phys = NULL; L_inquiry inq; Path_struct *path_struct; while (argv[path_index] != NULL) { /* * See what kind of device we are talking to. */ if ((err = l_convert_name(argv[path_index], &path_phys, &path_struct, Options & PVERBOSE)) != 0) { (void) fprintf(stderr, MSGSTR(33, " Error: converting" " %s to physical path.\n" " Invalid pathname.\n"), argv[path_index]); if (err != -1) { (void) print_errString(err, argv[path_index]); } exit(-1); } if (err = g_get_inquiry(path_phys, &inq)) { (void) print_errString(err, argv[path_index]); exit(-1); } if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) != 0) || (strncmp((char *)inq.inq_vid, "SUN ", sizeof (inq.inq_vid)) && ((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI))) { if (err = l_download(path_phys, file_name, (Options & SAVE), (Options & PVERBOSE))) { (void) print_errString(err, (err == L_OPEN_PATH_FAIL) ? argv[path_index]: file_name); exit(-1); } } else { (void) fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), argv[path_index]); } path_index++; } } /* * display_link_status() Reads and displays the link status. * * RETURNS: * none. */ void display_link_status(char **argv) { AL_rls *rls = NULL, *n; int path_index = 0, err = 0; char *path_phys = NULL; Path_struct *path_struct; while (argv[path_index] != NULL) { if ((err = l_convert_name(argv[path_index], &path_phys, &path_struct, Options & PVERBOSE)) != 0) { (void) fprintf(stderr, MSGSTR(33, " Error: converting" " %s to physical path.\n" " Invalid pathname.\n"), argv[path_index]); if (err != -1) { (void) print_errString(err, argv[path_index]); } exit(-1); } if (err = g_rdls(path_phys, &rls, Options & PVERBOSE)) { (void) print_errString(err, argv[path_index]); exit(-1); } n = rls; if (n != NULL) { (void) fprintf(stdout, MSGSTR(2007, "\nLink Error Status " "information for loop:%s\n"), n->driver_path); (void) fprintf(stdout, MSGSTR(2008, "al_pa lnk fail " " sync loss signal loss sequence err" " invalid word CRC\n")); } while (n) { if ((n->payload.rls_linkfail == 0xffffffff) && (n->payload.rls_syncfail == 0xffffffff) && (n->payload.rls_sigfail == 0xffffffff) && (n->payload.rls_primitiverr == 0xffffffff) && (n->payload.rls_invalidword == 0xffffffff) && (n->payload.rls_invalidcrc == 0xffffffff)) { (void) fprintf(stdout, "%x\t%-12d%-12d%-14d%-15d%-15d%-12d\n", n->al_ha, n->payload.rls_linkfail, n->payload.rls_syncfail, n->payload.rls_sigfail, n->payload.rls_primitiverr, n->payload.rls_invalidword, n->payload.rls_invalidcrc); } else { (void) fprintf(stdout, "%x\t%-12u%-12u%-14u%-15u%-15u%-12u\n", n->al_ha, n->payload.rls_linkfail, n->payload.rls_syncfail, n->payload.rls_sigfail, n->payload.rls_primitiverr, n->payload.rls_invalidword, n->payload.rls_invalidcrc); } n = n->next; } path_index++; } (void) fprintf(stdout, MSGSTR(2009, "NOTE: These LESB counts are not" " cleared by a reset, only power cycles.\n" "These counts must be compared" " to previously read counts.\n")); } /* * ib_present_chk() Check to see if IB 0 or 1 is present in the box. * * RETURN: * 1 if ib present * 0 otherwise */ int ib_present_chk(struct l_state_struct *l_state, int which_one) { Ctlr_elem_st ctlr; int i; int elem_index = 0; int result = 1; for (i = 0; i < (int)l_state->ib_tbl.config.enc_num_elem; i++) { elem_index++; /* skip global */ if (l_state->ib_tbl.config.type_hdr[i].type == ELM_TYP_IB) { (void) bcopy((const void *) &l_state->ib_tbl.p2_s.element[elem_index + which_one], (void *)&ctlr, sizeof (ctlr)); if (ctlr.code == S_NOT_INSTALLED) { result = 0; } break; } elem_index += l_state->ib_tbl.config.type_hdr[i].num; } return (result); } /* * print_individual_state() Print individual disk status. * * RETURNS: * none. */ void print_individual_state(int status, int port) { if (status & L_OPEN_FAIL) { (void) fprintf(stdout, " ("); (void) fprintf(stdout, MSGSTR(28, "Open Failed")); (void) fprintf(stdout, ") "); } else if (status & L_NOT_READY) { (void) fprintf(stdout, " ("); (void) fprintf(stdout, MSGSTR(20, "Not Ready")); (void) fprintf(stdout, ") "); } else if (status & L_NOT_READABLE) { (void) fprintf(stdout, "("); (void) fprintf(stdout, MSGSTR(88, "Not Readable")); (void) fprintf(stdout, ") "); } else if (status & L_SPUN_DWN_D) { (void) fprintf(stdout, " ("); (void) fprintf(stdout, MSGSTR(68, "Spun Down")); (void) fprintf(stdout, ") "); } else if (status & L_SCSI_ERR) { (void) fprintf(stdout, " ("); (void) fprintf(stdout, MSGSTR(70, "SCSI Error")); (void) fprintf(stdout, ") "); } else if (status & L_RESERVED) { if (port == PORT_A) { (void) fprintf(stdout, MSGSTR(2010, " (Rsrv cnflt:A) ")); } else if (port == PORT_B) { (void) fprintf(stdout, MSGSTR(2011, " (Rsrv cnflt:B) ")); } else { (void) fprintf(stdout, MSGSTR(2012, " (Reserve cnflt)")); } } else if (status & L_NO_LABEL) { (void) fprintf(stdout, "("); (void) fprintf(stdout, MSGSTR(92, "No UNIX Label")); (void) fprintf(stdout, ") "); } } /* * display_disk_msg() Displays status for * an individual SENA device. * * RETURNS: * none. */ void display_disk_msg(struct l_disk_state_struct *dsk_ptr, struct l_state_struct *l_state, Bp_elem_st *bp, int front_flag) { int loop_flag = 0; int a_and_b = 0; int state_a = 0, state_b = 0; if (dsk_ptr->ib_status.code == S_NOT_INSTALLED) { (void) fprintf(stdout, MSGSTR(30, "Not Installed")); (void) fprintf(stdout, " "); if (dsk_ptr->ib_status.fault || dsk_ptr->ib_status.fault_req) { (void) fprintf(stdout, "("); (void) fprintf(stdout, MSGSTR(2013, "Faulted")); (void) fprintf(stdout, ") "); } else if (dsk_ptr->ib_status.ident || dsk_ptr->ib_status.rdy_to_ins || dsk_ptr->ib_status.rmv) { (void) fprintf(stdout, MSGSTR(2014, "(LED Blinking) ")); } else { (void) fprintf(stdout, " "); } } else if (dsk_ptr->ib_status.dev_off) { (void) fprintf(stdout, MSGSTR(2015, "Off")); if (dsk_ptr->ib_status.fault || dsk_ptr->ib_status.fault_req) { (void) fprintf(stdout, "("); (void) fprintf(stdout, MSGSTR(2016, "Faulted")); (void) fprintf(stdout, ") "); } else if (dsk_ptr->ib_status.bypass_a_en && dsk_ptr->ib_status.bypass_b_en) { (void) fprintf(stdout, MSGSTR(2017, "(Bypassed:AB)")); (void) fprintf(stdout, " "); } else if (dsk_ptr->ib_status.bypass_a_en) { (void) fprintf(stdout, MSGSTR(2018, "(Bypassed: A)")); (void) fprintf(stdout, " "); } else if (dsk_ptr->ib_status.bypass_b_en) { (void) fprintf(stdout, MSGSTR(2019, "(Bypassed: B)")); (void) fprintf(stdout, " "); } else { (void) fprintf(stdout, " "); } } else { (void) fprintf(stdout, MSGSTR(2020, "On")); if (dsk_ptr->ib_status.fault || dsk_ptr->ib_status.fault_req) { (void) fprintf(stdout, " ("); (void) fprintf(stdout, MSGSTR(2021, "Faulted")); (void) fprintf(stdout, ") "); } else if (dsk_ptr->ib_status.bypass_a_en && dsk_ptr->ib_status.bypass_b_en) { (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(2022, "(Bypassed:AB)")); (void) fprintf(stdout, " "); } else if (ib_present_chk(l_state, 0) && dsk_ptr->ib_status.bypass_a_en) { /* * Before printing that the port is bypassed * verify that there is an IB for this port. * If not then don't print. */ (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(2023, "(Bypassed: A)")); (void) fprintf(stdout, " "); } else if (ib_present_chk(l_state, 1) && dsk_ptr->ib_status.bypass_b_en) { (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(2024, "(Bypassed: B)")); (void) fprintf(stdout, " "); } else if ((bp->code != S_NOT_INSTALLED) && ((bp->byp_a_enabled || bp->en_bypass_a) && !(bp->byp_b_enabled || bp->en_bypass_b))) { (void) fprintf(stdout, MSGSTR(2025, " (Bypassed BP: A)")); } else if ((bp->code != S_NOT_INSTALLED) && ((bp->byp_b_enabled || bp->en_bypass_b) && !(bp->byp_a_enabled || bp->en_bypass_a))) { (void) fprintf(stdout, MSGSTR(2026, "(Bypassed BP: B)")); } else if ((bp->code != S_NOT_INSTALLED) && ((bp->byp_a_enabled || bp->en_bypass_a) && (bp->byp_b_enabled || bp->en_bypass_b))) { (void) fprintf(stdout, MSGSTR(2027, "(Bypassed BP:AB)")); } else { state_a = dsk_ptr->g_disk_state.d_state_flags[PORT_A]; state_b = dsk_ptr->g_disk_state.d_state_flags[PORT_B]; a_and_b = state_a & state_b; if (dsk_ptr->l_state_flag & L_NO_LOOP) { (void) fprintf(stdout, MSGSTR(2028, " (Loop not accessible)")); loop_flag = 1; } else if (dsk_ptr->l_state_flag & L_INVALID_WWN) { (void) fprintf(stdout, MSGSTR(2029, " (Invalid WWN) ")); } else if (dsk_ptr->l_state_flag & L_INVALID_MAP) { (void) fprintf(stdout, MSGSTR(2030, " (Login failed) ")); } else if (dsk_ptr->l_state_flag & L_NO_PATH_FOUND) { (void) fprintf(stdout, MSGSTR(2031, " (No path found)")); } else if (a_and_b) { print_individual_state(a_and_b, PORT_A_B); } else if (state_a && (!state_b)) { print_individual_state(state_a, PORT_A); } else if ((!state_a) && state_b) { print_individual_state(state_b, PORT_B); } else if (state_a || state_b) { /* NOTE: Double state - should do 2 lines. */ print_individual_state(state_a | state_b, PORT_A_B); } else { (void) fprintf(stdout, " ("); (void) fprintf(stdout, MSGSTR(29, "O.K.")); (void) fprintf(stdout, ") "); } } if (loop_flag) { (void) fprintf(stdout, " "); } else if (strlen(dsk_ptr->g_disk_state.node_wwn_s)) { (void) fprintf(stdout, "%s", dsk_ptr->g_disk_state.node_wwn_s); } else { (void) fprintf(stdout, " "); } } if (front_flag) { (void) fprintf(stdout, " "); } } /* * pho_display_config() Displays device status * information for a SENA enclosure. * * RETURNS: * none. */ void pho_display_config(char *path_phys) { L_state l_state; Bp_elem_st bpf, bpr; int i, j, elem_index = 0, err = 0; /* Get global status */ if (err = l_get_status(path_phys, &l_state, (Options & PVERBOSE))) { (void) print_errString(err, path_phys); exit(-1); } /* * Look for abnormal status. */ if (l_state.ib_tbl.p2_s.ui.ab_cond) { abnormal_condition_display(&l_state); } (void) fprintf(stdout, MSGSTR(2032, " DISK STATUS \n" "SLOT FRONT DISKS (Node WWN) " " REAR DISKS (Node WWN)\n")); /* * Print the status for each disk */ for (j = 0; j < (int)l_state.ib_tbl.config.enc_num_elem; j++) { elem_index++; if (l_state.ib_tbl.config.type_hdr[j].type == ELM_TYP_BP) break; elem_index += l_state.ib_tbl.config.type_hdr[j].num; } (void) bcopy((const void *) &(l_state.ib_tbl.p2_s.element[elem_index]), (void *)&bpf, sizeof (bpf)); (void) bcopy((const void *) &(l_state.ib_tbl.p2_s.element[elem_index + 1]), (void *)&bpr, sizeof (bpr)); for (i = 0; i < (int)l_state.total_num_drv/2; i++) { (void) fprintf(stdout, "%-2d ", i); display_disk_msg(&l_state.drv_front[i], &l_state, &bpf, 1); display_disk_msg(&l_state.drv_rear[i], &l_state, &bpr, 0); (void) fprintf(stdout, "\n"); } /* * Display the subsystem status. */ (void) fprintf(stdout, MSGSTR(2242, " SUBSYSTEM STATUS\nFW Revision:")); print_chars(l_state.ib_tbl.config.prod_revision, sizeof (l_state.ib_tbl.config.prod_revision), 1); (void) fprintf(stdout, MSGSTR(2034, " Box ID:%d"), l_state.ib_tbl.box_id); (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(90, "Node WWN:")); for (i = 0; i < 8; i++) { (void) fprintf(stdout, "%1.2x", l_state.ib_tbl.config.enc_node_wwn[i]); } /* Make sure NULL terminated although it is supposed to be */ if (strlen((const char *)l_state.ib_tbl.enclosure_name) <= sizeof (l_state.ib_tbl.enclosure_name)) { (void) fprintf(stdout, MSGSTR(2035, " Enclosure Name:%s\n"), l_state.ib_tbl.enclosure_name); } /* * */ elem_index = 0; /* Get and print CONTROLLER messages */ for (i = 0; i < (int)l_state.ib_tbl.config.enc_num_elem; i++) { elem_index++; /* skip global */ switch (l_state.ib_tbl.config.type_hdr[i].type) { case ELM_TYP_PS: ps_messages(&l_state, i, elem_index); break; case ELM_TYP_FT: fan_messages(&l_state, i, elem_index); break; case ELM_TYP_BP: back_plane_messages(&l_state, i, elem_index); break; case ELM_TYP_IB: ctlr_messages(&l_state, i, elem_index); break; case ELM_TYP_LN: /* * NOTE: I just use the Photon's message * string here and don't look at the * language code. The string includes * the language name. */ if (l_state.ib_tbl.config.type_hdr[i].text_len != 0) { (void) fprintf(stdout, "%s\t", l_state.ib_tbl.config.text[i]); } break; case ELM_TYP_LO: /* Loop configuration */ loop_messages(&l_state, i, elem_index); break; case ELM_TYP_MB: /* Loop configuration */ mb_messages(&l_state, i, elem_index); break; } /* * Calculate the index to each element. */ elem_index += l_state.ib_tbl.config.type_hdr[i].num; } (void) fprintf(stdout, "\n"); } /* * dpm_display_config() Displays device status * information for a DAKTARI enclosure. * * RETURNS: * none. */ void dpm_display_config(char *path_phys) { L_state l_state; Bp_elem_st bpf, bpr; int i, j, elem_index = 0, err = 0, count; /* Get global status */ if (err = l_get_status(path_phys, &l_state, (Options & PVERBOSE))) { (void) print_errString(err, path_phys); exit(-1); } /* * Look for abnormal status. */ if (l_state.ib_tbl.p2_s.ui.ab_cond) { abnormal_condition_display(&l_state); } (void) fprintf(stdout, MSGSTR(2247, " DISK STATUS \n" "SLOT DISKS (Node WWN) \n")); /* * Print the status for each disk */ for (j = 0; j < (int)l_state.ib_tbl.config.enc_num_elem; j++) { elem_index++; if (l_state.ib_tbl.config.type_hdr[j].type == ELM_TYP_BP) break; elem_index += l_state.ib_tbl.config.type_hdr[j].num; } (void) bcopy((const void *) &(l_state.ib_tbl.p2_s.element[elem_index]), (void *)&bpf, sizeof (bpf)); (void) bcopy((const void *) &(l_state.ib_tbl.p2_s.element[elem_index + 1]), (void *)&bpr, sizeof (bpr)); for (i = 0, count = 0; i < (int)l_state.total_num_drv/2; i++, count++) { (void) fprintf(stdout, "%-2d ", count); display_disk_msg(&l_state.drv_front[i], &l_state, &bpf, 1); (void) fprintf(stdout, "\n"); } for (i = 0; i < (int)l_state.total_num_drv/2; i++, count++) { (void) fprintf(stdout, "%-2d ", count); display_disk_msg(&l_state.drv_rear[i], &l_state, &bpf, 1); (void) fprintf(stdout, "\n"); } /* * Display the subsystem status. */ (void) fprintf(stdout, MSGSTR(2033, "\t\tSUBSYSTEM STATUS\nFW Revision:")); for (i = 0; i < sizeof (l_state.ib_tbl.config.prod_revision); i++) { (void) fprintf(stdout, "%c", l_state.ib_tbl.config.prod_revision[i]); } (void) fprintf(stdout, MSGSTR(2034, " Box ID:%d"), l_state.ib_tbl.box_id); (void) fprintf(stdout, "\n "); (void) fprintf(stdout, MSGSTR(90, "Node WWN:")); for (i = 0; i < 8; i++) { (void) fprintf(stdout, "%1.2x", l_state.ib_tbl.config.enc_node_wwn[i]); } /* Make sure NULL terminated although it is supposed to be */ if (strlen((const char *)l_state.ib_tbl.enclosure_name) <= sizeof (l_state.ib_tbl.enclosure_name)) { (void) fprintf(stdout, MSGSTR(2035, " Enclosure Name:%s\n"), l_state.ib_tbl.enclosure_name); } /* * */ elem_index = 0; /* Get and print CONTROLLER messages */ for (i = 0; i < (int)l_state.ib_tbl.config.enc_num_elem; i++) { elem_index++; /* skip global */ switch (l_state.ib_tbl.config.type_hdr[i].type) { case ELM_TYP_PS: ps_messages(&l_state, i, elem_index); break; case ELM_TYP_FT: fan_messages(&l_state, i, elem_index); break; case ELM_TYP_BP: dpm_SSC100_messages(&l_state, i, elem_index); break; case ELM_TYP_IB: ctlr_messages(&l_state, i, elem_index); break; case ELM_TYP_LN: /* * NOTE: I just use the Photon's message * string here and don't look at the * language code. The string includes * the language name. */ if (l_state.ib_tbl.config.type_hdr[i].text_len != 0) { (void) fprintf(stdout, "%s\t", l_state.ib_tbl.config.text[i]); } break; case ELM_TYP_LO: /* Loop configuration */ loop_messages(&l_state, i, elem_index); break; case ELM_TYP_MB: /* Loop configuration */ mb_messages(&l_state, i, elem_index); break; case ELM_TYP_FL: trans_messages(&l_state, 1); break; } /* * Calculate the index to each element. */ elem_index += l_state.ib_tbl.config.type_hdr[i].num; } (void) fprintf(stdout, "\n"); } /* * Change the FPM (Front Panel Module) password of the * subsystem associated with the IB addressed by the * enclosure or pathname to name. * */ void intfix(void) { if (termio_fd) { termios.c_lflag |= ECHO; ioctl(termio_fd, TCSETS, &termios); } exit(SIGINT); } /* * up_password() Changes the password for SENA enclosure. * * RETURNS: * none. */ void up_password(char **argv) { int path_index = 0, err = 0; char password[1024]; char input[1024]; int i, j, matched, equal; L_inquiry inq; void (*sig)(); char *path_phys = NULL; Path_struct *path_struct; if ((termio_fd = open("/dev/tty", O_RDONLY)) == -1) { (void) fprintf(stderr, MSGSTR(2036, "Error: tty open failed.\n")); exit(-1); } ioctl(termio_fd, TCGETS, &termios); sig = sigset(SIGINT, (void (*)())intfix); /* * Make sure path valid and is to a PHO * before bothering operator. */ if ((err = l_convert_name(argv[path_index], &path_phys, &path_struct, Options & PVERBOSE)) != 0) { (void) fprintf(stderr, MSGSTR(33, " Error: converting" " %s to physical path.\n" " Invalid pathname.\n"), argv[path_index]); if (err != -1) { (void) print_errString(err, argv[path_index]); } exit(-1); } if (err = g_get_inquiry(path_phys, &inq)) { (void) print_errString(err, argv[path_index]); exit(-1); } if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) && (!(strncmp((char *)inq.inq_vid, "SUN ", sizeof (inq.inq_vid)) && ((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) { /* * Again this is like the ssaadm code in that the name * is still not defined before this code must be released. */ (void) fprintf(stderr, MSGSTR(2037, "Error: Enclosure is not a %s\n"), ENCLOSURE_PROD_ID); exit(-1); } (void) fprintf(stdout, MSGSTR(2038, "Changing FPM password for subsystem %s\n"), argv[path_index]); equal = 0; while (!equal) { memset(input, 0, sizeof (input)); memset(password, 0, sizeof (password)); (void) fprintf(stdout, MSGSTR(2039, "New password: ")); termios.c_lflag &= ~ECHO; ioctl(termio_fd, TCSETS, &termios); (void) gets(input); (void) fprintf(stdout, MSGSTR(2040, "\nRe-enter new password: ")); (void) gets(password); termios.c_lflag |= ECHO; ioctl(termio_fd, TCSETS, &termios); for (i = 0; input[i]; i++) { if (!isdigit(input[i])) { (void) fprintf(stderr, MSGSTR(2041, "\nError: Invalid password." " The password" " must be 4 decimal-digit characters.\n")); exit(-1); } } if (i && (i != 4)) { (void) fprintf(stderr, MSGSTR(2042, "\nError: Invalid password." " The password" " must be 4 decimal-digit characters.\n")); exit(-1); } for (j = 0; password[j]; j++) { if (!isdigit(password[j])) { (void) fprintf(stderr, MSGSTR(2043, "\nError: Invalid password." " The password" " must be 4 decimal-digit characters.\n")); exit(-1); } } if (i != j) { matched = -1; } else for (i = matched = 0; password[i]; i++) { if (password[i] == input[i]) { matched++; } } if ((matched != -1) && (matched == i)) { equal = 1; } else { (void) fprintf(stdout, MSGSTR(2044, "\npassword: They don't match;" " try again.\n")); } } (void) fprintf(stdout, "\n"); sscanf(input, "%s", password); (void) signal(SIGINT, sig); /* restore signal handler */ /* Send new password to IB */ if (l_new_password(path_phys, input)) { (void) print_errString(err, path_phys); exit(-1); } } /* * Call g_failover to process failover command */ void adm_failover(char **argv) { int path_index = 0, err = 0; char pathclass[20]; char *path_phys = NULL; (void) memset(pathclass, 0, sizeof (pathclass)); (void) strcpy(pathclass, argv[path_index++]); if ((strcmp(pathclass, "primary") != 0) && (strcmp(pathclass, "secondary") != 0)) { (void) fprintf(stderr, MSGSTR(2300, "Incorrect pathclass\n")); exit(-1); } while (argv[path_index] != NULL) { path_phys = g_get_physical_name(argv[path_index++]); if ((path_phys == NULL) || (strstr(path_phys, SCSI_VHCI) == NULL)) { (void) fprintf(stderr, MSGSTR(2301, "Incorrect pathname\n")); exit(-1); } if (err = g_failover(path_phys, pathclass)) { (void) print_errString(err, NULL); exit(-1); } } } /* * up_encl_name() Update the enclosures logical name. * * RETURNS: * none. */ void up_encl_name(char **argv, int argc) { int i, rval, al_pa, path_index = 0, err = 0; L_inquiry inq; Box_list *b_list = NULL; uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE]; char wwn1[(WWN_SIZE*2)+1], name[1024], *path_phys = NULL; Path_struct *path_struct; (void) memset(name, 0, sizeof (name)); (void) memset(&inq, 0, sizeof (inq)); (void) sscanf(argv[path_index++], "%s", name); for (i = 0; name[i]; i++) { if ((!isalnum(name[i]) && ((name[i] != '#') && (name[i] != '-') && (name[i] != '_') && (name[i] != '.'))) || i >= 16) { (void) fprintf(stderr, MSGSTR(2045, "Error: Invalid enclosure name.\n")); (void) fprintf(stderr, MSGSTR(2046, "Usage: %s [-v] subcommand {a name consisting of" " 1-16 alphanumeric characters}" " {enclosure... | pathname...}\n"), whoami); exit(-1); } } if (((Options & PVERBOSE) && (argc != 5)) || (!(Options & PVERBOSE) && (argc != 4))) { (void) fprintf(stderr, MSGSTR(114, "Error: Incorrect number of arguments.\n")); (void) fprintf(stderr, MSGSTR(2047, "Usage: %s [-v] subcommand {a name consisting of" " 1-16 alphanumeric characters}" " {enclosure... | pathname...}\n"), whoami); exit(-1); } if ((err = l_convert_name(argv[path_index], &path_phys, &path_struct, Options & PVERBOSE)) != 0) { (void) fprintf(stderr, MSGSTR(33, " Error: converting" " %s to physical path.\n" " Invalid pathname.\n"), argv[path_index]); if (err != -1) { (void) print_errString(err, argv[path_index]); } exit(-1); } /* * Make sure we are talking to an IB. */ if (err = g_get_inquiry(path_phys, &inq)) { (void) print_errString(err, argv[path_index]); exit(-1); } if ((strstr((char *)inq.inq_pid, ENCLOSURE_PROD_ID) == 0) && (!(strncmp((char *)inq.inq_vid, "SUN ", sizeof (inq.inq_vid)) && ((inq.inq_dtype & DTYPE_MASK) == DTYPE_ESI)))) { /* * Again this is like the ssaadm code in that the name * is still not defined before this code must be released. */ (void) fprintf(stderr, MSGSTR(2048, "Error: Pathname does not point to a %s" " enclosure\n"), ENCLOSURE_PROD_NAME); exit(-1); } if (err = g_get_wwn(path_phys, port_wwn, node_wwn, &al_pa, Options & PVERBOSE)) { (void) print_errString(err, argv[path_index]); exit(-1); } for (i = 0; i < WWN_SIZE; i++) { (void) sprintf(&wwn1[i << 1], "%02x", node_wwn[i]); } if ((err = l_get_box_list(&b_list, Options & PVERBOSE)) != 0) { (void) print_errString(err, argv[path_index]); exit(-1); } if (b_list == NULL) { (void) fprintf(stdout, MSGSTR(93, "No %s enclosures found " "in /dev/es\n"), ENCLOSURE_PROD_NAME); exit(-1); } else if (l_duplicate_names(b_list, wwn1, name, Options & PVERBOSE)) { (void) fprintf(stderr, MSGSTR(2049, "Warning: The name you selected, %s," " is already being used.\n" "Please choose a unique name.\n" "You can use the \"probe\" subcommand to" " see all of the enclosure names.\n"), name); (void) l_free_box_list(&b_list); exit(-1); } (void) l_free_box_list(&b_list); /* Send new name to IB */ if (rval = l_new_name(path_phys, name)) { (void) print_errString(rval, path_phys); exit(-1); } if (Options & PVERBOSE) { (void) fprintf(stdout, MSGSTR(2050, "The enclosure has been renamed to %s\n"), name); } } static int get_enclStatus(char *phys_path, char *encl_name, int off_flag) { int found_pwrOnDrv = 0, slot; int found_pwrOffDrv = 0, err = 0; L_state l_state; if ((err = l_get_status(phys_path, &l_state, Options & PVERBOSE)) != 0) { (void) print_errString(err, encl_name); return (err); } if (off_flag) { for (slot = 0; slot < l_state.total_num_drv/2; slot++) { if (((l_state.drv_front[slot].ib_status.code != S_NOT_INSTALLED) && (!l_state.drv_front[slot].ib_status.dev_off)) || ((l_state.drv_rear[slot].ib_status.code != S_NOT_INSTALLED) && (!l_state.drv_rear[slot].ib_status.dev_off))) { found_pwrOnDrv++; break; } } if (!found_pwrOnDrv) { (void) fprintf(stdout, MSGSTR(2051, "Notice: Drives in enclosure" " \"%s\" have already been" " powered off.\n\n"), encl_name); return (-1); } } else { for (slot = 0; slot < l_state.total_num_drv/2; slot++) { if (((l_state.drv_front[slot].ib_status.code != S_NOT_INSTALLED) && (l_state.drv_front[slot].ib_status.dev_off)) || ((l_state.drv_rear[slot].ib_status.code != S_NOT_INSTALLED) && (l_state.drv_rear[slot].ib_status.dev_off))) { found_pwrOffDrv++; break; } } if (!found_pwrOffDrv) { (void) fprintf(stdout, MSGSTR(2052, "Notice: Drives in enclosure" " \"%s\" have already been" " powered on.\n\n"), encl_name); return (-1); } } return (0); } /* * adm_led() The led_request subcommand requests the subsystem * to display the current state or turn off, on, or blink * the yellow LED associated with the disk specified by the * enclosure or pathname. * * RETURNS: * none. */ void adm_led(char **argv, int led_action) { int path_index = 0, err = 0; gfc_map_t map; L_inquiry inq; Dev_elem_st status; char *path_phys = NULL; Path_struct *path_struct; int enc_t = 0; /* enclosure type */ char ses_path[MAXPATHLEN]; L_inquiry ses_inq; while (argv[path_index] != NULL) { if ((err = l_convert_name(argv[path_index], &path_phys, &path_struct, Options & PVERBOSE)) != 0) { /* Make sure we have a device path. */ if (path_struct->ib_path_flag) { path_phys = path_struct->p_physical_path; } else { (void) fprintf(stderr, MSGSTR(33, " Error: converting" " %s to physical path.\n" " Invalid pathname.\n"), argv[path_index]); if (err != -1) { (void) print_errString(err, argv[path_index]); } exit(-1); } } if (!path_struct->ib_path_flag) { if (err = g_get_inquiry(path_phys, &inq)) { (void) print_errString(err, argv[path_index]); exit(-1); } if ((inq.inq_dtype & DTYPE_MASK) != DTYPE_DIRECT) { (void) fprintf(stderr, MSGSTR(2053, "Error: pathname must be to a disk device.\n" " %s\n"), argv[path_index]); exit(-1); } } /* * See if we are in fact talking to a loop or not. */ if (err = g_get_dev_map(path_phys, &map, (Options & PVERBOSE))) { (void) print_errString(err, argv[path_index]); } if (led_action == L_LED_ON) { (void) fprintf(stderr, MSGSTR(2054, "The led_on functionality is not applicable " "to this subsystem.\n")); exit(-1); } if (err = l_led(path_struct, led_action, &status, (Options & PVERBOSE))) { (void) print_errString(err, argv[path_index]); exit(-1); } /* Check to see if we have a daktari */ if (l_get_ses_path(path_phys, ses_path, &map, (Options & PVERBOSE)) == 0) { if (g_get_inquiry(ses_path, &ses_inq) == 0) { enc_t = l_get_enc_type(ses_inq); } } switch (led_action) { case L_LED_STATUS: if (status.fault || status.fault_req) { if (!path_struct->slot_valid) { (void) fprintf(stdout, MSGSTR(2055, "LED state is ON for " "device:\n %s\n"), path_phys); } else { if (enc_t == DAK_ENC_TYPE) { if (path_struct->f_flag) { (void) fprintf(stdout, MSGSTR(2236, "LED state is ON for " "device in location: slot %d\n"), path_struct->slot); } else { (void) fprintf(stdout, MSGSTR(2236, "LED state is ON for " "device in location: slot %d\n"), path_struct->slot + (MAX_DRIVES_DAK/2)); } } else { (void) fprintf(stdout, (path_struct->f_flag) ? MSGSTR(2056, "LED state is ON for " "device in location: front,slot %d\n") : MSGSTR(2057, "LED state is ON for " "device in location: rear,slot %d\n"), path_struct->slot); } } } else if (status.ident || status.rdy_to_ins || status.rmv) { if (!path_struct->slot_valid) { (void) fprintf(stdout, MSGSTR(2058, "LED state is BLINKING for " "device:\n %s\n"), path_phys); } else { if (enc_t == DAK_ENC_TYPE) { if (path_struct->f_flag) { (void) fprintf(stdout, MSGSTR(2237, "LED state is BLINKING for " "device in location: slot %d\n"), path_struct->slot); } else { (void) fprintf(stdout, MSGSTR(2237, "LED state is BLINKING for " "device in location: slot %d\n"), path_struct->slot + (MAX_DRIVES_DAK/2)); } } else { (void) fprintf(stdout, (path_struct->f_flag) ? MSGSTR(2059, "LED state is BLINKING for " "device in location: front,slot %d\n") : MSGSTR(2060, "LED state is BLINKING for " "device in location: rear,slot %d\n"), path_struct->slot); } } } else { if (!path_struct->slot_valid) { (void) fprintf(stdout, MSGSTR(2061, "LED state is OFF for " "device:\n %s\n"), path_phys); } else { if (enc_t == DAK_ENC_TYPE) { if (path_struct->f_flag) { (void) fprintf(stdout, MSGSTR(2238, "LED state is OFF for " "device in location: slot %d\n"), path_struct->slot); } else { (void) fprintf(stdout, MSGSTR(2238, "LED state is OFF for " "device in location: slot %d\n"), path_struct->slot + MAX_DRIVES_DAK/2); } } else { (void) fprintf(stdout, (path_struct->f_flag) ? MSGSTR(2062, "LED state is OFF for " "device in location: front,slot %d\n") : MSGSTR(2063, "LED state is OFF for " "device in location: rear,slot %d\n"), path_struct->slot); } } } break; } free((void *)map.dev_addr); path_index++; } } /* * dump() Dump information * * RETURNS: * none. */ void dump(char **argv) { uchar_t *buf; int path_index = 0, err = 0; L_inquiry inq; char hdr_buf[MAXNAMELEN]; Rec_diag_hdr *hdr, *hdr_ptr; char *path_phys = NULL; Path_struct *path_struct; /* * get big buffer */ if ((hdr = (struct rec_diag_hdr *)calloc(1, MAX_REC_DIAG_LENGTH)) == NULL) { (void) print_errString(L_MALLOC_FAILED, NULL); exit(-1); } buf = (uchar_t *)hdr; while (argv[path_index] != NULL) { if ((err = l_convert_name(argv[path_index], &path_phys, &path_struct, Options & PVERBOSE)) != 0) { (void) fprintf(stderr, MSGSTR(33, " Error: converting" " %s to physical path.\n" " Invalid pathname.\n"), argv[path_index]); if (err != -1) { (void) print_errString(err, argv[path_index]); } exit(-1); } if (err = g_get_inquiry(path_phys, &inq)) { (void) print_errString(err, argv[path_index]); } else { (void) g_dump(MSGSTR(2065, "INQUIRY data: "), (uchar_t *)&inq, 5 + inq.inq_len, HEX_ASCII); } (void) memset(buf, 0, MAX_REC_DIAG_LENGTH); if (err = l_get_envsen(path_phys, buf, MAX_REC_DIAG_LENGTH, (Options & PVERBOSE))) { (void) print_errString(err, argv[path_index]); exit(-1); } (void) fprintf(stdout, MSGSTR(2066, "\t\tEnvironmental Sense Information\n")); /* * Dump all pages. */ hdr_ptr = hdr; while (hdr_ptr->page_len != 0) { (void) sprintf(hdr_buf, MSGSTR(2067, "Page %d: "), hdr_ptr->page_code); (void) g_dump(hdr_buf, (uchar_t *)hdr_ptr, HEADER_LEN + hdr_ptr->page_len, HEX_ASCII); hdr_ptr += ((HEADER_LEN + hdr_ptr->page_len) / sizeof (struct rec_diag_hdr)); } path_index++; } (void) free(buf); } /* * display_socal_stats() Display socal driver kstat information. * * RETURNS: * none. */ void display_socal_stats(int port, char *socal_path, struct socal_stats *fc_stats) { int i; int header_flag = 0; char status_msg_buf[MAXNAMELEN]; int num_status_entries; (void) fprintf(stdout, MSGSTR(2068, "\tInformation for FC Loop on port %d of" " FC100/S Host Adapter\n\tat path: %s\n"), port, socal_path); if (fc_stats->version > 1) { (void) fprintf(stdout, "\t"); (void) fprintf(stdout, MSGSTR(32, "Information from %s"), fc_stats->drvr_name); (void) fprintf(stdout, "\n"); if ((*fc_stats->node_wwn != '\0') && (*fc_stats->port_wwn[port] != '\0')) { (void) fprintf(stdout, MSGSTR(104, " Host Adapter WWN's: Node:%s" " Port:%s\n"), fc_stats->node_wwn, fc_stats->port_wwn[port]); } if (*fc_stats->fw_revision != '\0') { (void) fprintf(stdout, MSGSTR(105, " Host Adapter Firmware Revision: %s\n"), fc_stats->fw_revision); } if (fc_stats->parity_chk_enabled != 0) { (void) fprintf(stdout, MSGSTR(2069, " This Host Adapter checks S-Bus parity.\n")); } } (void) fprintf(stdout, MSGSTR(2070, " Version Resets Req_Q_Intrpts Qfulls" " Unsol_Resps Lips\n")); (void) fprintf(stdout, " %4d%8d%11d%13d%10d%7d\n", fc_stats->version, fc_stats->resets, fc_stats->reqq_intrs, fc_stats->qfulls, fc_stats->pstats[port].unsol_resps, fc_stats->pstats[port].lips); (void) fprintf(stdout, MSGSTR(2071, " Els_rcvd Abts" " Abts_ok Offlines Loop_onlines Onlines\n")); (void) fprintf(stdout, " %4d%9d%10d%9d%13d%10d\n", fc_stats->pstats[port].els_rcvd, fc_stats->pstats[port].abts, fc_stats->pstats[port].abts_ok, fc_stats->pstats[port].offlines, fc_stats->pstats[port].online_loops, fc_stats->pstats[port].onlines); /* If any status conditions exist then display */ if (fc_stats->version > 1) { num_status_entries = FC_STATUS_ENTRIES; } else { num_status_entries = 64; } for (i = 0; i < num_status_entries; i++) { if (fc_stats->pstats[port].resp_status[i] != 0) { if (header_flag++ == 0) { (void) fprintf(stdout, MSGSTR(2072, " Fibre Channel Transport status:\n " "Status Value" " Count\n")); } (void) l_format_fc_status_msg(status_msg_buf, fc_stats->pstats[port].resp_status[i], i); (void) fprintf(stdout, " %s\n", status_msg_buf); } } } /* * display_sf_stats() Display sf driver kstat information. * * This routine is called by private loop device only * * RETURNS: * none. */ void display_sf_stats(char *path_phys, int dtype, struct sf_stats *sf_stats) { int i, al_pa, err = 0; gfc_map_t map; uchar_t node_wwn[WWN_SIZE]; uchar_t port_wwn[WWN_SIZE]; gfc_port_dev_info_t *dev_addr_list; if (sf_stats->version > 1) { (void) fprintf(stdout, "\n\t"); (void) fprintf(stdout, MSGSTR(32, "Information from %s"), sf_stats->drvr_name); (void) fprintf(stdout, "\n"); } else { (void) fprintf(stdout, MSGSTR(2073, "\n\t\tInformation from sf driver:\n")); } (void) fprintf(stdout, MSGSTR(2074, " Version Lip_count Lip_fail" " Alloc_fail #_cmds " "Throttle_limit Pool_size\n")); (void) fprintf(stdout, " %4d%9d%12d%11d%10d%11d%12d\n", sf_stats->version, sf_stats->lip_count, sf_stats->lip_failures, sf_stats->cralloc_failures, sf_stats->ncmds, sf_stats->throttle_limit, sf_stats->cr_pool_size); (void) fprintf(stdout, MSGSTR(2075, "\n\t\tTARGET ERROR INFORMATION:\n")); (void) fprintf(stdout, MSGSTR(2076, "AL_PA Els_fail Timouts Abts_fail" " Tsk_m_fail " " Data_ro_mis Dl_len_mis Logouts\n")); if (err = g_get_dev_map(path_phys, &map, (Options & PVERBOSE))) { (void) print_errString(err, path_phys); exit(-1); } if (dtype == DTYPE_DIRECT) { if (err = g_get_wwn(path_phys, port_wwn, node_wwn, &al_pa, Options & PVERBOSE)) { (void) print_errString(err, path_phys); exit(-1); } /* for san toleration, only need to modify the code */ /* such that the current sf_al_map structure replaced */ /* by the new gfc_map structure for private loop device */ for (i = 0, dev_addr_list = map.dev_addr; i < map.count; i++, dev_addr_list++) { if (dev_addr_list->gfc_port_dev.priv_port.sf_al_pa == al_pa) { (void) fprintf(stdout, "%3x%10d%8d%10d%11d%13d%11d%9d\n", al_pa, sf_stats->tstats[i].els_failures, sf_stats->tstats[i].timeouts, sf_stats->tstats[i].abts_failures, sf_stats->tstats[i].task_mgmt_failures, sf_stats->tstats[i].data_ro_mismatches, sf_stats->tstats[i].dl_len_mismatches, sf_stats->tstats[i].logouts_recvd); break; } } if (i >= map.count) { (void) print_errString(L_INVALID_LOOP_MAP, path_phys); exit(-1); } } else { for (i = 0, dev_addr_list = map.dev_addr; i < map.count; i++, dev_addr_list++) { (void) fprintf(stdout, "%3x%10d%8d%10d%11d%13d%11d%9d\n", dev_addr_list->gfc_port_dev.priv_port.sf_al_pa, sf_stats->tstats[i].els_failures, sf_stats->tstats[i].timeouts, sf_stats->tstats[i].abts_failures, sf_stats->tstats[i].task_mgmt_failures, sf_stats->tstats[i].data_ro_mismatches, sf_stats->tstats[i].dl_len_mismatches, sf_stats->tstats[i].logouts_recvd); } } free((void *)map.dev_addr); } /* * adm_display_err() Displays enclosure specific * error information. * * RETURNS: * none. */ static void adm_display_err(char *path_phys, int dtype) { int i, drvr_inst, sf_inst, socal_inst, port, al_pa, err = 0; char *char_ptr, socal_path[MAXPATHLEN], drvr_path[MAXPATHLEN]; struct stat sbuf; kstat_ctl_t *kc; kstat_t *ifp_ks, *sf_ks, *fc_ks; sf_stats_t sf_stats; socal_stats_t fc_stats; ifp_stats_t ifp_stats; int header_flag = 0, pathcnt = 1; char status_msg_buf[MAXNAMELEN]; gfc_map_t map; uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE]; uint_t path_type; gfc_port_dev_info_t *dev_addr_list; mp_pathlist_t pathlist; int p_on = 0, p_st = 0; if ((kc = kstat_open()) == (kstat_ctl_t *)NULL) { (void) fprintf(stderr, MSGSTR(2077, " Error: can't open kstat\n")); exit(-1); } if (strstr(path_phys, SCSI_VHCI)) { (void) strcpy(drvr_path, path_phys); if (err = g_get_pathlist(drvr_path, &pathlist)) { (void) print_errString(err, NULL); exit(-1); } pathcnt = pathlist.path_count; p_on = p_st = 0; for (i = 0; i < pathcnt; i++) { if (pathlist.path_info[i].path_state < MAXPATHSTATE) { if (pathlist.path_info[i].path_state == MDI_PATHINFO_STATE_ONLINE) { p_on = i; break; } else if (pathlist.path_info[i].path_state == MDI_PATHINFO_STATE_STANDBY) { p_st = i; } } } if (pathlist.path_info[p_on].path_state == MDI_PATHINFO_STATE_ONLINE) { /* on_line path */ (void) strcpy(drvr_path, pathlist.path_info[p_on].path_hba); } else { /* standby or path0 */ (void) strcpy(drvr_path, pathlist.path_info[p_st].path_hba); } free(pathlist.path_info); } else { (void) strcpy(drvr_path, path_phys); if ((char_ptr = strrchr(drvr_path, '/')) == NULL) { (void) print_errString(L_INVLD_PATH_NO_SLASH_FND, path_phys); exit(-1); } *char_ptr = '\0'; /* Make into nexus or HBA driver path. */ } /* * Each HBA and driver stack has its own structures * for this, so we have to handle each one individually. */ path_type = g_get_path_type(drvr_path); if (path_type) { /* Quick sanity check for valid path */ if ((err = g_get_nexus_path(drvr_path, &char_ptr)) != 0) { (void) print_errString(err, path_phys); exit(-1); } (void) strcpy(socal_path, char_ptr); } /* attach :devctl to get node stat instead of dir stat. */ (void) strcat(drvr_path, FC_CTLR); if (stat(drvr_path, &sbuf) < 0) { (void) print_errString(L_LSTAT_ERROR, path_phys); exit(-1); } drvr_inst = minor(sbuf.st_rdev); /* * first take care of ifp card. */ if (path_type & FC4_PCI_FCA) { if ((ifp_ks = kstat_lookup(kc, "ifp", drvr_inst, "statistics")) != NULL) { if (kstat_read(kc, ifp_ks, &ifp_stats) < 0) { (void) fprintf(stderr, MSGSTR(2082, "Error: could not read ifp%d\n"), drvr_inst); exit(-1); } (void) fprintf(stdout, MSGSTR(2083, "\tInformation for FC Loop of" " FC100/P Host Adapter\n\tat path: %s\n"), drvr_path); if (ifp_stats.version > 1) { (void) fprintf(stdout, "\t"); (void) fprintf(stdout, MSGSTR(32, "Information from %s"), ifp_stats.drvr_name); (void) fprintf(stdout, "\n"); if ((*ifp_stats.node_wwn != '\0') && (*ifp_stats.port_wwn != '\0')) { (void) fprintf(stdout, MSGSTR(104, " Host Adapter WWN's: Node:%s" " Port:%s\n"), ifp_stats.node_wwn, ifp_stats.port_wwn); } if (*ifp_stats.fw_revision != 0) { (void) fprintf(stdout, MSGSTR(105, " Host Adapter Firmware Revision: %s\n"), ifp_stats.fw_revision); } if (ifp_stats.parity_chk_enabled != 0) { (void) fprintf(stdout, MSGSTR(2084, " This Host Adapter checks " "PCI-Bus parity.\n")); } } (void) fprintf(stdout, MSGSTR(2085, " Version Lips\n")); (void) fprintf(stdout, " %10d%7d\n", ifp_stats.version, ifp_stats.lip_count); /* If any status conditions exist then display */ for (i = 0; i < FC_STATUS_ENTRIES; i++) { if (ifp_stats.resp_status[i] != 0) { if (header_flag++ == 0) { (void) fprintf(stdout, MSGSTR(2086, " Fibre Channel Transport " "status:\n " "Status " " Value" " Count\n")); } (void) l_format_ifp_status_msg( status_msg_buf, ifp_stats.resp_status[i], i); (void) fprintf(stdout, " %s\n", status_msg_buf); } } (void) fprintf(stdout, MSGSTR(2087, "\n\t\tTARGET ERROR INFORMATION:\n")); (void) fprintf(stdout, MSGSTR(2088, "AL_PA logouts_recvd task_mgmt_failures" " data_ro_mismatches data_len_mismatch\n")); if (err = g_get_dev_map(path_phys, &map, (Options & PVERBOSE))) { (void) print_errString(err, path_phys); exit(-1); } if (dtype == DTYPE_DIRECT) { if (err = g_get_wwn(path_phys, port_wwn, node_wwn, &al_pa, Options & PVERBOSE)) { (void) print_errString(err, path_phys); exit(-1); } for (i = 0, dev_addr_list = map.dev_addr; i < map.count; i++, dev_addr_list++) { if (dev_addr_list->gfc_port_dev. priv_port.sf_al_pa == al_pa) { (void) fprintf (stdout, "%3x%14d%18d%20d%20d\n", al_pa, ifp_stats.tstats[i]. logouts_recvd, ifp_stats.tstats[i]. task_mgmt_failures, ifp_stats.tstats[i]. data_ro_mismatches, ifp_stats.tstats[i]. dl_len_mismatches); break; } } if (i >= map.count) { (void) print_errString( L_INVALID_LOOP_MAP, path_phys); exit(-1); } } else { for (i = 0, dev_addr_list = map.dev_addr; i < map.count; i++, dev_addr_list++) { (void) fprintf(stdout, "%3x%14d%18d%20d%20d\n", dev_addr_list->gfc_port_dev. priv_port.sf_al_pa, ifp_stats.tstats[i].logouts_recvd, ifp_stats.tstats[i].task_mgmt_failures, ifp_stats.tstats[i].data_ro_mismatches, ifp_stats.tstats[i].dl_len_mismatches); } } free((void *)map.dev_addr); } } else if (path_type & FC4_SF_XPORT) { /* * process cards with sf xport nodes. */ if (stat(socal_path, &sbuf) < 0) { (void) print_errString(L_LSTAT_ERROR, path_phys); exit(-1); } socal_inst = minor(sbuf.st_rdev)/2; port = socal_inst%2; sf_inst = LUX_SF_MINOR2INST(minor(sbuf.st_rdev)); if (!(sf_ks = kstat_lookup(kc, "sf", sf_inst, "statistics"))) { (void) fprintf(stderr, MSGSTR(2078, " Error: could not lookup driver stats for sf%d\n"), sf_inst); exit(-1); } if (!(fc_ks = kstat_lookup(kc, "socal", socal_inst, "statistics"))) { (void) fprintf(stderr, MSGSTR(2079, " Error: could not lookup driver stats for socal%d\n"), socal_inst); exit(-1); } if (kstat_read(kc, sf_ks, &sf_stats) < 0) { (void) fprintf(stderr, MSGSTR(2080, " Error: could not read driver stats for sf%d\n"), sf_inst); exit(-1); } if (kstat_read(kc, fc_ks, &fc_stats) < 0) { (void) fprintf(stderr, MSGSTR(2081, " Error: could not read driver stats for socal%d\n"), socal_inst); exit(-1); } (void) display_socal_stats(port, socal_path, &fc_stats); (void) display_sf_stats(path_phys, dtype, &sf_stats); } else if ((path_type & FC_FCA_MASK) == FC_PCI_FCA) { fprintf(stderr, MSGSTR(2252, "\n WARNING!! display -r on qlc is" " currently not supported.\n")); } else { fprintf(stderr, MSGSTR(2253, "\n WARNING!! display -r is not supported on path\n" " %s\n"), drvr_path); } (void) kstat_close(kc); } /*ARGSUSED*/ /* * adm_display_verbose_disk() Gets the mode page information * for a SENA disk and prints that information. * * RETURNS: * none. */ void adm_display_verbose_disk(char *path, int verbose) { uchar_t *pg_buf; Mode_header_10 *mode_header_ptr; Mp_01 *pg1_buf; Mp_04 *pg4_buf; struct mode_page *pg_hdr; int offset, hdr_printed = 0, err = 0; if ((err = l_get_mode_pg(path, &pg_buf, verbose)) == 0) { mode_header_ptr = (struct mode_header_10_struct *)(int)pg_buf; pg_hdr = ((struct mode_page *)((int)pg_buf + (uchar_t)sizeof (struct mode_header_10_struct) + (uchar_t *)(uintptr_t)(mode_header_ptr->bdesc_length))); offset = sizeof (struct mode_header_10_struct) + mode_header_ptr->bdesc_length; while (offset < (mode_header_ptr->length + sizeof (mode_header_ptr->length))) { switch (pg_hdr->code) { case 0x01: pg1_buf = (struct mode_page_01_struct *) (int)pg_hdr; P_DPRINTF(" adm_display_verbose_disk:" "Mode Sense page 1 found.\n"); if (hdr_printed++ == 0) { (void) fprintf(stdout, MSGSTR(2089, " Mode Sense data:\n")); } (void) fprintf(stdout, MSGSTR(2090, " AWRE:\t\t\t%d\n" " ARRE:\t\t\t%d\n" " Read Retry Count:\t\t" "%d\n" " Write Retry Count:\t\t" "%d\n"), pg1_buf->awre, pg1_buf->arre, pg1_buf->read_retry_count, pg1_buf->write_retry_count); break; case MODEPAGE_GEOMETRY: pg4_buf = (struct mode_page_04_struct *) (int)pg_hdr; P_DPRINTF(" adm_display_verbose_disk:" "Mode Sense page 4 found.\n"); if (hdr_printed++ == 0) { (void) fprintf(stdout, MSGSTR(2091, " Mode Sense data:\n")); } if (pg4_buf->rpm) { (void) fprintf(stdout, MSGSTR(2092, " Medium rotation rate:\t" "%d RPM\n"), pg4_buf->rpm); } break; } offset += pg_hdr->length + sizeof (struct mode_page); pg_hdr = ((struct mode_page *)((int)pg_buf + (uchar_t)offset)); } } else if (getenv("_LUX_P_DEBUG") != NULL) { (void) print_errString(err, path); } } /* * Print out the port_wwn or node_wwn */ void print_wwn(FILE *fd, uchar_t *pn_wwn) { (void) fprintf(fd, " %1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x", pn_wwn[0], pn_wwn[1], pn_wwn[2], pn_wwn[3], pn_wwn[4], pn_wwn[5], pn_wwn[6], pn_wwn[7]); } /* * Print out the fabric dev port_id, hard_addr, port_wwn and node_wwn */ void print_fabric_prop(int pos, uchar_t *port_wwn, uchar_t *node_wwn, int port_addr, int hard_addr) { (void) fprintf(stdout, "%-4d %-6x %-6x ", pos, port_addr, hard_addr); print_wwn(stdout, port_wwn); print_wwn(stdout, node_wwn); } /* * Print out the private loop dev port_id, hard_addr, port_wwn and node_wwn */ void print_private_loop_prop(int pos, uchar_t *port_wwn, uchar_t *node_wwn, int port_addr, int hard_addr) { (void) fprintf(stdout, "%-3d %-2x %-2x %-2x ", pos, port_addr, g_sf_alpa_to_switch[port_addr], hard_addr); print_wwn(stdout, port_wwn); print_wwn(stdout, node_wwn); } /* * Get the device map from * fc nexus driver and prints the map. * * RETURNS: * none. */ void dump_map(char **argv) { int i = 0, path_index = 0, pathcnt = 1; int limited_map_flag = 0, err = 0; char *path_phys = NULL; Path_struct *path_struct; struct lilpmap limited_map; uint_t dev_type; char temp2path[MAXPATHLEN]; mp_pathlist_t pathlist; int p_pw = 0, p_on = 0, p_st = 0; gfc_dev_t map_root, map_dev; int *port_addr, *hard_addr, pos = 0, count; uchar_t *hba_port_wwn, *port_wwn, *node_wwn, *dtype_prop; uint_t map_topo; while (argv[path_index] != NULL) { if ((err = l_convert_name(argv[path_index], &path_phys, &path_struct, Options & PVERBOSE)) != 0) { (void) fprintf(stderr, MSGSTR(33, " Error: converting" " %s to physical path.\n" " Invalid pathname.\n"), argv[path_index]); if (err != -1) { (void) print_errString(err, argv[path_index]); } exit(-1); } if (strstr(path_phys, SCSI_VHCI) != NULL) { /* obtain phci */ (void) strcpy(temp2path, path_phys); if (err = g_get_pathlist(temp2path, &pathlist)) { (void) print_errString(err, NULL); exit(-1); } pathcnt = pathlist.path_count; p_pw = p_on = p_st = 0; for (i = 0; i < pathcnt; i++) { if (pathlist.path_info[i].path_state < MAXPATHSTATE) { if (strstr(pathlist.path_info[i]. path_addr, path_struct->argv) != NULL) { p_pw = i; break; } if (pathlist.path_info[i].path_state == MDI_PATHINFO_STATE_ONLINE) { p_on = i; } if (pathlist.path_info[i].path_state == MDI_PATHINFO_STATE_STANDBY) { p_st = i; } } } if (strstr(pathlist.path_info[p_pw].path_addr, path_struct->argv) != NULL) { /* matching input pwwn */ (void) strcpy(temp2path, pathlist.path_info[p_pw].path_hba); } else if (pathlist.path_info[p_on].path_state == MDI_PATHINFO_STATE_ONLINE) { /* on_line path */ (void) strcpy(temp2path, pathlist.path_info[p_on].path_hba); } else { /* standby or path0 */ (void) strcpy(temp2path, pathlist.path_info[p_st].path_hba); } free(pathlist.path_info); (void) strcat(temp2path, FC_CTLR); } else { (void) strcpy(temp2path, path_phys); } if ((dev_type = g_get_path_type(temp2path)) == 0) { (void) print_errString(L_INVALID_PATH, argv[path_index]); exit(-1); } if ((map_root = g_dev_map_init(temp2path, &err, MAP_FORMAT_LILP)) == NULL) { if (dev_type & FC_FCA_MASK) { (void) print_errString(err, argv[path_index]); exit(-1); } else { /* * This did not work so try the FCIO_GETMAP * type ioctl. */ if (err = g_get_limited_map(path_phys, &limited_map, (Options & PVERBOSE))) { (void) print_errString(err, argv[path_index]); exit(-1); } limited_map_flag++; } } if (limited_map_flag) { (void) fprintf(stdout, MSGSTR(2093, "Host Adapter AL_PA: %x\n"), limited_map.lilp_myalpa); (void) fprintf(stdout, MSGSTR(2094, "Pos AL_PA\n")); for (i = 0; i < (uint_t)limited_map.lilp_length; i++) { (void) fprintf(stdout, "%-3d %-2x\n", i, limited_map.lilp_list[i]); } } else { if ((err = g_dev_prop_lookup_bytes(map_root, PORT_WWN_PROP, &count, &hba_port_wwn)) != 0) { g_dev_map_fini(map_root); (void) print_errString(err, argv[path_index]); exit(-1); } if ((err = g_get_map_topology( map_root, &map_topo)) != 0) { (void) print_errString(err, argv[path_index]); exit(-1); } if ((map_dev = g_get_first_dev(map_root, &err)) == NULL) { if (err == L_NO_SUCH_DEV_FOUND) { g_dev_map_fini(map_root); (void) fprintf(stderr, MSGSTR(2308, " No devices are found on %s.\n"), argv[path_index]); exit(-1); } else { g_dev_map_fini(map_root); (void) print_errString(err, argv[path_index]); exit(-1); } } switch (map_topo) { case FC_TOP_FABRIC: case FC_TOP_PUBLIC_LOOP: case FC_TOP_PT_PT: (void) fprintf(stdout, MSGSTR(2095, "Pos Port_ID Hard_Addr Port WWN" " Node WWN Type\n")); while (map_dev) { if ((err = g_dev_prop_lookup_ints( map_dev, PORT_ADDR_PROP, &port_addr)) != 0) { g_dev_map_fini(map_root); (void) print_errString(err, argv[path_index]); exit(-1); } if ((err = g_dev_prop_lookup_bytes(map_dev, PORT_WWN_PROP, &count, &port_wwn)) != 0) { g_dev_map_fini(map_root); (void) print_errString(err, argv[path_index]); exit(-1); } if ((err = g_dev_prop_lookup_bytes(map_dev, NODE_WWN_PROP, &count, &node_wwn)) != 0) { g_dev_map_fini(map_root); (void) print_errString(err, argv[path_index]); exit(-1); } if ((err = g_dev_prop_lookup_ints( map_dev, HARD_ADDR_PROP, &hard_addr)) != 0) { g_dev_map_fini(map_root); (void) print_errString(err, argv[path_index]); exit(-1); } print_fabric_prop(pos++, port_wwn, node_wwn, *port_addr, *hard_addr); if ((err = g_dev_prop_lookup_bytes(map_dev, INQ_DTYPE_PROP, &count, &dtype_prop)) != 0) { (void) fprintf(stdout, MSGSTR(2307, " Failed to get the type.\n")); } else { print_fabric_dtype_prop(hba_port_wwn, port_wwn, *dtype_prop); } if (((map_dev = g_get_next_dev( map_dev, &err)) == NULL) && (err != L_NO_SUCH_DEV_FOUND)) { g_dev_map_fini(map_root); (void) print_errString(err, argv[path_index]); exit(-1); } } break; case FC_TOP_PRIVATE_LOOP: (void) fprintf(stdout, MSGSTR(2295, "Pos AL_PA ID Hard_Addr " "Port WWN Node WWN Type\n")); while (map_dev) { if ((err = g_dev_prop_lookup_ints( map_dev, PORT_ADDR_PROP, &port_addr)) != 0) { g_dev_map_fini(map_root); (void) print_errString(err, argv[path_index]); exit(-1); } if ((err = g_dev_prop_lookup_bytes(map_dev, PORT_WWN_PROP, &count, &port_wwn)) != 0) { g_dev_map_fini(map_root); (void) print_errString(err, argv[path_index]); exit(-1); } if ((err = g_dev_prop_lookup_bytes(map_dev, NODE_WWN_PROP, &count, &node_wwn)) != 0) { g_dev_map_fini(map_root); (void) print_errString(err, argv[path_index]); exit(-1); } if ((err = g_dev_prop_lookup_ints( map_dev, HARD_ADDR_PROP, &hard_addr)) != 0) { g_dev_map_fini(map_root); (void) print_errString(err, argv[path_index]); exit(-1); } print_private_loop_prop(pos++, port_wwn, node_wwn, *port_addr, *hard_addr); if ((err = g_dev_prop_lookup_bytes(map_dev, INQ_DTYPE_PROP, &count, &dtype_prop)) != 0) { (void) fprintf(stdout, MSGSTR(2307, " Failed to get the type.\n")); } else { print_private_loop_dtype_prop(hba_port_wwn, port_wwn, *dtype_prop); } if (((map_dev = g_get_next_dev( map_dev, &err)) == NULL) && (err != L_NO_SUCH_DEV_FOUND)) { g_dev_map_fini(map_root); (void) print_errString(err, argv[path_index]); exit(-1); } } break; default: (void) print_errString(L_UNEXPECTED_FC_TOPOLOGY, argv[path_index]); exit(-1); } g_dev_map_fini(map_root); } limited_map_flag = 0; path_index++; } } /* * Gets a list of non-SENA fcal devices * found on the system. * * OUTPUT: * wwn_list pointer * NULL: No non-enclosure devices found. * !NULL: Devices found * wwn_list points to a linked list of wwn's. * RETURNS: * 0 O.K. */ int n_get_non_encl_list(WWN_list **wwn_list_ptr, int verbose) { int i, j, k, err, found_ib = 0, pathcnt = 1; WWN_list *wwn_list; Box_list *b_list = NULL; gfc_map_t map; uchar_t box_id; gfc_port_dev_info_t *dev_addr_list; char phci_path[MAXPATHLEN], oldphci_path[MAXPATHLEN]; mp_pathlist_t pathlist; /* * Only interested in devices that are not part of * a Photon enclosure. */ if ((err = l_get_box_list(&b_list, verbose)) != 0) { return (err); /* Failure */ } if (err = g_get_wwn_list(&wwn_list, verbose)) { (void) l_free_box_list(&b_list); return (err); } while (b_list != NULL) { pathcnt = 1; if (strstr(b_list->b_physical_path, SCSI_VHCI) != NULL) { (void) strcpy(phci_path, b_list->b_physical_path); if (err = g_get_pathlist(phci_path, &pathlist)) { (void) print_errString(err, NULL); exit(-1); } pathcnt = pathlist.path_count; } for (k = 0; k < pathcnt; k++) { if ((k > 0) && (strstr(oldphci_path, pathlist.path_info[k].path_hba))) { continue; } if (strstr(b_list->b_physical_path, SCSI_VHCI) == NULL) { if ((err = g_get_dev_map(b_list->b_physical_path, &map, verbose)) != 0) { (void) g_free_wwn_list(&wwn_list); (void) l_free_box_list(&b_list); return (err); } } else { (void) strcpy(phci_path, pathlist.path_info[k].path_hba); (void) strcpy(oldphci_path, phci_path); (void) strcat(phci_path, FC_CTLR); if (g_get_dev_map(phci_path, &map, verbose)) { continue; } if (pathcnt == 1) { free(pathlist.path_info); } } switch (map.hba_addr.port_topology) { case FC_TOP_FABRIC: case FC_TOP_PUBLIC_LOOP: for (i = 0, dev_addr_list = map.dev_addr; i < map.count; i++, dev_addr_list++) { for (found_ib = 1, j = 0; j < WWN_SIZE; j++) { if (b_list->b_node_wwn[j] != dev_addr_list->gfc_port_dev. pub_port.dev_nwwn.raw_wwn[j]) { found_ib = 0; } } if (found_ib) { (void) n_rem_list_entry_fabric( dev_addr_list->gfc_port_dev. pub_port.dev_did.port_id, &map, &wwn_list); } } break; case FC_TOP_PRIVATE_LOOP: for (i = 0, dev_addr_list = map.dev_addr; i < map.count; i++, dev_addr_list++) { for (found_ib = 1, j = 0; j < WWN_SIZE; j++) { if (b_list->b_node_wwn[j] != dev_addr_list->gfc_port_dev. priv_port.sf_node_wwn[j]) { found_ib = 0; } } if (found_ib) { box_id = g_sf_alpa_to_switch [dev_addr_list->gfc_port_dev. priv_port.sf_al_pa] & BOX_ID_MASK; /* This function has been added */ /* here only to keep from having */ /* to tab over farther */ (void) n_rem_list_entry(box_id, &map, &wwn_list); if (wwn_list == NULL) { /* Return the list */ *wwn_list_ptr = NULL; break; } } } break; case FC_TOP_PT_PT: (void) free((void *)map.dev_addr); return (L_PT_PT_FC_TOP_NOT_SUPPORTED); default: (void) free((void *)map.dev_addr); return (L_UNEXPECTED_FC_TOPOLOGY); } free((void *)map.dev_addr); } if (pathcnt > 1) { free(pathlist.path_info); } b_list = b_list->box_next; } /* Return the list */ *wwn_list_ptr = wwn_list; (void) l_free_box_list(&b_list); return (0); } /* * n_rem_list_entry() We found an IB so remove disks that * are in the Photon from the individual device list. * * OUTPUT: * wwn_list - removes the fcal disks that are in SENA enclosure * * RETURNS: * none */ void n_rem_list_entry(uchar_t box_id, struct gfc_map *map, struct wwn_list_struct **wwn_list) { int k; gfc_port_dev_info_t *dev_addr_list; N_DPRINTF(" n_rem_list_entry: Removing devices" " with box_id=0x%x from device list.\n", box_id); for (k = 0, dev_addr_list = map->dev_addr; k < map->count; k++, dev_addr_list++) { if ((g_sf_alpa_to_switch[dev_addr_list->gfc_port_dev. priv_port.sf_hard_address] & BOX_ID_MASK) == box_id) { n_rem_wwn_entry(dev_addr_list->gfc_port_dev. priv_port.sf_node_wwn, wwn_list); } } } /* * n_rem_list_entry_fabric() We found an IB so remove disks that * are in the Photon from the individual device list. * * OUTPUT: * wwn_list - removes the fcal disks that are in SENA enclosure * * RETURNS: * none */ void n_rem_list_entry_fabric(int pa, struct gfc_map *map, struct wwn_list_struct **wwn_list) { int k; gfc_port_dev_info_t *dev_addr_ptr; N_DPRINTF(" n_rem_list_entry: Removing devices" " with the same domain and area ID as" " 0x%x PA from device list.\n", pa); for (k = 0, dev_addr_ptr = map->dev_addr; k < map->count; k++, dev_addr_ptr++) { /* matching the domain and area id with input alpa, */ /* ignoring last 8 bits. */ if ((dev_addr_ptr->gfc_port_dev.pub_port.dev_did.port_id | 0xff) == (pa | 0xff)) { n_rem_wwn_entry(dev_addr_ptr-> gfc_port_dev.pub_port.dev_nwwn.raw_wwn, wwn_list); } } } /* * n_rem_wwn_entry() removes input wwn from wwn_list. * * OUTPUT: * wwn_list - removes the input wwn from wwn_list if found. * * RETURNS: * none */ void n_rem_wwn_entry(uchar_t node_wwn[], struct wwn_list_struct **wwn_list) { int l, found_dev; WWN_list *inner, *l1; inner = *wwn_list; while (inner != NULL) { for (found_dev = 1, l = 0; l < WWN_SIZE; l++) { if (inner->w_node_wwn[l] != node_wwn[l]) { found_dev = 0; } } if (found_dev) { /* Remove this entry from the list */ if (inner->wwn_prev != NULL) { inner->wwn_prev->wwn_next = inner->wwn_next; } else { *wwn_list = inner->wwn_next; } if (inner->wwn_next != NULL) { inner->wwn_next->wwn_prev = inner->wwn_prev; } l1 = inner; N_DPRINTF(" n_rem_wwn_entry: " "Removing Logical=%s " "Current=0x%x, " "Prev=0x%x, Next=0x%x\n", l1->logical_path, l1, l1->wwn_prev, l1->wwn_next); inner = inner->wwn_next; if ((l1->wwn_prev == NULL) && (l1->wwn_next) == NULL) { (void) free(l1->physical_path); (void) free(l1->logical_path); (void) free(l1); *wwn_list = NULL; N_DPRINTF(" n_rem_list_entry: " "No non-Photon " "devices left" " in the list.\n"); return; } (void) free(l1->physical_path); (void) free(l1->logical_path); (void) free(l1); } else { inner = inner->wwn_next; } } } /* * non_encl_probe() Finds and displays a list of * non-SENA fcal devices which is found on the * system. * * RETURNS: * none. */ void non_encl_probe() { WWN_list *wwn_list, *wwn_listh, *inner, *l1; int err = 0; char lun_a[MAXPATHLEN], lun_b[MAXPATHLEN], temppath[MAXPATHLEN]; char *tempptra = NULL, *tempptrb, *tempptr; mp_pathlist_t pathlist; int compare_result, retr_outer = 0; ddi_devid_t devid1 = NULL, devid2 = NULL; di_node_t root = DI_NODE_NIL; if (err = n_get_non_encl_list(&wwn_list, (Options & PVERBOSE))) { (void) print_errString(err, NULL); exit(-1); } g_sort_wwn_list(&wwn_list); wwn_listh = wwn_list; if (wwn_list != NULL) { if (wwn_list->wwn_next != NULL) { (void) fprintf(stdout, MSGSTR(2098, "\nFound Fibre Channel device(s):\n")); } else { (void) fprintf(stdout, MSGSTR(2099, "\nFound Fibre Channel device:\n")); } } else { return; } while (wwn_list != NULL) { if (strstr(wwn_list->physical_path, SCSI_VHCI) != NULL) { (void) strcpy(temppath, wwn_list->physical_path); if ((!g_get_pathlist(temppath, &pathlist)) && ((tempptra = strchr(pathlist.path_info[0]. path_addr, ','))) != NULL) { tempptra++; (void) strcpy(lun_a, tempptra); free(pathlist.path_info); } } else { if ((((tempptr = strstr(wwn_list->physical_path, SLSH_DRV_NAME_ST)) != NULL) || ((tempptr = strstr(wwn_list->physical_path, SLSH_DRV_NAME_SSD)) != NULL)) && ((tempptra = strchr(tempptr, ',')) != NULL)) { tempptra++; (void) strcpy(lun_a, tempptra); } } (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(90, "Node WWN:")); (void) fprintf(stdout, "%s ", wwn_list->node_wwn_s); if (wwn_list->device_type < 0x10) { (void) fprintf(stdout, MSGSTR(35, "Device Type:")); (void) fprintf(stdout, "%s", dtype[wwn_list->device_type]); } else if (wwn_list->device_type < 0x1f) { (void) fprintf(stdout, MSGSTR(2100, "Type:Reserved")); } else { (void) fprintf(stdout, MSGSTR(2101, "Type:Unknown")); } (void) fprintf(stdout, "\n "); (void) fprintf(stdout, MSGSTR(31, "Logical Path:%s"), wwn_list->logical_path); (void) fprintf(stdout, "\n"); if (Options & OPTION_P) { (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(5, "Physical Path:")); (void) fprintf(stdout, "\n %s\n", wwn_list->physical_path); } inner = wwn_list->wwn_next; while (inner != NULL) { if (strcmp(inner->node_wwn_s, wwn_list->node_wwn_s) == 0) { if (tempptra != NULL) { if (strstr(inner->physical_path, SCSI_VHCI) != NULL) { (void) strcpy(temppath, inner->physical_path); if ((!g_get_pathlist(temppath, &pathlist)) && ((tempptrb = strchr( pathlist.path_info[0].path_addr, ','))) != NULL) { tempptrb++; (void) strcpy(lun_b, tempptrb); free(pathlist.path_info); } } else { if ((((tempptr = strstr(inner->physical_path, SLSH_DRV_NAME_ST)) != NULL) || ((tempptr = strstr(inner->physical_path, SLSH_DRV_NAME_SSD)) != NULL)) && ((tempptrb = strchr(tempptr, ',')) != NULL)) { tempptrb++; (void) strcpy(lun_b, tempptrb); } } } if (((tempptra == NULL) || (strcmp(lun_a, lun_b)) == 0)) { /* * Have we retrieved a snapshot yet? */ if (root == DI_NODE_NIL) { if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) { (void) fprintf(stdout, MSGSTR(2319, "\nFailed to get device tree snapshot:\n")); exit(1); } } /* Apply devid to ssd devices only */ if (!retr_outer && strstr(wwn_list->physical_path, SLSH_DRV_NAME_SSD) != NULL) { if ((err = g_devid_get(wwn_list->physical_path, &devid1, root, SSD_DRVR_NAME)) != 0) { (void) print_errString(err, wwn_list->physical_path); } /* * Try retrieve of devid only once. If it fails * don't try it again but print error, * There should be a devid prop. */ retr_outer = 1; } /* * Apply devid to block devices only. * Get devid of inner path and compare * with outer path's devid. */ if ((strstr(inner->physical_path, SLSH_DRV_NAME_SSD) != NULL) && devid1 != NULL) { if ((err = g_devid_get(inner->physical_path, &devid2, root, SSD_DRVR_NAME)) != 0) { (void) print_errString(err, inner->physical_path); compare_result = 0; } else { compare_result = devid_compare(devid1, devid2); } } else { /* devid isn't applied */ compare_result = 0; } if (compare_result == 0) { if (strcmp(wwn_list->logical_path, inner->logical_path)) { (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(31, "Logical Path:%s"), inner->logical_path); (void) fprintf(stdout, "\n"); if (Options & OPTION_P) { (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(5, "Physical Path:")); (void) fprintf(stdout, "\n %s\n", inner->physical_path); } } /* Remove this entry from the list */ if (inner->wwn_prev != NULL) { inner->wwn_prev->wwn_next = inner->wwn_next; } if (inner->wwn_next != NULL) { inner->wwn_next->wwn_prev = inner->wwn_prev; } free(inner->physical_path); free(inner->logical_path); l1 = inner; inner = inner->wwn_next; (void) free(l1); } else { inner = inner->wwn_next; } /* End if (compare_result == 0) */ } else { inner = inner->wwn_next; } } else { inner = inner->wwn_next; } devid2 = NULL; } wwn_list = wwn_list->wwn_next; retr_outer = 0; devid1 = NULL; } /* End while (wwn_list != NULL) */ (void) g_free_wwn_list(&wwn_listh); (void) di_fini(root); } void pho_probe() { Box_list *b_list, *o_list, *c_list; int multi_path_flag, multi_print_flag; int duplicate_names_found = 0, err = 0; b_list = o_list = c_list = NULL; if ((err = l_get_box_list(&b_list, Options & PVERBOSE)) != 0) { (void) print_errString(err, NULL); exit(-1); } if (b_list == NULL) { (void) fprintf(stdout, MSGSTR(93, "No %s enclosures found " "in /dev/es\n"), ENCLOSURE_PROD_NAME); } else { o_list = b_list; if (b_list->box_next != NULL) { (void) fprintf(stdout, MSGSTR(2102, "Found Enclosure(s)")); } else { (void) fprintf(stdout, MSGSTR(2103, "Found Enclosure")); } (void) fprintf(stdout, ":\n"); while (b_list != NULL) { /* Don't re-print multiple paths */ c_list = o_list; multi_print_flag = 0; while (c_list != b_list) { if (strcmp(c_list->b_node_wwn_s, b_list->b_node_wwn_s) == 0) { multi_print_flag = 1; break; } c_list = c_list->box_next; } if (multi_print_flag) { b_list = b_list->box_next; continue; } (void) fprintf(stdout, MSGSTR(2104, "%s Name:%s Node WWN:%s "), b_list->prod_id_s, b_list->b_name, b_list->b_node_wwn_s); /* * Print logical path on same line if not multipathed. */ multi_path_flag = 0; c_list = o_list; while (c_list != NULL) { if ((c_list != b_list) && (strcmp(c_list->b_node_wwn_s, b_list->b_node_wwn_s) == 0)) { multi_path_flag = 1; } c_list = c_list->box_next; } if (multi_path_flag) { (void) fprintf(stdout, "\n "); } (void) fprintf(stdout, MSGSTR(31, "Logical Path:%s"), b_list->logical_path); if (Options & OPTION_P) { (void) fprintf(stdout, "\n "); (void) fprintf(stdout, MSGSTR(5, "Physical Path:")); (void) fprintf(stdout, "%s", b_list->b_physical_path); } c_list = o_list; while (c_list != NULL) { if ((c_list != b_list) && (strcmp(c_list->b_node_wwn_s, b_list->b_node_wwn_s) == 0)) { (void) fprintf(stdout, "\n "); (void) fprintf(stdout, MSGSTR(31, "Logical Path:%s"), c_list->logical_path); if (Options & OPTION_P) { (void) fprintf(stdout, "\n "); (void) fprintf(stdout, MSGSTR(5, "Physical Path:")); (void) fprintf(stdout, "%s", c_list->b_physical_path); } } c_list = c_list->box_next; } (void) fprintf(stdout, "\n"); /* Check for duplicate names */ if (l_duplicate_names(o_list, b_list->b_node_wwn_s, (char *)b_list->b_name, Options & PVERBOSE)) { duplicate_names_found++; } b_list = b_list->box_next; } } if (duplicate_names_found) { (void) fprintf(stdout, MSGSTR(2105, "\nWARNING: There are enclosures with " "the same names.\n" "You can not use the \"enclosure\"" " name to specify these subsystems.\n" "Please use the \"enclosure_name\"" " subcommand to select unique names.\n\n")); } (void) l_free_box_list(&b_list); } /* * display_port_status() Prints the device's * port status. * * RETURNS: * none. */ void display_port_status(int d_state_flag) { if (d_state_flag & L_OPEN_FAIL) { (void) fprintf(stdout, MSGSTR(28, "Open Failed")); } else if (d_state_flag & L_NOT_READY) { (void) fprintf(stdout, MSGSTR(20, "Not Ready")); } else if (d_state_flag & L_NOT_READABLE) { (void) fprintf(stdout, MSGSTR(88, "Not Readable")); } else if (d_state_flag & L_SPUN_DWN_D) { (void) fprintf(stdout, MSGSTR(68, "Spun Down")); } else if (d_state_flag & L_SCSI_ERR) { (void) fprintf(stdout, MSGSTR(70, "SCSI Error")); } else if (d_state_flag & L_RESERVED) { (void) fprintf(stdout, MSGSTR(73, "Reservation conflict")); } else if (d_state_flag & L_NO_LABEL) { (void) fprintf(stdout, MSGSTR(92, "No UNIX Label")); } else { (void) fprintf(stdout, MSGSTR(29, "O.K.")); } (void) fprintf(stdout, "\n"); } /* * Displays individual SENA * FC disk information. * * Caller to this routine should free the storage due to * the use of g_get_dev_map * * RETURNS: * none. */ void display_fc_disk(struct path_struct *path_struct, char *ses_path, gfc_map_t *map, L_inquiry inq, int verbose) { static WWN_list *wwn_list = NULL; static char path_phys[MAXPATHLEN]; static L_disk_state l_disk_state; static L_inquiry local_inq; static uchar_t node_wwn[WWN_SIZE]; char same_path_phys = B_FALSE; /* To chk for repeat args */ uchar_t port_wwn[WWN_SIZE], *pg_buf; char logical_path[MAXPATHLEN]; int al_pa, port_a_flag = 0; int offset, mode_data_avail = 0; int no_path_flag = 0, err = 0; L_state l_state; Mode_header_10 *mode_header_ptr = NULL; struct mode_page *pg_hdr = NULL; /* * Do a quick check to see if its the same path as in last call. * path_phys is a static array and so dont worry about its * initialization. */ if (strcmp(path_phys, path_struct->p_physical_path) == 0) same_path_phys = B_TRUE; (void) strcpy(path_phys, path_struct->p_physical_path); (void) memset((char *)logical_path, 0, sizeof (logical_path)); /* * slot_valid is 1 when argument is of the form 'enclosure,[f|r]'. * If slot_valid != 1, g_get_dev_map and l_get_ses_path would * already have been called */ if (path_struct->slot_valid == 1) { /* Get the location information. */ if (err = g_get_dev_map(path_phys, map, (Options & PVERBOSE))) { (void) print_errString(err, path_phys); exit(-1); } if (err = l_get_ses_path(path_phys, ses_path, map, (Options & PVERBOSE))) { (void) print_errString(err, path_phys); exit(-1); } } /* * Get the WWN for our disk if we already haven't or if there was an * error earlier */ if (same_path_phys == B_FALSE) { if (err = g_get_wwn(path_phys, port_wwn, node_wwn, &al_pa, (Options & PVERBOSE))) { (void) print_errString(err, path_phys); exit(-1); } if (err = g_get_inquiry(ses_path, &local_inq)) { (void) print_errString(err, ses_path); exit(-1); } } /* * We are interested only a couple of ib_tbl fields and * those get filled using l_get_ib_status. * Note that NOT ALL of ib_tbl fields get filled here */ if ((err = l_get_ib_status(ses_path, &l_state, Options & PVERBOSE)) != 0) { (void) print_errString(err, ses_path); exit(-1); } /* * Get path to all the FC disk and tape devices. * if we haven't already done so in a previous pass */ if ((wwn_list == NULL) && (err = g_get_wwn_list(&wwn_list, verbose))) { (void) print_errString(err, ses_path); exit(-1); /* Failure */ } /* * Get the disk status if it is a different path_phys from * last time. */ if (same_path_phys == B_FALSE) { (void) memset(&l_disk_state, 0, sizeof (struct l_disk_state_struct)); if (err = l_get_disk_status(path_phys, &l_disk_state, wwn_list, (Options & PVERBOSE))) { (void) print_errString(err, path_phys); exit(-1); } } if (l_disk_state.l_state_flag & L_NO_PATH_FOUND) { (void) fprintf(stderr, MSGSTR(2106, "\nWARNING: No path found " "in /dev/rdsk directory\n" " Please check the logical links in /dev/rdsk\n" " (It may be necessary to run the \"disks\" " "program.)\n\n")); /* Just call to get the status directly. */ if (err = l_get_port(ses_path, &port_a_flag, verbose)) { (void) print_errString(err, ses_path); exit(-1); } if (err = l_get_disk_port_status(path_phys, &l_disk_state, port_a_flag, (Options & PVERBOSE))) { (void) print_errString(err, path_phys); exit(-1); } no_path_flag++; } if (strlen(l_disk_state.g_disk_state.node_wwn_s) == 0) { (void) sprintf(l_disk_state.g_disk_state.node_wwn_s, "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x", node_wwn[0], node_wwn[1], node_wwn[2], node_wwn[3], node_wwn[4], node_wwn[5], node_wwn[6], node_wwn[7]); } /* get mode page information for FC device */ if (l_get_mode_pg(path_phys, &pg_buf, Options & PVERBOSE) == 0) { mode_header_ptr = (struct mode_header_10_struct *)(int)pg_buf; pg_hdr = ((struct mode_page *)((int)pg_buf + (uchar_t)sizeof (struct mode_header_10_struct) + (uchar_t *)(uintptr_t)(mode_header_ptr->bdesc_length))); offset = sizeof (struct mode_header_10_struct) + mode_header_ptr->bdesc_length; while (offset < (mode_header_ptr->length + sizeof (mode_header_ptr->length)) && !mode_data_avail) { if (pg_hdr->code == MODEPAGE_CACHING) { mode_data_avail++; break; } offset += pg_hdr->length + sizeof (struct mode_page); pg_hdr = ((struct mode_page *)((int)pg_buf + (uchar_t)offset)); } } switch ((inq.inq_dtype & DTYPE_MASK)) { case DTYPE_DIRECT: fprintf(stdout, MSGSTR(121, "DEVICE PROPERTIES for disk: %s\n"), path_struct->argv); break; case DTYPE_SEQUENTIAL: /* Tape */ fprintf(stdout, MSGSTR(2249, "DEVICE PROPERTIES for tape: %s\n"), path_struct->argv); break; default: fprintf(stdout, MSGSTR(2250, "DEVICE PROPERTIES for: %s\n"), path_struct->argv); break; } if (l_disk_state.g_disk_state.port_a_valid) { (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(141, "Status(Port A):")); (void) fprintf(stdout, "\t"); display_port_status( l_disk_state.g_disk_state.d_state_flags[PORT_A]); } else { if (path_struct->f_flag) { if ((ib_present_chk(&l_state, 0) == 1) && (l_state.drv_front[path_struct->slot].ib_status.bypass_a_en)) { (void) fprintf(stdout, MSGSTR(66, " Status(Port A):\tBYPASSED\n")); } } else { if ((ib_present_chk(&l_state, 0) == 1) && (l_state.drv_rear[path_struct->slot].ib_status.bypass_a_en)) { (void) fprintf(stdout, MSGSTR(66, " Status(Port A):\tBYPASSED\n")); } } } if (l_disk_state.g_disk_state.port_b_valid) { (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(142, "Status(Port B):")); (void) fprintf(stdout, "\t"); display_port_status(l_disk_state.g_disk_state.d_state_flags[PORT_B]); } else { if (path_struct->f_flag) { if ((ib_present_chk(&l_state, 1) == 1) && (l_state.drv_front[path_struct->slot].ib_status.bypass_b_en)) { (void) fprintf(stdout, MSGSTR(65, " Status(Port B):\tBYPASSED\n")); } } else { if ((ib_present_chk(&l_state, 1) == 1) && (l_state.drv_rear[path_struct->slot].ib_status.bypass_b_en)) { (void) fprintf(stdout, MSGSTR(65, " Status(Port B):\tBYPASSED\n")); } } } if (no_path_flag) { (void) fprintf(stdout, " "); if (port_a_flag != 0) { (void) fprintf(stdout, MSGSTR(142, "Status(Port B):")); } else { (void) fprintf(stdout, MSGSTR(141, "Status(Port A):")); } (void) fprintf(stdout, "\t"); display_port_status( l_disk_state.g_disk_state.d_state_flags[port_a_flag]); } else if ((!l_disk_state.g_disk_state.port_a_valid) && (!l_disk_state.g_disk_state.port_b_valid)) { (void) fprintf(stdout, MSGSTR(2107, " Status:\t\t" "No state available.\n")); } (void) display_disk_info(inq, l_disk_state, path_struct, pg_hdr, mode_data_avail, (char *)local_inq.inq_box_name, verbose); } /* * non_encl_fc_disk_display() Prints the device specific * information for an individual fcal device. * * RETURNS: * none. */ static int non_encl_fc_disk_display(Path_struct *path_struct, L_inquiry inq_struct, int verbose) { char phys_path[MAXPATHLEN]; uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE], *pg_buf = NULL; L_disk_state l_disk_state; struct dlist *mlist; int i = 0, al_pa, offset, mode_data_avail = 0, err = 0; int path_a_found = 0, path_b_found = 0, argpwwn = 0, argnwwn = 0, pathcnt = 1; L_inquiry local_inq; Mode_header_10 *mode_header_ptr; struct mode_page *pg_hdr = NULL; WWN_list *wwn_list, *wwn_list_ptr, *list_start; char temppath[MAXPATHLEN], last_logical_path[MAXPATHLEN]; mp_pathlist_t pathlist; (void) strcpy(phys_path, path_struct->p_physical_path); /* Get path to all the FC disk and tape devices. */ if (err = g_get_wwn_list(&wwn_list, verbose)) { return (err); } g_sort_wwn_list(&wwn_list); list_start = wwn_list; (void) strcpy(last_logical_path, phys_path); for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL; wwn_list_ptr = wwn_list_ptr->wwn_next) { if (strcasecmp(wwn_list_ptr->port_wwn_s, path_struct->argv) == 0) { list_start = wwn_list_ptr; argpwwn = 1; break; } else if (strcasecmp(wwn_list_ptr->node_wwn_s, path_struct->argv) == 0) { list_start = wwn_list_ptr; argnwwn = 1; break; } } for (wwn_list_ptr = list_start; wwn_list_ptr != NULL; wwn_list_ptr = wwn_list_ptr->wwn_next) { if (argpwwn) { if (strcasecmp(wwn_list_ptr->port_wwn_s, path_struct->argv) != 0) { continue; } (void) strcpy(phys_path, wwn_list_ptr->physical_path); path_a_found = 0; path_b_found = 0; mode_data_avail = 0; } else if (argnwwn) { if (strstr(wwn_list_ptr->logical_path, last_logical_path) != NULL) { continue; } if (strcasecmp(wwn_list_ptr->node_wwn_s, path_struct->argv) != 0) { continue; } (void) strcpy(phys_path, wwn_list_ptr->physical_path); (void) strcpy(last_logical_path, wwn_list_ptr->logical_path); path_a_found = 0; path_b_found = 0; mode_data_avail = 0; } (void) memset(&l_disk_state, 0, sizeof (struct l_disk_state_struct)); if ((err = g_get_multipath(phys_path, &(l_disk_state.g_disk_state.multipath_list), wwn_list, verbose)) != 0) { return (err); } mlist = l_disk_state.g_disk_state.multipath_list; if (mlist == NULL) { l_disk_state.l_state_flag = L_NO_PATH_FOUND; N_DPRINTF(" non_encl_fc_disk_display: Error finding" " multiple paths to the disk.\n"); (void) g_free_wwn_list(&wwn_list); return (-1); } /* get mode page information for FC device */ if (l_get_mode_pg(phys_path, &pg_buf, verbose) == 0) { mode_header_ptr = (struct mode_header_10_struct *)(int)pg_buf; pg_hdr = ((struct mode_page *)((int)pg_buf + (uchar_t)sizeof (struct mode_header_10_struct) + (uchar_t *)(uintptr_t)(mode_header_ptr->bdesc_length))); offset = sizeof (struct mode_header_10_struct) + mode_header_ptr->bdesc_length; while (offset < (mode_header_ptr->length + sizeof (mode_header_ptr->length)) && !mode_data_avail) { if (pg_hdr->code == MODEPAGE_CACHING) { mode_data_avail++; break; } offset += pg_hdr->length + sizeof (struct mode_page); pg_hdr = ((struct mode_page *)((int)pg_buf + (uchar_t)offset)); } } switch ((inq_struct.inq_dtype & DTYPE_MASK)) { case DTYPE_DIRECT: fprintf(stdout, MSGSTR(121, "DEVICE PROPERTIES for disk: %s\n"), path_struct->argv); break; case DTYPE_SEQUENTIAL: /* Tape */ fprintf(stdout, MSGSTR(2249, "DEVICE PROPERTIES for tape: %s\n"), path_struct->argv); break; default: fprintf(stdout, MSGSTR(2250, "DEVICE PROPERTIES for: %s\n"), path_struct->argv); break; } while ((mlist != NULL) && (!(path_a_found && path_b_found))) { (void) strcpy(phys_path, mlist->dev_path); if (err = g_get_inquiry(phys_path, &local_inq)) { (void) fprintf(stderr, MSGSTR(2114, "non_encl_fc_disk_display: Inquiry failed\n")); (void) print_errString(err, phys_path); (void) g_free_multipath( l_disk_state.g_disk_state.multipath_list); (void) g_free_wwn_list(&wwn_list); return (-1); } if ((err = g_get_wwn(mlist->dev_path, port_wwn, node_wwn, &al_pa, verbose)) != 0) { (void) print_errString(err, mlist->dev_path); (void) g_free_multipath( l_disk_state.g_disk_state.multipath_list); (void) g_free_wwn_list(&wwn_list); return (-1); } if (strlen(l_disk_state.g_disk_state.node_wwn_s) == 0) { (void) sprintf(l_disk_state.g_disk_state.node_wwn_s, "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x", node_wwn[0], node_wwn[1], node_wwn[2], node_wwn[3], node_wwn[4], node_wwn[5], node_wwn[6], node_wwn[7]); } if ((err = l_get_disk_port_status(phys_path, &l_disk_state, (local_inq.inq_port) ? FC_PORT_B : FC_PORT_A, verbose)) != 0) { (void) print_errString(err, phys_path); (void) g_free_multipath( l_disk_state.g_disk_state.multipath_list); exit(-1); } if ((!local_inq.inq_port) && (!path_a_found)) { (void) sprintf(l_disk_state.g_disk_state.port_a_wwn_s, "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x", port_wwn[0], port_wwn[1], port_wwn[2], port_wwn[3], port_wwn[4], port_wwn[5], port_wwn[6], port_wwn[7]); path_a_found = l_disk_state.g_disk_state.port_a_valid = 1; } if ((local_inq.inq_port) && (!path_b_found)) { path_b_found = l_disk_state.g_disk_state.port_b_valid = 1; (void) sprintf(l_disk_state.g_disk_state.port_b_wwn_s, "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x", port_wwn[0], port_wwn[1], port_wwn[2], port_wwn[3], port_wwn[4], port_wwn[5], port_wwn[6], port_wwn[7]); } if ((strstr(mlist->dev_path, SCSI_VHCI) != NULL) && (!l_get_disk_port_status(phys_path, &l_disk_state, (!local_inq.inq_port) ? FC_PORT_B : FC_PORT_A, verbose))) { (void) strcpy(temppath, mlist->dev_path); if (err = g_get_pathlist(temppath, &pathlist)) { (void) print_errString(err, NULL); exit(-1); } pathcnt = pathlist.path_count; if (pathcnt > 1) { for (i = 0; i < pathcnt; i++) { if ((!path_a_found) && (path_b_found) && (strstr(pathlist.path_info[i]. path_addr, l_disk_state.g_disk_state. port_b_wwn_s) == NULL)) { (void) strncpy(l_disk_state. g_disk_state.port_a_wwn_s, pathlist.path_info[i]. path_addr, 16); path_a_found = l_disk_state. g_disk_state.port_a_valid = 1; } if ((path_a_found) && (!path_b_found) && (strstr(pathlist.path_info[i]. path_addr, l_disk_state.g_disk_state. port_a_wwn_s) == NULL)) { (void) strncpy(l_disk_state. g_disk_state.port_b_wwn_s, pathlist.path_info[i]. path_addr, 16); path_b_found = l_disk_state. g_disk_state.port_b_valid = 1; } if ((path_a_found) && (path_b_found)) { break; } } } free(pathlist.path_info); } mlist = mlist->next; } if (l_disk_state.g_disk_state.port_a_valid) { (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(141, "Status(Port A):")); (void) fprintf(stdout, "\t"); display_port_status(l_disk_state.g_disk_state.d_state_flags[FC_PORT_A]); } if (l_disk_state.g_disk_state.port_b_valid) { (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(142, "Status(Port B):")); (void) fprintf(stdout, "\t"); display_port_status(l_disk_state.g_disk_state.d_state_flags[FC_PORT_B]); } (void) display_disk_info(local_inq, l_disk_state, path_struct, pg_hdr, mode_data_avail, NULL, verbose); (void) g_free_multipath(l_disk_state.g_disk_state.multipath_list); if (!(argpwwn || argnwwn)) { break; } } (void) g_free_wwn_list(&wwn_list); return (0); } /* * display_disk_info() Prints the device specific information * for any FC_AL disk device. * * RETURNS: * none. */ void display_disk_info(L_inquiry inq, L_disk_state l_disk_state, Path_struct *path_struct, struct mode_page *pg_hdr, int mode_data_avail, char *name_buf, int options) { float num_blks; struct dlist *mlist; int port_a, port_b; struct my_mode_caching *pg8_buf; L_inquiry enc_inq; char *enc_phys_path; Path_struct *enc_path_struct; int enc_type = 0; L_inquiry80 inq80; size_t serial_len; int err; serial_len = sizeof (inq80.inq_serial); err = g_get_serial_number(path_struct->p_physical_path, inq80.inq_serial, &serial_len); if (err) { fprintf(stderr, "\n"); print_errString(err, path_struct->p_physical_path); fprintf(stderr, "\n"); exit(1); } (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(3, "Vendor:")); (void) fprintf(stdout, "\t\t"); print_chars(inq.inq_vid, sizeof (inq.inq_vid), 0); (void) fprintf(stdout, MSGSTR(2115, "\n Product ID:\t\t")); print_chars(inq.inq_pid, sizeof (inq.inq_pid), 0); (void) fprintf(stdout, MSGSTR(2116, "\n WWN(Node):\t\t%s"), l_disk_state.g_disk_state.node_wwn_s); if (l_disk_state.g_disk_state.port_a_valid) { (void) fprintf(stdout, MSGSTR(2117, "\n WWN(Port A):\t\t%s"), l_disk_state.g_disk_state.port_a_wwn_s); } if (l_disk_state.g_disk_state.port_b_valid) { (void) fprintf(stdout, MSGSTR(2118, "\n WWN(Port B):\t\t%s"), l_disk_state.g_disk_state.port_b_wwn_s); } (void) fprintf(stdout, "\n "); (void) fprintf(stdout, MSGSTR(2119, "Revision:")); (void) fprintf(stdout, "\t\t"); print_chars(inq.inq_revision, sizeof (inq.inq_revision), 0); (void) fprintf(stdout, "\n "); (void) fprintf(stdout, MSGSTR(17, "Serial Num:")); (void) fprintf(stdout, "\t\t"); print_chars(inq80.inq_serial, serial_len, 0); num_blks = l_disk_state.g_disk_state.num_blocks; if (num_blks) { num_blks /= 2048; /* get Mbytes */ (void) fprintf(stdout, "\n "); (void) fprintf(stdout, MSGSTR(60, "Unformatted capacity:\t%6.3f MBytes"), num_blks); } (void) fprintf(stdout, "\n"); if (l_disk_state.g_disk_state.persistent_reserv_flag) { (void) fprintf(stdout, MSGSTR(2120, " Persistent Reserve:\t")); if (l_disk_state.g_disk_state.persistent_active) { (void) fprintf(stdout, MSGSTR(39, "Active")); (void) fprintf(stdout, "\n"); } if (l_disk_state.g_disk_state.persistent_registered) { (void) fprintf(stdout, MSGSTR(2121, "Found Registered Keys")); } else { (void) fprintf(stdout, MSGSTR(87, "Not being used")); } (void) fprintf(stdout, "\n"); } if ((mode_data_avail) && (pg_hdr->code == MODEPAGE_CACHING)) { pg8_buf = (struct my_mode_caching *)(int)pg_hdr; if (pg8_buf->wce) { (void) fprintf(stdout, MSGSTR(2122, " Write Cache:\t\t" "Enabled\n")); } if (pg8_buf->rcd == 0) { (void) fprintf(stdout, MSGSTR(2123, " Read Cache:\t\t" "Enabled\n")); (void) fprintf(stdout, MSGSTR(2320, " Minimum prefetch:" "\t0x%x\n" " Maximum prefetch:" "\t0x%x\n"), pg8_buf->min_prefetch, pg8_buf->max_prefetch); } } /* * When /dev/rdsk/cxtxdxsx form of input is specified * for display command the initial library version didn't * display Location information. The change is made * to display the same Location info as the non-library version. */ if (name_buf != NULL) { fprintf(stdout, MSGSTR(2125, " Location:\t\t")); if (path_struct->slot_valid) { /* * We have to do another inquiry on the enclosure (name_buf) * to determine if this device is within a daktari, or * a two sided device. */ if (!l_convert_name(name_buf, &enc_phys_path, &enc_path_struct, 0)) { if (!g_get_inquiry(enc_phys_path, &enc_inq)) { enc_type = l_get_enc_type(enc_inq); } } /* If either of the above fail, we just assume the default */ free(enc_phys_path); free(enc_path_struct); if (enc_type == DAK_ENC_TYPE) { if (path_struct->f_flag) { (void) fprintf(stdout, MSGSTR(2239, "In slot %d in the enclosure named: %s\n"), path_struct->slot, name_buf); } else { (void) fprintf(stdout, MSGSTR(2239, "In slot %d in the enclosure named: %s\n"), path_struct->slot + (MAX_DRIVES_DAK/2), name_buf); } } else { /* Default enclosure type */ (void) fprintf(stdout, path_struct->f_flag ? MSGSTR(2126, "In slot %d in the Front of the enclosure named: %s\n") : MSGSTR(2127, "In slot %d in the Rear of the enclosure named: %s\n"), path_struct->slot, name_buf); } } else { (void) fprintf(stdout, MSGSTR(2228, "In the enclosure named: %s\n"), name_buf); } } (void) fprintf(stdout, " %s\t\t%s\n", MSGSTR(35, "Device Type:"), dtype[inq.inq_dtype & DTYPE_MASK]); mlist = l_disk_state.g_disk_state.multipath_list; (void) fprintf(stdout, MSGSTR(2128, " Path(s):\n")); if (strstr(mlist->dev_path, SCSI_VHCI) != NULL) { (void) fprintf(stdout, " %s\n %s\n", mlist->logical_path, mlist->dev_path); (void) adm_print_pathlist(mlist->dev_path); } else { while (mlist) { (void) fprintf(stdout, " %s\n %s\n", mlist->logical_path, mlist->dev_path); mlist = mlist->next; } } if (Options & OPTION_V) { if (path_struct->slot_valid) { port_a = PORT_A; port_b = PORT_B; } else { port_a = FC_PORT_A; port_b = FC_PORT_B; } /* Only bother if the state is O.K. */ if ((l_disk_state.g_disk_state.port_a_valid) && (l_disk_state.g_disk_state.d_state_flags[port_a] == 0)) adm_display_verbose_disk(path_struct->p_physical_path, options); else if ((l_disk_state.g_disk_state.port_b_valid) && (l_disk_state.g_disk_state.d_state_flags[port_b] == 0)) adm_display_verbose_disk(path_struct->p_physical_path, options); } (void) fprintf(stdout, "\n"); } /* * temp_decode() Display temperature bytes 1-3 state. * * RETURNS: * none. */ void temp_decode(Temp_elem_st *temp) { if (temp->ot_fail) { (void) fprintf(stdout, MSGSTR(2129, ": FAILURE - Over Temperature")); } if (temp->ut_fail) { (void) fprintf(stdout, MSGSTR(2130, ": FAILURE - Under Temperature")); } if (temp->ot_warn) { (void) fprintf(stdout, MSGSTR(2131, ": WARNING - Over Temperature")); } if (temp->ut_warn) { (void) fprintf(stdout, MSGSTR(2132, ": WARNING - Under Temperature")); } } /* * disp_degree() Display temperature in Degrees Celsius. * * RETURNS: * none. */ void disp_degree(Temp_elem_st *temp) { int t; t = temp->degrees; t -= 20; /* re-adjust */ /* * NL_Comment * The %c is the degree symbol. */ (void) fprintf(stdout, ":%1.2d%cC ", t, 186); } /* * trans_decode() Display tranceivers state. * * RETURNS: * none. */ void trans_decode(Trans_elem_st *trans) { if (trans->disabled) { (void) fprintf(stdout, ": "); (void) fprintf(stdout, MSGSTR(34, "Disabled")); } if (trans->lol) { (void) fprintf(stdout, MSGSTR(2133, ": Not receiving a signal")); } if (trans->lsr_fail) { (void) fprintf(stdout, MSGSTR(2134, ": Laser failed")); } } /* * trans_messages() Display tranceiver status. * * NOTE: The decoding of the status assumes that the elements * are in order with the first two elements are for the * "A" IB. It also assumes the tranceivers are numbered * 0 and 1. * * RETURNS: * none. */ void trans_messages(struct l_state_struct *l_state, int ib_a_flag) { Trans_elem_st trans; int i, j, k; int count = 0; int elem_index = 0; /* Get and print messages */ for (i = 0; i < (int)l_state->ib_tbl.config.enc_num_elem; i++) { elem_index++; if (l_state->ib_tbl.config.type_hdr[i].type == ELM_TYP_FL) { if (l_state->ib_tbl.config.type_hdr[i].text_len != 0) { (void) fprintf(stdout, "\n\t\t%s\n", l_state->ib_tbl.config.text[i]); } count = k = 0; for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[i].num; j++) { /* * Only display the status for the selected IB. */ if ((count < 2 && ib_a_flag) || (count >= 2 && !ib_a_flag)) { (void) bcopy((const void *) &l_state->ib_tbl.p2_s.element[elem_index + j], (void *)&trans, sizeof (trans)); if (k == 0) { (void) fprintf(stdout, "\t\t%d ", k); } else { (void) fprintf(stdout, "\n\t\t%d ", k); } if (trans.code == S_OK) { (void) fprintf(stdout, MSGSTR(29, "O.K.")); revision_msg(l_state, elem_index + j); } else if ((trans.code == S_CRITICAL) || (trans.code == S_NONCRITICAL)) { (void) fprintf(stdout, MSGSTR(2135, "Failed")); revision_msg(l_state, elem_index + j); trans_decode(&trans); } else if (trans.code == S_NOT_INSTALLED) { (void) fprintf(stdout, MSGSTR(30, "Not Installed")); } else if (trans.code == S_NOT_AVAILABLE) { (void) fprintf(stdout, MSGSTR(34, "Disabled")); revision_msg(l_state, elem_index + j); } else { (void) fprintf(stdout, MSGSTR(4, "Unknown status")); } k++; } count++; } } /* * Calculate the index to each element. */ elem_index += l_state->ib_tbl.config.type_hdr[i].num; } (void) fprintf(stdout, "\n"); } /* * temperature_messages() Display temperature status. * * RETURNS: * none. */ void temperature_messages(struct l_state_struct *l_state, int rear_flag) { Temp_elem_st temp; int i, j, last_ok = 0; int all_ok = 1; int elem_index = 0; /* Get and print messages */ for (i = 0; i < (int)l_state->ib_tbl.config.enc_num_elem; i++) { elem_index++; /* skip global */ if (l_state->ib_tbl.config.type_hdr[i].type == ELM_TYP_TS) { if (!rear_flag) { rear_flag = 1; /* only do front or rear backplane */ if (l_state->ib_tbl.config.type_hdr[i].text_len != 0) { (void) fprintf(stdout, "\t %s", l_state->ib_tbl.config.text[i]); } /* * Check global status and if not all O.K. * then print individually. */ (void) bcopy((const void *)&l_state->ib_tbl.p2_s.element[i], (void *)&temp, sizeof (temp)); for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[i].num; j++) { (void) bcopy((const void *) &l_state->ib_tbl.p2_s.element[elem_index + j], (void *)&temp, sizeof (temp)); if ((j == 0) && (temp.code == S_OK) && (!(temp.ot_fail || temp.ot_warn || temp.ut_fail || temp.ut_warn))) { (void) fprintf(stdout, "\n\t %d", j); } else if ((j == 6) && (temp.code == S_OK) && all_ok) { (void) fprintf(stdout, "\n\t %d", j); } else if (last_ok && (temp.code == S_OK)) { (void) fprintf(stdout, "%d", j); } else { (void) fprintf(stdout, "\n\t\t%d", j); } if (temp.code == S_OK) { disp_degree(&temp); if (temp.ot_fail || temp.ot_warn || temp.ut_fail || temp.ut_warn) { temp_decode(&temp); all_ok = 0; last_ok = 0; } else { last_ok++; } } else if (temp.code == S_CRITICAL) { (void) fprintf(stdout, MSGSTR(122, "Critical failure")); last_ok = 0; all_ok = 0; } else if (temp.code == S_NONCRITICAL) { (void) fprintf(stdout, MSGSTR(89, "Non-Critical Failure")); last_ok = 0; all_ok = 0; } else if (temp.code == S_NOT_INSTALLED) { (void) fprintf(stdout, MSGSTR(30, "Not Installed")); last_ok = 0; all_ok = 0; } else if (temp.code == S_NOT_AVAILABLE) { (void) fprintf(stdout, MSGSTR(34, "Disabled")); last_ok = 0; all_ok = 0; } else { (void) fprintf(stdout, MSGSTR(4, "Unknown status")); last_ok = 0; all_ok = 0; } } if (all_ok) { (void) fprintf(stdout, MSGSTR(2136, " (All temperatures are " "NORMAL.)")); } all_ok = 1; (void) fprintf(stdout, "\n"); } else { rear_flag = 0; } } elem_index += l_state->ib_tbl.config.type_hdr[i].num; } } /* * ib_decode() Display IB byte 3 state. * * RETURNS: * none. */ void ib_decode(Ctlr_elem_st *ctlr) { if (ctlr->overtemp_alart) { (void) fprintf(stdout, MSGSTR(2137, " - IB Over Temperature Alert ")); } if (ctlr->ib_loop_1_fail) { (void) fprintf(stdout, MSGSTR(2138, " - IB Loop 1 has failed ")); } if (ctlr->ib_loop_0_fail) { (void) fprintf(stdout, MSGSTR(2139, " - IB Loop 0 has failed ")); } } /* * mb_messages() Display motherboard * (interconnect assembly) messages. * * RETURNS: * none. */ void mb_messages(struct l_state_struct *l_state, int index, int elem_index) { int j; Interconnect_st interconnect; if (l_state->ib_tbl.config.type_hdr[index].text_len != 0) { (void) fprintf(stdout, "%s\n", l_state->ib_tbl.config.text[index]); } for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[index].num; j++) { (void) bcopy((const void *) &l_state->ib_tbl.p2_s.element[elem_index + j], (void *)&interconnect, sizeof (interconnect)); (void) fprintf(stdout, "\t"); if (interconnect.code == S_OK) { (void) fprintf(stdout, MSGSTR(29, "O.K.")); revision_msg(l_state, elem_index + j); } else if (interconnect.code == S_NOT_INSTALLED) { (void) fprintf(stdout, MSGSTR(30, "Not Installed")); } else if (interconnect.code == S_CRITICAL) { if (interconnect.eprom_fail != 0) { (void) fprintf(stdout, MSGSTR(2140, "Critical Failure: EEPROM failure")); } else { (void) fprintf(stdout, MSGSTR(2141, "Critical Failure: Unknown failure")); } revision_msg(l_state, elem_index + j); } else if (interconnect.code == S_NONCRITICAL) { if (interconnect.eprom_fail != 0) { (void) fprintf(stdout, MSGSTR(2142, "Non-Critical Failure: EEPROM failure")); } else { (void) fprintf(stdout, MSGSTR(2143, "Non-Critical Failure: Unknown failure")); } revision_msg(l_state, elem_index + j); } else if (interconnect.code == S_NOT_AVAILABLE) { (void) fprintf(stdout, MSGSTR(34, "Disabled")); revision_msg(l_state, elem_index + j); } else { (void) fprintf(stdout, MSGSTR(4, "Unknown status")); } (void) fprintf(stdout, "\n"); } } /* * back_plane_messages() Display back_plane messages * including the temperature's. * * RETURNS: * none. */ void back_plane_messages(struct l_state_struct *l_state, int index, int elem_index) { Bp_elem_st bp; int j; char status_string[MAXPATHLEN]; if (l_state->ib_tbl.config.type_hdr[index].text_len != 0) { (void) fprintf(stdout, "%s\n", l_state->ib_tbl.config.text[index]); } for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[index].num; j++) { (void) bcopy((const void *) &l_state->ib_tbl.p2_s.element[elem_index + j], (void *)&bp, sizeof (bp)); if (j == 0) { (void) fprintf(stdout, MSGSTR(2144, "\tFront Backplane: ")); } else { (void) fprintf(stdout, MSGSTR(2145, "\tRear Backplane: ")); } (void) l_element_msg_string(bp.code, status_string); (void) fprintf(stdout, "%s", status_string); if (bp.code != S_NOT_INSTALLED) { revision_msg(l_state, elem_index + j); if ((bp.byp_a_enabled || bp.en_bypass_a) && !(bp.byp_b_enabled || bp.en_bypass_b)) { (void) fprintf(stdout, " ("); (void) fprintf(stdout, MSGSTR(130, "Bypass A enabled")); (void) fprintf(stdout, ")"); } else if ((bp.byp_b_enabled || bp.en_bypass_b) && !(bp.byp_a_enabled || bp.en_bypass_a)) { (void) fprintf(stdout, " ("); (void) fprintf(stdout, MSGSTR(129, "Bypass B enabled")); (void) fprintf(stdout, ")"); /* This case covers where a and b are bypassed */ } else if (bp.byp_b_enabled || bp.en_bypass_b) { (void) fprintf(stdout, MSGSTR(2146, " (Bypass's A & B enabled)")); } (void) fprintf(stdout, "\n"); temperature_messages(l_state, j); } else { (void) fprintf(stdout, "\n"); } } } /* * dpm_SSC100_messages() Display SSC100 messages * including the temperature's. * * RETURNS: * none. */ void dpm_SSC100_messages(struct l_state_struct *l_state, int index, int elem_index) { Bp_elem_st bp; int j; char status_string[MAXPATHLEN]; if (l_state->ib_tbl.config.type_hdr[index].text_len != 0) { (void) fprintf(stdout, "%s\n", l_state->ib_tbl.config.text[index]); } for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[index].num; j++) { (void) bcopy((const void *) &l_state->ib_tbl.p2_s.element[elem_index + j], (void *)&bp, sizeof (bp)); (void) fprintf(stdout, MSGSTR(2246, " SSC100 #%d: "), j); (void) l_element_msg_string(bp.code, status_string); (void) fprintf(stdout, "%s", status_string); if (bp.code != S_NOT_INSTALLED) { revision_msg(l_state, elem_index + j); if ((bp.byp_a_enabled || bp.en_bypass_a) && !(bp.byp_b_enabled || bp.en_bypass_b)) { (void) fprintf(stdout, " ("); (void) fprintf(stdout, MSGSTR(130, "Bypass A enabled")); (void) fprintf(stdout, ")"); } else if ((bp.byp_b_enabled || bp.en_bypass_b) && !(bp.byp_a_enabled || bp.en_bypass_a)) { (void) fprintf(stdout, " ("); (void) fprintf(stdout, MSGSTR(129, "Bypass B enabled")); (void) fprintf(stdout, ")"); /* This case covers where a and b are bypassed */ } else if (bp.byp_b_enabled || bp.en_bypass_b) { (void) fprintf(stdout, MSGSTR(2146, " (Bypass's A & B enabled)")); } (void) fprintf(stdout, "\n"); } else { (void) fprintf(stdout, "\n"); } } temperature_messages(l_state, 0); } /* * loop_messages() Display loop messages. * * RETURNS: * none. */ void loop_messages(struct l_state_struct *l_state, int index, int elem_index) { Loop_elem_st loop; int j; if (l_state->ib_tbl.config.type_hdr[index].text_len != 0) { (void) fprintf(stdout, "%s\n", l_state->ib_tbl.config.text[index]); } for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[index].num; j++) { (void) bcopy((const void *) &l_state->ib_tbl.p2_s.element[elem_index + j], (void *)&loop, sizeof (loop)); (void) fprintf(stdout, "\t"); if (j == 0) { if (loop.code == S_NOT_INSTALLED) { (void) fprintf(stdout, MSGSTR(2147, "Loop A is not installed")); } else { if (loop.split) { (void) fprintf(stdout, MSGSTR(2148, "Loop A is configured as two separate loops.")); } else { (void) fprintf(stdout, MSGSTR(2149, "Loop A is configured as a single loop.")); } } } else { if (loop.code == S_NOT_INSTALLED) { (void) fprintf(stdout, MSGSTR(2150, "Loop B is not installed")); } else { if (loop.split) { (void) fprintf(stdout, MSGSTR(2151, "Loop B is configured as two separate loops.")); } else { (void) fprintf(stdout, MSGSTR(2152, "Loop B is configured as a single loop.")); } } } (void) fprintf(stdout, "\n"); } } /* * ctlr_messages() Display ESI Controller status. * * RETURNS: * none. */ void ctlr_messages(struct l_state_struct *l_state, int index, int elem_index) { Ctlr_elem_st ctlr; int j; int ib_a_flag = 1; if (l_state->ib_tbl.config.type_hdr[index].text_len != 0) { (void) fprintf(stdout, "%s\n", l_state->ib_tbl.config.text[index]); } for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[index].num; j++) { (void) bcopy((const void *) &l_state->ib_tbl.p2_s.element[elem_index + j], (void *)&ctlr, sizeof (ctlr)); if (j == 0) { (void) fprintf(stdout, MSGSTR(2153, "\tA: ")); } else { (void) fprintf(stdout, MSGSTR(2154, "\tB: ")); ib_a_flag = 0; } if (ctlr.code == S_OK) { (void) fprintf(stdout, MSGSTR(29, "O.K.")); /* If any byte 3 bits set display */ ib_decode(&ctlr); /* Display Version message */ revision_msg(l_state, elem_index + j); /* * Display the tranciver module state for this * IB. */ trans_messages(l_state, ib_a_flag); } else if (ctlr.code == S_CRITICAL) { (void) fprintf(stdout, MSGSTR(122, "Critical failure")); ib_decode(&ctlr); (void) fprintf(stdout, "\n"); } else if (ctlr.code == S_NONCRITICAL) { (void) fprintf(stdout, MSGSTR(89, "Non-Critical Failure")); ib_decode(&ctlr); (void) fprintf(stdout, "\n"); } else if (ctlr.code == S_NOT_INSTALLED) { (void) fprintf(stdout, MSGSTR(30, "Not Installed")); (void) fprintf(stdout, "\n"); } else if (ctlr.code == S_NOT_AVAILABLE) { (void) fprintf(stdout, MSGSTR(34, "Disabled")); (void) fprintf(stdout, "\n"); } else { (void) fprintf(stdout, MSGSTR(4, "Unknown status")); (void) fprintf(stdout, "\n"); } } } /* * fan_decode() Display Fans bytes 1-3 state. * * RETURNS: * none. */ void fan_decode(Fan_elem_st *fan) { if (fan->fail) { (void) fprintf(stdout, MSGSTR(2155, ":Yellow LED is on")); } if (fan->speed == 0) { (void) fprintf(stdout, MSGSTR(2156, ":Fan stopped")); } else if (fan->speed < S_HI_SPEED) { (void) fprintf(stdout, MSGSTR(2157, ":Fan speed Low")); } else { (void) fprintf(stdout, MSGSTR(2158, ":Fan speed Hi")); } } /* * fan_messages() Display Fan status. * * RETURNS: * none. */ void fan_messages(struct l_state_struct *l_state, int hdr_index, int elem_index) { Fan_elem_st fan; int j; /* Get and print messages */ if (l_state->ib_tbl.config.type_hdr[hdr_index].text_len != 0) { (void) fprintf(stdout, "%s\n", l_state->ib_tbl.config.text[hdr_index]); } for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[hdr_index].num; j++) { (void) bcopy((const void *) &l_state->ib_tbl.p2_s.element[elem_index + j], (void *)&fan, sizeof (fan)); (void) fprintf(stdout, "\t%d ", j); if (fan.code == S_OK) { (void) fprintf(stdout, MSGSTR(29, "O.K.")); revision_msg(l_state, elem_index + j); } else if (fan.code == S_CRITICAL) { (void) fprintf(stdout, MSGSTR(122, "Critical failure")); fan_decode(&fan); revision_msg(l_state, elem_index + j); } else if (fan.code == S_NONCRITICAL) { (void) fprintf(stdout, MSGSTR(89, "Non-Critical Failure")); fan_decode(&fan); revision_msg(l_state, elem_index + j); } else if (fan.code == S_NOT_INSTALLED) { (void) fprintf(stdout, MSGSTR(30, "Not Installed")); } else if (fan.code == S_NOT_AVAILABLE) { (void) fprintf(stdout, MSGSTR(34, "Disabled")); revision_msg(l_state, elem_index + j); } else { (void) fprintf(stdout, MSGSTR(4, "Unknown status")); } } (void) fprintf(stdout, "\n"); } /* * ps_decode() Display Power Supply bytes 1-3 state. * * RETURNS: * none. */ void ps_decode(Ps_elem_st *ps) { if (ps->dc_over) { (void) fprintf(stdout, MSGSTR(2159, ": DC Voltage too high")); } if (ps->dc_under) { (void) fprintf(stdout, MSGSTR(2160, ": DC Voltage too low")); } if (ps->dc_over_i) { (void) fprintf(stdout, MSGSTR(2161, ": DC Current too high")); } if (ps->ovrtmp_fail || ps->temp_warn) { (void) fprintf(stdout, MSGSTR(2162, ": Temperature too high")); } if (ps->ac_fail) { (void) fprintf(stdout, MSGSTR(2163, ": AC Failed")); } if (ps->dc_fail) { (void) fprintf(stdout, MSGSTR(2164, ": DC Failed")); } } /* * revision_msg() Print the revision message from page 7. * * RETURNS: * none. */ void revision_msg(struct l_state_struct *l_state, int index) { if (strlen((const char *) l_state->ib_tbl.p7_s.element_desc[index].desc_string)) { (void) fprintf(stdout, "(%s)", l_state->ib_tbl.p7_s.element_desc[index].desc_string); } } /* * ps_messages() Display Power Supply status. * * RETURNS: * none. */ void ps_messages(struct l_state_struct *l_state, int index, int elem_index) { Ps_elem_st ps; int j; /* Get and print Power Supply messages */ if (l_state->ib_tbl.config.type_hdr[index].text_len != 0) { (void) fprintf(stdout, "%s\n", l_state->ib_tbl.config.text[index]); } for (j = 0; j < (int)l_state->ib_tbl.config.type_hdr[index].num; j++) { (void) bcopy((const void *) &l_state->ib_tbl.p2_s.element[elem_index + j], (void *)&ps, sizeof (ps)); (void) fprintf(stdout, "\t%d ", j); if (ps.code == S_OK) { (void) fprintf(stdout, MSGSTR(29, "O.K.")); revision_msg(l_state, elem_index + j); } else if (ps.code == S_CRITICAL) { (void) fprintf(stdout, MSGSTR(122, "Critical failure")); ps_decode(&ps); revision_msg(l_state, elem_index + j); } else if (ps.code == S_NONCRITICAL) { (void) fprintf(stdout, MSGSTR(89, "Non-Critical Failure")); ps_decode(&ps); revision_msg(l_state, elem_index + j); } else if (ps.code == S_NOT_INSTALLED) { (void) fprintf(stdout, MSGSTR(30, "Not Installed")); } else if (ps.code == S_NOT_AVAILABLE) { (void) fprintf(stdout, MSGSTR(34, "Disabled")); revision_msg(l_state, elem_index + j); } else { (void) fprintf(stdout, MSGSTR(4, "Unknown status")); } } (void) fprintf(stdout, "\n"); } /* * abnormal_condition() Display any abnormal condition messages. * * RETURNS: * none. */ void abnormal_condition_display(struct l_state_struct *l_state) { (void) fprintf(stdout, "\n"); if (l_state->ib_tbl.p2_s.ui.crit) { (void) fprintf(stdout, MSGSTR(2165, " " "CRITICAL CONDITION DETECTED\n")); } if (l_state->ib_tbl.p2_s.ui.non_crit) { (void) fprintf(stdout, MSGSTR(2166, " " "WARNING: NON-CRITICAL CONDITION DETECTED\n")); } if (l_state->ib_tbl.p2_s.ui.invop) { (void) fprintf(stdout, MSGSTR(2167, " " "WARNING: Invalid Operation bit set.\n" "\tThis means an Enclosure Control page" " or an Array Control page with an invalid\n" "\tformat has previously been transmitted to the" " Enclosure Services card by a\n\tSend Diagnostic" " SCSI command.\n")); } (void) fprintf(stdout, "\n"); } /* * adm_start() Spin up the given list * of SENA devices. * * RETURNS: * none. */ int adm_start(char **argv) { char *path_phys = NULL; Path_struct *path_struct; int err = 0, retval = 0; while (*argv != NULL) { if ((err = l_convert_name(*argv, &path_phys, &path_struct, Options & PVERBOSE)) != 0) { (void) fprintf(stderr, MSGSTR(33, " Error: converting" " %s to physical path.\n" " Invalid pathname.\n"), *argv); if (err != -1) { (void) print_errString(err, *argv); } (argv)++; retval++; continue; } VERBPRINT(MSGSTR(101, "Issuing start to:\n %s\n"), *argv); if (err = g_start(path_phys)) { (void) print_errString(err, *argv); (argv)++; retval++; continue; } (argv)++; } return (retval); } /* * adm_stop() Spin down a * given list of SENA devices. * * RETURNS: * none. */ int adm_stop(char **argv) { char *path_phys = NULL; Path_struct *path_struct; int err = 0, retval = 0; while (*argv != NULL) { if ((err = l_convert_name(*argv, &path_phys, &path_struct, Options & PVERBOSE)) != 0) { (void) fprintf(stderr, MSGSTR(33, " Error: converting" " %s to physical path.\n" " Invalid pathname.\n"), *argv); if (err != -1) { (void) print_errString(err, *argv); } (argv)++; retval++; continue; } /* * scsi stop is not supported for tape drives. * The scsi unload op code for tape is the same as a * scsi stop for disk so this command will eject the tape. * If an eject is the desired behavior then remove the * following if block. ('mt offline' will give you * the same eject functionality). */ if (strstr(path_phys, SLSH_DRV_NAME_ST)) { errno = ENOTSUP; (void) print_errString(0, path_phys); (argv)++; continue; } VERBPRINT(MSGSTR(100, "Issuing stop to:\n %s\n"), *argv); if (err = g_stop(path_phys, 1)) { (void) print_errString(err, *argv); (argv)++; retval++; continue; } (argv)++; } return (retval); } /* * On a SOC+ chip, the port is either put into (offline) or pulled out * of (online) a loopback mode since the laser cannot be turned on or off. * As of this writing, this feature is yet to be supported by the ifp * driver on a QLogic card. * * INPUT : * Command line args and flag - LUX_P_ONLINE or LUX_P_OFFLINE * The path that is passed has to be the physical path to the port. * For example : * /devices/sbus@2,0/SUNW,socal@2,0:0 * /devices/io-unit@f,e0200000/sbi@0,0/SUNW,socal@2,0:0 * /devices/pci@1f,4000/SUNW,ifp@2:devctl * RETURNS : * Nothing */ int adm_port_offline_online(char *argv[], int flag) { int err, retval = 0; char *path_phys = NULL; char *nexus_path_ptr = NULL; Path_struct *path_struct = NULL; while (*argv != NULL) { if ((err = l_convert_name(*argv, &path_phys, &path_struct, Options & PVERBOSE)) != 0) { (void) fprintf(stderr, MSGSTR(33, " Error: converting" " %s to physical path.\n" " Invalid pathname.\n"), *argv); if (err != -1) { (void) print_errString(err, *argv); } argv++; retval++; continue; } /* Get the nexus path - need this to print messages */ if ((err = g_get_nexus_path(path_phys, &nexus_path_ptr)) != 0) { (void) print_errString(err, *argv); retval++; goto cleanup_and_go; } if (flag == LUX_P_OFFLINE) { if ((err = g_port_offline(nexus_path_ptr))) { (void) print_errString(err, nexus_path_ptr); retval++; goto cleanup_and_go; } fprintf(stdout, MSGSTR(2223, "Port %s has been disabled\n"), nexus_path_ptr); } else if (flag == LUX_P_ONLINE) { if ((err = g_port_online(nexus_path_ptr))) { (void) print_errString(err, nexus_path_ptr); retval++; goto cleanup_and_go; } fprintf(stdout, MSGSTR(2224, "Port %s has been enabled\n"), nexus_path_ptr); } else { (void) fprintf(stderr, MSGSTR(2225, "Unknown action requested " "on port - %d\nIgnoring."), flag); retval++; } cleanup_and_go: free(path_phys); free(path_struct); free(nexus_path_ptr); argv++; } return (retval); } /* * Expert level subcommand 'luxadm -e port' * which displays all FC ports on a host and state information for * connectivity (CONNECTED or NOT CONNECTED) indicating whether there * are devices attached to the port. * * Sample output for ifp: * * /devices/pci@1f,4000/SUNW,ifp@2:devctl CONNECTED * /devices/pci@1f,2000/SUNW,ifp@1:devctl NOT CONNECTED * * Sample output for socal: * * /devices/sbus@2,0/SUNW,socal@d,10000:0 CONNECTED * /devices/sbus@2,0/SUNW,socal@d,10000:1 NOT CONNECTED * /devices/sbus@2,0/SUNW,socal@2,0:0 NOT CONNECTED * /devices/sbus@2,0/SUNW,socal@2,0:1 CONNECTED * * Note: for socal the path returned is not a devctl path as there is no * devctl path for socal. * * Sample output for fp: * * /devices/sbus@2,0/SUNW,qlc@5/fp@0,0:devctl CONNECTED * /devices/sbus@2,0/SUNW,qlc@4/fp@1,0:devctl CONNECTED */ int adm_display_port(int verbose) { /* * If another port driver needs to be searched, add it here */ static char *portdrvr_list[] = {"socal", "fp", "ifp", NULL}; portlist_t portlist; int x = 0, err = 0, retval = 0; int port_state; portlist.hbacnt = 0; /* * Look for all HBA ports as listed in portdrvr_list[] */ while (portdrvr_list[x]) { if (err = g_get_port_path(portdrvr_list[x], &portlist)) { if (err != L_PORT_DRIVER_NOT_FOUND && err != L_PHYS_PATH_NOT_FOUND) { (void) print_errString(err, portdrvr_list[x]); retval++; } } x++; } /* * For each port path found get the connection state. * If there are devices attached the state is considered connected. */ for (x = 0; x < portlist.hbacnt; x++) { if (err = g_get_port_state(portlist.physpath[x], &port_state, verbose)) { (void) print_errString(err, portlist.physpath[x]); retval++; } else { fprintf(stdout, "%-65s ", portlist.physpath[x]); if (port_state == PORT_CONNECTED) { (void) fprintf(stdout, MSGSTR(2233, "CONNECTED\n")); } else { (void) fprintf(stdout, MSGSTR(2234, "NOT CONNECTED\n")); } } } g_free_portlist(&portlist); return (retval); } /* * Expert level subcommand 'luxadm -e external_loopback * internal_loopback * no_loopback * Does just what you would think. Sets port in designated loopback * mode. * INPUT: portpath - path to device on which to set loopback mode * flag - loopback mode to set. Values are: * EXT_LOOPBACK * INT_LOOPBACK * NO_LOOPBACK * * RETURN: 0 on success * non-zero on failure */ int adm_port_loopback(char *portpath, int flag) { int err; char *path_phys = NULL; Path_struct *path_struct = NULL; int cmd; if ((err = l_convert_name(portpath, &path_phys, &path_struct, Options & PVERBOSE)) != 0) { (void) fprintf(stderr, MSGSTR(33, " Error: converting" " %s to physical path.\n" " Invalid pathname.\n"), portpath); if (err != -1) { (void) print_errString(err, portpath); } return (-1); } switch (flag) { case EXT_LOOPBACK: cmd = EXT_LPBACK; break; case INT_LOOPBACK: cmd = INT_LPBACK; break; case NO_LOOPBACK: cmd = NO_LPBACK; break; default: (void) fprintf(stderr, MSGSTR(2225, "Unknown action requested " "on port - %d\nIgnoring."), flag); free(path_phys); free(path_struct); return (-1); } if ((err = g_loopback_mode(path_phys, cmd)) != 0) { (void) print_errString(err, portpath); free(path_phys); free(path_struct); return (-1); } else { switch (flag) { case EXT_LOOPBACK: (void) fprintf(stdout, MSGSTR(2230, "External loopback mode set " "on:\n%s\n"), portpath); break; case INT_LOOPBACK: (void) fprintf(stdout, MSGSTR(2231, "Internal loopback mode set " "on:\n%s\n"), portpath); break; case NO_LOOPBACK: (void) fprintf(stdout, MSGSTR(2232, "Loopback mode unset " "on:\n%s\n"), portpath); break; default: fprintf(stderr, MSGSTR(2248, "Undefined command\n")); break; } } free(path_phys); free(path_struct); return (0); } /* * To print the pathlist and mpxio path attributes */ void adm_print_pathlist(char *dev_path) { int i, pathcnt = 1; mp_pathlist_t pathlist; int retval = 0; char temppath[MAXPATHLEN]; char wwns[(WWN_SIZE *2) +1]; uchar_t wwn_data[WWN_SIZE]; int err; int state, ext_state = 0; char *path_state[5]; path_state[0] = MSGSTR(2400, "INIT"); path_state[1] = MSGSTR(2401, "ONLINE"); path_state[2] = MSGSTR(2402, "STANDBY"); path_state[3] = MSGSTR(2403, "FAULT"); path_state[4] = MSGSTR(2404, "OFFLINE"); (void) strcpy(temppath, dev_path); retval = g_get_pathlist(temppath, &pathlist); if (retval != 0) { (void) print_errString(retval, NULL); exit(-1); } pathcnt = pathlist.path_count; for (i = 0; i < pathcnt; i++) { (void) fprintf(stdout, MSGSTR(2303, " Controller \t%s\n"), pathlist.path_info[i].path_hba); (void) fprintf(stdout, MSGSTR(2304, " Device Address\t\t%s\n"), pathlist.path_info[i].path_addr); if ((err = get_host_controller_pwwn( pathlist.path_info[i].path_hba, (uchar_t *)&wwn_data)) != 0) { if (err != ENOTSUP) { (void) print_errString(err, pathlist.path_info[i].path_hba); exit(1); } } if (!err) { copy_wwn_data_to_str(wwns, wwn_data); (void) fprintf(stdout, MSGSTR(2326, " Host controller port WWN\t%s\n"), wwns); } (void) fprintf(stdout, MSGSTR(2305, " Class\t\t\t%s\n"), pathlist.path_info[i].path_class); if (pathlist.path_info[i].path_state < MAXPATHSTATE) { (void) fprintf(stdout, MSGSTR(2306, " State\t\t\t%s\n"), path_state[pathlist.path_info[i].path_state]); } if ((err = g_stms_get_path_state(dev_path, pathlist.path_info[i].path_hba, &state, &ext_state)) != 0) { (void) print_errString(err, pathlist.path_info[i].path_hba); exit(1); } else { if ((ext_state & MDI_PATHINFO_STATE_USER_DISABLE) == MDI_PATHINFO_STATE_USER_DISABLE) { ext_state = 0; fprintf(stdout, MSGSTR(2327, " I/Os disabled on this %s path\n\n"), path_state[pathlist.path_info[i].path_state]); } } } /* Free memory for per path info properties */ free(pathlist.path_info); } /* * compare_multipath * compares path with all paths in pathlist * If there is a match, 0 is returned, otherwise 1 is returned */ int compare_multipath(char *path, struct mplist_struct *pathlist) { while (pathlist != NULL) { if (strncmp(path, pathlist->devpath, MAXPATHLEN) == 0) { return (0); } pathlist = pathlist->next; } return (1); } /* * lun_display() Prints the * information for an individual lun. * * RETURNS: * none. */ static int lun_display(Path_struct *path_struct, L_inquiry inq_struct, int verbose) { char phys_path[MAXPATHLEN], last_logical_path[MAXPATHLEN]; uchar_t *pg_buf = NULL; L_disk_state l_disk_state; struct dlist *mlist; int offset, mode_data_avail, err = 0; Mode_header_10 *mode_header_ptr; struct mode_page *pg_hdr = NULL; WWN_list *wwn_list, *list_start, *wwn_list_ptr; WWN_list *wwn_list_find; int found = 0; int argpwwn = 0, argnwwn = 0; struct mplist_struct *mplistp, *mpl, *mpln; struct dlist *dlist; strcpy(phys_path, path_struct->p_physical_path); strcpy(last_logical_path, phys_path); mplistp = mpl = mpln = (struct mplist_struct *)NULL; /* * Get path to all the FC disk and tape devices. * If there is no slash in the argument in this routine, we assume * it is a wwn argument. */ if (strstr(path_struct->argv, "/") != NULL) { if ((err = g_devices_get_all(&wwn_list)) != 0) { return (err); } } else { if ((err = g_get_wwn_list(&wwn_list, verbose)) != 0) { return (err); } } g_sort_wwn_list(&wwn_list); list_start = wwn_list; for (wwn_list_ptr = wwn_list; wwn_list_ptr != NULL; wwn_list_ptr = wwn_list_ptr->wwn_next) { if (strcasecmp(wwn_list_ptr->port_wwn_s, path_struct->argv) == 0) { list_start = wwn_list_ptr; argpwwn = 1; break; } else if (strcasecmp(wwn_list_ptr->node_wwn_s, path_struct->argv) == 0) { list_start = wwn_list_ptr; argnwwn = 1; break; } } for (wwn_list_ptr = list_start; wwn_list_ptr != NULL; wwn_list_ptr = wwn_list_ptr->wwn_next) { if (argpwwn) { if (strcasecmp(wwn_list_ptr->port_wwn_s, path_struct->argv) != 0) { continue; } (void) strcpy(phys_path, wwn_list_ptr->physical_path); } else if (argnwwn) { if (strstr(wwn_list_ptr->logical_path, last_logical_path) != NULL) { continue; } if (strcasecmp(wwn_list_ptr->node_wwn_s, path_struct->argv) != 0) { continue; } (void) strcpy(phys_path, wwn_list_ptr->physical_path); (void) strcpy(last_logical_path, wwn_list_ptr->logical_path); } if (argnwwn || argpwwn) { if (compare_multipath(wwn_list_ptr->logical_path, mplistp) == 0) { continue; } } mode_data_avail = 0; (void) memset(&l_disk_state, 0, sizeof (struct l_disk_state_struct)); /* * Don't call g_get_multipath if this is a SCSI_VHCI device * dlist gets alloc'ed here to retain the free at the end */ if (strstr(phys_path, SCSI_VHCI) == NULL) { if ((err = g_get_multipath(phys_path, &(l_disk_state.g_disk_state.multipath_list), wwn_list, verbose)) != 0) { return (err); } mlist = l_disk_state.g_disk_state.multipath_list; if (mlist == NULL) { l_disk_state.l_state_flag = L_NO_PATH_FOUND; N_DPRINTF(" lun_display: Error finding" " multiple paths to the disk.\n"); (void) g_free_wwn_list(&wwn_list); return (L_NO_VALID_PATH); } } else { /* Search for match on physical path name */ for (wwn_list_find = list_start; wwn_list_find != NULL; wwn_list_find = wwn_list_find->wwn_next) { if (strncmp(wwn_list_find->physical_path, phys_path, strlen(wwn_list_find->physical_path)) == 0) { found++; break; } } if (!found) { return (L_NO_VALID_PATH); } else { found = 0; } if ((dlist = (struct dlist *) calloc(1, sizeof (struct dlist))) == NULL) { return (L_MALLOC_FAILED); } if ((dlist->logical_path = (char *)calloc(1, strlen(wwn_list_find->logical_path) + 1)) == NULL) { return (L_MALLOC_FAILED); } if ((dlist->dev_path = (char *)calloc(1, strlen(phys_path) + 1)) == NULL) { return (L_MALLOC_FAILED); } strncpy(dlist->logical_path, wwn_list_find->logical_path, strlen(wwn_list_find->logical_path)); strncpy(dlist->dev_path, phys_path, strlen(phys_path)); l_disk_state.g_disk_state.multipath_list = dlist; } if (argnwwn || argpwwn) { for (mlist = l_disk_state.g_disk_state.multipath_list; mlist != NULL; mlist = mlist->next) { /* add the path to the list for compare */ if ((mpl = (struct mplist_struct *) calloc(1, sizeof (struct mplist_struct))) == NULL) { adm_mplist_free(mplistp); return (L_MALLOC_FAILED); } mpl->devpath = (char *)calloc(1, MAXPATHLEN+1); if (mpl->devpath == NULL) { adm_mplist_free(mplistp); return (L_MALLOC_FAILED); } strncpy(mpl->devpath, mlist->logical_path, strlen(mlist->logical_path)); if (mplistp == NULL) { mplistp = mpln = mpl; } else { mpln->next = mpl; mpln = mpl; } } } /* get mode page information for FC device */ if (l_get_mode_pg(phys_path, &pg_buf, verbose) == 0) { mode_header_ptr = (struct mode_header_10_struct *) (void *)pg_buf; offset = sizeof (struct mode_header_10_struct) + mode_header_ptr->bdesc_length; pg_hdr = (struct mode_page *)&pg_buf[offset]; while (offset < (mode_header_ptr->length + sizeof (mode_header_ptr->length)) && !mode_data_avail) { if (pg_hdr->code == MODEPAGE_CACHING) { mode_data_avail++; break; } offset += pg_hdr->length + sizeof (struct mode_page); pg_hdr = (struct mode_page *)&pg_buf[offset]; } } switch ((inq_struct.inq_dtype & DTYPE_MASK)) { case DTYPE_DIRECT: fprintf(stdout, MSGSTR(121, "DEVICE PROPERTIES for disk: %s\n"), path_struct->argv); break; case DTYPE_SEQUENTIAL: /* Tape */ fprintf(stdout, MSGSTR(2249, "DEVICE PROPERTIES for tape: %s\n"), path_struct->argv); break; default: fprintf(stdout, MSGSTR(2250, "DEVICE PROPERTIES for: %s\n"), path_struct->argv); break; } (void) display_lun_info(l_disk_state, path_struct, pg_hdr, mode_data_avail, wwn_list, phys_path); (void) g_free_multipath(l_disk_state.g_disk_state.multipath_list); if (!(argpwwn || argnwwn)) { break; } } /* End for wwn_list_ptr = list_start... */ (void) g_free_wwn_list(&wwn_list); adm_mplist_free(mplistp); return (0); } /* * display_lun_info() Prints the device specific information * for a lun. * * RETURNS: * none. */ void display_lun_info(L_disk_state l_disk_state, Path_struct *path_struct, struct mode_page *pg_hdr, int mode_data_avail, WWN_list *wwn_list, char *phys_path) { float lunMbytes; struct scsi_capacity_16 cap_data; struct dlist *mlist; struct my_mode_caching *pg8_buf; int err; L_inquiry inq; hrtime_t start_time = 0, end_time; char *envdb = NULL; int peripheral_qual; L_inquiry80 inq80; size_t serial_len = sizeof (inq80.inq_serial); if ((envdb = getenv("_LUX_T_DEBUG")) != NULL) { start_time = gethrtime(); } memset(&cap_data, 0, sizeof (cap_data)); if (err = g_get_inquiry(phys_path, &inq)) { fprintf(stderr, "\n"); print_errString(err, phys_path); fprintf(stderr, "\n"); exit(1); } if (err = g_get_serial_number(phys_path, inq80.inq_serial, &serial_len)) { fprintf(stderr, "\n"); print_errString(err, phys_path); fprintf(stderr, "\n"); exit(1); } /* * check to see if the peripheral qualifier is zero * if it is non-zero, we will return with an error. */ peripheral_qual = inq.inq_dtype & ~DTYPE_MASK; if (peripheral_qual != DPQ_POSSIBLE) { fprintf(stderr, MSGSTR(2254, "\n Error: Logical Unit " "(%s) is not available.\n"), phys_path); exit(1); } fprintf(stdout, " "); fprintf(stdout, MSGSTR(3, "Vendor:")); fprintf(stdout, "\t\t"); print_chars(inq.inq_vid, sizeof (inq.inq_vid), 0); fprintf(stdout, MSGSTR(2115, "\n Product ID:\t\t")); print_chars(inq.inq_pid, sizeof (inq.inq_pid), 0); fprintf(stdout, "\n "); fprintf(stdout, MSGSTR(2119, "Revision:")); fprintf(stdout, "\t\t"); print_chars(inq.inq_revision, sizeof (inq.inq_revision), 0); fprintf(stdout, "\n "); fprintf(stdout, MSGSTR(17, "Serial Num:")); fprintf(stdout, "\t\t"); print_chars(inq80.inq_serial, serial_len, 0); if ((inq.inq_dtype & DTYPE_MASK) == DTYPE_DIRECT) { if ((err = get_lun_capacity(phys_path, &cap_data)) != 0) { print_errString(err, phys_path); exit(1); } if (cap_data.sc_capacity > 0 && cap_data.sc_lbasize > 0) { lunMbytes = cap_data.sc_capacity + 1; lunMbytes *= cap_data.sc_lbasize; lunMbytes /= (float)(1024*1024); fprintf(stdout, "\n "); fprintf(stdout, MSGSTR(60, "Unformatted capacity:\t%6.3f MBytes"), lunMbytes); } } fprintf(stdout, "\n"); if ((mode_data_avail) && (pg_hdr->code == MODEPAGE_CACHING)) { pg8_buf = (struct my_mode_caching *)(void *)pg_hdr; if (pg8_buf->wce) { fprintf(stdout, MSGSTR(2122, " Write Cache:\t\t" "Enabled\n")); } if (pg8_buf->rcd == 0) { fprintf(stdout, MSGSTR(2123, " Read Cache:\t\t" "Enabled\n")); fprintf(stdout, MSGSTR(2124, " Minimum prefetch:" "\t0x%x\n Maximum prefetch:\t0x%x\n"), pg8_buf->min_prefetch, pg8_buf->max_prefetch); } } fprintf(stdout, " %s\t\t%s\n", MSGSTR(35, "Device Type:"), dtype[inq.inq_dtype & DTYPE_MASK]); fprintf(stdout, MSGSTR(2128, " Path(s):\n")); fprintf(stdout, "\n"); if ((mlist = l_disk_state.g_disk_state.multipath_list) == NULL) { fprintf(stderr, MSGSTR(2323, "Error: No paths found (%s)"), path_struct->argv); exit(1); } if (strstr(mlist->dev_path, SCSI_VHCI) != NULL) { fprintf(stdout, " %s\n %s\n", mlist->logical_path, mlist->dev_path); adm_print_pathlist(mlist->dev_path); } else { /* * first display user's requested path * This will avoid duplicate inquiries as well */ for (mlist = l_disk_state.g_disk_state.multipath_list; mlist != NULL; mlist = mlist->next) { if ((strcmp(mlist->dev_path, path_struct->p_physical_path)) == 0) { display_path_info(mlist->dev_path, mlist->logical_path, wwn_list); break; } } /* * Now display rest of paths * skipping one already displayed */ for (mlist = l_disk_state.g_disk_state.multipath_list; mlist != NULL; mlist = mlist->next) { if ((strcmp(mlist->dev_path, path_struct->p_physical_path)) == 0) { continue; } if (err = g_get_inquiry(mlist->dev_path, &inq)) { fprintf(stderr, "\n"); print_errString(err, mlist->dev_path); fprintf(stderr, "\n"); exit(1); } display_path_info(mlist->dev_path, mlist->logical_path, wwn_list); } } fprintf(stdout, "\n"); if (envdb != NULL) { end_time = gethrtime(); fprintf(stdout, " display_lun_info: " "\t\tTime = %lld millisec\n", (end_time - start_time)/1000000); } } /* * display_path_info() Prints the path specific information * for a lun. * Note: Only applies to ssd nodes currently * * RETURNS: * none. */ static void display_path_info(char *devpath, char *logicalpath, WWN_list *wwn_list) { WWN_list *wwn_list_walk; int err; uchar_t wwn_data[WWN_SIZE]; char wwns[(WWN_SIZE *2) +1]; char drvr_path[MAXPATHLEN]; char *cptr; int status; fprintf(stdout, " %s\n", logicalpath); fprintf(stdout, " %s\n", devpath); fprintf(stdout, " %s\t\t", MSGSTR(2321, "LUN path port WWN:")); /* * Walk the wwn list passed in and print the * port wwn matching the device path */ for (wwn_list_walk = wwn_list; wwn_list_walk != NULL; wwn_list_walk = wwn_list_walk->wwn_next) { if (strcmp(wwn_list_walk->physical_path, devpath) == 0) { fprintf(stdout, "%s", wwn_list_walk->port_wwn_s); break; } } /* * newline here in case port wwn not found */ fprintf(stdout, "\n"); drvr_path[0] = '\0'; (void) strcat(drvr_path, devpath); if (((cptr = strstr(drvr_path, SLSH_DRV_NAME_SSD)) != NULL) || ((cptr = strstr(drvr_path, SLSH_DRV_NAME_ST)) != NULL)) {; *cptr = '\0'; } else { fprintf(stderr, MSGSTR(2324, "Error: Incorrect path (%s)\n"), drvr_path); exit(1); } *cptr = '\0'; if ((err = get_host_controller_pwwn(drvr_path, (uchar_t *)&wwn_data)) != 0) { print_errString(err, drvr_path); exit(1); } copy_wwn_data_to_str(wwns, wwn_data); fprintf(stdout, " %s\t%s\n", MSGSTR(2322, "Host controller port WWN:"), wwns); /* * Determine path status */ if ((err = get_path_status(devpath, &status)) != 0) { print_errString(err, devpath); exit(1); } else { fprintf(stdout, " %s\t\t", MSGSTR(2329, "Path status:")); display_port_status(status); } } /* * Retrieves the lun capacity */ static int get_lun_capacity(char *devpath, struct scsi_capacity_16 *cap_data) { int fd; if (devpath == NULL || cap_data == NULL) { return (L_INVALID_PATH); } if ((fd = g_object_open(devpath, O_RDONLY | O_NDELAY)) == -1) { return (L_OPEN_PATH_FAIL); } else { (void) g_scsi_read_capacity_1016_cmd(fd, cap_data, sizeof (struct scsi_capacity_16)); close(fd); } return (0); } /* * Retrieves the reservation status */ static int get_path_status(char *devpath, int *status) { int fd, mystatus = 0; if (devpath == NULL || status == NULL) { return (L_INVALID_PATH); } *status = 0; if ((fd = g_object_open(devpath, O_RDONLY | O_NDELAY)) == -1) { return (L_OPEN_PATH_FAIL); } else { if ((mystatus = g_scsi_tur(fd)) != 0) { if ((mystatus & L_SCSI_ERROR) && ((mystatus & ~L_SCSI_ERROR) == STATUS_CHECK)) { *status = L_NOT_READY; } else if ((mystatus & L_SCSI_ERROR) && ((mystatus & ~L_SCSI_ERROR) == STATUS_RESERVATION_CONFLICT)) { *status = L_RESERVED; } else { *status = L_SCSI_ERR; } } } close(fd); return (0); } /* * Description: * Retrieves the port wwn associated with the hba node * * hba_path: /devices/pci@8,600000/SUNW,qlc@4/fp@0,0 * pwwn: ptr to a uchar_t array of size WWN_SIZE */ static int get_host_controller_pwwn(char *hba_path, uchar_t *pwwn) { char *cptr, *portptr; int found = 0, err, devlen; char my_hba_path[MAXPATHLEN]; di_node_t node; di_prom_prop_t promprop; uchar_t *port_wwn_data = NULL; int di_ret; di_prom_handle_t ph; char *promname; uchar_t *promdata; uint_t path_type; fc_port_dev_t hba_port; if (hba_path == NULL || pwwn == NULL) { return (L_INVALID_PATH); } if ((path_type = g_get_path_type(hba_path)) == 0) { return (L_INVALID_PATH); } /* * ifp nodes do not have a port-wwn prom property * so handle them via FC4 device map */ if (path_type & FC4_XPORT_MASK) { if ((err = get_FC4_host_controller_pwwn(hba_path, pwwn)) != 0) { return (err); } else { return (0); } /* For Leadville path get the port wwn through g_get_host param. */ } else if ((path_type & FC_GEN_XPORT) && ((path_type & FC_FCA_MASK) == FC_FCA_MASK)) { /* * For Leadville path, get the port wwn through * g_get_host param. This is a general solution * to support 3rd party vendor Leadville FCA. */ my_hba_path[0] = '\0'; (void) strlcat(my_hba_path, hba_path, sizeof (my_hba_path)); (void) snprintf(my_hba_path, sizeof (my_hba_path), "%s%s", hba_path, FC_CTLR); if ((err = g_get_host_params( my_hba_path, &hba_port, 0)) != 0) { return (err); } else { (void) memcpy(pwwn, &hba_port.dev_pwwn.raw_wwn[0], WWN_SIZE); return (0); } } else if ((path_type & FC_FCA_MASK) == FC_PCI_FCA) { /* * Get port WWN through prom property */ my_hba_path[0] = '\0'; (void) strlcat(my_hba_path, hba_path, sizeof (my_hba_path)); /* * sanity check for /devices mount point */ if (strlen(my_hba_path) > (devlen = strlen("/devices"))) { cptr = &my_hba_path[devlen]; } else { return (L_INVALID_PATH); } /* * Now strip off the trailing "/fp@" */ if ((portptr = strstr(cptr, "/fp@")) != NULL) { *portptr = '\0'; } if ((node = di_init(cptr, DINFOCPYALL)) == DI_NODE_NIL) { return (L_DEV_SNAPSHOT_FAILED); } if (di_nodeid(node) == DI_SID_NODEID) { di_ret = di_prop_lookup_bytes(DDI_DEV_T_ANY, node, "port-wwn", &port_wwn_data); if (di_ret == -1 || port_wwn_data == NULL) { di_fini(node); return (L_NO_WWN_PROP_FOUND); } else { (void) memcpy(pwwn, port_wwn_data, WWN_SIZE); found++; } } else if (di_nodeid(node) == DI_PROM_NODEID) { if ((ph = di_prom_init()) == DI_PROM_HANDLE_NIL) { di_fini(node); return (L_PROM_INIT_FAILED); } for (promprop = di_prom_prop_next(ph, node, DI_PROM_PROP_NIL); promprop != DI_PROM_PROP_NIL; promprop = di_prom_prop_next(ph, node, promprop)) { if (((promname = di_prom_prop_name( promprop)) != NULL) && (strcmp(promname, "port-wwn") == 0) && (di_prom_prop_data(promprop, &promdata) == WWN_SIZE)) { /* Found port-wwn */ (void) memcpy(pwwn, promdata, WWN_SIZE); found++; break; } } di_prom_fini(ph); } di_fini(node); if (found) { return (0); } else { return (L_INVALID_PATH); } } else { return (L_INVALID_PATH_TYPE); } } /* * Description: * Retrieve pwwn via SFIOCGMAP */ static int get_FC4_host_controller_pwwn(char *hba_path, uchar_t *pwwn) { sf_al_map_t sf_map; char my_hba_path[MAXPATHLEN]; int fd; if (hba_path == NULL || pwwn == NULL) { return (L_INVALID_PATH); } (void) snprintf(my_hba_path, sizeof (my_hba_path), "%s%s", hba_path, FC_CTLR); if ((fd = g_object_open(my_hba_path, O_NDELAY | O_RDONLY)) == -1) { return (errno); } memset(&sf_map, 0, sizeof (sf_al_map_t)); if (ioctl(fd, SFIOCGMAP, &sf_map) != 0) { close(fd); return (L_SFIOCGMAP_IOCTL_FAIL); } close(fd); if (sf_map.sf_count == 0) { close(fd); return (L_SFIOCGMAP_IOCTL_FAIL); } (void) memcpy(pwwn, &sf_map.sf_hba_addr.sf_port_wwn[0], WWN_SIZE); return (0); } /* * from_ptr: ptr to uchar_t array of size WWN_SIZE * to_ptr: char ptr to string of size WWN_SIZE*2+1 */ void copy_wwn_data_to_str(char *to_ptr, const uchar_t *from_ptr) { if ((to_ptr == NULL) || (from_ptr == NULL)) return; sprintf(to_ptr, "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x", from_ptr[0], from_ptr[1], from_ptr[2], from_ptr[3], from_ptr[4], from_ptr[5], from_ptr[6], from_ptr[7]); } /* * Frees a previously allocated mplist_struct */ void adm_mplist_free(struct mplist_struct *mplistp) { struct mplist_struct *mplistn; while (mplistp != NULL) { mplistn = mplistp->next; if (mplistp->devpath != NULL) { free(mplistp->devpath); mplistp->devpath = NULL; } free(mplistp); mplistp = mplistn; } } int adm_reserve(char *path) { char *path_phys = NULL; int err; if ((path_phys = g_get_physical_name(path)) == NULL) { (void) fprintf(stderr, "%s: ", whoami); (void) fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), path); (void) fprintf(stderr, "\n"); return (1); } if ((err = g_reserve(path_phys)) != 0) { (void) print_errString(err, path); return (1); } return (0); } int adm_release(char *path) { char *path_phys = NULL; int err; if ((path_phys = g_get_physical_name(path)) == NULL) { (void) fprintf(stderr, "%s: ", whoami); (void) fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), path); (void) fprintf(stderr, "\n"); return (1); } if ((err = g_release(path_phys)) != 0) { (void) print_errString(err, path); return (1); } return (0); } void i18n_catopen() { (void) g_i18n_catopen(); } int adm_check_file(char **path, int flag) { int err; if (err = l_check_file(*path, flag)) { (void) print_errString(err, *path); return (-1); } (void) fprintf(stdout, MSGSTR(2212, "Download file O.K. \n\n")); return (0); } /* * Print out private loop dev dtype */ void print_private_loop_dtype_prop(uchar_t *hba_port_wwn, uchar_t *port_wwn, uchar_t dtype_prop) { if ((dtype_prop & DTYPE_MASK) < 0x10) { (void) fprintf(stdout, " 0x%-2x (%s", (dtype_prop & DTYPE_MASK), dtype[(dtype_prop & DTYPE_MASK)]); } else if ((dtype_prop & DTYPE_MASK) < 0x1f) { (void) fprintf(stdout, MSGSTR(2243, " 0x%-2x (Reserved"), (dtype_prop & DTYPE_MASK)); } else { (void) fprintf(stdout, MSGSTR(2245, " 0x%-2x (Unknown Type"), (dtype_prop & DTYPE_MASK)); } /* Check to see if this is the HBA */ if (wwnConversion(hba_port_wwn) == wwnConversion(port_wwn)) { /* MATCH */ (void) fprintf(stdout, MSGSTR(2244, ",Host Bus Adapter)\n")); } else { (void) fprintf(stdout, ")\n"); } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * PHOTON CONFIGURATION MANAGER * Common definitions */ /* * I18N message number ranges * This file: 13000 - 13499 * Shared common messages: 1 - 1999 */ #ifndef _HOT_H #define _HOT_H /* * Include any headers you depend on. */ #ifdef __cplusplus extern "C" { #endif #define NODE_CREATION_TIME 60 /* # seconds */ /* * Version 0.16 of the SES firmware powers up disks in front/back pairs. * However, the first disk inserted is usually spun up by itself, so * we need to calculate a timeout for 22/2 + 1 = 12 disks. * * Measured times are about 40s/disk for a total of 40*12=8 min total * The timeout assumes 10s/iteration or 4*12*10=8 min */ #define PHOTON_SPINUP_TIMEOUT (4*12) #define PHOTON_SPINUP_DELAY 10 #define QLC_LIP_DELAY 17 #define TARGET_ID(box_id, f_r, slot) \ ((box_id | ((f_r == 'f' ? 0 : 1) << 4)) | (slot + 2)) #define NEWER(time1, time2) (time1.tv_sec > time2.tv_sec) extern int Options; #ifdef __cplusplus } #endif #endif /* _HOT_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /*LINTLIBRARY*/ /* * Hotplug program for SENA, RSM and SSA * subsystems and individual FC_AL devices. */ /* #define _POSIX_SOURCE 1 */ /* * I18N message number ranges * This file: 5500 - 5999 * Shared common messages: 1 - 1999 */ /* Includes */ #include #include #include #include #include #include #include #include #include #include #include #include #include /* for min */ #include #include #include #include #include #include #include #include #include #include #include "hot.h" #include "common.h" #include "luxadm.h" /* Internal variables. */ static char *cmdStrg[][4] = { { "disks", "-C", 0, 0 }, { "disks", 0, 0, 0 }, { "drvconfig", "-i", "ssd", 0 }, { "drvconfig", 0, 0, 0 }, { "devlinks", 0, 0, 0 }, { "tapes", "-C", 0, 0 } }; /* External variables */ extern char *dtype[]; /* From adm.c */ extern int Options; extern const int OPTION_CAPF; /* Internal functions */ /* SENA and Individual FC device Hotplug */ static int h_pre_insert_encl_dev(timestruc_t *, timestruc_t *, timestruc_t *); static int h_post_insert_dev(timestruc_t, timestruc_t); static int h_pre_remove_dev(Hotplug_Devlist *, WWN_list *wwn_list, int, int); static int h_post_remove_dev(Hotplug_Devlist *, int, int); static int h_pre_hotplug(Hotplug_Devlist **, WWN_list *, int, int, int); static int h_post_hotplug(Hotplug_Devlist *, WWN_list *, int, int, int, int); static int h_post_insert_encl(timestruc_t); static int h_pre_hotplug_sena(Hotplug_Devlist *, WWN_list *, int, int, int); static int h_post_hotplug_sena(Hotplug_Devlist *, WWN_list *, int, int, int, int); static int h_remove_ses_nodes(struct dlist *); static int h_print_list_warn(Hotplug_Devlist *, int, int); static int h_display_logical_nodes(struct dlist *); static void h_print_logical_nodes(struct dlist *); static int h_remove_nodes(struct dlist *); static int h_print_list(Hotplug_Devlist *, int *, int); static int h_get_fcdev_state(char *, char *, int, int *, int *, int); static int h_chk_dev_busy(Hotplug_Devlist *, WWN_list *, int *, int, int); static int h_execCmnd(char **, int); int hotplug(int, char **, int, int); int h_insertSena_fcdev(); static int h_find_new_device_link(char *, timestruc_t); /* * Assists the user in hot inserting FC_AL * individual device(s) and SENA enclosure(s). * * RETURNS: * 0 if OK * non-zero otherwise */ int h_insertSena_fcdev() { timestruc_t ses_time, dsk_time, rmt_time; int err; struct stat ses_stat; if ((err = h_pre_insert_encl_dev(&ses_time, &dsk_time, &rmt_time)) != 0) { return (err); } (void) fprintf(stdout, MSGSTR(5500, "Please hit when you have finished" " adding Fibre Channel Enclosure(s)/Device(s): ")); (void) getchar(); if ((err = h_post_insert_dev(dsk_time, rmt_time)) != 0) { return (err); } if (stat(SES_DIR, &ses_stat) < 0) { /* * Non existence of /dev/es dir indicates * no ses devices inserted. * No need to call h_post_insert_encl(). */ if (errno == ENOENT) { (void) fprintf(stdout, MSGSTR(5662, " No new enclosure(s) were added!!\n\n")); return (0); } else { return (L_LSTAT_ES_DIR_ERROR); } } /* * if the latest mod time of /dev/es is not newer than * the original mod time no need to call * h_post_insert_encl(). */ if ((&ses_time != (timestruc_t *)NULL) && !(NEWER(ses_stat.st_ctim, ses_time))) { (void) fprintf(stdout, MSGSTR(5662, " No new enclosure(s) were added!!\n\n")); return (0); } if ((err = h_post_insert_encl(ses_time)) != 0) { return (err); } return (0); } /* * gets the devices state - check for disk's reservations. * * RETURNS: * 0 if OK * non-zero otherwise */ static int h_get_fcdev_state(char *fc_dev, char *path_phys, int force_flag, int *busy_flag, int *reserve_flag, int verbose_flag) { int err; L_inquiry inq; L_disk_state l_disk_state; if ((err = g_get_inquiry(path_phys, &inq)) != 0) { (void) fprintf(stderr, MSGSTR(5501, "Inquiry failed for %s\n"), path_phys); return (err); } if (inq.inq_port) { if ((err = l_get_disk_port_status(path_phys, &l_disk_state, FC_PORT_B, verbose_flag)) != 0) { return (err); } } else { if ((err = l_get_disk_port_status(path_phys, &l_disk_state, FC_PORT_A, verbose_flag)) != 0) { return (err); } } /* * Don't print error msg. if disk is reserved * and tried to be removed from the same port. * If force flag is set, remove the disk without * checking the disk reservations. */ if (!force_flag) { if (((inq.inq_port) && (l_disk_state.g_disk_state.d_state_flags[FC_PORT_B] & L_RESERVED)) || ((!inq.inq_port) && (l_disk_state.g_disk_state.d_state_flags[FC_PORT_A] & L_RESERVED))) { *reserve_flag = 1; } } return (0); } /* * Forks a child process and let the child to * execute a given command string by calling the * the execvp() function. Then, the parent process * waits for the child to exit. Once the parent process * is notified by the kernel with the termination of * the child, then the parent checks for the exit * status of the child and return to the caller with -1 in case * of error and zero otherwise. * * RETURNS: * 0 if OK * non-zero otherwise */ int h_execCmnd(char *argStr[], int nArg) { pid_t pid; int ix, status; if ((pid = fork()) < 0) { (void) fprintf(stderr, MSGSTR(133, "Error: Failed to fork a process.\n")); return (-1); } else if (pid == 0) { /* child process */ if (execvp(argStr[0], argStr) < 0) { (void) fprintf(stderr, MSGSTR(5502, " Error: execvp() failed to run " "the command:")); for (ix = 0; ix < nArg; ix++) { (void) fprintf(stderr, " %s", argStr[ix]); } (void) fprintf(stderr, "\n"); /* let parent know about the error. */ exit(ENOEXEC); } } /* parent executes the following. */ if (waitpid(pid, &status, 0) != pid) { (void) fprintf(stderr, MSGSTR(5503, "Error: waitpid() failed.\n")); return (-1); } if (WIFEXITED(status) && WEXITSTATUS(status) == ENOEXEC) { /* child failed to run the command string. */ return (-1); } return (0); } /* * frees the hotplug disk list structure. * * RETURNS: * N/A */ void h_free_hotplug_dlist(Hotplug_Devlist **hotplug_dlist) { Hotplug_Devlist *list = NULL; while (*hotplug_dlist != NULL) { list = *hotplug_dlist; *hotplug_dlist = (*hotplug_dlist)->next; (void) g_free_multipath(list->seslist); (void) g_free_multipath(list->dlhead); (void) free((void *)list); } } /* * finds whether device (SENA or an FCAL device) is busy or not. * * OUTPUT: * busy_flag = 1 (if device busy) * * RETURNS: * 0 if O.K. * non-zero otherwise */ static int h_chk_dev_busy(Hotplug_Devlist *hotplug_dev, WWN_list *wwn_list, int *busy_flag, int force_flag, int verbose_flag) { int err; struct dlist *dlist; if (hotplug_dev->dev_type == DTYPE_ESI) { if ((err = l_offline_photon(hotplug_dev, wwn_list, force_flag, verbose_flag)) != 0) { if (err == L_DEV_BUSY) { *busy_flag = 1; } else { return (err); } } for (dlist = hotplug_dev->dlhead; dlist != NULL; dlist = dlist->next) { (void) g_online_drive(dlist->multipath, force_flag); } } else { if ((err = g_offline_drive(hotplug_dev->dlhead, force_flag)) != 0) { if (err == L_DEV_BUSY) { *busy_flag = 1; } else { return (err); } } (void) g_online_drive(hotplug_dev->dlhead, force_flag); } return (0); } /* * prints the given list to stdout, * gets the input from user whether * to skip the busy devices or quit * and passes that input to the calling * function. * * OUTPUT: * int *action * s = Skip * q = Quit * * RETURNS: * 0 if OK * non-zero otherwise */ static int h_print_list(Hotplug_Devlist *bsyRsrv_disk_list, int *action, int enc_type) { Hotplug_Devlist *list; int i = 1; char choice[2]; (void) fprintf(stdout, MSGSTR(5504, "The list of devices being used" " (either busy or reserved) by the host:\n")); for (list = bsyRsrv_disk_list; list != NULL; list = list->next, i++) { if ((list->dev_type == DTYPE_DIRECT) && (list->dev_location == SENA)) { if (list->f_flag != 0) { if (enc_type == DAK_ENC_TYPE) { (void) fprintf(stdout, MSGSTR(5663, " %d: Box Name: \"%s\" slot %d\n"), i, list->box_name, list->slot); } else { (void) fprintf(stdout, MSGSTR(137, " %d: Box Name: \"%s\" front slot %d\n"), i, list->box_name, list->slot); } } else { if (enc_type == DAK_ENC_TYPE) { (void) fprintf(stdout, MSGSTR(5663, " %d: Box Name: \"%s\" slot %d\n"), i, list->box_name, list->slot + (MAX_DRIVES_DAK/2)); } else { (void) fprintf(stdout, MSGSTR(136, " %d: Box Name: \"%s\" rear slot %d\n"), i, list->box_name, list->slot); } } } else if (((list->dev_type == DTYPE_DIRECT) || (list->dev_type == DTYPE_SEQUENTIAL)) && (list->dev_location == NON_SENA)) { (void) fprintf(stdout, MSGSTR(5505, " %d: Device %s\n"), i, list->dev_name); } else if (list->dev_type == DTYPE_ESI) { (void) fprintf(stdout, MSGSTR(5506, " %d: Box: %s\n"), i, list->box_name); } } /* Get the user input and continue accordingly. */ (void) fprintf(stdout, MSGSTR(5507, "\n\nPlease enter 's' or to Skip the \"busy/reserved\"" " device(s) or\n'q' to Quit and run the" " subcommand with\n-F (force) option. [Default: s]: ")); for (;;) { (void) gets(choice); if (choice[0] == 'q' || choice[0] == 'Q' || choice[0] == 's' || choice[0] == 'S' || choice[0] == '\0') { break; } (void) fprintf(stdout, MSGSTR(5508, " Enter an appropriate option [s,,q]: ")); } if (choice[0] == 'q' || choice[0] == 'Q') { *action = QUIT; } else { *action = SKIP; } (void) fprintf(stdout, "\n\n"); return (0); } /* * prints the warning message. * * RETURNS: * None. */ static void h_prt_warning() { (void) fprintf(stderr, MSGSTR(5509, "\n WARNING!!! Please ensure that no" " filesystems are mounted on these device(s).\n" " All data on these devices should have been" " backed up.\n\n\n")); } /* * handle helper-mode hotplug commands * * RETURNS: * 0 if OK * non-zero otherwise */ int hotplug(int todo, char **argv, int verbose_flag, int force_flag) { char ses_path[MAXPATHLEN], dev_path[MAXPATHLEN]; char *path_phys = NULL, code, node_wwn_s[WWN_S_LEN]; char inq_path[MAXNAMELEN], *ptr = NULL; uchar_t node_wwn[WWN_SIZE], port_wwn[WWN_SIZE]; int tid, slot = 0, path_index, dtype, f_r, err = 0; int al_pa, i, dev_location = 0, found_nullwwn = 0; int busy_flag = 0, reserve_flag = 0, action = 0; int pathcnt = 1; L_state l_state; gfc_map_t map; Path_struct *path_struct; WWN_list *wwn_list = NULL; Box_list *box_list; Hotplug_Devlist *disk_list, *disk_list_head, *disk_list_tail; Hotplug_Devlist *bsyRsrv_dskLst_head, *bsyRsrv_dskLst_tail; int enc_type = 0; L_inquiry inq; char *physpath; Path_struct *p_pathstruct; char temp2path[MAXPATHLEN]; mp_pathlist_t pathlist; int p_pw = 0, p_on = 0, p_st = 0; /* Initialize structures and pointers here */ disk_list_head = disk_list_tail = (Hotplug_Devlist *)NULL; bsyRsrv_dskLst_head = (Hotplug_Devlist *)NULL; bsyRsrv_dskLst_tail = (Hotplug_Devlist *)NULL; map.dev_addr = NULL; #ifdef DEBUG (void) fprintf(stderr, "DEBUG: luxadm: hotplug() entering for \"%s\" ...\n", argv[0] ? argv[0] : ""); #endif if ((err = l_get_box_list(&box_list, 0)) != 0) { return (err); } if (todo == REMOVE_DEVICE) { (void) h_prt_warning(); } /* * At this point user want to insert or remove * one or more pathnames they've specified. */ if ((err = g_get_wwn_list(&wwn_list, verbose_flag)) != 0) { (void) l_free_box_list(&box_list); return (err); } for (path_index = 0; argv[path_index] != NULL; path_index++) { if ((err = l_convert_name(argv[path_index], &path_phys, &path_struct, verbose_flag)) != 0) { /* Make sure we have a device path. */ (void) strcpy(inq_path, argv[path_index]); if (((ptr = strstr(inq_path, ",")) != NULL) && ((*(ptr + 1) == 'f') || (*(ptr + 1) == 'r') || (*(ptr +1) == 's')) && todo == REMOVE_DEVICE) { if (err != -1) { (void) print_errString(err, argv[path_index]); err = 0; continue; } *ptr = '\0'; slot = path_struct->slot; f_r = path_struct->f_flag; if ((err = l_convert_name(inq_path, &path_phys, &path_struct, verbose_flag)) != 0) { (void) fprintf(stderr, "\n"); (void) fprintf(stderr, MSGSTR(33, " Error: converting" " %s to physical path.\n" " Invalid pathname.\n"), argv[path_index]); if (err != -1) { (void) print_errString(err, argv[path_index]); } err = 0; continue; } if ((err = print_devState(argv[path_index], path_struct->p_physical_path, f_r, slot, verbose_flag)) != 0) { err = 0; continue; } } if (path_struct->ib_path_flag) { path_phys = path_struct->p_physical_path; } else { if (err != -1) { (void) print_errString(err, argv[path_index]); } else { (void) fprintf(stderr, "\n"); (void) fprintf(stderr, MSGSTR(33, " Error: converting" " %s to physical path.\n" " Invalid pathname.\n"), argv[path_index]); } err = 0; continue; } } if (path_struct->slot_valid || strstr(path_phys, DRV_NAME_SSD)) { dtype = DTYPE_DIRECT; } else if (strstr(path_phys, SLSH_DRV_NAME_ST)) { dtype = DTYPE_SEQUENTIAL; } else { dtype = DTYPE_ESI; } if (strstr(path_phys, SCSI_VHCI) != NULL) { /* obtain phci */ (void) strcpy(temp2path, path_phys); if (err = g_get_pathlist(temp2path, &pathlist)) { (void) print_errString(err, NULL); exit(-1); } pathcnt = pathlist.path_count; p_pw = p_on = p_st = 0; for (i = 0; i < pathcnt; i++) { if (pathlist.path_info[i].path_state < MAXPATHSTATE) { if (strstr(pathlist.path_info[i]. path_addr, path_struct->argv) != NULL) { p_pw = i; break; } if (pathlist.path_info[i].path_state == MDI_PATHINFO_STATE_ONLINE) { p_on = i; } if (pathlist.path_info[i].path_state == MDI_PATHINFO_STATE_STANDBY) { p_st = i; } } } if (strstr(pathlist.path_info[p_pw].path_addr, path_struct->argv) != NULL) { /* matching input pwwn */ (void) strcpy(temp2path, pathlist.path_info[p_pw].path_hba); } else if (pathlist.path_info[p_on].path_state == MDI_PATHINFO_STATE_ONLINE) { /* on_line path */ (void) strcpy(temp2path, pathlist.path_info[p_on].path_hba); } else { /* standby or path0 */ (void) strcpy(temp2path, pathlist.path_info[p_st].path_hba); } free(pathlist.path_info); (void) strcat(temp2path, FC_CTLR); } else { (void) strcpy(temp2path, path_phys); } if ((err = g_get_dev_map(temp2path, &map, verbose_flag)) != 0) { return (err); } if ((map.hba_addr.port_topology == FC_TOP_PUBLIC_LOOP) || (map.hba_addr.port_topology == FC_TOP_FABRIC)) { /* public or fabric loop device */ free((void *)map.dev_addr); (void) fprintf(stderr, MSGSTR(5540, "This operation is not " "supported in this topology.\n")); exit(-1); } if (todo == REPLACE_DEVICE) { (void) fprintf(stderr, MSGSTR(5511, "Error:" " replace_device is not supported" " on this subsystem.\n")); exit(-1); } if ((todo == REMOVE_DEVICE) && (dtype == DTYPE_DIRECT || dtype == DTYPE_SEQUENTIAL || dtype == DTYPE_UNKNOWN)) { if (l_chk_null_wwn(path_struct, ses_path, &l_state, verbose_flag) == 1) { found_nullwwn = 1; /* * set dev_path to NULL, * if disk has null wwn. */ *dev_path = '\0'; dev_location = SENA; goto getinfo; } } (void) strcpy(ses_path, path_phys); if (strstr(ses_path, "ses") == NULL && l_get_ses_path(path_phys, ses_path, &map, verbose_flag) != 0) { /* Could be a non-photon disk device */ if ((todo == REMOVE_DEVICE) && (dtype == DTYPE_DIRECT || dtype == DTYPE_SEQUENTIAL)) { dev_location = NON_SENA; if ((err = h_get_fcdev_state(argv[path_index], path_phys, force_flag, &busy_flag, &reserve_flag, verbose_flag)) != 0) { goto done; } (void) strcpy(dev_path, path_phys); if ((err = g_get_wwn(dev_path, port_wwn, node_wwn, &al_pa, verbose_flag)) != 0) { goto done; } (void) sprintf(node_wwn_s, "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x", node_wwn[0], node_wwn[1], node_wwn[2], node_wwn[3], node_wwn[4], node_wwn[5], node_wwn[6], node_wwn[7]); tid = g_sf_alpa_to_switch[al_pa]; goto loop; } continue; } if (strstr(ses_path, "ses") != NULL) { dev_location = SENA; if ((err = l_convert_name(ses_path, &physpath, &p_pathstruct, 0)) != 0) { free(physpath); free(p_pathstruct); goto done; } if ((err = g_get_inquiry(physpath, &inq)) != 0) { free(physpath); free(p_pathstruct); goto done; } enc_type = l_get_enc_type(inq); } if ((err = l_get_status(ses_path, &l_state, verbose_flag)) != 0) { goto done; } if (dtype == DTYPE_ESI) { /* could be removing a photon */ if (todo == REMOVE_DEVICE) { /* * Need the select ID (tid) for the IB. */ if ((err = g_get_wwn(ses_path, port_wwn, node_wwn, &al_pa, verbose_flag)) != 0) { goto done; } (void) sprintf(node_wwn_s, "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x", node_wwn[0], node_wwn[1], node_wwn[2], node_wwn[3], node_wwn[4], node_wwn[5], node_wwn[6], node_wwn[7]); tid = g_sf_alpa_to_switch[al_pa]; *dev_path = '\0'; /* * Check if any disk in this photon * is reserved by another host */ if (!force_flag) { for ( i = 0; i < l_state.total_num_drv/2; i++) { if ((l_state.drv_front[i].g_disk_state.d_state_flags[PORT_A] & L_RESERVED) || (l_state.drv_front[i].g_disk_state.d_state_flags[PORT_B] & L_RESERVED) || (l_state.drv_rear[i].g_disk_state.d_state_flags[PORT_A] & L_RESERVED) || (l_state.drv_rear[i].g_disk_state.d_state_flags[PORT_B] & L_RESERVED)) { reserve_flag = 1; } } } goto loop; } (void) fprintf(stderr, MSGSTR(5512, "Error: %s already exists!!\n"), argv[path_index]); goto done; } getinfo: if (!path_struct->slot_valid) { /* We are passing the disks path */ if ((err = l_get_slot(path_struct, &l_state, verbose_flag)) != 0) { goto done; } } slot = path_struct->slot; if (path_struct->f_flag) { tid = l_state.drv_front[slot].ib_status.sel_id; code = l_state.drv_front[slot].ib_status.code; (void) strcpy(node_wwn_s, l_state.drv_front[slot].g_disk_state.node_wwn_s); } else { tid = l_state.drv_rear[slot].ib_status.sel_id; code = l_state.drv_rear[slot].ib_status.code; (void) strcpy(node_wwn_s, l_state.drv_rear[slot].g_disk_state.node_wwn_s); } if (found_nullwwn) { goto loop; } l_make_node(ses_path, tid, dev_path, &map, 0); if ((todo == INSERT_DEVICE) && (g_device_in_map(&map, tid) || (code != S_NOT_INSTALLED))) { (void) fprintf(stderr, MSGSTR(5513, "\nNotice: %s may " "already be present.\n"), argv[path_index]); if (path_struct->f_flag) { if ((l_state.drv_front[slot].l_state_flag != L_NO_PATH_FOUND) && (!l_state.drv_front[slot].ib_status.dev_off)) continue; } else { if ((l_state.drv_rear[slot].l_state_flag != L_NO_PATH_FOUND) && (!l_state.drv_rear[slot].ib_status.dev_off)) continue; } } /* Check if disk is reserved */ if ((todo == REMOVE_DEVICE) && (!force_flag)) { if (path_struct->f_flag) { if ((l_state.drv_front[slot].g_disk_state.d_state_flags[PORT_A] & L_RESERVED) || (l_state.drv_front[slot].g_disk_state.d_state_flags[PORT_B] & L_RESERVED)) { reserve_flag = 1; } } else { if ((l_state.drv_rear[slot].g_disk_state.d_state_flags[PORT_A] & L_RESERVED) || (l_state.drv_rear[slot].g_disk_state.d_state_flags[PORT_B] & L_RESERVED)) { reserve_flag = 1; } } } loop: if ((disk_list = (Hotplug_Devlist *) calloc(1, sizeof (Hotplug_Devlist))) == NULL) { (void) print_errString(L_MALLOC_FAILED, NULL); goto done; } /* * dev_path is NULL when removing a whole encloser. We * don't want to call g_get_multipath while removing whole * enclosure. Its being taken care later in the code path */ if ((todo != INSERT_DEVICE) && (dtype != DTYPE_ESI)) { if ((err = g_get_multipath(dev_path, &(disk_list->dlhead), wwn_list, verbose_flag)) != 0) { if (disk_list->dlhead != NULL) { (void) g_free_multipath( disk_list->dlhead); } goto done; } } disk_list->dev_type = dtype; disk_list->dev_location = dev_location; (void) strcpy(disk_list->dev_name, argv[path_index]); disk_list->tid = tid; (void) strcpy(disk_list->node_wwn_s, node_wwn_s); if (dev_location == SENA) { if ((err = l_get_allses(ses_path, box_list, &(disk_list->seslist), 0)) != 0) { if (disk_list->seslist != NULL) { (void) g_free_multipath(disk_list->seslist); } goto done; } (void) strcpy(disk_list->box_name, (char *)l_state.ib_tbl.enclosure_name); disk_list->slot = slot; disk_list->f_flag = path_struct->f_flag; } if (todo == REMOVE_DEVICE && !force_flag && !reserve_flag) { if ((err = h_chk_dev_busy(disk_list, wwn_list, &busy_flag, force_flag, verbose_flag)) != 0) { goto done; } } if (reserve_flag || busy_flag) { if (reserve_flag) disk_list->reserve_flag = 1; if (busy_flag) disk_list->busy_flag = 1; if (bsyRsrv_dskLst_head == NULL) { bsyRsrv_dskLst_head = bsyRsrv_dskLst_tail = disk_list; } else { disk_list->prev = bsyRsrv_dskLst_tail; bsyRsrv_dskLst_tail->next = disk_list; bsyRsrv_dskLst_tail = disk_list; } reserve_flag = 0; busy_flag = 0; } else if (disk_list_head == NULL) { disk_list_head = disk_list_tail = disk_list; } else { disk_list->prev = disk_list_tail; disk_list_tail->next = disk_list; disk_list_tail = disk_list; } } if (bsyRsrv_dskLst_head != NULL) { if ((err = h_print_list(bsyRsrv_dskLst_head, &action, enc_type)) != 0) { goto done; } if (action == SKIP) { (void) h_free_hotplug_dlist(&bsyRsrv_dskLst_head); } else if (action == QUIT) { goto done; } } if (disk_list_head != NULL) { if ((h_print_list_warn(disk_list_head, todo, enc_type)) != 0) { goto done; } if ((err = h_pre_hotplug(&disk_list_head, wwn_list, todo, verbose_flag, force_flag)) != 0) { goto done; } if (disk_list_head != NULL) { if (todo == REMOVE_DEVICE) { (void) fprintf(stdout, MSGSTR(5514, "\nHit after " "removing the device(s).")); } else { (void) fprintf(stdout, MSGSTR(5515, "\nHit after " "inserting the device(s).")); } (void) getchar(); (void) fprintf(stdout, "\n"); if ((err = h_post_hotplug(disk_list_head, wwn_list, todo, verbose_flag, force_flag, enc_type)) != 0) { goto done; } } } done: (void) l_free_box_list(&box_list); (void) g_free_wwn_list(&wwn_list); if (err && err != -1) { return (err); } free((void *)map.dev_addr); return (0); } /* * Internal routine to clean up ../'s in paths. * returns 0 if no "../" are left. * * Wouldn't it be nice if there was a standard system library * routine to do this...? */ static int cleanup_dotdot_path(char *path) { char holder[MAXPATHLEN]; char *dotdot; char *previous_slash; /* Find the first "/../" in the string */ dotdot = strstr(path, "/../"); if (dotdot == NULL) { return (0); } /* * If the [0] character is '/' and "../" immediatly * follows it, then we can strip the ../ * * /../../foo/bar == /foo/bar * */ if (dotdot == path) { strcpy(holder, &path[3]); /* strip "/.." */ strcpy(path, holder); return (1); } /* * Now look for the LAST "/" before the "/../" * as this is the parent dir we can get rid of. * We do this by temporarily truncating the string * at the '/' just before "../" using the dotdot pointer. */ *dotdot = '\0'; previous_slash = strrchr(path, '/'); if (previous_slash == NULL) { /* * hmm, somethings wrong. path looks something * like "foo/../bar/" so we can't really deal with it. */ return (0); } /* * Now truncate the path just after the previous '/' * and slam everything after the "../" back on */ *(previous_slash+1) = '\0'; (void) strcat(path, dotdot+4); return (1); /* We may have more "../"s */ } /* * Follow symbolic links from the logical device name to * the /devfs physical device name. To be complete, we * handle the case of multiple links. This function * either returns NULL (no links, or some other error), * or the physical device name, alloc'ed on the heap. * * For S10 the physical path may be non-existent. * * NOTE: If the path is relative, it will be forced into * an absolute path by pre-pending the pwd to it. */ char * h_get_physical_name_from_link(char *path) { struct stat stbuf; char source[MAXPATHLEN]; char scratch[MAXPATHLEN]; char pwd[MAXPATHLEN]; char *tmp; int cnt; /* return NULL if path is NULL */ if (path == NULL) { return (NULL); } strcpy(source, path); for (;;) { /* * First make sure the path is absolute. If not, make it. * If it's already an absolute path, we have no need * to determine the cwd, so the program should still * function within security-by-obscurity directories. */ if (source[0] != '/') { tmp = getcwd(pwd, MAXPATHLEN); if (tmp == NULL) { O_DPRINTF("getcwd() failed - %s\n", strerror(errno)); return (NULL); } /* * Handle special case of "./foo/bar" */ if (source[0] == '.' && source[1] == '/') { strcpy(scratch, source+2); } else { /* no "./" so just take everything */ strcpy(scratch, source); } strcpy(source, pwd); (void) strcat(source, "/"); (void) strcat(source, scratch); } /* * Clean up any "../"s that are in the path */ while (cleanup_dotdot_path(source)); /* * source is now an absolute path to the link we're * concerned with * * S10: Do NOT ignore dangling links, pointing to devfs nodes. */ if (strstr(source, "/devices")) { return (g_alloc_string(source)); } if (lstat(source, &stbuf) == -1) { O_DPRINTF("lstat() failed for - %s\n", source, strerror(errno)); return (NULL); } /* * If the file is not a link, we're done one * way or the other. If there were links, * return the full pathname of the resulting * file. * * Note: All of our temp's are on the stack, * so we have to copy the final result to the heap. */ if (!S_ISLNK(stbuf.st_mode)) { return (g_alloc_string(source)); } cnt = readlink(source, scratch, sizeof (scratch)); if (cnt < 0) { O_DPRINTF("readlink() failed - %s\n", strerror(errno)); return (NULL); } /* * scratch is on the heap, and for some reason readlink * doesn't always terminate things properly so we have * to make certain we're properly terminated */ scratch[cnt] = '\0'; /* * Now check to see if the link is relative. If so, * then we have to append it to the directory * which the source was in. (This is non trivial) */ if (scratch[0] != '/') { tmp = strrchr(source, '/'); if (tmp == NULL) { /* Whoa! Something's hosed! */ O_DPRINTF("Internal error... corrupt path.\n"); return (NULL); } /* Now strip off just the directory path */ *(tmp+1) = '\0'; /* Keeping the last '/' */ /* and append the new link */ (void) strcat(source, scratch); /* * Note: At this point, source should have "../"s * but we'll clean it up in the next pass through * the loop. */ } else { /* It's an absolute link so no worries */ strcpy(source, scratch); } } /* Never reach here */ } /* * Function for getting physical pathnames * * For S10 the physical path may not exist at the time devctl calls * are made. So we should not return error if stat fails on /devices path. * * This function can handle 2 different inputs. * * 1) Inputs of the form /dev/rdsk/cNtNdNsN * These are identified by being a link * The physical path they are linked to is returned. * * 2) Inputs of the form /devices/... * These are actual physical names. * They are not converted. */ char * h_get_physical_name(char *path) { struct stat stbuf; char s[MAXPATHLEN]; char savedir[MAXPATHLEN]; char *result = NULL; int status = 0; /* return invalid path if path NULL */ if (path == NULL) { return (NULL); } (void) strcpy(s, path); status = lstat(s, &stbuf); /* * S10: If string is devfs node we allow failed lstat. */ if ((status == -1) || !S_ISLNK(stbuf.st_mode)) { /* Make sure a full path as that is required. */ if (strstr(s, "/devices")) { result = g_alloc_string(s); } else { if (getcwd(savedir, sizeof (savedir)) == NULL) { return (NULL); } /* * Check for this format: * ./ssd@0,1:g,raw */ if (s[0] == '.') { (void) strcat(savedir, &s[1]); } else { (void) strcat(savedir, "/"); (void) strcat(savedir, s); } if ((status != -1) || strstr(s, "/devices")) { result = g_alloc_string(savedir); } } } else { /* * Entry is linked file * so follow link to physical name */ result = h_get_physical_name_from_link(path); } exit: return (result); } /* * handle expert-mode hotplug commands * * return 0 iff all is okay */ int hotplug_e(int todo, char **argv, int verbose_flag, int force_flag) { char *path_phys = NULL; char bus_path[MAXPATHLEN]; char *ptr; int exit_code = 1; devctl_hdl_t dcp; uint_t devstate; int i = 0, pathcnt = 1; mp_pathlist_t pathlist; int p_pw = 0, p_on = 0, p_st = 0; switch (todo) { case DEV_ONLINE: case DEV_OFFLINE: case DEV_GETSTATE: case DEV_RESET: /* get physical name */ if ((path_phys = h_get_physical_name(argv[0])) == NULL) { (void) fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), argv[0]); (void) fprintf(stderr, "\n"); return (1); } if (verbose_flag) { (void) fprintf(stdout, MSGSTR(5516, "phys path = \"%s\"\n"), path_phys); } /* acquire rights to hack on device */ if ((dcp = devctl_device_acquire(path_phys, force_flag ? 0 : DC_EXCL)) == NULL) { (void) fprintf(stderr, MSGSTR(5517, "Error: can't acquire \"%s\": %s\n"), path_phys, strerror(errno)); return (1); } switch (todo) { case DEV_ONLINE: exit_code = devctl_device_online(dcp); break; case DEV_OFFLINE: exit_code = devctl_device_offline(dcp); break; case DEV_GETSTATE: if ((exit_code = devctl_device_getstate(dcp, &devstate)) == 0) { print_dev_state(argv[0], devstate); } break; case DEV_RESET: exit_code = devctl_device_reset(dcp); break; } if (exit_code != 0) { perror(MSGSTR(5518, "devctl")); } /* all done now -- release device */ devctl_release(dcp); break; /* for hotplugging bus operations */ case BUS_QUIESCE: case BUS_UNQUIESCE: case BUS_GETSTATE: case BUS_RESET: case BUS_RESETALL: /* get physical name */ if ((path_phys = h_get_physical_name(argv[0])) == NULL) { (void) fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), argv[0]); (void) fprintf(stderr, "\n"); return (1); } if (verbose_flag) { printf(MSGSTR(5519, "phys path = \"%s\"\n"), path_phys); } /* acquire rights to hack on device */ /* delete leaf part from path_phys. */ if (strstr(path_phys, SCSI_VHCI) != NULL) { /* obtain phci */ (void) strcpy(bus_path, path_phys); if (g_get_pathlist(bus_path, &pathlist)) { (void) fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), path_phys); (void) fprintf(stderr, "\n"); return (1); } pathcnt = pathlist.path_count; p_pw = p_on = p_st = 0; for (i = 0; i < pathcnt; i++) { if (pathlist.path_info[i].path_state < MAXPATHSTATE) { if (strstr(pathlist.path_info[i]. path_addr, argv[0]) != NULL) { p_pw = i; break; } if (pathlist.path_info[i].path_state == MDI_PATHINFO_STATE_ONLINE) { p_on = i; } if (pathlist.path_info[i].path_state == MDI_PATHINFO_STATE_STANDBY) { p_st = i; } } } if (strstr(pathlist.path_info[p_pw].path_addr, argv[0]) != NULL) { /* matching input pwwn */ (void) strcpy(bus_path, pathlist.path_info[p_pw].path_hba); } else if (pathlist.path_info[p_on].path_state == MDI_PATHINFO_STATE_ONLINE) { /* on_line path */ (void) strcpy(bus_path, pathlist.path_info[p_on].path_hba); } else { /* standby or path0 */ (void) strcpy(bus_path, pathlist.path_info[p_st].path_hba); } free(pathlist.path_info); } else { (void) strcpy(bus_path, path_phys); ptr = strrchr(bus_path, '/'); if (ptr) { *ptr = '\0'; } else { (void) fprintf(stderr, MSGSTR(112, "Error: Invalid pathname (%s)"), path_phys); (void) fprintf(stderr, "\n"); return (1); } } if ((dcp = devctl_bus_acquire(bus_path, force_flag ? 0 : DC_EXCL)) == NULL) { (void) fprintf(stderr, MSGSTR(5521, " Error: can't acquire bus node from" " the path \"%s\": %s\n"), bus_path, strerror(errno)); return (1); } switch (todo) { case BUS_QUIESCE: exit_code = devctl_bus_quiesce(dcp); break; case BUS_UNQUIESCE: exit_code = devctl_bus_unquiesce(dcp); break; case BUS_GETSTATE: if ((exit_code = devctl_bus_getstate(dcp, &devstate)) == 0) { print_bus_state(argv[0], devstate); } break; case BUS_RESET: exit_code = devctl_bus_reset(dcp); break; case BUS_RESETALL: exit_code = devctl_bus_resetall(dcp); break; } if (exit_code != 0) { perror(MSGSTR(5522, "devctl")); } /* all done now -- release device */ devctl_release(dcp); break; } return (exit_code); } /* * Prepares an individual FC_AL device * to be removed from the specified * slot. * * RETURNS: * 0 if OK * non-zero otherwise. */ static int h_pre_remove_dev(Hotplug_Devlist *hotplug_disk, WWN_list *wwn_list, int verbose_flag, int force_flag) { char *dev_path, device_name[MAXNAMELEN]; int err; /* Initialize pointers */ dev_path = NULL; if (hotplug_disk->dlhead != NULL) { dev_path = hotplug_disk->dlhead->dev_path; (void) strcpy(device_name, (hotplug_disk->dlhead)->logical_path); } (void) fprintf(stdout, MSGSTR(157, "stopping: %s...."), device_name); if (!(strstr(dev_path, SLSH_DRV_NAME_ST))) { if ((err = g_dev_stop(dev_path, wwn_list, verbose_flag)) != 0) return (err); } (void) fprintf(stdout, MSGSTR(156, "Done\n")); (void) fprintf(stdout, MSGSTR(158, "offlining: %s...."), device_name); if ((err = g_offline_drive(hotplug_disk->dlhead, force_flag)) != 0) { (void) fprintf(stdout, MSGSTR(160, "\nonlining: %s\n"), device_name); (void) g_online_drive(hotplug_disk->dlhead, force_flag); (void) fprintf(stdout, MSGSTR(159, "starting: %s...."), device_name); if ((err = g_dev_start(dev_path, 0)) != 0) { return (err); } (void) fprintf(stdout, MSGSTR(156, "Done\n")); return (err); } (void) fprintf(stdout, MSGSTR(156, "Done\n")); return (0); } /* * Prepares a SENA enclosure or SENA FC_AL device * to be inserted/removed from a specified slot. * * RETURNS: * 0 if OK * non-zero otherwise. */ static int h_pre_hotplug_sena(Hotplug_Devlist *hotplug_dev, WWN_list *wwn_list, int todo, int verbose_flag, int force_flag) { int slot, f_r, i, found_null_wwn = 0, err; char *ses_path, *dev_path, code; char node_wwn_s[WWN_SIZE], device_name[MAXNAMELEN]; struct l_state_struct l_state; struct dlist *dl; if (hotplug_dev->dev_type == DTYPE_ESI) { /* entire photon is being removed */ if ((err = l_offline_photon(hotplug_dev, wwn_list, force_flag, verbose_flag)) != 0) { return (err); } return (0); } /* if device is an individual sena disk */ dl = hotplug_dev->seslist; while (dl) { ses_path = dl->dev_path; if ((err = l_get_status(ses_path, &l_state, verbose_flag)) == 0) break; dl = dl->next; } if (dl == NULL) { return (L_GET_STATUS_FAILED); } f_r = hotplug_dev->f_flag; slot = hotplug_dev->slot; (void) l_get_drive_name(device_name, slot, f_r, hotplug_dev->box_name); /* check if disk has null wwn */ if (f_r) { (void) strncpy(node_wwn_s, l_state.drv_front[slot].g_disk_state.node_wwn_s, WWN_SIZE); } else { (void) strncpy(node_wwn_s, l_state.drv_rear[slot].g_disk_state.node_wwn_s, WWN_SIZE); } for (i = 0; i < WWN_SIZE; i++) { if (node_wwn_s[i] != '0') break; found_null_wwn = 1; } switch (todo) { case INSERT_DEVICE: if (hotplug_dev->f_flag) { code = l_state.drv_front[slot].ib_status.code; } else { code = l_state.drv_rear[slot].ib_status.code; } if (code & S_NOT_INSTALLED) { /* * At this point we know that the drive is not * there. Turn on the RQST INSERT bit to make * the LED blink */ if ((err = l_encl_status_page_funcs (SET_RQST_INSRT, 0, todo, ses_path, &l_state, f_r, slot, verbose_flag)) != 0) { (void) print_errString(err, device_name); (void) fprintf(stderr, MSGSTR(5530, " %s: could not turn " "on LED\n"), device_name); } } else { /* * Drive is there so start it. */ if ((err = l_encl_status_page_funcs (SET_DRV_ON, 0, todo, ses_path, &l_state, f_r, slot, verbose_flag)) != 0) { (void) print_errString(err, device_name); (void) fprintf(stderr, MSGSTR(5531, " could not enable" " %s\n"), device_name); } } break; case REMOVE_DEVICE: /* * if disk has null wwn, then * there is no need to check the * disk/loop status. */ if (found_null_wwn == 1) { if (getenv("_LUX_W_DEBUG") != NULL) { (void) fprintf(stdout, "Device %s has " "null WWN.\n", device_name); } goto rmv; } if (hotplug_dev->f_flag) { if ( l_state.drv_front[slot].ib_status.code == S_NOT_INSTALLED) { (void) fprintf(stderr, MSGSTR(86, " Notice: %s may already" " be removed.\n"), device_name); return (0); } } else if ( l_state.drv_rear[slot].ib_status.code == S_NOT_INSTALLED) { (void) fprintf(stderr, MSGSTR(86, " Notice: %s may already" " be removed.\n"), device_name); return (0); } rmv: if (hotplug_dev->dlhead == NULL) { dev_path = NULL; } else { dev_path = hotplug_dev->dlhead->dev_path; } (void) fprintf(stdout, MSGSTR(157, "stopping: %s...."), device_name); if ((err = g_dev_stop(dev_path, wwn_list, 0)) != 0) { return (err); } (void) fprintf(stdout, MSGSTR(156, "Done\n")); (void) fprintf(stdout, MSGSTR(158, "offlining: %s...."), device_name); if ((err = g_offline_drive(hotplug_dev->dlhead, force_flag)) != 0) { (void) fprintf(stdout, MSGSTR(160, "\nonlining: %s\n"), device_name); (void) g_online_drive(hotplug_dev->dlhead, force_flag); (void) fprintf(stdout, MSGSTR(159, "starting: %s...."), device_name); (void) g_dev_start(dev_path, 0); (void) fprintf(stdout, MSGSTR(156, "Done\n")); return (err); } (void) fprintf(stdout, MSGSTR(156, "Done\n")); /* * Take the drive off the loop * and blink the LED. */ if (hotplug_dev->dev_location == SENA) { if ((err = l_encl_status_page_funcs(SET_RQST_RMV, 0, todo, ses_path, &l_state, f_r, slot, verbose_flag)) != 0) { (void) print_errString(err, device_name); (void) fprintf(stderr, MSGSTR(5539, " %s: could not blink" " the yellow LED\n"), device_name); } } break; } return (0); } /* * Performs the post removal operations for * a SENA enclosure or a SENA FC_AL disk. * * RETURNS: * 0 if OK * non-zero otherwise */ static int h_post_hotplug_sena(Hotplug_Devlist *hotplug_dev, WWN_list *wwn_list, int todo, int verbose_flag, int force_flag, int enc_type) { char *ses_path = NULL, *dev_path = NULL, device_name[MAXNAMELEN]; int tid, slot, f_r, al_pa, timeout = 0; uchar_t port_wwn[WWN_SIZE], node_wwn[WWN_SIZE]; char code; int wait_spinup_flag = 0, wait_map_flag = 0; int wait_node_flag = 0, err = 0, nArg; gfc_map_t map; WWN_list *newWwn_list = NULL; struct dlist *dl, *dl1; struct l_state_struct l_state; dl = hotplug_dev->seslist; slot = hotplug_dev->slot; f_r = hotplug_dev->f_flag; tid = hotplug_dev->tid; if (hotplug_dev->dev_type == DTYPE_ESI) { /* * See if photon has really been removed. If not, * try onlining the devices if applicable */ H_DPRINTF(" post_hotplug_sena: Seeing if enclosure " "has really been removed:\n" " tid=0x%x, ses_path %s\n", tid, dl->dev_path); while (dl) { ses_path = dl->dev_path; if ((err = g_get_dev_map(ses_path, &map, 0)) == 0) { if ((map.hba_addr.port_topology == FC_TOP_PUBLIC_LOOP) || (map.hba_addr.port_topology == FC_TOP_FABRIC)) { /* public or fabric loop device */ free((void *)map.dev_addr); (void) fprintf(stdout, MSGSTR(5540, "This operation is not " "supported in this topology.\n")); return (0); } if ((err = g_get_wwn(ses_path, port_wwn, node_wwn, &al_pa, verbose_flag)) == 0) { tid = g_sf_alpa_to_switch[al_pa]; if (g_device_in_map(&map, tid)) { free((void *)map.dev_addr); break; } } FREE_DEV_ADDR(map.dev_addr); } dl = dl->next; } FREE_DEV_ADDR(map.dev_addr); if (dl) { (void) fprintf(stdout, MSGSTR(5640, "Photon \"%s\" not removed." " Onlining Drives in enclosure.\n"), hotplug_dev->box_name); for (dl = hotplug_dev->dlhead; dl; ) { (void) g_online_drive(dl->multipath, force_flag); (void) g_free_multipath(dl->multipath); dl1 = dl; dl = dl->next; (void) free(dl1); } hotplug_dev->dlhead = NULL; return (0); } /* * Remove logical nodes for this * photon, this includes ses and * /dev/dsk entries. * In Solaris7, disks with -C option * removes the /dev/dsk entries. * The -C option is available * only for Solaris7. From Solaris8 * or higher releases, the "disks" * program will be replaced by the * devfsadm program. */ /* pass "disks -C" as cmdStrg. */ nArg = 2; if (h_execCmnd(cmdStrg[0], nArg) != 0) { for (dl = hotplug_dev->dlhead; dl != NULL; dl = dl->next) { if ((err = h_remove_nodes(dl->multipath)) != 0) { return (err); } } } else { (void) fprintf(stdout, MSGSTR(5541, " Logical Nodes being removed" " under /dev/dsk/ and /dev/rdsk:\n")); for (dl = hotplug_dev->dlhead; dl != NULL; dl = dl->next) { (void) h_print_logical_nodes(dl->multipath); } } for (dl = hotplug_dev->dlhead; dl != NULL; ) { (void) g_free_multipath(dl->multipath); dl1 = dl; dl = dl->next; (void) free(dl1); } hotplug_dev->dlhead = NULL; if ((err = h_remove_ses_nodes(hotplug_dev->seslist)) != 0) { return (err); } return (0); } /* post hotplug operations for a SENA disk. */ if (enc_type == DAK_ENC_TYPE) { (void) sprintf(device_name, MSGSTR(5664, " Drive in Box Name \"%s\" slot %d"), hotplug_dev->box_name, f_r ? slot : slot + (MAX_DRIVES_DAK/2)); } else { if (tid & 0x10) { (void) sprintf(device_name, MSGSTR(5542, " Drive in Box Name \"%s\" rear slot %d"), hotplug_dev->box_name, slot); } else { (void) sprintf(device_name, MSGSTR(5543, " Drive in Box Name \"%s\" front slot %d"), hotplug_dev->box_name, slot); } } (void) fprintf(stdout, "%s\n", device_name); dl = hotplug_dev->seslist; while (dl) { ses_path = dl->dev_path; if ((err = l_get_status(ses_path, &l_state, verbose_flag)) == 0) break; dl = dl->next; } if (dl == NULL) { print_errString(err, ses_path); return (L_GET_STATUS_FAILED); } code = 0; while (((err = l_encl_status_page_funcs(OVERALL_STATUS, &code, todo, ses_path, &l_state, f_r, slot, verbose_flag)) != 0) || (code != 0)) { if (err) { (void) print_errString(err, ses_path); } else if (todo == REMOVE_DEVICE) { if (code == S_OK) { (void) fprintf(stderr, MSGSTR(5544, "\n Warning: Device has not been" " removed from the enclosure\n" " and is still on the loop.")); return (0); } else { (void) fprintf(stderr, MSGSTR(5545, " Notice: Device has not been" " removed from the enclosure.\n" " It has been removed from the" " loop and is ready to be\n" " removed" " from the enclosure, and" " the LED is blinking.\n\n")); } goto loop2; } else if ((todo == INSERT_DEVICE) && ((code != S_NOT_AVAILABLE) || (timeout > PHOTON_SPINUP_TIMEOUT) || err)) { (void) fprintf(stderr, MSGSTR(5546, "\n Warning: Disk status is" " Not OK!\n\n")); return (0); } (void) sleep(PHOTON_SPINUP_DELAY); if (wait_spinup_flag++ == 0) { (void) fprintf(stdout, MSGSTR(5547, " Waiting for the disk to spin up:")); } else { (void) fprintf(stdout, "."); } timeout++; } if (wait_spinup_flag) { (void) fprintf(stdout, "\n"); } loop2: switch (todo) { case INSERT_DEVICE: /* check loop map that drive is present */ for (;;) { dl = hotplug_dev->seslist; map.dev_addr = (gfc_port_dev_info_t *)NULL; while (dl) { ses_path = dl->dev_path; if ((err = g_get_dev_map(ses_path, &map, verbose_flag)) != 0) { (void) fprintf(stderr, MSGSTR(5548, " Error: Could not get" " map for %s.\n"), ses_path); return (err); } if (g_device_in_map(&map, tid)) { goto loop3; } FREE_DEV_ADDR(map.dev_addr); dl = dl->next; } if (timeout > PHOTON_SPINUP_TIMEOUT) { (void) fprintf(stderr, MSGSTR(5549, " Warning: Device not in" " loop map.\n")); FREE_DEV_ADDR(map.dev_addr); return (0); } if (wait_map_flag++ == 0) { (void) fprintf(stdout, MSGSTR(5550, " Waiting for the device " "to appear in the loop map:")); } else { (void) fprintf(stdout, "."); } timeout++; (void) sleep(PHOTON_SPINUP_DELAY); } loop3: if (wait_map_flag) { (void) fprintf(stdout, "\n"); } /* * Run drvconfig and disks to create * logical nodes */ for (;;) { /* pass "disks" as cmdStrg */ nArg = 3; if (h_execCmnd(cmdStrg[2], nArg) != 0) { (void) fprintf(stderr, MSGSTR(5551, " Could not " "run drvconfig.\n")); FREE_DEV_ADDR(map.dev_addr); return (L_DRVCONFIG_ERROR); } if (l_device_present(ses_path, tid, &map, verbose_flag, &dev_path) == 1) break; if (timeout > PHOTON_SPINUP_TIMEOUT) { (void) fprintf(stderr, MSGSTR(5552, " Warning: Could not find " "any node for inserted " "device\n")); FREE_DEV_ADDR(map.dev_addr); return (0); } if (wait_node_flag++ == 0) { (void) fprintf(stdout, MSGSTR(5553, " Waiting for the logical " "node to be created:")); } else { (void) fprintf(stdout, "."); } timeout++; (void) sleep(PHOTON_SPINUP_DELAY); } FREE_DEV_ADDR(map.dev_addr); if (wait_node_flag) { (void) fprintf(stdout, "\n"); } /* * In Solaris7, disks with -C * option creates the new links * and removes any stale links. * In pre-Solaris7 releases, just * disks should do it all. */ /* pass "disks -C" as cmdStrg */ nArg = 2; if (h_execCmnd(cmdStrg[0], nArg) != 0) { return (L_DISKS_ERROR); } /* * Get a new wwn list here in order to * get the multiple paths to a newly added * device. */ if ((err = g_get_wwn_list(&newWwn_list, verbose_flag)) != 0) { return (err); } if ((err = g_get_multipath(dev_path, &dl, newWwn_list, 0)) != 0) { return (err); } if ((err = h_display_logical_nodes(dl)) != 0) { return (err); } break; case REMOVE_DEVICE: /* * TBD * Need to check all loops. */ /* check whether device is still in loop map */ if ((err = g_get_dev_map(ses_path, &map, verbose_flag)) != 0) { return (err); } if ((map.hba_addr.port_topology == FC_TOP_PUBLIC_LOOP) || (map.hba_addr.port_topology == FC_TOP_FABRIC)) { /* public or fabric loop device */ free((void *)map.dev_addr); (void) fprintf(stderr, MSGSTR(5540, "This operation is not " "supported in this topology.\n")); /* * calling routine expects a 0 return code * or a pre-defined luxadm error code. * Here we do not have a pre-defined error * code, a 0 is returned. */ return (0); } if (g_device_in_map(&map, tid)) { (void) fprintf(stderr, MSGSTR(5554, " Warning: Device still in the loop map.\n")); FREE_DEV_ADDR(map.dev_addr); return (0); } FREE_DEV_ADDR(map.dev_addr); /* * In Solaris7, "disks -C" program * removes the /dev/{r}dsk entries. * The -C option is available only * for Solaris7. From Solaris8 or * higher releases, the "disks" program * will be replaced by devfsadm. */ /* pass "disks -C" as cmdStrg */ nArg = 2; if (h_execCmnd(cmdStrg[0], nArg) != 0) { return (L_DISKS_ERROR); } (void) fprintf(stdout, MSGSTR(5555, " Logical Nodes being removed" " under /dev/dsk/ and /dev/rdsk:\n")); (void) h_print_logical_nodes( hotplug_dev->dlhead); break; } return (0); } /* * Creates new ses entries under /dev/es * directory for the newly added * enclosures. * * RETURNS: * 0 if OK * non-zero otherwise */ static int h_post_insert_encl(timestruc_t ses_lastmtim) { struct stat ses_stat; char lname[MAXPATHLEN]; int err, found_newlink = 0; DIR *dir; struct dirent *dirent; Box_list *bl1, *box_list = NULL; if ((dir = opendir(SES_DIR)) == NULL) { return (L_OPEN_ES_DIR_FAILED); } if ((err = l_get_box_list(&box_list, 0)) != 0) { closedir(dir); return (err); } /* * The mod time of /dev/es was newer than the mod time prior to * insert so dir entry is checked at this time. */ while ((dirent = readdir(dir)) != (struct dirent *)NULL) { if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) continue; (void) sprintf(lname, SES_DIR"/%s", dirent->d_name); if (lstat(lname, &ses_stat) < 0) { (void) print_errString(L_LSTAT_ES_DIR_ERROR, lname); continue; } for (bl1 = box_list; bl1; bl1 = bl1->box_next) { if (strstr(lname, bl1->b_physical_path)) break; } if (box_list && bl1) continue; if (NEWER(ses_stat.st_ctim, ses_lastmtim)) { /* New enclosure was detected. */ found_newlink++; if (found_newlink == 1) { (void) fprintf(stdout, MSGSTR(5556, " New Logical Nodes under /dev/es:\n")); } (void) fprintf(stdout, "\t%s\n", dirent->d_name); } } if (!found_newlink) { (void) fprintf(stdout, MSGSTR(5662, " No new enclosure(s) were added!!\n\n")); } closedir(dir); (void) l_free_box_list(&box_list); return (0); } /* * performs the post removal of individual * FC_AL disks. * * RETURNS: * 0 if OK * non-zero otherwise */ static int h_post_remove_dev(Hotplug_Devlist *hotplug_disk, int todo, int verbose_flag) { char device_name[MAXNAMELEN], *dev_path = NULL; int tid, err; gfc_map_t map; int nArg; tid = hotplug_disk->tid; (void) sprintf(device_name, MSGSTR(5557, "\n Device: %s"), (hotplug_disk->dlhead)->logical_path); (void) fprintf(stdout, "%s\n", device_name); dev_path = (hotplug_disk->dlhead)->dev_path; /* * On qlc, after a forcelip on a FC combo box, it sometimes takes 17 * seconds for the loop to come back online. During this 17 seconds, * g_get_dev_map * will return L_NO_DEVICES_FOUND. This delay * has been added to assure that the L_NO_DEVICES_FOUND returned from * g_get_dev_map is not the result of the 17 second delay on FC combo. * This only affects qlc. */ if ((err = g_get_dev_map(dev_path, &map, verbose_flag)) != 0) { if ((err == L_NO_DEVICES_FOUND) && (strstr(dev_path, "SUNW,qlc@") != NULL)) { sleep(QLC_LIP_DELAY); if ((err = g_get_dev_map(dev_path, &map, verbose_flag)) != 0) { if (err != L_NO_DEVICES_FOUND) return (err); } } else if (err != L_NO_DEVICES_FOUND) return (err); } /* * if g_get_dev_map returns L_NO_DEVICES_FOUND, then there are not * devices attached to the HBA and there is no sense in calling * g_device_in_map(). */ if (err != L_NO_DEVICES_FOUND) { if ((map.hba_addr.port_topology == FC_TOP_PUBLIC_LOOP) || (map.hba_addr.port_topology == FC_TOP_FABRIC)) { /* public or fabric loop device */ free((void *)map.dev_addr); (void) fprintf(stderr, MSGSTR(5540, "This operation is not " "supported in this topology.\n")); return (0); } if (g_device_in_map(&map, tid) != 0) { (void) fprintf(stderr, MSGSTR(5558, " Warning: Device has" " not been removed from\n" " the slot and is still" " in the loop map.\n\n")); free((void *)map.dev_addr); return (0); } free((void *)map.dev_addr); } /* * In Solaris7, "disks -C" program * removes the /dev/{r}dsk entries. * The -C option is available only * for Solaris7. From Solaris8 or * higher releases, the "disks" program * will be replaced by devfsadm. */ /* pass "disks -C" as cmdStrg. */ nArg = 2; if (h_execCmnd(cmdStrg[0], nArg) != 0) { return (L_DISKS_ERROR); } /* pass "tapes -C as cmdStrg. */ if (h_execCmnd(cmdStrg[5], nArg) != 0) { return (L_TAPES_ERROR); } (void) h_print_logical_nodes(hotplug_disk->dlhead); return (0); } /* * Gets the last modification time for * /dev/es/ and /dev/rdsk directories * and passes these values to the caller. * * RETURNS: * 0 if OK * non-zero in case of error */ static int h_pre_insert_encl_dev(timestruc_t *ses_time, timestruc_t *dsk_time, timestruc_t *rmt_time) { struct stat ses_stat, dsk_stat, rmt_stat; if (stat(SES_DIR, &ses_stat) < 0) { /* * Even if there exists no /dev/es don't fail it. * The host doesn't have to have any enclosure device * configured. */ if (errno == ENOENT) { ses_time = (timestruc_t *)NULL; } else { return (L_LSTAT_ES_DIR_ERROR); } } else { *ses_time = ses_stat.st_mtim; } if (stat(DEV_DSK_DIR, &dsk_stat) < 0) { return (L_STAT_DEV_DIR_ERROR); } else { *dsk_time = dsk_stat.st_mtim; } if (stat(DEV_TAPE_DIR, &rmt_stat) < 0) { /* * Even if there exists no /dev/rmt don't fail it. * The host doesn't have to have any tape device * configured. */ if (errno == ENOENT) { rmt_time = (timestruc_t *)NULL; } else { return (L_STAT_RMT_DIR_ERROR); } } else { *rmt_time = rmt_stat.st_mtim; } return (0); } /* * Waits for loop intialization to complete * and runs drvconfig, disks and devlinks to create device nodes * for devices that are being added and prints the newly created * /dev/rdsk entries. * * RETURNS: * 0 if OK * non-zero in case of error */ static int h_post_insert_dev(timestruc_t dsk_lastmtim, timestruc_t rmt_lastmtim) { int found_newlink = 0, nArg; (void) fprintf(stdout, MSGSTR(5560, "\nWaiting for Loop Initialization to complete...\n")); /* * We sleep here to let the system create nodes. Not sleeping * could cause the drvconfig below to run too soon. */ (void) sleep(NODE_CREATION_TIME); /* * Run drvconfig and disks to create * logical nodes */ /* pass "drvconfig" as cmdStrg */ nArg = 1; if (h_execCmnd(cmdStrg[3], nArg) != 0) { return (L_DRVCONFIG_ERROR); } /* * In 2.7, disks with the -C * option should be used to * create new links and remove * any stale links. * In pre-2.7 releases, just * disks should do it all. */ /* pass "disks -C" as cmdStrg */ nArg = 2; if (h_execCmnd(cmdStrg[0], nArg) != 0) { return (L_DISKS_ERROR); } /* pass "tapes -C as cmdStrg */ if (h_execCmnd(cmdStrg[5], nArg) != 0) { return (L_TAPES_ERROR); } /* pass "devlinks" as cmdStrg */ nArg = 1; if (h_execCmnd(cmdStrg[4], nArg) != 0) { return (L_DEVLINKS_ERROR); } /* check /dev/dsk and /dev/rmt for new links */ found_newlink = h_find_new_device_link(DEV_DSK_DIR, dsk_lastmtim) + h_find_new_device_link(DEV_TAPE_DIR, rmt_lastmtim); if (!found_newlink) { (void) fprintf(stdout, MSGSTR(5562, " No new device(s) were added!!\n\n")); } return (0); } /* * Performs the pre hotplug operations on SENA enclosure(s), * SENA disk(s) and individual fcal disk(s). * If the device is failed to remove, then it removes the device from the * hotplug list and continues with the next device in the list. * * RETURNS: * 0 if OK * prints an error message to stderr and returns 0 */ static int h_pre_hotplug(Hotplug_Devlist **disk_list_head_ptr, WWN_list *wwn_list, int todo, int verbose_flag, int force_flag) { Hotplug_Devlist *list, *disk_list; int err = 0; disk_list = *disk_list_head_ptr; while (disk_list != NULL) { if ((disk_list->dev_type == DTYPE_ESI) || (disk_list->dev_location == SENA)) { if ((err = h_pre_hotplug_sena(disk_list, wwn_list, todo, verbose_flag, force_flag)) != 0) { (void) print_errString(err, disk_list->dev_name); goto delete; } } else if (disk_list->dev_location == NON_SENA) { if ((err = h_pre_remove_dev(disk_list, wwn_list, verbose_flag, force_flag)) != 0) { (void) print_errString(err, disk_list->dev_name); goto delete; } } disk_list = disk_list->next; continue; delete: list = disk_list->prev; if (list != NULL) { list->next = disk_list->next; if (list->next != NULL) list->next->prev = list; } list = disk_list; disk_list = disk_list->next; if (list == *disk_list_head_ptr) *disk_list_head_ptr = disk_list; (void) g_free_multipath(list->seslist); (void) g_free_multipath(list->dlhead); (void) free(list); } return (0); } /* * Performs the post removal of a list of SENA enclosure(s), * SENA disk(s) and individual fcal disk(s). * * RETURNS: * 0 O.K. * non-zero otherwise */ static int h_post_hotplug(Hotplug_Devlist *hotplug_dlist, WWN_list *wwn_list, int todo, int verbose_flag, int force_flag, int enc_type) { Hotplug_Devlist *list; int err; /* Do a lip on every loop so that we get the latest loop maps */ if (todo != INSERT_DEVICE) { if ((err = g_forcelip_all(hotplug_dlist)) != 0) { return (err); } } while (hotplug_dlist != NULL) { if ((hotplug_dlist->dev_location == SENA) || (hotplug_dlist->dev_type == DTYPE_ESI)) { if ((err = h_post_hotplug_sena(hotplug_dlist, wwn_list, todo, verbose_flag, force_flag, enc_type)) != 0) (void) print_errString(err, hotplug_dlist->dev_name); } else if (hotplug_dlist->dev_location == NON_SENA) { if ((err = h_post_remove_dev(hotplug_dlist, todo, verbose_flag)) != 0) (void) print_errString(err, hotplug_dlist->dev_name); } list = hotplug_dlist; hotplug_dlist = hotplug_dlist->next; (void) g_free_multipath(list->seslist); (void) g_free_multipath(list->dlhead); (void) free(list); } return (0); } /* * removes the device's logical paths. * * RETURNS: * 0 if OK * non-zero otherwise */ static int h_remove_nodes(struct dlist *dl) { char link[MAXPATHLEN], path[MAXPATHLEN]; char lname[MAXPATHLEN], *ptr; DIR *dir; struct dirent *dirent; struct dlist *dlist; if ((dir = opendir(DEV_DSK_DIR)) == NULL) { return (L_READ_DEV_DIR_ERROR); } if (dl == NULL) { /* pass "disks" as cmdStrg */ if (h_execCmnd(cmdStrg[1], 1) != 0) { return (L_DISKS_ERROR); } } (void) fprintf(stdout, MSGSTR(5563, " Removing Logical Nodes: \n")); while ((dirent = readdir(dir)) != (struct dirent *)NULL) { if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) { continue; } (void) sprintf(lname, DEV_DSK_DIR"/%s", dirent->d_name); if (readlink((const char *)lname, (char *)link, (size_t)MAXPATHLEN) <= 0) { (void) fprintf(stderr, MSGSTR(5564, " Error: Could not read %s\n"), lname); continue; } for (dlist = dl; dlist != NULL; dlist = dlist->next) { (void) strcpy(path, dlist->dev_path); ptr = strrchr(path, ':'); if (ptr) *ptr = '\0'; if (strstr(link, path)) { (void) unlink(lname); (void) sprintf(lname, "/dev/rdsk/%s", dirent->d_name); (void) fprintf(stdout, MSGSTR(5565, "\tRemoving %s\n"), dirent->d_name); (void) unlink(lname); } } } closedir(dir); return (0); } /* * removes the SENA's ses paths. * * RETURNS: * 0 if OK * non-zero otherwise */ static int h_remove_ses_nodes(struct dlist *dlist) { char link[MAXPATHLEN], lname[MAXPATHLEN]; DIR *dir; struct dirent *dirent; struct dlist *dl; if ((dir = opendir(SES_DIR)) == NULL) { return (L_READ_DEV_DIR_ERROR); } (void) fprintf(stdout, MSGSTR(5566, " Removing Ses Nodes:\n")); /* * Remove the ses entries * of the form ses<#> * from the /dev/es directory. */ while ((dirent = readdir(dir)) != (struct dirent *)NULL) { if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) continue; (void) sprintf(lname, SES_DIR"/%s", dirent->d_name); if (readlink((const char *)lname, (char *)link, (size_t)MAXPATHLEN) <= 0) { (void) fprintf(stderr, MSGSTR(5564, " Error: Could not read %s\n"), lname); continue; } for (dl = dlist; dl != NULL; dl = dl->next) { if (strstr(link, dl->dev_path)) { (void) fprintf(stdout, MSGSTR(5568, "\tRemoving %s\n"), lname); (void) unlink(lname); } } } closedir(dir); (void) g_free_multipath(dlist); return (0); } /* * prints the device's logical * paths for disks to stdout. * * RETURNS: * 0 if OK * non-zero otherwise */ static void h_print_logical_nodes(struct dlist *disk_list) { char *lpath, *ptr, *buf_ptr, buf[MAXNAMELEN], dev[MAXNAMELEN]; struct dlist *dlist; int i, found_dev = 0; char *tape_entries[] = { "", "b", "bn", "c", "cb", "cbn", "cn", "h", "hb", "hbn", "hn", "l", "lb", "lbn", "ln", "m", "mb", "mbn", "mn", "n", "u", "ub", "ubn", "un", NULL}; for (dlist = disk_list; dlist != NULL; dlist = dlist->next) { lpath = dlist->logical_path; if ((ptr = strrchr(lpath, 'c')) == NULL) continue; (void) strcpy(buf, ptr); if ((ptr = strrchr(buf, 's')) == NULL) continue; *(++ptr) = '\0'; found_dev++; if (found_dev == 1) (void) fprintf(stdout, MSGSTR(5559, " Logical Nodes being " "removed under /dev/dsk/ and " "/dev/rdsk:\n")); for (i = 0; i <= 7; i++) { (void) sprintf(dev, "%s%d", buf, i); (void) fprintf(stdout, "\t%s\n", dev); } } found_dev = 0; for (dlist = disk_list; dlist != NULL; dlist = dlist->next) { lpath = dlist->logical_path; if (strstr(lpath, DEV_TAPE_DIR)) { if ((ptr = strrchr(lpath, '/')) == NULL) continue; found_dev++; if (found_dev == 1) (void) fprintf(stdout, "Logical Nodes being " "removed under /dev/rmt:\n"); ptr++; buf_ptr = ptr; while (*ptr >= '0' && *ptr <= '9') ptr++; *ptr = '\0'; for (i = 0, ptr = tape_entries[0]; ptr != NULL; i++, ptr = tape_entries[i]) { (void) sprintf(dev, "%s%s", buf_ptr, ptr); (void) fprintf(stdout, "\t%s\n", dev); } } } } /* * displays logical paths to a * device to stdout. * * RETURNS: * 0 if OK * non-zero otherwise */ static int h_display_logical_nodes(struct dlist *dlist) { char link[MAXPATHLEN], path[MAXPATHLEN]; char lname[MAXPATHLEN], *d1; DIR *dir; struct dirent *dirent; struct dlist *dl; if ((dir = opendir(DEV_DSK_DIR)) == NULL) { return (L_READ_DEV_DIR_ERROR); } (void) fprintf(stdout, MSGSTR(5569, " Logical Nodes under /dev/dsk and /dev/rdsk :\n")); while ((dirent = readdir(dir)) != (struct dirent *)NULL) { if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) { continue; } (void) sprintf(lname, DEV_DSK_DIR"/%s", dirent->d_name); if (readlink((const char *)lname, (char *)link, (size_t)MAXPATHLEN) <= 0) { (void) print_errString(L_SYMLINK_ERROR, lname); continue; } for (dl = dlist; dl; dl = dl->next) { (void) strcpy(path, dl->dev_path); d1 = strrchr(path, ':'); if (d1) *d1 = '\0'; if (strstr(link, path)) { (void) fprintf(stdout, "\t%s\n", dirent->d_name); } } } closedir(dir); return (0); } /* * prints a list of devices which * will be inserted or removed * to the stdout and asks for * the user's confirmation. * * RETURNS: * 0 if OK * non-zero otherwise */ static int h_print_list_warn(Hotplug_Devlist *disk_list_head, int todo, int enc_type) { int i; char choice[2]; struct dlist *dl_ses, *dl_multi; Hotplug_Devlist *disk_list = disk_list_head; (void) fprintf(stdout, MSGSTR(5570, "The list of devices which will be ")); switch (todo) { case INSERT_DEVICE: (void) fprintf(stdout, MSGSTR(5571, "inserted is:\n")); break; case REMOVE_DEVICE: (void) fprintf(stdout, MSGSTR(5572, "removed is:\n")); break; } for (i = 1; disk_list; i++, disk_list = disk_list->next) { if ((disk_list->dev_type == DTYPE_DIRECT) && (disk_list->dev_location == SENA)) { if (disk_list->f_flag != 0) { if (enc_type == DAK_ENC_TYPE) { (void) fprintf(stdout, MSGSTR(5665, " %d: Box Name: \"%s\" slot %d\n"), i, disk_list->box_name, disk_list->slot); } else { (void) fprintf(stdout, MSGSTR(137, " %d: Box Name: \"%s\" front slot %d\n"), i, disk_list->box_name, disk_list->slot); } } else { if (enc_type == DAK_ENC_TYPE) { (void) fprintf(stdout, MSGSTR(5665, " %d: Box Name: \"%s\" slot %d\n"), i, disk_list->box_name, disk_list->slot + (MAX_DRIVES_DAK/2)); } else { (void) fprintf(stdout, MSGSTR(136, " %d: Box Name: \"%s\" rear slot %d\n"), i, disk_list->box_name, disk_list->slot); } } } else if (((disk_list->dev_type == DTYPE_DIRECT) || (disk_list->dev_type == DTYPE_SEQUENTIAL)) && (disk_list->dev_location == NON_SENA)) { (void) fprintf(stdout, MSGSTR(5573, " %d: Device name: %s\n"), i, disk_list->dev_name); } else if (disk_list->dev_type == DTYPE_ESI) { (void) fprintf(stdout, MSGSTR(5574, " %d: Box name: %s\n"), i, disk_list->box_name); } if (getenv("_LUX_H_DEBUG") != NULL) { if (disk_list->dev_location == SENA) { (void) fprintf(stdout, " Select ID:\t0x%x\n", disk_list->tid); if (disk_list->dev_type != DTYPE_ESI) { if (enc_type == DAK_ENC_TYPE) { (void) fprintf(stdout, " Location: \tSlot %d \n", disk_list->f_flag ? disk_list->slot : disk_list->slot +MAX_DRIVES_DAK/2); } else { (void) fprintf(stdout, " Location: \tSlot %d %s \n", disk_list->slot, disk_list->f_flag ? "front" : "rear"); } } } } if (todo == REMOVE_DEVICE) { (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(90, "Node WWN:")); (void) fprintf(stdout, " %s\n", disk_list->node_wwn_s); (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(35, "Device Type:")); if (disk_list->dev_type == DTYPE_ESI) { (void) fprintf(stdout, MSGSTR(5581, " SENA (%s)\n"), dtype[disk_list->dev_type]); } else { (void) fprintf(stdout, "%s\n", dtype[disk_list->dev_type]); } if (disk_list->dev_type == DTYPE_ESI) { dl_ses = disk_list->seslist; (void) fprintf(stdout, MSGSTR(5575, " SES Paths:\n")); while (dl_ses) { (void) fprintf(stdout, MSGSTR(5576, " %s\n"), dl_ses->dev_path); dl_ses = dl_ses->next; } } else { dl_multi = disk_list->dlhead; (void) fprintf(stdout, MSGSTR(5577, " Device Paths:\n")); while (dl_multi) { (void) fprintf(stdout, MSGSTR(5578, " %s\n"), dl_multi->logical_path); dl_multi = dl_multi->next; } } } (void) fprintf(stdout, "\n"); } (void) fprintf(stdout, MSGSTR(5579, "\nPlease verify the above list of devices" " and\nthen enter 'c' or to Continue" " or 'q' to Quit. [Default: c]: ")); /* Get the user input and continue accordingly. */ for (;;) { (void) gets(choice); if (choice[0] == 'c' || choice[0] == 'C' || choice[0] == 'q' || choice[0] == 'Q' || choice[0] == '\0') { break; } (void) fprintf(stdout, MSGSTR(5580, " Enter an appropriate option [c,,q]: ")); } if (choice[0] == 'q' || choice[0] == 'Q') { return (-1); } return (0); } static int h_find_new_device_link(char *device_dir, timestruc_t lastmtim) { struct stat dsk_stat; char lname[MAXPATHLEN], link[MAXPATHLEN]; char *link_ptr; DIR *dir; struct dirent *dirent; int found_newlink = 0; if ((dir = opendir(device_dir)) == NULL) { if (errno == ENOENT) { return (0); } else { return (L_READ_DEV_DIR_ERROR); } } while ((dirent = readdir(dir)) != (struct dirent *)NULL) { if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) { continue; } (void) sprintf(lname, "%s/%s", device_dir, dirent->d_name); if (lstat(lname, &dsk_stat) < 0) { (void) print_errString(L_LSTAT_ES_DIR_ERROR, lname); continue; } if (readlink((const char *)lname, (char *)link, (size_t)MAXPATHLEN) <= 0) { (void) print_errString(L_SYMLINK_ERROR, lname); continue; } /* * "link" can be a relative pathname. But, since * g_get_path_type() only accepts absolute paths, we * will skip to the part where "/devices/" begins and pass a * pointer from there. Since "link" is got from readlink(), * it is unlikely that it will not have /devices string, but * we will check for it anyways. */ if (!(link_ptr = strstr(link, "/devices/"))) continue; if (!g_get_path_type(link_ptr)) { continue; } if (NEWER(dsk_stat.st_ctim, lastmtim)) { found_newlink++; if (found_newlink == 1) { if (! (strcmp(device_dir, DEV_DSK_DIR))) { (void) fprintf(stdout, MSGSTR(5561, " New Logical Nodes under " "/dev/dsk and /dev/rdsk :\n")); } else { /* device_dir is /dev/rmt */ (void) fprintf(stdout, "New Logical " "Node under /dev/rmt:\n"); } } (void) fprintf(stdout, "\t%s\n", dirent->d_name); } } closedir(dir); return (found_newlink); } /* * prints the device state. * * RETURNS: * None. */ void print_dev_state(char *devname, int state) { (void) printf("\t%s: ", devname); if (state & DEVICE_ONLINE) { (void) printf(MSGSTR(3000, "Online")); if (state & DEVICE_BUSY) { (void) printf(" "); (void) printf(MSGSTR(37, "Busy")); } if (state & DEVICE_DOWN) { (void) printf(" "); (void) printf(MSGSTR(118, "Down")); } } else { if (state & DEVICE_OFFLINE) { (void) printf(MSGSTR(3001, "Offline")); if (state & DEVICE_DOWN) { (void) printf(" "); (void) printf(MSGSTR(118, "Down")); } } } (void) printf("\n"); } /* * prints the bus state. * * RETURNS: * None. */ void print_bus_state(char *devname, int state) { (void) printf("\t%s: ", devname); if (state == BUS_QUIESCED) { (void) printf(MSGSTR(3002, "Quiesced")); } else if (state == BUS_ACTIVE) { (void) printf(MSGSTR(39, "Active")); } else if (state == BUS_SHUTDOWN) { (void) printf(MSGSTR(3003, "Shutdown")); } (void) printf("\n"); } õ¡ ðð‘üЭ^¬Ðð]ÿB¥¤C§€¦CBÀ1²vQC!@ ‚ð‘ȣᇶrsSK²tQB!@ ƒð‘ȣᇴrrRJßwáÕð‘@¡ ÐÀ1À0ð‘¡ ðð‘@(#)FW Rev V1.09 È'€Àÿ€$h‡j£e6ݪh@(#)Wed Mar 3 13:32:24 1999 Òµ @PF @¡ «ÍÀ0ð‘G¯®þ QÀ1Å3Ê5Ï73L­ ¬Úð]À1Ÿtáóð‘­€¬~ð]ð‘­¬ÐÀ,ð‘­¬À!ñð‘A£¢B¥€¤@Ê5­¬®ð]Ï7A£€¢B¥€¤ ð]ð‘­¬îË%ñð‘@¡€ ÒÐÀ ð‘$hÀ3ñð‘­¬ðð‘Èð‘HÿãÈð‘À4ð‘È5ðãÈð‘HÿãÈð‘À´ð‘Ì7ÃóÄõÀ1À¥á‡BpRHßsáÇð‘ðÑð‘A£¢B¥¤ ­¬®ð]ð‘A£¢B¥¤<Ê5­¬®ð]Ï7E«ªRË%ñ›ð‘@¡ À ð‘Á1ñ›ð‘À ð‘$hÁ1ñ›À1àð‘@¡ À1À0ð‘A£€¢š!@ Cð‘ßqá÷ð‘A£ü¢Ð˜Å3Ð2ð‘Âóßqá÷ð‘@¡N lffÀ0ð‘@¡ VÀ ð‘hÁqÀ0ð‘ @¡ üÀÐð‘­º¬Âð]ð‘­¼¬Þð]ð‘­\¬~ð]ð‘­c¬ªð]ð‘­¬ð]ð‘­]¬ð]ð‘­;¬òð]ð‘­@¬ð]ð‘­A¬Fð]ð‘g€@­‰¬úð]ð‘@¡ À ð‘ßqÀ0ð‘á“ð‘2À0ð‘­¹¬ðð]ð‘@¡ À ð‘ßqÀ0ð‘á“ð‘À0ð‘­c¬ôð]ð‘@¡ À ð‘ßqÀ0ð‘á“ð‘dÀ0ð‘­„¬"ð]ð‘@¡ À ð‘ßqÀ0ð‘á“ð‘ À0ð‘­ö¬æð]ð‘­ ¬H@¡/ HÀð‘€ ñð‘@¡/ ZÀð‘€ ñð‘@¡_ üÀ ð‘À!ñð‘@¡ À ð‘ßqÀ0ð‘á“ð‘ À0ð‘­Ë¬êð]ð‘@¡ À ð‘ßqÀ0ð‘á“ð‘dÀ0ð‘­Ê¬tð]ð‘@¡ À ð‘ßqÀ0ð‘á“ð‘ôÀ0ð‘­Ê¬âð]ð‘@¡  À ð‘ßqÀ0ð‘á“ð‘ôÀ0ð‘­Ú¬¾ð]ð‘­à¬$ð]ð‘@¡ °À ò9ðSð‘­¬ð@^Ð$ °YðYà   ÐÀ(p(`< ^Ð%  1ð1à^Ð ^Ð ^Ð ^Ð ^Ð ^Ð ^Ð ^Ð ^Ð ^Ð ^Ð ^Ð ^Ð €ðÑg€ðÑð‘ðÑð‘ðÑð‘­^¬Ð€¨ñ&ðÑð‘ð‘ð‘ðÑð‘À1Å3.... ..... .$.(.,.0.4.8ðÑ.ðð‘(‘‡:á…))ö1Ê8ð‘Í8ð‘Áq­¬äñð‘(ð„¨À‰1­ ¬†ñð‘Àˆ°áÁˆ°áð‘ŠÄ8ð‘Ô¸ð‘ðÑð‘ŠÄ8ð‘Ô¸ð‘ðÑð‘(„°­¬*ñ„°­ ¬ìñð‘(舨(‰1á𑊠Ä8ð‘Ô¸ð‘ðÑð‘­]¬Xð]ð‘Ê8ð‘Í8ð‘À!á—ö1ŠÄ8ð‘Ô¸ð‘ðÑð‘²v!@ Cð‘À1@°vÑÇ0ð‘ê…!Жð‘(Íð‘*Œ€¨„°á1„°á)„°á!ñ7­]¬‚ð]ð‘ŠÄ8ð‘Ô¸ð‘ðÑð‘LÁÖð‘²vô£"! ð‘­5¬¼ð]ð‘Á6ù1á!ð‘hñ7­]¬‚ð]ð‘ŠlÄ8ð‘Ô¸ð‘ðÑð‘Ψð‘Áqθð‘ê(ð‘ò5Ôƒ-š"! ð‘("„°­ ¬Æñð‘¾à ð‘2Ê(ò9á’ð‘Ä8ð‘Ô¸ð‘çð‘à{ð‘­¬Úðð‘)C§ö¦€€À†ð‘H€8á! €¨ê… €°á“ð‘Ȧð‘)XÁ1­¬”ñð‘ßwáÞ‡­ ¬üñCpðSH­]¬Xð]ð‘À!­¬Èñö1²v!@ Cð‘(Íð‘p€¨ÁÖð‘*ŒH­5¬¼ð]ð‘Á6ù1­¬¾ñð‘ê…!Жð‘Ψð‘Áqθð‘àð‘ñ7²vô£"! ð‘Ä8ð‘Ô¸ð‘çð‘à{ð‘­¬Úðð‘ñ7­]¬‚ð]ð‘Ä8ð‘Ô¸ð‘çð‘à{ð‘­¬Úðð‘ñ7­¬*À†ð‘€8ñ­¬üðð‘(ˆ²á ²ñ dwefð"!²vô£ ð‘æð‘ðð‘A£¢rðSð‘(Íð‘à†ð‘„:ñ Ľá­¬€ã&ð‘ó¦ð‘ð­¬*ð °hاÊ(ö9tÁ¶ð‘²vÔƒ|Ôð‘À1Î6ð‘*ÍÈâ—ð‘ŠÄ8ð‘Ô¸ð‘ðÑð‘Ó%áiÊ%á Óâð‘n-ªâ&ð‘ò¦ð‘ÍÈ .¬nó7.2-4Ã(ð‘Á$Åäð‘j­'¬àð]-(p @Ä8ð‘Ô¸ð‘ðÑð‘­¬*Ŧð‘Ö&ð‘*Œ–±ñÏ3ñð‘(Íð‘Ȧð‘)XÅ1­¬Vñð‘›6@¡ BÀ ð‘À!á ­^¬Ðð]ŠÄ8ð‘Ô¸ð‘ðÑð‘­¬rð]ð‘(ð„¨À‰1­¬öñð‘à†ð‘„:á‹ð‘­¬*ðð‘­¬Þˆ¨$ñŸr*ñŸrñŸr$ñŸr,ñŸr4ñŸr4ñŸr2ñð‘ŠÄ8ð‘Ô¸ð‘ðÑð‘Ä8ð‘Ô¸ð‘çð‘à{ð‘­¬Úðð‘­¬*à†ð‘H(áð‘¸Ä8ð‘Ô¸ð‘çð‘à{ð‘­¬Úðð‘„:ñ(#„°­¬Rñð‘! Ä8ð‘Ô¸ð‘çð‘à{ð‘­¬Úðð‘Ä8ð‘Ô¸ð‘çð‘à{ð‘­¬Úðð‘ðÑð‘)ÄFð‘H8áý€¨ÄVð‘)˶ð‘)ÁqË6ð‘Ä𑀠ᑲvÕƒ"! ð‘ðÑð‘D©€¨@#à D©€¨# ÁÈð‘€ ÁØð‘&Ì(ð‘ܨð‘ÁsÀyÌ8ð‘ܸð‘­¬<ù€0 …)…A@¡ ÐÀ ð‘¼hð𑆆†..†.†Ä(ð‘¼hĨð‘ðð‘ ‚8áð‘cð‘­¬†ðð‘:"!4h ð‘åð‘à{ð‘))(€8áð‘­1¬°ð]ð‘­¬’ðð‘ ­1¬°ð]ð‘Ê(ð‘À!­¬ñö1ÄFð‘€ ÄVð‘ÁÈð‘‚8­¬Êñð‘Ĩð‘´hB"@´ð‘ÁØð‘:ÁÁ!Á$Åäð‘jÃ8ð‘Ȉð‘ŸpȘð‘c&ðÑð‘­'¬Æð]ð‘ÁØð‘:ÁÁ!Á$Åäð‘jÃ8ð‘Ȉð‘ŸpȘð‘c&ðÑð‘Ã(ð‘"!4h ð‘åð‘à{ð‘ñ9À>ð‘ÿ¯B¥4¤ÈÄä¨ð‘­¬ð]Ï7ê…##ð¯À.ð‘ø1­¬ðð‘Ã(ð‘"!4h ð‘åð‘à{ð‘(„¨€0@¡ °ÐÀð‘À>ð‘€°­¬ñð‘(„­¬ñÄññ9À>ð‘ÿ¯B¥4¤ÈÂä¨ð‘­¬ð]Ï7ê…##ð¯À.ð‘ø1­¬ðð‘.œ(D„¨0„ µ-•Õà1ð‘à)ð‘à ð‘ð‘²v׃"! ð‘­¬Ôðð‘²v׃"! ð‘€0(\ÁA@¡ zÐÀ ð‘¼hðð‘ÔºººººººÔºÔºººººÔÔººÔÔººººÔÔÔÔÔÔñ9À>ð‘ÿ¯À1­]¬Èð]´vð¯À.ð‘ø1Á&ò9ʦð‘­4¬Ðð]ð‘­'¬Æð]ð‘ÁØð‘:ÁÁ!Á$Åäð‘jÃ8ð‘Ȉð‘ŸpȘð‘c&ðÑð‘‰2à*É!á‡ð‘Ú¦ð‘Ð>ð‘ÿ¯Á&ò9­4¬Ðð]j­'¬Æð]ð‘ÁØð‘:ÁÁ!Á$Åäð‘jÃ8ð‘Ȉð‘ŸpȘð‘c&ð¯Ð.ð‘Ê(ö9À†ð‘†8á¥ð‘ʦð‘Áʶð‘À!á•ð‘(„¨á ð‘­#¬^ð]ð‘ðÑð‘ö1ÆÆð‘€¨á‹ð‘­%¬\ðð‘ðÑð‘ö1ÆÆð‘¿€¨ÆÖð‘ÇVð‘À1ɶð‘Ô–ð‘@¡ ð¦ð‘Ó¦ð‘ÄÓ¶ð‘Ú6ð‘ ð‘Á€Åâ 5á 5€7­%¬Òðð‘ðÑð‘ "1HÃ(ð‘Á$Åäð‘j4h ð‘åð‘à{ð‘Ê(ö9**€²vò#Ôð‘é¶ð‘ú6ð‘Á¦ð9Á€ð‘€°­¬Êñð‘ñ9À>ð‘ÿ¯Í𑄨€0@¡ °ÐÀð‘H¡ ­3¬ð]Àê…##ð¯À.ð‘ø1­'¬Æð]ð‘ÁØð‘:ÁÁ!Á$Åäð‘jÃ8ð‘Ȉð‘ŸpȘð‘c&­#¬^ð]ð‘ðÑð‘À†ð‘@€ À–ð‘ÁÆð‘€°­¬pñð‘ñ9À>ð‘ÿ¯Í𑄨€0@¡ °ÐÀð‘H¡ ­3¬ð]Àê…##ð¯À.ð‘ø1­'¬Æð]ð‘ÁØð‘:ÁÁ!Á$Åäð‘jÃ8ð‘Ȉð‘ŸpȘð‘c&­#¬^ð]ð‘ðÑð‘(ð€¨€„°­¬ ñð‘­'¬Æð]ð‘ÁØð‘:ÁÁ!Á$Åäð‘jÃ8ð‘Ȉð‘ŸpȘð‘c&ðÑð‘Á¦ð9Á€ð‘€°­¬\ñð‘ñ9À>ð‘ÿ¯Í𑄨€0@¡ °ÐÀð‘H¡ ­3¬ð]Àê…##ð¯À.ð‘ø1­'¬Æð]ð‘ÁØð‘:ÁÁ!Á$Åäð‘jÃ8ð‘Ȉð‘ŸpȘð‘c&­'¬Žðð‘,­¬.Àð‘„ð‘€0ÔÆð‘Õfð‘Í!ñjÁwÿÏ)Áwñð‘Àð‘€ ­¬ñð‘ÿÀ8ð‘иð‘À¤ð‘ÿðÅ)áð‘ÒØð‘Á¤ð‘Ìâ…ð‘j͸ð‘ D(„°áð‘ÁHð‘å¦ð‘öfð‘­4¬Øðð‘ðÑð‘Ê(ð‘@¡ €Ð ð‘Å#áð‘Å1áð‘ò1Á’ð‘­¬Æðð‘:Ó(ð‘Á#äÁ$Åäð‘j(Ó+‰2Áøð‘ã¨ð‘@¡˜ Àà0ð‘Ã(ð‘Á$Åäð‘jÑ­¬pð]ð‘­¬Æðð‘:Ó(ð‘Á#äÁ$Åäð‘j(Ó+‰2Áøð‘@Éäð‘jI#"1HÃ(ð‘Á$Åäð‘j4h ð‘åð‘à{ð‘Ê(ö9€0(@ˆ’âÁAĨð‘­¬Öðð‘@¡ PÐÀ ð‘¼hĨð‘ðð‘ÖÖÖvÖÖÖÖÖÖÖÖÖÖÖÖÖÖÖ@¡€  ²p"!0 ð‘Ã(ð‘PÁ$Åäð‘j"! 4h ð‘åð‘à{ð‘²p0Ôƒ"! ð‘A£¢€B¥€¤ ­¬ ð](Ĩð‘@¡Ž À(„°­¬vñ„°­¬,ñð‘Á&ò9Á¢ð‘Ï9­¬<ñ( „°­¬¨ñP„°­¬vñR„°­¬ìñ„°­¬ŠñÁð‘ ÁÐð‘,Âð‘ÂPð‘À0ð‘À°ð‘À1Á0ð‘àð‘À°ð‘À1Á0ð‘­¬Æðð‘B¥¤€²tQB"!0 ð‘ÔQ@"!0 ð‘0Ô…QB"! ð‘6ÔQ@"! ð‘A£¢À"ð‘ǰð‘À¢ð‘È0ð‘Á"ð‘Ȱð‘Á¢ð‘É0ð‘A£¢ê‰ð‘A£¢À"ð‘Űð‘À¢ð‘Æ0ð‘Á"ð‘Æ°ð‘Á¢ð‘Ç0ð‘&ÔQ@! Cð‘tÀ0ð‘­¬`ðð‘À0ð‘­¬`ðð‘A£¢ê‰ð‘A£¢À"ð‘°ð‘À¢ð‘Ã0ð‘Á"ð‘ðð‘Á¢ð‘Ä0ð‘A£€¢@ê‰ð‘A£€¢À1Á°ð‘ÐÂð‘Âpð‘À0ð‘À°ð‘À1Á0ð‘­¬nðð‘ÔQ@! Cð‘Àð‘ÀÐð‘Á0ð‘Áð‘!Âð‘ÅPð‘À0ð‘­¬Æðð‘À1Á°ð‘­¬ê‡ð‘­¬Ð ð‘Â0ð‘A£¢À"ð‘İð‘À¢ð‘Å0ð‘Á"ð‘Űð‘Á¢ð‘Æ0ð‘A£¢ê‰ð‘A£¢À"ð‘°ð‘À¢ð‘Ã0ð‘Á"ð‘ðð‘Á¢ð‘Ä0ð‘A£€¢@ê‰ð‘A£€¢À1ưð‘ÐÂð‘Ç0ð‘À0ð‘­¬`ðð‘­¬@ê‡ð‘­¬(À,ð‘Á°ð‘À¬ð‘Â0ð‘Á,ð‘°ð‘Á¬ð‘Ã0ð‘Â,ð‘ðð‘¬ð‘Ä0ð‘Ã,ð‘İð‘ìð‘Å0ð‘Ä,ð‘Űð‘Ĭð‘Æ0ð‘Å,ð‘Æ°ð‘Ŭð‘Ç0ð‘À0ð‘­¬`ðð‘:Ó(ð‘Á#äÁ$Åäð‘j(Ó+‰2Áøð‘ã¨ð‘)Â@¡˜ ÀÀ0ð‘Ã(ð‘Á$Åäð‘jÑ)^Ñ­¬pð]ð‘­¬Æðð‘#Q@@ÍâMK"1N4h ð‘åð‘à{ð‘²p"1N ð‘Éâ#ð‘áð‘Ñ@Á$Åäð‘j­¬tðð‘ðÑð‘­¬üð]ð‘(„¨á ð‘­#¬^ð]ð‘ðÑð‘Ê8ð‘ö1­¬Êð]ð‘.<ê…##Ê(ö9(€8À†ð‘á‰ïà€¨€ À–ð‘ñ7À>ð‘ÿ¯­'¬Æð]ð‘ÁØð‘:ÁÁ!Á$Åäð‘jÃ8ð‘Ȉð‘ŸpȘð‘c&ÁÆð‘€°­¬¢ñð‘Í𑄨€0@¡ °ÐÀð‘H¡ Ê5­3¬ð]Àê…##ð¯À.ð‘ö1ðÑð‘à†ð‘:á‹þ­]¬‚ðñ7‰+à–ð‘ðÑð‘­ ¬Úð]À1Å(ð‘Õ¨ð‘.Á(ð‘‚Å!-Díð‘r‰ªá…ð‘r,†,‡Ã¨ð‘רð‘Èä ð‘hÀ1.Ê5.Œ²xö#Äð‘..”²vÔƒ"$! ð‘ó7ðÑ-v´hB:Ó(ð‘Á#äÁ$Åäð‘j(Ó+‰2Áøð‘Ê(ö9Þ&ð‘ÀaÀaÄÞ6ð‘­ ¬ÊÁÈð‘‚8ñ"@´ð‘ÁØð‘:ÁÁ!Á$Åäð‘jÃ8ð‘Ȉð‘ŸpȘð‘c&ðÑð‘ÁØð‘:ÁÁ!Á$Åäð‘jÃ8ð‘Ȉð‘ŸpȘð‘c&­"¬Bð]vðÑð‘Ê(ö9:Ó(ð‘Á#äÁ$Åäð‘j(Ó+‰2Áøð‘@ÉäIK#"1HÃ(ð‘Á$Åäð‘j4h ð‘åð‘à{ð‘(@‰á…€0Nˆ’­!¬òÁAĨð‘­"¬8ðð‘@¡! ¦ÐÀ ð‘¼hĨð‘ðð‘"8"8"8!Ø!Ì"8"8"8"8"8"8"8"8"8"8"8"8"8"8(ˆ„:­"¬4ñð‘@¡€  ²p"!0 ð‘Ã(ð‘PÁ$Åäð‘j"! 4h ð‘åð‘à{ð‘²p0Ôƒ"! ð‘A£¢€B¥€¤ ­¬ ð]NĨð‘­¬Æðð‘ö1û¦ð‘Áwû¶ð‘ë&ð‘Ëà>ð‘ÿ¯Á¦ð9Á€ð‘€°­"¬Ìñð‘­"¬ÄÄFð‘‚8á‰ð‘Ê%ñð‘ÄFð‘€8ñþ€¨ÄVð‘ÁØð‘:ÁÁ!Á$Åäð‘jÃ8ð‘Ȉð‘ŸpȘð‘c&­#¬@ðð‘Ê%­#¬@ñð‘ñ9À>ð‘ÿ¯²vÔƒ"! ð‘Ȉð‘pȘð‘cð‘Í𑄨€0@¡ °ÐÀð‘H¡ nŸtáÀÁ­3¬ð]ð‘ê…##ð¯À.ð‘ø1­#¬Nðð‘Ȉð‘pȘð‘cð‘ð¯Ð.ð‘Å#áð‘ðÑð‘ÀÆð‘pÀÖð‘ÄFð‘€ ÄVð‘À1Ë6ð‘˶ð‘Äð‘€ ­'¬Žñð‘æÆð‘€:á…Ćð‘ð€¨À€°À†ð‘á‹ï8á‰3‰3€¨ À–ð‘Ćð‘„°áð‘ñ†ð‘ÅCA£$¢ÕƒÐ"ð‘¼jðð‘Á–ð‘@¡ €À ð‘ó7Á1á‡ð‘À0ð‘­'¬Fðð‘$$Œ%%2$Œ$RA£¢^À2ð‘Ôƒó7˜ÁÿÿÔð‘A£¢€Ð2ð‘@¡˜ Ààð‘ðÑð‘À1Ì6ð‘­'¬Žðð‘Ñ$ð‘Ä;áÀ1ÀÆð‘ŸpáÀ1É(ð‘Ì6ð‘ðÑð‘Ì6ð‘­'¬Žðð‘ÀÆð‘Ÿp­'¬ŽñÀ1ÆÆð‘߀¨€ ÆÖð‘Ćð‘"„°áŸA£Ž¢ÀÀ¢ð‘Å1á#Ô–ð‘àð‘„°­%¬ñÔ–ð‘A£¢À"ð‘¶ð‘À1öð‘T­%¬æ#ðð‘ðÑð‘ÆÆð‘„¨­'¬Žñð‘àÆð‘€:­'¬°ñ𑄨ñð‘­%¬\ðð‘ÆÆð‘„¨­'¬Žñð‘àÆð‘€:­%¬Šñ𑄨­'¬°ñð‘A£¢^À2ð‘Ôƒó7˜ÁÿÿÔð‘­'¬°ðð‘ÆÆð‘¿€¨ÆÖð‘ÇVð‘À1ɶð‘Ô–ð‘@¡ ðÁ ð‘öð‘Ê6ð‘ ð‘€Åâ Tá T€V¶ð‘A£˜¢À­%¬æ#ðð‘Á&ø9î†ð‘ƒ(áð‘ˆRç–ð‘È&ð‘ÁqÈ6ð‘à ð‘rî–ð‘ˆR°vÀ-@‰#,ƒÄ†ð‘€°á„±ƒ(¾áð‘Ø-ñ7-°rÑÓ¦ð‘Ñp@€0.Ò¦ð‘ÁÆð‘­8¬ð]ð‘ê…##ðÑð‘À1Ì6ð‘ÆÆð‘à†ð‘€8á‰ïàˆªˆ¢à–ð‘Á¦ð‘ÿßÀ+ò1À"ð‘Тð‘.Á(ð‘‚Å!-Díð‘r‰ªá…ð‘r,†,‡À1Þ&ð‘ÅCÁIÅCÁIã&ð‘ó¦ð‘ÍÈäð‘.Ê5.Œ²vò#Äð‘..”²vÔƒ"$! ð‘.<Ψð‘-"­'¬Žðð‘À1Ì6ð‘À†ð‘†8á‹ð‘­^¬Ðð]"Í𑄨€0@¡ °ÐÀð‘H¡ ­3¬Ìð]ð‘Ψð‘À!á‹ð‘­^¬Ðð]#ßqθð‘­]¬‚ðñ7ðÑð‘Á†ð‘‰0á À1@¡ €À0ð‘Á¶ð‘­]¬‚ðñ7ðÑð‘Ȉð‘pȘð‘cð‘ðÑð‘çð‘à{ð‘:Å3.(À1.,-4'´-r),).)*)2À!á)4À!áð1)*ß ð‘Åß°ð‘ß ð‘À{ß0ð‘ € á‹A­^¬Ðð]0²4°rÀ1-6-0"(! ð‘ðÑbà 42É1áò3â¢ð‘Ê%ˆsᇈsàmð‘€0òð‘ðÑð‘D©€¨@à D©€¨ 02Ñ1á‡@ðÑð‘°h ð‘À!ዼh­(¬xðbȈ𑀠á Â𑈰Á ð‘Á ð‘À ð‘à ð‘À!á#ò1À ð‘ï¢ð‘Èï²ð‘ï"ð‘Èï2ð‘à ð‘ã ð‘ð]ð‘­(¬xðb­ ¬4)PÀ<ð‘D©€¨@à ­ ¬0)`À<ð‘D©€¨ 'jkË8ð‘<˸𑭊¬ºð]ð‘­E¬`ð]ð‘ðÑð‘D©€¨@à D©€¨ ˨ð‘Û(ð‘ßqá'âßsÛ8ð‘˸ð‘ðÑ'˸ð‘Å#áð‘ðÑ'­*¬šÏ𑄨ñð‘p€¨€°á“ð‘­(¬òúð‘­)¬ðð‘ʘð‘˸ð‘j€klm­ ¬0ê*À<ð‘ðÑ'*Á<ð‘ðÑ'D©€¨@à D©€¨  ‚8á ð‘­)¬”ðð‘ʘð‘˸ð‘jk'­ ¬0ê*pÀ<ð‘ðÑð‘*`Á<ð‘ðÑð‘D©€¨@à D©€¨  ‚8á ð‘­)¬”ðð‘˨ð‘ßq˸ð‘á'ðÑ'˸ð‘jk'Ï𑄨ဨ HHS­ ¬Òð]ð‘ H­ ¬0ê+À<ð‘ðÑð‘*ðÁ<ð‘ðÑð‘D©€¨@à D©€¨ Ï𑄨á—ð‘ „¨áð‘@¡) ”ðð‘˨ð‘ßq˸ð‘á'ðÑ'ʘð‘˸ð‘Ï𑄨ဨ HHS­ ¬Òð]ð‘ H ^ X­ ¬Òð]ð‘ X­ ¬Òð]ð‘ X­ ¬Òð]ð‘­ ¬0ê+ÐÀ<ð‘ðÑ'+ÀÁ<ð‘ðÑ'D©€¨@à D©€¨ Ï𑄨á—ð‘ „¨áð‘@¡) ”ðð‘˨ð‘ßq˸ð‘á'ðÑ'­/¬pð]ð‘& ^˸ð‘ʘ𑭠¬0ê,`À<ð‘ðÑ',PÁ<ð‘ðÑ'D©€¨@à D©€¨ Ï𑄨á—ð‘ „¨à ð‘@¡) ”ðð‘"Â9­,¬¸ñ'HI­ ¬Òð]ð‘"˨ð‘ßq˸ð‘­)¬”ñð‘ðÑ'ʘð‘­E¬Šðð‘"HIü­ ¬Òð]ð‘"À1Â8ð‘ÈØð‘Ï𑄨Àüáð‘üzh ʘð‘Á˜ð‘­-¬¬ð]ð‘&l€m­ ¬0ê-PÀ<ð‘ðÑ'-@Á<ð‘ðÑ'D©€¨@à D©€¨ Ï𑄨püáð‘ü H€P"ˆ"Â(ð‘Æ+Á1­/¬4ñð‘ðÑð‘HI­1¬°ð]ð‘Â(ð‘"ôÆ+Å1ðÑð‘Á1áð‘­­¬þð]ð‘ðÑð‘­­¬œð]ð‘ðÑð‘À9á!D©€¨À>ð‘ÿ¯Áˆð‘H­.¬ð] ð¯À.ð‘Á9áD©€¨@Áˆð‘H­.¬ð] ðÑð‘­¬TÀ,ð‘ÁqÀ<ð‘Á˜ð‘ʘð‘­L¬Tð]ð‘êð‘­)¬ð]ð‘à ­(¬òð]ð‘­Š¬ºð]ð‘­/¬pð]ð‘ X­ ¬Òð]ð‘& ^‚0­.¬ºñð‘­-¬¬ð]ð‘­9¬Ìð]ð‘­:¬îð]ð‘­0¬ð]ð‘ ‚8áð‘­1¬°ð]ð‘àð‘&ÈØð‘à ð‘­9¬Ìð]ð‘ X­ ¬Òð]ð‘ ÷ ÷ Y­ ¬Òð]ð‘­ ¬Òð]ð‘ Y­ ¬Òð]ð‘ \ ]Ï𑄨ဨ HHS­ ¬Òð]ð‘ H X­ ¬Òð]ð‘ðÑð‘&< HÂ;á‹Ã;­-¬Šñð‘Ò8ð‘Áˆð‘€ áð‘­.¬ð]hðÑð‘­)¬”ðð‘ðÑð‘­/¬æð]ð‘ ^c­ ¬Òð]ð‘c­ ¬Òð]ð‘HÿIÿc­ ¬Òð]ð‘c ^Ó8ð‘Șð‘ÁØð‘€0ÂØð‘ \É8ð‘ɸð‘&ðð‘­‹¬4ð]ð‘­1¬,ðð‘p€¨€°­0¬þñð‘ ‚8­1¬8ñð‘ÏHð‘„8áŸp„¨­1¬$ñH€0ßXð‘­1¬>ðð‘ÏHð‘†8áBŸp„¨­1¬$ñH€0ßXð‘­1¬>ðð‘­Š¬èð]ð‘Áˆð‘­.¬ð]hßXð‘ðÑð‘D©€¨@à D©€¨ ­1¬¬Ïð‘‡8ñ„¨ñð‘„8ñð‘Áˆð‘„°ñð‘Ϩð‘À!á‹ð‘úàð‘ßqϸð‘}ÁâÏ𑀨 HSðÑð‘¡ @ê‡@¡ (ÐÀ ð‘Рð‘ÁsÀyÀ0ð‘аð‘ðÑð‘ðÑð‘@¡ Àà @¡ € È ð‘Ê ð‘À!­2¬`ñð‘(вpQ@ÄñÀóð‘ô1Ç$ð‘À!á À1Ç4ð‘à ð‘ñ5­\¬ ð]AÆ$ð‘À!á ¼hƤð‘ð]ð‘­1¬ø¡ Àú@¡ €ðð‘È ð‘À!­2¬´ñð‘B¥¤(À$ð‘Åò вpQ@ÄñÀóÀ ð‘ßqá“ð‘ð‘­\¬ ð]Aàð‘Á­\¬ð]ð‘ÂðÑa )n°j)ePKŸqä9Ÿpäò!-0²p"8! ð‘@,åpðÑ-nߤð‘ô3°tÅ#á Ìñà[-0­^¬Ðð]£­^¬Ðð]¤#-p-A£¢(à"ð‘Âä ð‘­^¬Ðð]¢²vÔƒ" ! ð‘,à-öÏ7-ô-À-Ü-Ì-Î,,,†°v@ÐÇ ð‘À!á­[¬Dð]Aà€ñ7-)À!áð‘,Ç À-@,²p"!8 ð‘²pÁ&ú9Ï*ð9Áñ3²pºpñ!Ð ð‘ð#ô#Å#á“ñ;ߪð‘²jA°rñ!ÂðÑð‘#,†-p-²vÔƒ" ! ð‘„, ,)ÿÿ-2À1-4-6,(-.--A£¢*Ȧð‘Á2ð‘ €. rA€0.$,°v@ÐÇ ð‘À!á­[¬Dð]Aà€ñ7-)À!áð‘,Ç À-î†ð‘rî–ð‘ˆR@ ,²p"!8 ð‘²pÁ&ð9Áñ3²pºpñ!Ð ð‘ð#ô#Å#á“ñ;ߪð‘²jA°rñ!Âʶð‘(€°á‹ð‘­8¬Òð]ð‘ðÑð‘ðÑð‘ðÑð‘ðÑð‘ðÑð‘  ԃ؅€Àð‘Ðð‘‰(‰)­5¬\ñð‘ñ3À>ð‘ÿ¯­5¬¼ð]ð‘Á¤ð‘Åäð‘°ð‘¤ð‘Ã0ð‘ð¯À.ð‘ò1Á ð‘Ï9á¥ð‘€Á!Á°ð‘ñ3À>ð‘ÿ¯­5¬rð]ð‘ð¯À.ð‘ò1ԃ؅t­4¬äõð‘ðÑð‘LêCA£¢à ‰2A£¢‰2ÕƒÀ"ð‘À!á‹ò1ðÑÐ!‹¶‰5+‰2ÅCÕƒÀ"ð‘À°ð‘À2ù1ðÑÀ1LêCA£¢à ‰2A£¢‰2ÕƒÀ"ð‘À!á‹ò1ðÑÀ!‹¶‰5+‰2ÅCÕƒÀ"ð‘À!­6¬0ñð1­6¬$Î ð‘Þ ð‘Ç3ñ†±ñð‘ñ1Ò ð‘ðÑÀ1À ð‘­5¬üðÀ!­[¬Dð]AዺpðÑð‘²z!@ Cð‘­[¬Dð]Aá²p­\¬ ð]Aà[ð‘Â:ð‘!@ Cð‘ÿÿÀ0ð‘À°ð‘Á0ð‘Á°ð‘Â0ð‘°ð‘Ã0ð‘ðð‘Ä0ð‘İð‘Å0ð‘Űð‘Æ0ð‘Æ°ð‘Ç0ð‘ǰð‘D©€¨@ê‰ð‘D©€¨ÊÈð‘@€°áð‘Áºð‘OÐÈð‘úð‘€0MÎ:ð‘þºð‘„ºð‘Ã:ð‘Èê‡ð‘ˆÏºð‘LŸpá-Ÿpá)Ÿp­7¬Ðñð‘Â*ð‘­\¬ ð]Añ;­\¬ ð]AðÑÐ1­[¬Dð]AᡲpÂ*ð‘­\¬ ð]Añ;­\¬ ð]AðÑÐ1Ï:ð‘!@ Cð‘Áªð‘Á!Áºð‘D©€¨@ê‰ð‘D©€¨ÊÈð‘@€°áÀ1OÐÈð‘ðð‘Á°ð‘Â*ð‘Â0ð‘Ï0ù;Àê‡ð‘€Ï°ð‘°zðÑÀ1°zðÑÀ1Ï$ð‘À!á ð‘­\¬ ð]AÂ$ð‘­\¬ ð]Añ5­\¬ ð]AðÑð‘,€. ñ7-À!á°v@ÐÇ ð‘À!áñ1À1-­[¬Dð]A€)À!áÀ1,Ç---ñ7À!á N,²p"! ð‘²p°xÁñ3²pºpñ!Ð ð‘ð#ô#Å#á“ñ;ߪð‘²jA°rñ!Âñ7À!á‡ð‘ðÑð‘ÁÆð‘€°á(„¨á ð‘ʦð‘Áqʶð‘à𑄨á‹ð‘­8¬Òð]ð‘ðÑð‘ÀÆð‘pÀÖð‘ÄFð‘€ ÄVð‘À1Ë6ð‘Ë¶ð‘æÆð‘€:á…À†ð‘ À–ð‘†8áð‘Ì6ð‘ðÑð‘ñ†ð‘ÅCA£9¢8ÕƒÐ"ð‘¼jðð‘9¦9D9Z9|9D9¢ÀÆð‘Ÿp­9¬¬ñÀ1Ì6ð‘ðÑð‘ÆÆð‘„¨­9¬¬ñð‘àÆð‘€:­'¬°ñð‘ðð‘ÆÆð‘„¨­9¬¬ñð‘àÆð‘€:­%¬Šñð‘­9¬¦ðð‘ðÑð‘ðÑð‘ö1À†ð‘D©€¨@…8á‹ D©€¨ ­'¬Žð𑥤Àê‡B¥¤€ÁÑ…PB²pQ@ÄñÀóÀ ð‘À!á•ð‘Äâãð‘­:¬Šðð‘ñ5À>ð‘ÿ¯Ð>ð‘ÿ¯ð‘ô1 °tPB²pQ@ÄñÔƒÕƒÀ ð‘À!áð‘À"ð‘À!á§ð‘Ä­:¬òð‘ð¯Ð.ð‘ð¯À.ð‘ô1­9¬Þðð‘ð‘ð1Ç ð‘À!áð‘ñ1­\¬ ð]A­:¬ðð‘¡ Àê‡@¡ €Ê ð‘À!­:¬èñð‘(вpQ@ÄñÀóð‘ô1Ç$ð‘À!á À1Ç4ð‘à ð‘ñ5­\¬ ð]A­:¬–¡ Àú@¡ €ðð‘ÂðÑð‘@¡ ê‰ð‘@¡ Q@ÕÀ"ð‘À!áò1ßsßsáíð‘ðÑð‘Ð>ð‘ÿ¯ À"ð‘À!á7ô1À¤ð‘À2ð‘rÀ>ð‘ÿ¯AÀ>ð‘ÿ¯­7¬Öð]ð‘ð¯À.ð‘QHð¯À.ð‘²hàEð‘ð£ßs­;¬&ñð‘ð¯Ð.ð‘@¡ ê‰ð‘@¡ ­;¬ðð‘A£¢!@ Cð‘A£¢!@ Cð‘A£¢P!@ Cð‘A£¢Ð!@ Cð‘A£¢À1Å3QÔð‘A£¢À1Å3‘ÑÔð‘ðÑð‘}@¡; ðÀ0ð‘ T@¡; îÀ0ð‘ðÑð‘@¡; îÀ ð‘ßq T­=¬Rñð‘À0ð‘@¡ Àð‘€ ­<¬Àñð‘­0¬Lð]ð‘­0¬Bð]ð‘­1¬Lð]ð‘­1¬Bð]ð‘A£¢"@¡# aÀ𑀨á·ú@¡€ Á€ð‘@¡€ @р𑈠áúˆ¨á“úÐ"ð‘ßs­=¬ñð‘Ð2ð‘@¡€ ÈÀð‘€ áð‘ŸpÈÐð‘€ á‘ð‘ ­1¬°ð]ð‘@¡€ @ÈÀð‘€ áð‘ŸpÈÐð‘€ á‘ð‘ ­1¬°ð]ð‘ðÑð‘@¡  ­i¬jð]ð‘©€¨­.¬ð]D ©€¨@­.¬ð]DA£¢"úÐ2ð‘ðÑð‘A£;¢ðÀ"ð‘@¡; îÀ0ð‘­ü¬6ð]ð‘­½¬¶ð]ð‘@¡@ XÀ ð‘ßqÀ0ð‘á“ð‘À0ð‘­¬¬˜ð]ð‘B¥ö¤€€À„ð‘ „¨á3ð‘Ü$ð‘Å#ዃ8á%ð‘à9ð‘ßsÜ4ð‘á—ƒ8᫆8­>¬Nñð‘­>¬žðð‘ßwáÚ…­=¬¨ñBpðRHðÑð‘D©€¨À„ð‘H…8á D©€¨@ Ψð‘À!á‹ð‘­^¬Ðð]#ßqθð‘ñ5À>ð‘ÿ¯­]¬‚ð]ð‘ð¯À.ð‘ô1­=¬äðð‘@¡ RÀ ð‘ÁqÀ0ð‘ñ5À>ð‘ÿ¯à>ð‘ÿ¯ð>ð‘ÿ¯­]¬Èð]´tð¯ð.ð‘ð¯à.ð‘ð¯À.ð‘ô1­=¬äðð‘D©€¨À„ð‘H…8á D©€¨@ Ψð‘À!á‹ð‘­^¬Ðð]#ßqθð‘ñ5À>ð‘ÿ¯à>ð‘ÿ¯ð>ð‘ÿ¯À>ð‘ÿ¯Á¤ö9ÏFð‘ „°1áÀ12­]¬Èð]´tð¯À.ð‘­]¬‚ð]ð‘ð¯ð.ð‘ð¯à.ð‘ð¯À.ð‘ô1­=¬äðð‘À>ð‘ÿ¯­?¬@Ÿpñð‘ð¯À.ð‘ðÑð‘­?¬4ð]ð‘­?¬4ð]ð‘­?¬4ð]ð‘­?¬4ð]ð‘­?¬4ð]ð‘ðÑð‘­?¬Pð]ð‘­?¬Pð]ð‘­?¬Pð]ð‘­?¬Pð]ð‘­?¬Pð]ð‘ðÑð‘À>ð‘ÿ¯Ð>ð‘ÿ¯èè­?¬4ð]ð‘ßqáõð‘ßsáëð‘ð¯Ð.ð‘ð¯À.ð‘ðÑð‘À>ð‘ÿ¯Ð>ð‘ÿ¯èè­?¬Pð]ð‘ßqáõð‘ßsáëð‘ð¯Ð.ð‘ð¯À.ð‘ðÑð‘ _  B¥¤ ^c­ ¬Òð]ð‘c­ ¬Òð]ð‘HÿIÿc­ ¬Òð]ð‘c­ ¬Òð]ð‘b D ^@¡@ &&B¥¤õ‘  @¡€ À0ð‘ð¡åùð‘A£€¢Á2ð‘Ñ’ð‘Ê’ð‘ÊÒð‘É2ð‘ɲð‘Ó2ð‘È’ð‘Ïð‘€ Ïð‘ @¡€ @À0ð‘ð¡åùð‘A£€¢@Á2ð‘Ñ’ð‘Ê’ð‘ÊÒð‘É2ð‘ɲð‘Ó2ð‘È’ð‘Ïð‘€ Ïð‘­)¬ð]ð‘­(¬òð]ð‘ðÑð‘@¡€ ­A¬nð] @¡€ @­A¬nð] ­;¬Žð]ð‘ðÑð‘ ¨Z­ ¬Òð]ð‘ (Z X­ ¬Òð]ð‘­ ¬Òð]ð‘Ï𑄨ဨ HS X­ ¬Òð]ð‘ ÷ ÷ Y­ ¬Òð]ð‘­ ¬Òð]ð‘ Y­ ¬Òð]ð‘ \ ] X­ ¬Òð]ð‘­ ¬Òð]ð‘ •µµHI Y­ ¬Òð]ð‘ ­ ¬Òð]ð‘a ­¬Àê‡À1­¬€À<ð‘åûð­ðÑð‘B@BðC DP"ïï8ÿÿÿÿTPTP@¡4 ,Àð‘H @¡ |åÿБ БÀð‘­¬Àð‘БÀð‘­¬Àð‘ðÑð‘­L¬Tð]ð‘no­ ¬8êF À<ð‘ðÑð‘F°Á<ð‘ðÑð‘ ÷ ÷ ­L¬Tð]ð‘ ^& ­ ¬Òð]ð‘Ñ˸ð‘nojklm­ ¬0E« ª8ê•FÀ<ð‘F À:ð‘ðÑ'FÁ<ð‘F°Á:ð‘ðÑ'D©€¨à D©€¨@ "<&<­F¬Ï𑄨áð‘ H‰(ñð‘"Å)ñð‘­W¬Î&<È9ñ'­W¬Þ"È9ñ'˨ð‘ßq˸ð‘áð‘ðÑ'ÊÈð‘„°á ð‘­W¬¶ð'­W¬¶ð'­W¬¶ð'D©€¨à D©€¨@  ^& ÷ ÷ Y­ ¬Òð]ð‘ ­ ¬Òð]ð‘­ ¬Òð]ð‘­ ¬Òð]ð‘ Yno' ÊØð‘Èð‘pÈð‘€ ­Y¬ñð‘àð‘"&<É9­G¬ñð‘ÊØð‘¶Ë¸ð‘jklmno­ ¬0êð‘G`À<ð‘ðÑ'GpÁ<ð‘ðÑ'D©€¨à D©€¨@ '"Â9­G¬¢ñð‘È9­G¬ªñð‘˨ð‘ßq˸ð‘áð‘ðÑ'­W¬¶ðð‘"Â9á‘ð‘È9áð‘­W¬Þðð‘­W¬¶ðð‘Ï𑄨Áüáð‘üzhl€m'no­ ¬8E« ª0ê—ð‘H0À<ð‘FÀ:ð‘àð‘H@Á<ð‘FÁ:ð‘Ñ˸ð‘' ðÑð‘D©€¨à D©€¨@ "­W¬¶Â9ñð‘­F¬¸&<È9ñð‘)ÊØð‘ÈHð‘pÈXð‘€ ­Y¬ñð‘LPÄ8ð‘­/¬pð]ð‘ ­D¬úê‡ð‘­D¬öÀ,ú9À¬ô9Op­E¬ê‡ð‘­E¬À<ð‘­V¬ð]ð‘ À4ð‘À”ð‘°tñ¡­E¬ ²|Äð‘¼r²pÔð‘åñ°rÇ´ð‘À1È4ð‘°t"ÐA£¢ê‰ð‘A£¢Äð‘²pÔð‘n ojk­ ¬8êI À<ð‘à ð‘I°Á<ð‘­E¬ê‡ð‘­D¬þÀ,ð‘À!á¯ð1|À>ð‘ÿ¯ï­6¬0ð]ð‘ð¯À.ð‘¼hÀ<ù1Ѱð‘Àð‘ï„°á‹ð‘­T¬|ðð‘­^¬Ðð]aD©€¨à D©€¨@ ­W¬Î&<È9ñð‘HI9ÊØð‘P`­E¬ê‡ð‘­E¬À<ð‘nojk­W¬òð]ð‘­ ¬8êð‘K`À<ð‘à KpÁ<ð‘èÿð‘ðð ”HI Y­ ¬Òð]ð‘ ÷ ÷ðÑð‘D©€¨à D©€¨@ ­W¬Î&<È9ñð‘­D¬úê‡ð‘­D¬öÀ,ú9À¬ô9HI Y­ ¬Òð]ð‘ ÷ ÷­W¬òð]ð‘R­E¬ê‡ð‘­E¬À<ð‘nojk­ ¬8êK`À<ð‘à ð‘KpÁ<ð‘À4ð‘À”ð‘°tñ¡­E¬ ²|Äð‘¼r²pÔð‘åñ°rÇ´ð‘À1È4ð‘°t"ÐÀ1Å3Ê5Ï7 ²pÔð‘åûð‘­¬ê‡ð‘­¬ð ð‘­V¬†ð]ð‘L×Q@MÐð‘ÿÀ8ð‘иð‘­T¬|ðð‘D©€¨à D©€¨@ ­W¬Î&<È9ñ'ÊØð‘ ÷ ÷ ­V¬Lð]ð‘­E¬ê‡ð‘­D¬þÀ,ô9À1À<ð‘­7¬Öð]ð‘­X¬Xð]ð‘no­ ¬8êL À<ð‘à ð‘LÁ<ð‘€0Èð‘ÈXð‘­,¬Æðð‘D©€¨@­ ¬8F°Á<ð‘à! D©€¨­ ¬8F À<ð‘ "&<Áˆð‘­M¬ð]H­W¬Îðð‘ðÑð‘ÊØð‘À1Î8ð‘À8ð‘þÀ¸ð‘ðÑð‘­E¬Šð]ð‘Á˜ð‘ʘð‘­L¬Tð]ð‘­Š¬ºð]ð‘­/¬pð]ð‘ X­ ¬Òð]ð‘ X­ ¬Òð]ð‘ \ ] X­ ¬Òð]ð‘& ^‚0á«ð‘­-¬¬ð]ð‘­9¬Ìð]ð‘­:¬îð]ð‘­0¬ð]ð‘à ð‘­9¬Ìð]ð‘ðÑð‘Á˜ð‘ʘð‘­L¬Tð]ð‘­Š¬ºð]ð‘­/¬pð]ð‘& ^‚0á«ð‘­-¬¬ð]ð‘­9¬Ìð]ð‘­:¬îð]ð‘­0¬ð]ð‘à ð‘­9¬Ìð]ð‘ðÑð‘D©€¨@­D¬ú#à D©€¨­D¬ö# À,ú9 ÿçð‘åûð‘ç ð‘­^¬Ðð]b­N¬Nùð‘&<€Å)­N¬rñð‘€0 …)…A@¡M ÞÐÀ ð‘¼hðð‘NrNrNrMîMîNrMîNrÁØð‘°z­U¬ð]ð‘­'¬Æð]ð‘ÁØð‘:ÁÁ!Á$Åäð‘jÃ8ð‘Ȉð‘ŸpȘð‘c&­E¬ê‡ð‘­E¬À,ð9ðð‘ ":"!4h ð‘åð‘à{ð‘*­W¬¶ðð‘­'¬Æð]ð‘ÁØð‘:ÁÁ!Á$Åäð‘jÃ8ð‘Ȉð‘ŸpȘð‘c&ðÑð‘@¡ Àà @¡ € &< Å)á ð‘ ^&&<"Ê ð‘À!­O¬^ñð‘(вpQ@ÄñÀóð‘ð‘ð‘ô1Ç$ð‘À!á À1Ç4ð‘à ð‘ñ5­\¬ ð]AÆ$ð‘À!á ð‘¼hƤð‘ð]ð‘¡ Àê‡@¡ €Ê ð‘À!á…ð‘a ðÑð‘­D¬úê‡ð‘­D¬öA£P¢B¥P¤ @¡P LÀ,ú9Ǫð‘Ä3ñ‘ð‘ÃJð‘ÒJð‘„°ñ‘€ ññ‘"¶z܇­¬ê‡ð‘­¬ Á¦ð‘Ѭð‘ÁÁ&ð‘Ñ,ð‘ÁÀ¦ð‘Ьð‘ÁÀ&ð‘Ð,ð‘Áóð‘òð‘ ðÑð‘­T¬Tðð‘9ÊØð‘èÿð‘­ ¬8êJ@À<ð‘à ð‘JPÁ<ð‘  ”ððHI YðÑð‘­W¬Þðð‘­D¬úê‡ð‘­D¬öÀ,ú9@¡Q ðǪð‘ÅôÄô€0À@¡P °ÐÀ ü9@¡T .ðð‘QðPÀPàQQ Q@Q€­S¬˜ð]ð‘Ǻð‘È:ð‘ðð‘­S¬¤ð]ð‘Ǻð‘È:ð‘ðð‘­S¬¶ð]ð‘Ǻð‘È:ð‘ðð‘­S¬üð]ð‘ÀÈð‘HǺð‘ðð‘²z"ԃ؊ð‘qØšð‘€0ÔƒÀÈð‘Àð‘Ǻð‘È:ð‘ðð‘²z"ÀƒÎ8ð‘pÀ>ð‘ÿ¯@À>ð‘ÿ¯Î(ð‘°h@Ðð‘@¡ ê‰ð‘@¡ à²h­i¬jð]ð‘ð¯À.ð‘PHð¯À.ð‘°hǺð‘È:ð‘ðð‘­W¬Þðð‘­D¬úê‡ð‘­D¬öÀ,ú9@¡S Çªð‘ÅôÄô€0À@¡R PÐÀ ü9@¡T .ðð‘SR`R€R RÐS S@­S¬¤ð]ð‘Ǻð‘È:ð‘ðð‘­S¬¶ð]ð‘Ǻð‘È:ð‘ðð‘­S¬üð]ð‘ÀÈð‘HǺð‘È:ð‘ðð‘­S¬Lðð‘È*ð‘Ÿpáíð‘„À:ð‘²z"Ôƒÿÿhhh Ôð‘åûð‘ÐÈð‘Ⱥð‘Ǻð‘È:ð‘ðð‘Ǻð‘È:ð‘ðð‘²z"ÀƒÎ8𑵵 …HI YÎ(ð‘°h@Ðð‘@¡ ê‰ð‘@¡ à²h­i¬jð]ð‘ðÑð‘­W¬Þðð‘À(ð‘Шð‘ðÑð‘À(ð‘Ш𑀠áƒð‘ðÑð‘À(ð‘Ш𑀠á·ð‘­¬ê‡ð‘­¬ð ð‘­V¬†ð]ð‘€ áð‘­V¬æð]ð‘€ á ð‘À8ð‘иð‘ðÑð‘À(ð‘Ш𑀠á£ð‘þ­W¬ð]ð‘€ áð‘­V¬æð]ð‘À8ð‘иð‘ðÑð‘­T¬Tð]ð‘­T¬|ð]ð‘ðÑð‘àð‘èÿð‘­D¬úê‡ð‘­D¬öÀ,ð‘Ьð‘Ð<ð‘À¼ð‘ ðÑð‘F­D¬üê‰ð‘F­D¬øÀ,ô9tǤð‘À1ö1#°tñ¡p@,C-D°t÷¡p@.ÊÈð‘)„°Tðáð‘À1-À„ð‘Ð$ð‘­E¬ê‡ð‘­D¬þaÀ,ø9­8¬ð]ð‘ðÑð‘D©€¨@ê‰ð‘D©€¨ÊÈð‘)„°­T¬|ñð‘ðÑð‘ñ1À>ð‘ÿ¯Ã(ð‘"!4h ð‘åð‘à{ð‘::Ó(ð‘Á#äÁ$Åäð‘j(Ó+‰2Áøð‘„Åäð‘„hÀ0ð‘ð¡²p"! ð‘Ê%­U¬ìñð‘°rÃ(ð‘Á$Åäð‘j@Š”Läð‘M"1J4h ð‘åð‘à{ð‘²p"1J ð‘@Á$Åäð‘j@Ñ–â ð‘­U¬ ñð‘ð¯À.ð‘ò1À‚𑄨€0@¡ °ÐÀð‘À’ð‘ðÑð‘­ ¬E« ª@ ]ê—ð‘M€À<ð‘NÐÀ:ð‘ðÑ&MpÁ<ð‘NÀÁ:ð‘ðÑ&­ ¬E« ª@ ]ê—ð‘  À<ð‘1ðÀ:ð‘ðÑ& Á<ð‘1àÁ:ð‘ðÑ&þ„³áð‘KA£¢Þ¶r ~à𑌲áð‘Áóåóð‘À1þÊ5à/ð‘vÉ“Mt–¬Ÿuà>ð‘Mä €”eåýð‘dddÅ3IÀ1ÿðÑð‘²z"׃L׃Ð𑊩ᑆ¡Ðð‘ÿðÑð‘ðÑð‘ ²z"׃Ð"ð‘Ð>ð‘ÿ¯ÀÆ#Ð2ð‘rÐ>ð‘Ð"ð‘Ásáð‘Ð"ð‘ráŸð‘Áóàð‘ð£åãð‘þà;ð‘Ð.ð‘Å“K€à𑳉Bâ‹ð‘”esàuð‘L‹B‚ŸsA£¢ÞÕƒðð‘ÿð.ð‘¼nð¯ð.ð‘ð<ð‘ðÑð‘­X¬Xð]ð‘Áˆð‘­.¬ð]HðÑð‘­X¬Xð]ð‘­F¬¸ðð‘­X¬Xð]ð‘­E¬Šð]ð‘ðÑð‘æ‡ð‘ðÑð‘ ÿçð‘åûð‘çð‘­^¬Ðð]eàeð‘­'¬Æð]ð‘ÁØð‘:ÁÁ!Á$Åäð‘jÃ8ð‘Ȉð‘ŸpȘð‘c&­W¬òðð‘¡ Àê‡@¡ €pÊ ð‘À!­X¬¸ñð‘(вpQ@ÄñÀóð‘ô1Ç$ð‘À!á À1Ç4ð‘à ð‘ñ5­\¬ ð]A­X¬d¡ Àú@¡ €ðð‘pÈ ð‘À!­X¬üñð‘ вpQ@ÄñÀóÀ ð‘ßqá“ð‘ð‘­\¬ ð]Aàð‘Á­\¬ð]ð‘ÂðÑð‘@¡A ‰Àð‘€ á ð‘­«¬äðð‘@¡ À­i¬jð]ð‘@¡# aÀ𑀨áð‘À1Èð‘ÈXð‘­W¬¶ðð‘ D©€¨À1Èð‘ÈXð‘Ï𑄨á™ð‘@¡ ­i¬jð]ð‘­Š¬èð]ð‘­X¬Xð]ð‘­.¬ð]ð‘ D©€¨@À1Èð‘ÈXð‘Ï𑄨á™ð‘@¡ ­i¬jð]ð‘­Š¬èð]ð‘­X¬Xð]ð‘­.¬ð]ð‘ðÑð‘D©€¨@à D©€¨ &< H" ߀¨„¨­Z¬@ñ𑄨áð‘&<Å)­Z¬Îñð‘Áˆð‘­.¬ð]HðÑð‘焨„¡­Z¬Æñð‘ð„¨„¡ñð‘ʈð‘H­Z¬ª„°ñ„°ñ„°ñ„°ñð‘"Å)ñð‘ÊÈð‘­W¬¶„°ñð‘Áˆð‘­.¬ð]HðÑð‘ À­ ¬Òð]ð‘­ ¬Òð]ð‘ ðÑð‘­^¬Ðð]Q ^­ ¬Òð]ð‘ ^æ‡ð‘ðÑ& ÿçð‘åûð‘çð‘àmð‘: ­'¬Æð]ð‘ÁØð‘:ÁÁ!Á$Åäð‘jÃ8ð‘Ȉð‘ŸpȘð‘c&­Z¬Þðð‘A¢$£À"ð‘À!á‹ð1­[¬jðð‘@¡ (ð‘ð1ðÑÀ!þ/²~ð£Ôð‘@ABCDEFþ/²~ð£Ôð‘tvxzþ/²~ð£Ôð‘|À>ð‘ÿ/À¾ð‘­1¬Öð]ð‘­1¬àê‡ð‘­1¬ðð]ð‘ñ/À.ð‘¼h²~ð£Äð‘ò/´h¶j¸lºn²~ð£Äð‘ò/PHQIRJSKTLUMVN²~ð£Äð‘ò/­[¬DðAA¢$£@¡ (ð‘ðÑð‘B¥¤(À$ð‘Ð ð‘ÁÀ4ð‘Å3Ð0ð‘@¡ &À ô9À"ð‘À¢ð‘À0ð‘ð1Ð0ð‘ñ5À!À"ð‘á‘ð‘@¡ $À0ð‘àð‘À4ð‘Ð2ð‘вð‘ðÑð‘@¡æ €@@Q@²p!@ Cð‘ßsáÒáñ@pPHàiQ@@@¡æ €A£¢(ð2ð‘A£¢$nÁqÒ‘â‰ð‘@ŸrPJßqáÒâ‰ð‘@rPJÀ2ù1àk²pÀ1À2ð‘@¡ &À0ù3ðÑð‘öþ€A£ö¢€@¡\ þÀ0ù3À1°rPAßwáÖƒá‡ArQJÀ0ù3Àð‘ài°rPA²pQ@À0ð‘Àð‘@¡] À0ù3ðÑð‘A£\¢þÀ"ð‘À!á‡ð1ðÑð‘@¡] ð‘ð1àð‘ðÑð‘ð1Á ô9Å3àð‘@¡] A£\¢þð‘­]¬Àñ5À!ñð‘Á¤ð‘€Å)ñð‘­7¬Öð]ð‘ðÑð‘@¡] ÄÀ0ð‘аð‘ñ5D©€¨À„ð‘H…8á D©€¨@ À„ð‘†8á• €¨€ À”ð‘É(ð‘Ì4ð‘Á¤ð‘À!­^¬rñö1ó5Ð>ð‘ÿ¯#Ô…"$! ð‘ð¯À.ð‘ô1̤ð‘À!á/ö1ÿð‘²vŸsá ð‘À¢ò9àuð‘Ï¢ð‘Ì´ð‘À1ϲð‘@¡^ ðð‘ðÑð‘ðÑð‘ðÑð‘ðÑð‘  À2ð‘:À²ð‘cåïÄóðÑð‘ ò5n"!@4h ð‘åð‘à{ð‘"!@ ð‘@ÏåÝð‘ðÑð‘À>ð‘ÿ¯p|À>ð‘ÿ¯@¡ ­i¬´ð]ð‘ð¯À.ð‘¼h@¡ DÀ0ð‘rÀ°ð‘tÁ0ð‘vÁ°ð‘xÂ0ð‘z°ð‘|Ã0ð‘~ðð‘ð¯À.ð‘Ä0ð‘Ô°ð‘å0ð‘õ°ð‘A£¢d­^¬~ð]ð‘A£¢ä­^¬‚ð] A£‚¢­^¬‚ð] #A£‚¢$"!@ ð‘#A£‚¢d"!@ ð‘#A£‚¢¤"!@ ð‘#A£‚¢ä"!@ ð‘ HS HS­c¬ôð]ð‘àwð‘ ?­?¬Pð]ð‘ ?ðÑð‘ ´3 ?­?¬Pð]ð‘ ?ðÑð‘ ´3 ?­?¬Pð]ð‘ ?ðÑð‘A£#¢fÊ)ßuÖƒà"ð‘²lAàð‘ ·3I=J:­_¬Äð]ð‘ðÑð‘A£#¢fÊ)ßuÖƒà"ð‘²lAð𑉢àð‘ ·3I=J:­_¬Äð]ð‘ðÑð‘A£#¢fÊ)ßuÖƒà"ð‘²lAÿ²à𑉪àð‘ ·3I=J:­_¬Äð]ð‘ðÑð‘ ·3J9K8­_¬Äð]ð‘ðÑð‘ ·3K9J8I=H< ?­a¬œð]ð‘ ?­a¬œðð‘À1À0ð‘À°ð‘Á0ð‘Á°ð‘Âð‘ðÑð‘@¡± ­a¬ ð]ð‘@¡± ÂPð‘Âð‘@¡¬ À­a¬ ð]ð‘@¡¬ ÀÂPð‘Âð‘ðÑð‘­`¬Þð]ð‘­`¬Þð]ð‘ ­`¬Þð]ð‘À­`¬Þð]ð‘­ ¬Òð]ð‘­ ¬Òð]ð‘ðÑð‘Â@ð‘­`¬Þð]ð‘­`¬Þð]ð‘­`¬Þð]ð‘0­`¬Þð]ð‘­`¬Þð]ð‘L­`¬Þð]ð‘­`¬Þð]ð‘­`¬Þð]ð‘­`¬Þð]ð‘À­`¬Þð]ð‘­`¬Þð]ð‘`­`¬Þð]ð‘­`¬Þð]ð‘­`¬Þð]ð‘­`¬Þð]ð‘­`¬Þð]ð‘ ­`¬Þð]ð‘­`¬Þð]ð‘ ­`¬Þð]ð‘­`¬Þð]ð‘ ­`¬Þð]ð‘Q­`¬Þð]𑳠­`¬Þð]ð‘ ·3K9L8I=H<­_¬Äð]ð‘ ­`¬Þð]ð‘­`¬Þð]ð‘­`¬Þð]ð‘­`¬Þð]ð‘ðÑð‘Â@ð‘­`¬Þð]ð‘­`¬Þð]ð‘­`¬Þð]ð‘Á­`¬Þð]ð‘­`¬Þð]ð‘h­`¬Þð]ð‘ðÑð‘­a¬hð]ð‘@¡¬ À­a¬°ð]ð‘­c¬ð]ð‘@¡± ­a¬°ð]ð‘­c¬ð]ð‘ðÑð‘A£¬¢À ­ü¬œð]ð‘­a¬$ð]ð‘­c¬nð]ð‘@¡$ A£¢Ü­i¬´ð]ð‘­m¬èð]ð‘­n¬ð]ð‘ðÑð‘­¿¬(ð]ð‘@¡± ­d¬ð]ð‘@¡¬ À­d¬ð]ð‘ðÑð‘A£±¢rpÅ5á%ð‘­d¬üð]ð‘­d¬‚€ ñð‘­g¬Lð]ð‘­l¬€ðð‘­d¬üð]ð‘­d¬‚€ ñð‘­g¬Lð]ð‘­s¬ªð]ð‘­¿¬ð]ð‘@¡± à-ð‘A£±¢rpÅ5áð‘­e¬Fð]ð‘­d¬ò€ ñð‘­f¬¢ðð‘­e¬Fð]ð‘­d¬ò€ ñð‘À ð‘Рð‘­f¬¢À3ñð‘A£/¢pÀð‘­d¬ò€ ñð‘€0Àð‘­f¬¢ðð‘ðÑð‘@¡¬ ÀÂ@ð‘­`¬Þð]ð‘â@ð‘ ´3I=J< ?­a¬¤ð]ð‘ ?€)€°­a¬œðð‘Â@ð‘­`¬Þð]ð‘â@ð‘ ´3I=J< ?­a¬¤ð]ð‘ ?€)€°­a¬œðð‘´pÌõРð‘Ù…Àð‘Ás À ð‘É5áð‘àð‘Å3Á1á“ð‘à ð‘Á1á…ð‘ßsаð‘ðÑð‘Ì!Àð‘Ï'áð‘Âð‘ðÑð‘­e¬ð]ð‘Õƒßwà[ð‘Àð‘­f¬,„ ñð‘­e¬ð]ð‘Àð‘ „1á‹ ­e¬ð]ð‘ÁóàSð‘­e¬ð]ð‘­f¬žÂð‘€ ñð‘Âð‘­e¬Fð]ð‘€ á ð‘­f¬žðð‘´pÌõÐ ð‘Ù…Àð‘€ á‡ð‘à)ð‘Ð>ð‘ÿ¯­f¬úð]ð‘ð¯Ð.ð‘ÁsÐ0ð‘à ð‘­f¬úð]ð‘ðÑð‘À ð‘Рð‘À3á•ð‘À1À0ð‘À°ð‘Âð‘ðÑð‘Ð ð‘²pÌóÕƒÀð‘Ð>ð‘ÿ¯­f¬úð]ð‘ð¯Ð.ð‘Ás Á1á…ð‘Å3Ð0ð‘ðÑð‘â€ð‘„± ·3I9H8K=J<­_¬Äð]ð‘­a¬œðð‘@¡¬ À­e¬Fð]ð‘€ áõð‘A£µ¢ðÀð‘­f¬úðð‘â€ð‘ ´3K=J< ?­a¬¤ð]ð‘ ?­a¬œðð‘@¡¬ À­d¬üð]ð‘€ áõð‘­g¬Lð]ð‘A£µ¢ôÀð‘ð‘ðÑA£µ¢ø‰2àRð‘@¡¶ €0ÀPð‘­g¬~ð]ð‘A£µ¢ôàð‘ 0á¡ð‘ 0á™ð‘@¡µ øÀ1À0ð‘­h¬ºðð‘ð…)0€°á  ˆ*‰àð‘‰(ˆR@¡µ øàð‘­g¬~ð]ð‘A£µ¢ôðð‘ °á;ð‘ °á3ð‘ð…©0€°á  Œ+àð‘¨@¡µ øà𑉂àð‘­h¬–ðð‘@¡¶ ÀPð‘@¡µ øàð‘ˆbˆbˆbˆb³Ð0ð‘à'ð‘@¡µ øà@ð‘‰"á‹ð‘­g¬~ð]ð‘@¡µ ø€0ÀPð‘ðÑð‘A£µ¢øàRð‘­g¬´ð]ð‘A£µ¢ø­i¬fÐ"ð‘£ñð‘@¡µ úÐ0ð‘A£¶¢ÐBð‘„°áð‘J‰2Ð0ð‘ðð‘­g¬´ð]ð‘A£µ¢øÐ"ð‘£á@¡µ úàð‘Àð‘àPð‘à-ð‘@¡µ úàPð‘A£¶¢ÐBð‘„°á‘ð‘€0Ðð‘ÀQ„¢À0ð‘ðÑð‘B¥µ¤p­j¬Þð]ð‘@¡¬ ÀA£µ¢p­e¬üð]ð‘ðÑð‘­i¬È¼ð‘Ø<ð‘ç¼ð‘÷<ð‘pƼð‘@Æ<ð‘rżð‘AÅ<ð‘tļð‘BÄ<ð‘vüð‘CÃ<ð‘x¼ð‘DÂ<ð‘zÁ¼ð‘EÁ<ð‘B¥µ¤p­j¬Þð]ð‘B¥µ¤pÀð‘­j¬z€ ñð‘ºtA£µ¢ðÀð‘­g¬&ð]ð‘A£µ¢ðÀð‘ „°á Ðð‘­g¬&ð]ð‘´zA£µ¢ðÀð‘ðe­j¬$ðð‘­i¬Á,ð‘UHÁ¬ð‘ºhÂ,ð‘TH¬ð‘¸hÃ,ð‘SHìð‘¶hÄ,ð‘RHĬð‘´hÅ,ð‘QHŬð‘²hÆ,ð‘PHƬð‘°h÷,ð‘ç¬ð‘Ø,ð‘Ȭð‘ô­ô­ðÑð‘pÀ!á“ð‘Ð𑀡á‰ð‘@¡$ ŽÐð‘ða„¡á‹ð‘­k¬¤ðð‘%´á ð‘­k¬–ðð‘Ðð‘ðas´á±ð‘rÊ%á‹ð‘­k¬šðð‘Ðð‘„¡á‹ð‘­j¬öðð‘Ðð‘ðcðeàeð‘c´á‹ràð‘à7ð‘x´á“ð‘­l¬4ð]ð‘­j¬öðð‘d´á—ð‘­k¬îð]ð‘­j¬öðð‘Ðð‘ðe­j¬öðð‘Ðð‘ðÑð‘Ï7ÁwÆâûð‘ßwÅÀÀQðÑð‘è­k¬®ð]ð‘d­k¬®ð]ð‘ ­k¬®ð]ð‘ÀðÑð‘À1r­k¬Äð]ð‘²hAtÐ>ð‘ÿ¯BÐ>ð‘ÿ¯B¥µ¤`Å3àð‘ðeŸsá÷‰2ð¯Ð.ð‘RJð¯Ð.ð‘´jÀ1rA£µ¢`C§$¦É-Þ‡Ðð‘Ðð‘ðcpÄcÄcÄcÄcÅ#áÛð‘Ö“àð‘àð‘ðeŸpáñð‘ðÑð‘ „°á  „°á±ð‘,ÕQ@Ñ ð‘ÙƒRA€0Àð‘­m¬Vð]ð‘­m¬èð]ð‘­m¬Rðð‘Ñ ð‘Ê3á#,ÕQ@Ñ ð‘ÕƒÀð‘ÁsѰð‘‰"­m¬Rñð‘pÐ>ð‘ÿ¯@Ð>ð‘ÿ¯@¡% ­i¬jð]ð‘ð¯Ð.ð‘PJð¯Ð.ð‘°jÐ>ð‘ÿ¯@Ð>ð‘ÿ¯,ÕQ@@¡% 6­i¬jð]ð‘ð¯Ð.ð‘PJð¯Ð.ð‘°jÀ1Á°ð‘ðÑð‘Ñ ð‘jÑ ð‘Å5á¡ð‘­m¬èð]ð‘,ÕQ@@¡$ l­i¬jðð‘C§,¦\E«,ªŠÏ7,ÕÀ&ð‘À!á1ð‘´hQ@R@­y¬èð]ð‘€ á ð‘Â÷ÂwàWð‘¶z߇À&ð‘¸hÀ1THðð‘p,ÕQ@@¡$ l­i¬jð]ð‘@¡¬ ÀÁ ð‘À!á…ð‘@H,ÕQ@„±Ðð‘ÁóåùÀ1Á°ð‘ðÑð‘@¡¶  ôÅ3àð‘ßqÁñÀ!áõð‘@¡¶  Áð‘Âð‘ðÑð‘­`¬Jð]€D©¸¨TÀ1Î8ð‘@¡r ¨­q¬Jð]ð‘°x­q¬üð]ð‘°xA£r¢œ­z¬ð]ð‘€ á ð‘­n¬Æðð‘­n¬òð]ð‘°x­q¬üð]ð‘­n¬òð]ð‘D©¸¨TÎ(ð‘À!áað‘­n¬îðð‘@¡% :D©¸¨TÀ(ð‘²h­i¬jð]ð‘Á(ð‘²h­i¬jð]ð‘ðÑð‘D©¸¨TÀ1Í8ð‘@¡¸ p­q¬üð]ð‘Ǩð‘ÁAB¥,¤ºØ…À$ð‘¼hðð‘@¡¸ €­q¬üð]ð‘Ë(ð‘Û¨ð‘°j„«PI­q¬.ð]ð‘Ì8ð‘ܸð‘@¡r  ­q¬Jð]ð‘@¡¸ „­q¬Jð]ð‘ðÑð‘@¡¸ €­q¬üð]ð‘@¡¸ „­q¬üð]ð‘Ë(ð‘Û¨ð‘°j„«PIÌ(ð‘ܨð‘­q¬ð]ð‘@¡r  ­q¬Jð]ð‘ðÑð‘@¡¸ €­q¬üð]ð‘@¡¸ „­q¬üð]ð‘4ܨð‘­p¬ðÄôð‘̨ð‘Û¨ð‘ë(ð‘–¬°hPMM­r¬ð]ð‘@¡r  ­q¬Jð]ð‘ðÑð‘@¡¸ €­q¬üð]ð‘@¡¸ „­q¬üð]ð‘4ܨð‘­p¬ðÄôð‘̨ð‘Шð‘à(ð‘–¬°hPMM­q¬Pð]ð‘@¡r  ­q¬Jð]ð‘ðÑð‘À1ÁqÎ8ð‘@¡¸ €­q¬üð]ð‘@¡r  ­q¬Jð]ð‘ðÑð‘@¡r  ­q¬Jð]ð‘@¡¶  @ô­q¬Pð]ð‘ðÑð‘@¡¶  @ô­r¬ð]ð‘@¡r  ­q¬Jð]ð‘ðÑð‘À1Í8ð‘A£r¢ ­q¬Jð]ð‘ðÑð‘pðÑð‘À0ð‘аð‘ðÑð‘À0ð‘ðÑð‘Àð‘ðÑð‘À ð‘Рð‘ðÑð‘Àð‘ðÑð‘À ð‘ðÑð‘@€0Æ8ð‘å˜ð‘pÕ8ð‘­d¬öð]ð‘À!á ð‘­g¬Lð]ð‘Æ(ð‘­q¬øÀ!ñð‘@¡¬ ÀßqÆ8ð‘Å(ð‘°hňð‘PHÀð‘°€`€`€`€`€!A£µ¢ðÀð‘­g¬&ð]ð‘Å(ð‘°hňð‘PHÀð‘€)°€!A£µ¢ðÀð‘­g¬&ð]ð‘Å(ð‘ÁqÅ8ð‘­q¬tðð‘ðÑð‘@€0Â8ð‘Õ¸ð‘pÕ8ð‘Â(ð‘­r¬˜À!ñð‘ßqÂ8ð‘­g¬~ð]ð‘C§µ¦ôÀð‘Ãð‘­g¬~ð]ð‘C§µ¦ôÀð‘Äð‘­g¬~ð]ð‘Å(ð‘°hňð‘PHÓ𑀌«á„«„Qäð‘€+á‰+…!Ðð‘ÁñpÕ8ð‘­r¬ðð‘ðÑ𑺾úξï±²³´A£/¢ À¢ð‘À!áð‘Èóåóð‘ðÑð‘À1À²ð‘Á¢ð‘À!áoð‘ò1@¡± âð‘‰"á“ð‘­e¬Òð]ð‘ðÑð‘­¿¬ð]ð‘ðÑð‘A£/¢Å3€8á‘ð‘8á‡ð‘ ՃТð‘Å#áð‘ðÑвð‘Ñ"ð‘ð3Ñ¢ð‘ô3ÑTð‘Á”ð‘â4ð‘Áð‘«ÍÀ4ð‘hÀ´ð‘À1´ð‘²tÀð‘Äð‘ðaðeßuÊ%áïð‘Å3Ò²ð‘¶rÀ"ð‘ð£Å1ßuÊ%áóð‘²vÒ²ð‘ðÑ€0A£¾¢@@¡/ zÐ ð‘ÕƒÀð‘ÁsÐ0ð‘­u¬Àòð‘­t¬nÀ3ñð‘A£¾¢@°r«ÍÀð‘­t¬Dƒ0ñð‘ßsðaÀð‘ƒ0á'ð‘ßsðaÀð‘ƒ0áð‘ßsðaÀð‘ƒ0á ð‘­t¬èðð‘­ü¬hð]ð‘@¡/ zÐ0ð‘ðÑð‘A£¾¢@­t¬è«ÍÀ"ð‘Ï1ñð‘À¢ð‘hÏ1ñð‘ðÑ€0­s¬âð]ð‘€ á ð‘­t¬èðð‘A£¾¢@ÈeÅ3À"ð‘ð£Å1ßuÊ%áóð‘­t¬èÅ#ñð‘­u¬ð]ð‘@¡/ ~À1À0ð‘À°ð‘@¡/ zÀ0ð‘@¡/ vÀ ð‘ÁqÀ°ð‘À1À0ð‘ðÑð‘@¡/ zÅ3Ð0ð‘@¡/ ~À ð‘ÁqÀ0ð‘@¡/ vÀ ð‘ÁqÀ0ð‘À1À°ð‘ðÑA£/¢°Á"ð‘ð1Á¢ð‘ò1ÑÀð‘Àð‘ðaðcßsáñð‘ðÑð‘À$ð‘ðÃ)PÏ1ðÑð‘B¥¼¤0 Ø…@¡Ž   À$ð‘À0ð‘ÂõÂñåóð‘@¡Ž ° À$ð‘À0ð‘ÂõÂñåóð‘B¥¼¤0¬Ø…@¡Ž ·Àð‘…¨à𑪱á‹ð‘Ðð‘à ð‘‡8áð‘Ðð‘B¥¼¤0ÀØ…C§/¦ràð‘‰"á3ð‘­y¬ªð]ð‘€ á7ð‘ÊÄð‘€ áð‘@¡/ HÀð‘­v¬~€ ñð‘ðÑð‘ÊÄð‘­v¬~€ ñð‘ðÑð‘­x¬‚ð]ð‘À1À6ð‘A£4¢Äð‘Á!Ë%­v¬~Â!ñð‘°tA£$¢†B¥4¤ ­y¬èð]ð‘´p€ áð‘ðÑð‘À1À6ð‘²tQBÄð‘­x¬~Å!Ï%Å'ñð‘­u¬Pð]ð‘Ï'áð‘ðÑð‘@¡4 ²tQB­z¬ð]ð‘€ á)A£4¢°t­ü¬hð]ð‘­ƒ¬pð]ð‘«§ªr­w¬øðð‘@¡4  ²tÔƒ ­z¬ð]ð‘­w¬ø«§ªr€ ñð‘@¡4 ,Úð‘Àð‘«§ªx€°á+ð‘@¡# ŠÀ ð‘­x¬~À!ñð‘@¡/ jÀ0ð‘­w¬øðð‘@¡4 -ÚDð‘Àð‘­w¬ª€°ñð‘@¡# ŠÀ ð‘­x¬~À!ñð‘«§ªrÚDð‘€°áð‘­|¬îð]ð‘à ð‘­|¬èð]ð‘­w¬øðð‘@¡4 0Û$ð‘À ð‘Á1«§ªrá¹ð‘@¡4 4À ð‘Ü$ð‘­x¬~Á1ñð‘Å#áð‘­³¬Šð]ð‘à ð‘­³¬žð]ð‘«§ªr@¡) x­i¬´ð]ð‘@¡4 ­y¬’ð]ð‘@¡4  ­y¬’ð]ð‘­y¬’ð]ð‘­y¬’ð]ð‘­y¬’ð]ð‘­y¬’ð]ð‘­y¬’ð]ð‘À$ð‘Фð‘À0ð‘аð‘@¡4 Á$ð‘Ѥð‘À0ð‘аð‘Eð[ð‘­ƒ¬pð]ð‘ðÑð‘@¡/ tÐð‘„¡á €0@¡/ jÀ0ð‘ðÑð‘B¥º¤  Ø…@¡Ž   À ð‘À4ð‘ÂõÂñåóð‘@¡Ž ° À ð‘À4ð‘ÂõÂñåóð‘B¥º¤ ¬Ø…@¡Ž ·Àð‘Àð‘@¡/ rР𑉢@¡º  ÀÐB¥4¤ëÔð‘­y¬’ð]ð‘B¥4¤ ­y¬’ð]ð‘­y¬’ð]ð‘­y¬’ð]ð‘­y¬’ð]ð‘­y¬’ð]ð‘­y¬’ð]ð‘À$ð‘Фð‘À0ð‘аð‘B¥4¤À$ð‘Фð‘Á0ð‘Ѱð‘@¡º  ÀÐÊð‘ðÑð‘²tQBÄð‘²pQ@Ôð‘ò!ò%ðÑð‘@¡º  A£¼¢0ÀÔƒÐË ð‘Ü ð‘hjË"ð‘Ü"ð‘Ê1Ï3Ë%’¤*­z¬ð]ð‘ðÑ€$ðð‘àð‘3á•ð‘ÁóÁõðð‘£áçð‘à€0ðÑð‘àð‘ðð‘²á“ð‘ÁñÁóŸpáëð‘À1ðÑð‘pðÑð‘àð‘ œbœgœgœgC§$¦Ë-Þ‡Ðð‘Ðð‘ðcŸpáð‘Jåßð‘ðe­z¬2ðð‘ðÑð‘Ðð‘Ðð‘ðc„¡áóðeðÑð‘@¡% T£¢­i¬´ð]ð‘­g¬¨ð]ð‘A£µ¢øÐ"ð‘…±á ð‘@¡µ þàð‘@¡% \£¢­i¬´ð]ð‘­g¬´ð]ð‘A£µ¢øÐ"ð‘…±á ð‘@¡¶ àð‘@¡µ þÐ𑌫á‹ð‘­{¬<ðð‘@¡% d£¢­i¬´ð]ð‘­h¬¾ð]ð‘A£µ¢úÐ"ð‘@¡¶ Ð0ð‘@¡¶ Àð‘@¡µ þ­{¬¶Ð𑌫ñð‘@¡¶ ˆ’äð‘àð‘Ð ð‘ ·3ð‘I=K:­_¬Äðð‘Ð ð‘ ·3ð‘J9K8I=H< ?­ ¬Òð]ð‘ ?ðÑð‘@¡µ þÐð‘@¡¶ Àð‘ ´3ð‘I=H<ðˆªá‡ð‘àð‘ ?­ ¬Òð]ð‘ ?àð‘ ?­?¬4ð]ð‘ ?@¡¶ À0ð‘@¡% n²h­i¬´ð]ð‘ðÑð‘@¡% Ô­i¬´ð]ð‘@¡% ¼­i¬´ð]ð‘ðÑð‘­©¬xð]ð‘­«¬ð]ð‘ðÑð‘­`¬Jð]?­`¬Jð]­`¬Jð]ˆÿÿ­ž¬šð]ð‘ÿÿ­ž¬šð]ð‘ðÑð‘­`¬†ð]?­`¬†ð]­`¬†ð]ˆÀ1­ž¬šð]ð‘À1­ž¬šð]ð‘ðÑð‘à€0A£4¢-Ðð‘÷A£#¢zÐð‘‡)„!Ðð‘­§¬†ð]ð‘ðÑð‘@¡' ’­i¬´ð]ð‘­g¬¨ð]ð‘A£µ¢øÐ"𑈪A£4¢,àð‘­§¬†ð]ð‘­ø¬Öð]ð‘@¡/ tÀð‘ðÑð‘–µ­ž¬nð]ð‘HÅ)£á§ð‘B¥4¤,àð‘ŠR³ –µj­ž¬šð]ð‘­}¬Îðð‘B¥4¤,Ðð‘I†Qƒ@„!ˆ¢ €j­ž¬šð]ð‘­E¬ð]ð‘ðÑð‘À1­~¬,ð]ð‘À2ð‘­~¬,ð]ð‘À²ð‘­~¬,ð]ð‘Á2ð‘ ­~¬,ð]ð‘Á²ð‘­§¬€ð]ð‘­ƒ¬pð]ð‘ðÑð‘²h@¡( R­i¬´ð]ð‘Ãq²h@¡( f­i¬´ð]ð‘­h¬¾ð]ð‘A£µ¢úÀ"ð‘A£4¢ðÑð‘@¡( t­i¬´ð]ð‘B¥µ¤p³ ðð‘ðeåùð‘’4B¥µ¤p­~¬Ü–5ñð‘­g¬~ð]ð‘ „°á/ „°á)/„âð‘tBßs´jRNŸtàð‘Àð‘tðe­~¬”ðð‘B¥µ¤pA£4¢ Àð‘Àð‘ðcðeåóð‘­§¬€ð]ð‘ðÑð‘­^¬Ððð‘­¬Î@¡_ þÀ ð‘À!ñ𑥤ŽàA£`¢@¡ ÐÀ ð‘Ê1á BàA£à¢Ð4ð‘­¬ÎÈð‘HðcÈð‘HJ$hÀ3ñð‘ÿã ¡à ­¦¬Âð]@¡ è­i¬´ð]@­à¬ð]ð‘¡ ­i¬´ð]@@¡ ŽÀ ò9 ¡à ­¦¬Âð]@@¡  ­i¬´ð]ð‘ðÑ𑡠Эi¬´ð]@àoð‘¡ß ü@À0ð‘À°ð‘ðÑð‘­|¬hð]ð‘­?¬¨ð]ð‘­ù¬¦ð]ð‘­³¬žð]ð‘­¿¬tð]ð‘­€¬~ð]ð‘­€¬Œð]ð‘­ƒ¬øð]ð‘­ƒ¬ð]ð‘­}¬jð]ð‘­ƒ¬<ð]ð‘­Š¬Œð]ð‘­|¬ªð]ð‘@¡@ JÀð‘€ áð‘@¡  À0ð‘ðÑð‘­`¬ð]ðÑð‘ÿ@¡¹ ­¥¬žð]ð‘­‚¬œð]ð‘A£#¢ŠÁ1áÀ1À2ð‘@¡' ð­i¬´ð]ð‘­¬ððð‘À2ð‘A£¢@¡0 ­¥¬ ð]ð‘A£¢@¡4 ­¥¬ ð]ð‘A£¢@¡¹ ­¥¬ ð]ð‘A£#¢Œ@¡¹ Á ð‘0Á1áð‘À ð‘À!á)À1À2ð‘@¡( ­i¬´ð]ð‘­§¬€ð]ð‘­‚¬˜ðð‘À2ð‘@¡' ¦­i¬´ð]ð‘­‚¬Àð]ð‘‰"á ð‘­¬ððð‘A£¢@¡0 ­¥¬ ð]ð‘A£¢@¡Æ €­¦¬Âð]ð‘ÿA£4¢@¡Æ €­z¬ð]ð‘­‚¬˜€ ñð‘­§¬€ð]ð‘­‚¬˜ðð‘@¡/ Èà ð‘À!á“ð‘Ã0ð‘À1Á°ð‘ðÑð‘@¡' °­i¬´ð]ð‘A£¢@¡¹ ­¦¬Âð]ð‘­‚¬œð]ð‘Á1á1ð‘@¡' Ö­i¬´ð]ð‘@¡/ Èà ð‘À!áð‘Ã0ð‘À1Á°ð‘ðÑð‘­‚¬Èð]ð‘‰"á›ð‘A£¢@¡0 ­¦¬Âð]ð‘ðÑð‘@¡¹ ÌÐÀ ð‘Рð‘ ­¾ïÂ1Ç3ðÑð‘­¥¬ àð‘­¦¬Â@¡ A£¢ð]ð‘A£¢­¨¬ð]ð‘‹"á ð‘@¡( à ð‘@¡( 6­i¬´ð]ð‘ðÑð‘@¡# zÀð‘÷€¨A£4¢-à𑉲ဠÀð‘ðÑð‘A£4¢Äð‘À'Å%À#á—ð‘A£0¢Äð‘A£4¢Ôð‘­ƒ¬pð]ð‘ðÑð‘A£4¢Äð‘A£¢Ôð‘À>ð‘ÿ¯A£/¢F€0Ðð‘„á ð‘­ƒ¬Òð]ð‘ð¯À.ð‘­ƒ¬Öð]ð‘A£¢Ôð‘­ƒ¬Öð]ð‘A£¢Ôð‘ðÑð‘ÏßwÁwá›ð‘Áuá•ð‘À>ð‘ÿ¯s¨ð¯À.ð‘ðÑð‘B¥2¤€0àð‘à ‰"pàð‘‰"á÷ñ%B¥#¤{Àð‘ðÑð‘­¿¬ð]ð‘á‡ð‘ðÑð‘@¡/ ÈÁð‘€(á‡ð‘ðÑð‘Á€ð‘€(áÁð‘­¬ôð]ð‘À1@¡# ‚À0ð‘@¡# ~À0ð‘@¡# {Àð‘€ á…EðÑ«2ªÐ*ð‘J­„¬Ê’$ñð‘£á'­„¬æð]Ÿs­…¬ð]¸p­„¬æð]ð‘­…¬jð]¸p£áÙð‘ñ+­„¬ˆð­…¬¾ð]ð‘­Š¬ð]ð‘­…¬Úð]ð‘ðÑð‘À>ð‘ÿ¯@¡" `€0LÐÐÀ ð‘ð1€0K„ƒÐÀ ð9ð¯À.ð‘ðÑð‘þ/²~ð£Ôð‘EÀ>ð‘ÿ¯zÀ>ð‘ÿ¯C§"¦”…D€0܇ð&ð‘Ï'á ð‘¼nð]ð‘ð¯À.ð‘ºhð¯À.ð‘UH²~ð£Äð‘ò/ðÑð‘þ/²~ð£Ôð‘EÀ>ð‘ÿ¯zÀ>ð‘ÿ¯C§"¦¸D›6߇ð&ð‘Ï'á ð‘¼nð]ð‘ð¯À.ð‘ºhð¯À.ð‘UH²~ð£Äð‘ò/ðÑð‘B¥#¤À$ð‘€ á…ð‘IŸpÀ4ð‘ðÑð‘­‹¬Èð]ð‘À ð‘@À9á'ð‘Ç9áð‘Ã9á“ð‘P­‹¬®ð]ð‘à ð‘­‹¬šð]ð‘­‹¬Èð]ð‘À ð‘€À9á'ð‘ Ç9áð‘ Ã9á“ð‘  ­‹¬®ð]ð‘à ð‘­‹¬šð]ð‘@­‹¬Èð]ð‘À ð‘À9áð‘Ä9áð‘­‹¬®ð]ð‘à ð‘­‹¬šð]ð‘€­‹¬Èð]ð‘À ð‘À9áð‘Ä9áð‘­‹¬®ð]ð‘à ð‘­‹¬šð]ð‘­‹¬Èð]ð‘À ð‘À9áð‘Ã9áð‘­‹¬®ð]ð‘à ð‘­‹¬šð]ð‘­‹¬Èð]ð‘À ð‘À9áð‘Ã9áð‘­‹¬®ð]ð‘à ð‘­‹¬šð]ð‘­‹¬Èð]ð‘À ð‘À9áð‘Ã9áð‘­‹¬®ð]ð‘à ð‘­‹¬šð]ð‘­„¬æð]ð‘A­‰¬ÏÀð‘„òð‘<­ˆ¬„òð‘­‹¬®ð]ð‘„â-ð‘Рð‘Ä;á£ð‘­‹¬Èð]ð‘À ð‘üÿÁ)À0ð‘à-ð‘­‹¬Èð]ð‘À ð‘Á!À0ð‘à ð‘­‹¬šð]ð‘H­„¬æð]ð‘A­‰¬ÏÀð‘„òð‘<­ˆ¬ž„òð‘ ­‹¬®ð]ð‘„â-ð‘Рð‘Ä;á£ð‘­‹¬Èð]ð‘À ð‘üÿÁ)À0ð‘à-ð‘­‹¬Èð]ð‘À ð‘Á!À0ð‘à ð‘­‹¬šð]ð‘HMD©#¨„ð$ð‘­‰¬žÇ+ñð‘B¥#¤}C§#¦€àð‘­ˆ¬ò‰"ñð‘àð‘XÐ6ð‘­‰¬öðð‘Ð&ð‘­‰¬öÅ#ñð‘B¥#¤}àð‘ÿ­‰¬ö‰²ñð‘­‹¬šð]ð‘H€0²h@¡# ˜­i¬´ð]ð‘²j@¡# ²­i¬´ð]ð‘€­‹¬Èð]ð‘À ð‘Ã!À0ð‘­‹¬Èð]ð‘À ð‘Ã!À0ð‘­‹¬Èð]ð‘À ð‘Ã!À0ð‘ÿB¥#¤}Àð‘ðÑð‘ÿ­‹¬Èð]ð‘À ð‘Ã)À0ð‘­‹¬Èð]ð‘À ð‘Ã)À0ð‘­‹¬Èð]ð‘À ð‘Ã)À0ð‘B¥#¤}Àð‘ðÑð‘­`¬Jð]€­?¬Pð]ð‘­`¬†ð]€ðÑð‘B¥#¤’À$ð‘À!á ð‘ßqÀ4ð‘ðÑð‘À¤ð‘À4ð‘­Š¬Œ@¡/ FÁð‘€ ñð‘Ā𑀠ñð‘@¡º  à0ð‘­s¬ð]ð‘­x¬ ð]ð‘­u¬dð]ð‘ðÑð‘@¡¼ 0à ð‘Ê%áð‘€0Àð‘ðaßuáõð‘­x¬‚ð]ð‘ðÑð‘@¡# aàð‘ꉈªˆRàpˆªÏð‘‡8á‹€¨ Ïð‘ðÑð‘H H"Ïð‘€ Ïð‘@¡# aÀð‘ê…€  ·3A£#¢aÀð‘ =H:­_¬Äð]ð‘ðÑð‘H H"Ïð‘Ïð‘@¡# aÀð‘ê…ïþ€¨ ·3A£#¢aÀð‘ =H:­_¬Äð]ð‘ðÑð‘A£#¢€À"ð‘À!á ð‘ßqÀ2ð‘ðÑð‘B¥#¤„Ð$ð‘Ç#Ð4ð‘ðÑð‘ÿÿÍ7B¥#¤„Ð$ð‘Ç+Ð4ð‘ðÑð‘ð>ð‘ÿ¯­„¬æð]ð‘›6JÓð¯ð.ð‘ðÑð‘Ð>ð‘ÿ¯Ã¨ð‘­Œ¬<À9ñð‘Шð‘€Ç+Ï)Ï3áð‘óÇ)Ç9áÏ7 €Ã#Ô¨ð‘Ç+Á!ĸð‘ÿðÌ/ó¸ð‘àð‘ô¨ð‘À?á ð‘ÿðÌ/ó¸ð‘ °xÐÀ1ð ð‘Рð‘Í/Ã!ñ!åñð‘Ç8ð‘ð¯Ð.ð‘ðÑð‘Ð>ð‘ÿ¯ °xÐñ!À1ð ð‘Рð‘Í/Ã!ñ!åñð‘ð¯Ð.ð‘ðÑð‘Ð>ð‘ÿ¯à>ð‘ÿ¯°xñ!аð‘Å3ñ!Ÿtáõð‘×8ð‘ð¯à.ð‘ð¯Ð.ð‘ðÑð‘­„¬æð]ð‘À ð‘Ë9áÅ3À9áÀ1Á!À¸ð‘ðÑð‘­‹¬æð]ð‘†ç(ð‘Ë-Å3­Œ¬¬ð]ð‘Á-á ­-¬ÎðÀaðÑð‘–µ­ž¬nð]ð‘HÁ)À8ð‘@¡# ˆÀ0ð‘Å3€°áÏ7Шð‘ÿþÆ+Ç#ÿÿÎ7Ç+B¥#¤†À$ð‘Â)Ä#иð‘­ž¬¼ð]ð‘ðÑð‘­›¬Àð]ð‘­‹¬æð]ð‘æç(ð‘Ë-À¨ð‘Ï)Ï5á‡ð‘ðÑð‘þÃ)Â!À¸ð‘Æ9á›6B¥#¤`Àð‘÷ƒ¨‡ Ðð‘­ž¬Vð]ð‘À¨ð‘Å9á›6 B¥#¤cÀð‘߃¨‡ Ðð‘­ž¬Vð]ð‘ðÑð‘@¡# v’³á‹@¡# x­ž¬6ð]ð‘ÐPð‘£áð‘’³á ð‘„a„a„a„a„¨Ï7‚9á𑟠9á𑟠€9á𑟠­ž¬6ð]ð‘£á ð‘„a’³á…ð‘„a„9áð‘„Ÿ  ­ž¬nð]ð‘£áð‘ÀaÀaÀa’³á‰ð‘ÀaÀaÀa„¨€°á¥ð‘KÀ8ð‘Å3и𑭌¬¬ð]ð‘M­¬dðð‘€0qÀ8𑟠Ê/á“ð‘@¡# ~Àð‘pÀð‘À¨ð‘Â)á ð‘À¨ð‘Ê/áð‘À¨ð‘ÿàÂ)Ã!Ë)Ë5á‰ð‘ÿçÃ)Ç9á‡ð‘À¸ð‘ £á ð‘‘D–³áð‘‘DB¥#¤|àð‘­¬ÖŠ*ñð‘Á¨ð‘ÿßÂ)ð¨ð‘Ë-á™Ê5À?áÊ5Ç?áÊ5 Â!àð‘€£á ð‘ˆbŸ³áð‘ˆbàð‘Á¸ð‘Шð‘­ž¬¼ð]ð‘ðÑð‘­ ¬¾ð]ð‘­‹¬æð]ð‘­¢¬–ð]ð‘ ç(ð‘Ë-À¨ð‘Ï)Ï5á‡ð‘ðÑð‘ÿ_Ã)Â!À¸ð‘ÁA£áð‘@GŸsás@Gÿƒ0ƒ¨›7B¥#¤dÐð‘‡)„!Ðð‘­ž¬Vð]ð‘B¥/¤HÀð‘€ á7ð‘B¥4¤,Ðð‘I†Qƒ@„!ˆ¢B¥#¤|ðð‘ÿ޳ €j­ž¬šð]ð‘ðÑð‘­ž¬6ð]ð‘@¡# tÐPð‘£á ð‘„a„a„a„a„¨A ­ž¬nð]ð‘£á…ð‘HШð‘ÿðÉ-„¨€°á™à¸ð‘Å3­Œ¬¬ð]ð‘à-𑟠›6Ë%Ç;á ð‘ÿñÉ-à¸ð‘­ž¬¼ð]𑄨€0À8ð‘ðÑð‘­ ¬¾ð]ð‘­¬Úð]ð‘­‹¬æð]ð‘­¢¬–ð]ð‘€ç(ð‘Ë-À¨ð‘Ï)Ï5á‡ð‘ðÑð‘ðÃ)Â!À¸ð‘Ë9á…–µB¥#¤`àð‘£áð‘”e˜fÿŸ7‹ª†¢Ðð‘­ž¬Vð]ð‘À¨ð‘ÁA£á‡ð‘€PœWƒ¨ÿ›7B¥#¤bÐð‘‡)„!Ðð‘­ž¬Vð]ð‘ðÑð‘@¡/ Hàð‘‰"áð‘­ž¬þð]ð‘à ð‘­ ¬ð]ð‘B¥¤C§¦ £áð‘B¥¤`C§ ¦­ž¬nð]ð‘‰)€0ÀQJÀ8ð‘IÀ¨ð‘ÿþÁ)вáÅ3Á!À¸ð‘À(ð‘€1á @¡2 ÓÐPð‘ÓÐPð‘@¡/ Hàð‘­“¬b‰"ñð‘@¡# ˆÀ@ð‘€ ñð‘ܨð‘‰"áð‘Ÿrܸ𑭓¬bðð‘Kˆ³á…s³ ܸð‘­ž¬nð]ð‘•…7á…ð‘À>ð‘ÿ¯ð>ð‘ÿ¯­¤¬ð]ð‘ð¯ð.ð‘ð¯À.ð‘HÐ(ð‘­“¬Pˆ2ñð‘7áð‘ ‰òð‘­¤¬ð]ð‘MIt­ž¬šð]ð‘Ÿtð¨ð‘À?áð‘À1ɸð‘È8ð‘ȸð‘É8ð‘­“¬Ôðð‘ÿÀ(ð‘€1áð‘­ž¬nð]ð‘ɸð‘­ž¬nð]ð‘Á)È8ð‘­ž¬nð]ð‘ȸð‘­ž¬nð]ð‘É8ð‘À(ð‘€1á ŸqIÀ1Ø(ð‘Å-áÏ7À'بð‘Å-áÏ7 À'Ù(ð‘Å-áÏ7À'Ù¨ð‘Å-áÏ7@À'Ф𑭔¬„À9ñð‘­”¬¦À;ñð‘€Ç#дð‘Ô¤ð‘ÿëÇ+Ô´ð‘ÿÿÎ7Ú(ð‘Ç+Ú8ð‘¶x¸t €­Œ¬¬ð]ð‘¸vÏ7à%ð‘À;áŸð‘Ô¤ð‘ÿ÷Ç+Ô´ð‘Ѥð‘Ç#Ñ´ð‘ŒÞФð‘Ç+Ä# Ã+ÀaÀaÄ#0Ã+ÀaÀaÀaÀaÄ#@Ã+ÀaÄ#@Ã+„`Œ£Ð´ð‘ÌHð‘ ­ž¬¼ð]ð‘ Ø…ÉE­“¬êõð‘Шð‘F­ž¬¼ð]ð‘ðÑð‘­ ¬¾ð]ð‘­œ¬>ð]ð‘­‹¬æð]ð‘­¢¬–ð]ð‘€B¥/¤Fàð‘‰"áð‘€ç(ð‘À¨ð‘Ë-Ï)Ï5áð‘A£#¢–Àð‘ Æç(ð‘À¨ð‘Ë-Ï)Ï5á‡ð‘ðÑð‘ó9Ã)Â!À¸ð‘B¥/¤Fàð‘‰"áð‘Ë9á’4à ð‘Ê9á’4€;áð‘T˜VB¥#¤aÿŸ7À𑃨† Ðð‘­ž¬Vð]ð‘°x­—¬ðð‘­œ¬pð]ð‘­‹¬æð]ð‘K€B¥/¤Fàð‘‰"áð‘€×(ð‘À¨ð‘Ç+Ï)Ï3áð‘A£#¢–Àð‘ŒÞ×(ð‘Ç+À¨ð‘Ï)Ï3á‡ð‘ðÑð‘s!Ã)Á!À¸ð‘‰4á­„¬æð]ð‘Ð>ð‘ÿ¯–¥á ð‘ÍGŸuàuð‘Û ð‘ÿÿË5Æ+Æ9ánÊ5Ï9á…nÊ5Æ#Û°ð‘Ú ð‘ÿÿË5Æ+Ë9á…nÊ5Æ#Ú°ð‘Û ð‘ÿÿË5Æ+Ê9á…nÊ5Æ#Û0ð‘Ú ð‘ÿÿË5Æ+Ç9á…Ê5nÆ#Ú0ð‘ð¯Ð.ð‘£á…Ë ð‘­ž¬šð]ð‘Ê ð‘­ž¬šð]ð‘Ë ð‘­ž¬šð]ð‘Ê ð‘­ž¬šð]ð‘Àð‘„±Ðð‘­—¬`€ ñð‘¸p­£¬¶ð]ð‘ðÑð‘B¥/¤FÀð‘°á/ð‘­ž¬þð]ð‘Шð‘À;á‹ð‘À8ð‘­ž¬¼ð]ð‘ðÑð‘­ ¬ð]ð‘­ž¬6ð]ð‘@¡# rÐP𑌨‰2Ð8ð‘Шð‘ÿøÇ+†9áÊ5Î'Ç#ÿÿÎ7Ç+B¥#¤†À$ð‘Â)Ä#иð‘B¥€¤Î$ð‘À!á B´hÐð‘Ù˜ð‘B¥€¤@Î$ð‘À!á B´hÐð‘ÙØð‘­ž¬¼ð]ð‘ðÑð‘­œ¬ºð]ð‘­‹¬æð]ð‘B¥/¤FÀð‘°á+ð‘­¢¬–ð]ð‘Ç(ð‘Å9áð‘­Œ¬¬ð]ð‘­¾¬òð]ð‘ðÑð‘­ ¬¾ð]ð‘]øç(ð‘Ë-À¨ð‘Ï)Ï5á‡ð‘ðÑð‘¢Ã)Â!À¸ð‘Å9á ð‘­¬¬Vðð‘Ç9á…0’4Ã9á…–µ’¤4B¥#¤`àð‘ÿŸ¶‹ª…$Ðð‘­ž¬Vð]ð‘À¨ð‘Æ9á’4B¥#¤càð‘ÿŸ¶‹ª†"Ðð‘­ž¬Vð]ð‘Јð‘B¥#¤aÐð‘­ž¬Vð]ð‘1èð‘0è˜ð‘9øØð‘ðÑð‘B¥/¤FÀð‘Kˆb0áð‘­ž¬þð]ð‘ðÑð‘­ ¬ð]ð‘ê—ð‘    àð‘    B¥€¤€;á ð‘LMB¥€¤@p–)ž5œgœgœgœg›6ð8ð‘Шð‘èþÇ+–5á™ð‘jÅ3­Œ¬¬ð]ð‘n­š¬Lðð‘Ï7€8áÊ5Î'‚8áÊ5Î'Â$ð‘Â9áÊ5Î'Á„ð‘„°á‡Ê5Î'Ç;áÊ5Ï'á‡ð‘Î'Î'Ç#Ë;á ð‘þÿÆ+иð‘­ž¬¼ð]ð‘ðÑð‘­¬6ð]ð‘­‹¬æð]ð‘B¥/¤FÀð‘Kˆb0áð‘­¢¬–ð]ð‘ðÑð‘­ ¬¾ð]ð‘Òç(ð‘Ë-À¨ð‘Ï)Ï5á‡ð‘ðÑð‘À¨ð‘÷-Ã)Â!À¸ð‘Æ9á…–µÄ9á…’4’¤€;áð‘’DšFB¥#¤cÀð‘ÿŸ¶ƒ¨„$Ðð‘­ž¬Vð]ð‘À¨ð‘Á9á‹ð‘„±’4àð‘€B¥€¤@€;á‰ð‘B¥€¤oï𑊪L”U†¡ˆ¢ïð‘€;áð‘T˜VB¥#¤aÀð‘ÿŸ7ƒ¨† Ðð‘­ž¬Vð]ð‘ï𑊪À¨ð‘Á9á–µ–¢ê…€;á…  MSJ€;á…­„¬æð]ð‘¸p­£¬¶ð]ð‘ðÑð‘À¨ð‘ Ï)B¥#¤Ð$ð‘‰"áÅ3Ï7Å9á‡Å3 Í'B¥#¤‚À$ð‘À!áÅ3@Í'B¥#¤ŒÀ$ð‘À!áÅ3Í'@¡# ŠÀ ð‘À!á‡Å3Í'Á¨ð‘þÁ)Ã!Á¸ð‘ðÑð‘à>ð‘ÿ¯ ÿÿÎ7À¨ð‘Ç9á…ð‘Ê5Á¨ð‘Ã)Â!Á¸ð‘ð¯à.ð‘ðÑð‘à>ð‘ÿ¯B¥#¤ð$ð‘›&á­ð‘À¨ð‘Ï)Ï'á Ê5Ï9á‡Ê5€Á¨ð‘ÿÃ)Â!Á¸ð‘ð¯à.ð‘ðÑð‘à>ð‘ÿ¯B¥#¤zÀð‘‡(B¥#¤aÀð‘÷ƒ(€ Á˜ð‘á¨ð‘ÿ7Ë-À¨ð‘À9á Ï7Ç9á‡Ï7@Ë%B¥#¤†À$ð‘Ã)áÏ7Ë%À9áÏ7€Ë%á¸ð‘ð¯à.ð‘ðÑð‘à>ð‘ÿ¯À¨ð‘á¨ð‘÷}Î/Ë9á‰ð‘Ç9á¡ð‘B¥#¤zàð‘€;áð‘T‘,áÊ5‚Ë%á¸ð‘À¨ð‘á¨ð‘ÿïË-À9á Ï7Ç9á‡Ï7Ë%ÿ¿Ë-À9á#Ï7Ç9áÏ7@É9á“ð‘Ë9áÏ7È9áÏ7@Ë%á¸ð‘ð¯à.ð‘ðÑð‘Ð>ð‘ÿ¯à>ð‘ÿ¯À¨ð‘á¨ð‘÷ÿË-À9á Ï7Ç9á‡Ï7Ë%ûÿË-À9áÏ7Å)áÏ7Ë%á¸ð‘ð¯à.ð‘ð¯Ð.ð‘ðÑð‘J= ´3 ?­?¬Pð]ð‘ ?ðÑð‘ ·3H=I:­_¬Äð]ð‘ðÑð‘ ´3ð‘L=M<ð‘ ?­?¬Pð]ð‘ ?ðÑð‘ ·3ð‘H9I8L=M<­_¬Äð]ð‘ðÑð‘þ/²~ð£Ôð‘Ï+á'ð‘ÅCŸpáûð‘ÿÿÍ7@¡# ‚À ð‘Ã)Á!À0ð‘²~ð£Äð‘ò/ðÑð‘Ð>ð‘ÿ¯à>ð‘ÿ¯B¥¼¤0­£¬„ð]ð‘­Ÿ¬š–´ñð‘À¤ð‘À¸ð‘À$ð‘À8ð‘­ ¬–´ñð‘Âð‘Èð‘ÂDð‘ÈXð‘„ð‘Șð‘ÂÄð‘ÈØð‘£á ð‘äð‘àð‘Ã$ð‘ɸð‘@¡/ XÀð‘€ ñð‘‰Ð¸ð‘Ð8ð‘ðð‘À¤ð‘Ã)à¨ð‘ÿïË-È%à¸ð‘Íð‘Ìð‘ÌÄð‘ÏØð‘²x £á ³­„¬æð]ð‘Êð‘Íð‘€ á…<”â–µ†¡À°ð‘ðeðcsŸráÏð‘ð¯à.ð‘ð¯Ð.ð‘ðÑð‘B¥º¤ ­£¬„ð]ð‘­ ¬Œ–´ñð‘À(ð‘À4ð‘À¨ð‘À´ð‘Ká´ð‘­ ¬º–´ñð‘Èð‘Âð‘ÈHð‘ÂTð‘Ȉð‘”ð‘ÈÈð‘ÂÔð‘ɨð‘£á ð‘ôð‘ðð‘Ã4ð‘ðð‘À¨ð‘À´ð‘Ìð‘Íð‘ÏÈð‘ÌÔð‘°x Íð‘Êð‘ðaðeŸráñð‘ðÑð‘Ð>ð‘ÿ¯à>ð‘ÿ¯B¥¼¤0ð$ð‘Ã1á%ð‘@¡/ FÁð‘€ áð‘Ā𑀠á‹ð‘­¢¬†ðð‘­£¬„ð]ð‘Á$ð‘Æ¸ð‘­¢¬†–´ñð‘À(ð‘€1á ÌHð‘H³­„¬æð]ð‘Ð>ð‘ÿ¯­¡¬~Â$ð‘Ã)ñð‘À ð‘À9ñð‘Ç9ñð‘Á ð‘óÁ)Á°ð‘Á ð‘ÿïÁ)Á°ð‘ð¯Ð.ð‘­¡¬6ÍGsŸrñð‘À(ð‘€1á ÌHð‘H³­„¬æð]ð‘Ð>ð‘ÿ¯Ä$ð‘­¡¬ÒÀ9ñð‘A£¢  ð2ð‘Æ°ð‘²t€ÔƒÄ ð‘­¢¬À9ñð‘ÿþð"ð‘Á)Í/Ã1áð‘À1ư𑭢¬Vðð‘ô°ð‘­¢¬Vðð‘À"ð‘À9áð‘İð‘ÿþÁ)À2ð‘à%ð‘A£¢ Ð"ð‘Íâð‘Ô ð‘Å#á‡ð‘İð‘À ð‘ÿ÷À9á‡ð‘ÿ»Ä ð‘Ã)İð‘ð¯Ð.ð‘ð¥s­¡¬¨Ÿrñð‘ð¯à.ð‘ð¯Ð.ð‘ðÑð‘Ð>ð‘ÿ¯à>ð‘ÿ¯­Œ¬|ð]ð‘B¥º¤ ­£¬„ð]ð‘Á4ð‘Ká´ð‘­£¬t–´ñð‘Ê(ð‘Â4ð‘ʨð‘´ð‘Ë(ð‘Ã4ð‘˨ð‘ôð‘À(ð‘€1á ÌHð‘H³¶x­„¬æð]ð‘¸p­Œ¬|ð]ð‘Ð>ð‘ÿ¯A£¢ Ð"ð‘Íâ ð‘Ѩð‘Á!Ò¨ð‘Ç+Á!Ä4ð‘²t€ÔƒÄ¨ð‘ŒßÁ)À2ð‘ð¯Ð.ð‘ð¥s­£¬Ÿrñð‘¸vð¯à.ð‘ð¯Ð.ð‘ðÑð‘À>ð‘ÿ¯@¡# @€0LÐÐÀ ð‘ð1€0K„ƒÐÀ ð‘Ø…ð¯À.ð‘ðÑð‘ÌHð‘D©€¨@”5á‹ð‘D©€¨Áˆð‘HJ­.¬ð]ð‘ðÑð‘€0ÀahÀaÅÀaÀaÄÀaÀaÅKðÑð‘²v­£¬æð]ð‘O­¤¬‚ð¨ð‘À?ñ„±­¤¬d²ñð‘£â𑥜âð‘àÈð‘ï‹*àØð‘­¥¬ðð‘Шð‘Ç#и𑭥¬ðð‘ð¨ð‘Ä?á—Fœâ<œâ à‰2€0…!‰2°xÑÍð‘£á³ð‘çˆð‘ìð‘ǘð‘<™â“ð‘ð¨ð‘™&ð¸ð‘àð‘ð¨ð‘ï™.ð¸ð‘€ á%ð‘çˆð‘˜âHǘð‘J£áð‘ïÈ𑛈fïØð‘£áð‘Ÿs ߇àqð‘À¶ð‘¶rðÑð‘r­¥¬L–¥ñ’4h›6Ë­¥¬@’$ñð‘r’4–”Âhl­¥¬”ð]ð‘nàð‘­¥¬”ð]ð‘ðÑð‘­¥¬‚€ ñð‘hÀ1­¥¬”ð]ð‘nŸpÕƒrÅ#á‡ArQJ­¥¬V€ ñð‘„¡á ð‘­¥¬”ð]ð‘ðÑð‘ŸqrKJAIjHl ­ž¬šð]ð‘J­ž¬nð]ð‘Ðð‘ÁñpÅ#á‡@rPJååuðÑð‘rJAÀ>ù9ÿ¯À>ù;ÿ¯¸pºr­©¬&ð]ð‘ –µ€0U­ž¬šð]ð‘U ­ž¬šð]ð‘ j­ž¬šð]ð‘–µ€0°x ÿÐð‘­ž¬šð]ð‘­?¬4ð]ð‘ðaåéu È­?¬|ð]ð‘­?¬|ð]ð‘åïð‘@¡¹ ÿ­¥¬žð]ð‘°xA£¹¢ À ð‘Ð"ð‘Á1áð‘ð¡ð£åíð‘ð¯À.ú9ð¯À.ø9À1ðÑð‘ð¯À.ú9ð¯À.ø9’$á€0­©¬dð]ð‘ðÑhÈð‘ð‘ðcÀð‘ðaßsÅ#áíð‘ðÑð‘QJK³²jÀ>ù9ÿ¯À>ù;ÿ¯¸pºrA£U¢UªØð‘ð‘A£U¢UUØð‘ð‘A£U¢U Øð‘ð‘°x²z ÿÀð‘Øð‘­?¬4ð]ð‘ðaðcåëð‘ È­?¬|ð]ð‘­?¬|ð]ð‘åïð‘²z@¡¹ ­¦¬Âð]ð‘­¦¬nð’4À1à1ð‘à)ð‘À1àð‘@¡/ Jàð‘‰"áð‘@¡/ ràð‘@¡@ JÁ0ð‘­¨¬ð]ð‘@¡' °­i¬´ð]ð‘@¡0 ºpÐ>ð‘ÿ¯­¦¬Þð]ð‘ð¯Ð.ð‘­¨¬^ð]ð‘s°zПv›&áÓð‘­Å¬ð]ð‘ðÑð‘A£0¢@¡? ÈÀ1À0ð‘À°ð‘Å3Ï7 ÿÀ"ð‘Ä3À¢ð‘Ì7ñ#åñð‘­¨¬.Ÿtñð‘@¡? ÈÐ0ð‘ð°ð‘ðÑð‘²j€ áð‘€0­©¬dð]ð‘@¡' Æà ð‘@¡' º­i¬´ð]ð‘ðÑð‘C§¥¦Øà ð‘C§¦¦æB¥¹¤Ð4ð‘pÀ´ð‘@Á4ð‘rÑ´ð‘JAÒ4ð‘ðWB¥¹¤Ѥð‘Jâð‘­É¬:ð]ð‘B¥¹¤À¤ð‘p°hÑ$ð‘€ á…ð‘rPJB¥¹¤Á¤ð‘p²hÒ$ð‘À!á…ð‘rQJÐ$ð‘­¨¬žßsñð‘ðÑð‘ –µ€0U­ž¬šð]ð‘Uª­ž¬šð]ð‘ –µ*­ž¬šð]ð‘ªU­ž¬šð]ð‘ðÑð‘@¡# †à ð‘À%À0ð‘ðÑð‘¡  `­i¬´ð]@@¡  ˜£¢Ü­i¬´ð]A@¡  ®B¥¤Ø­ª¬<ð]@¡  ÆB¥¤ü­ª¬<ð]@¡  ØB¥¤­ª¬<ð]@¡  èB¥¤­ª¬<ð]@¡  B¥4¤,Ðð‘­i¬´ð]²h@¡  £4¢ ­i¬´ð]A@¡  A£1¢ À"ð‘1Æ0ð‘09ưð‘­i¬´ð]ð‘ðÑð‘­i¬´ð]ð‘À$ð‘­ª¬”ð’(ñð‘­ª¬¼ð]ð‘’(á³ð‘­ª¬¼ð]ð‘ð’)á£ð‘­ª¬¼ð]ð‘’)á“ð‘­ª¬¼ð]ð‘­ª¬¢ðð‘@¡  ø­i¬´ð]²h­ª¬DŸrñÂõ¡  ü­i¬´ð]@ðÑð‘¡  J­i¬´ð]@ðÑð‘­«¬Bà&ð‘’$ñ@Ѧð‘°jÀ ð‘Ã=á5ð‘²pÿÀÍ/²nТ𑭫¬:À;ñð‘ÿÐ"𑉲áð‘Ã)àð‘Á=á ð‘€0Ðð‘²hÑ&ð‘°jЦð‘¼jð]@­ª¬Ìðò'ðÑð‘­9¬Ìð]ð‘­:¬îð]ð‘ ^­ ¬Òð]ð‘ X­ ¬Òð]ð‘c Vb À ðÑð‘¡  L­i¬´ð]@ ´3­ ¬Òð]ð‘@¡  .­i¬´ð]²h§.¦|­ª¬Ìð]CðÑð‘ ­«¬Fð]ð‘ ­«¬Fð]ð‘ðÑð‘­«¬ôð]ð‘­¬¬ðð‘ ©€¨­.¬ð]DðÑð‘ ©€¨@­.¬ð]DðÑð‘A£¢8@¡ ÀÀ"ð‘¸r­i¬´ð]²hðÑð‘àð‘­¾¬òð]ð‘„±­ž¬Vð]ð‘­ù¬ððð‘­`¬ð] ^¡ €­i¬´ð]@­g¬´ð]ð‘@¡µ øàð‘@¡# zàð‘­`¬ð]ðÑð‘@¡A ˆÀ 𑄡ဠá›@¡/ ÎÀð‘€ á…ð‘ðÑ­®¬\ð]ð‘«@ªZE­°¬ºð]ð‘€ á/€0À>ð‘ÿ¯­­¬ð]ð‘ð¯À.ð‘€ áðÑò+Ð*ð‘à[ð‘­­¬ð]ð‘ðÑð‘ÀŠð‘­­¬d€ ñð‘‰2ðÊð‘@¡@ jÑá ð‘€8ቼlà ð‘¼lð>ð‘ÿ¯ð]ð‘ð¯ð.ð‘€0ÐÚð‘@¡@ jÐÀ ð‘¼hðð‘Ð*ð‘‰"áŸs­°¬ºð]ð‘€ áŸð‘â ð‘‰"á•ð‘‡;á ð‘­¯¬Vðð‘ðZð‘ðÑð‘@¡A ˆÀ 𑄡ဠá‡EðÑð‘«@ªZ­°¬ºð]ð‘á‹Âð‘à ê‡àò+Àð‘ÀÊð‘6€°á­¯¬„ððÑð‘ÀÚð‘­°¬Ìðð‘@¡A ˆÀ 𑄡ဠá‡EðÑð‘«@ªZê‹Àð‘àÂð‘­°¬ºð]ð‘áê‡àò+­¯¬„ðÀ ð‘Ò ð‘€¨áíð‘ðÑð‘@¡A ˆÀð‘@¡ €À ð‘€ á @¡A †Àð‘@¡ À€ á @¡A ‡Àð‘@¡/ F­¯¬"Àð‘€ ññ@¡@ ¦À0ð‘‘@¡@ ®À0ð‘a@¡@ ÆÀ0ð‘@¡@ ÎÀ0ð‘@¡@ ¶À°ð‘Ñ0ð‘@¡@ ¾À°ð‘Ñ0ð‘@¡@ Ö @À°ð‘Ñ0ð‘å÷ò!«@ªZE­°¬ºð]ð‘áò+­°¬Ìð]ÀÚð‘þ+ÀÚð‘­°¬Ìðð‘ÑÊ𑄡ዟq­¯¬„ðÑÚð‘­¯¬˜ð]ð‘€?á…­¯¬Üðð‘Àšð‘ðÑð‘ÁÚð‘€0Àšð‘A£@¢Z€?áÀRð‘Àð‘€ á ð‘­¯¬Üð]?áò#ÀRð‘Àð‘€ á ð‘­¯¬Üð]ðÑð‘€ áð‘@¡@ ®À ð9Å ð‘Á!Űð‘ðÑð‘¡@ Æ€ á@¡@ Îà@¡@ ¶€ á @@¡@ ¾Ð ð‘À ð9Å ð‘Á!Űð‘ðÑð‘H@¡@ ÖH€0ÃA­°¬$ðÐH¡A .àk@¡@ Æ€ á@¡@ Îà@¡@ ¶€ á @@¡@ ¾pРð‘ÿÿÄ3À ð9Å ð‘Á)Űð‘ðÑð‘H@¡@ ÖH€0ÃA­°¬|ðÐH¡A .àk@@¡@ ®À ð9À ð‘ðÑÈ9€?á=À1@¡@ ÆÀ ð9Űð‘@¡@ ¶À ð9Űð‘@¡A †àð‘J@¡@ ÖÀ ò9Ųð‘å÷ò!?á;@¡@ ÎÀ ð9Űð‘@¡@ ¾À ð9Űð‘@¡A ‡àð‘J@¡A .À ò9Ųð‘å÷ò!­¯¬Œðð‘ðÑ6ðÑ€?á3D©°¨:B¥A¤†­°¬ð]L­°¬ð]LÀð‘HHðYMåûŸu’$á“B¥A¤‡D©°¨P?áÍ­¯¬Œðð‘@¡@ ¦À ò9Ñ ð‘ÿÿÄ3Å¢ð‘Á)Ųð‘€?á… ðÑð‘€?á…­©¬dð]ðÑ­°¬lð]­¯¬Œðð‘@¡A †Àð‘Áð‘ðÑ¡@ ¶­³¬hð]@­°¬ð]?á$ðÑð‘Á ð‘­°¬šð]ð‘­¯¬Œðð‘ñ ð‘K‰2ÇC¡@ ÖÑ­³¬hð]@­°¬:ð]ð‘Á ð‘€ á ŸpÁð‘ðÑð‘?á…$ðÑð‘­°¬lð]­¯¬Œðð‘@¡A †Àð‘Áð‘ðÑ¡@ ¾­³¬hð]@­°¬ð]ðÑ$Á ð‘­°¬°ð]ð‘­¯¬Œðð‘ñ ð‘K‰2ÇC¡A .Ñ­³¬hð]@­°¬Pð]ð‘Á ð‘€ á ŸpÁð‘ðÑð‘€?á…$*ðÑð‘­°¬Zð]­¯¬Œðð‘?á…*6ðÑð‘?á…*0ðÑð‘­°¬Zð]­¯¬Œðð‘ðÑ6ðÑ0­¯¬Œðð‘ðÑ6ðÑðÑð‘ðÑ6ðÑ0À>ð‘ÿ¯Á ð‘À ð9Õ ð‘Ä#Õ°ð‘ð¯À.ð‘ðÑð‘@¡A ‰Àð‘­®¬\ðð‘@¡A ˆÀ0ð‘ðÑð‘­`¬Jð]€@¡- ~­i¬´ð]ð‘@¡- ¨­i¬´ð]ð‘A£¸¢€0Àð‘­g¬~ð]ð‘A£µ¢ôÀð‘ „°á…ð‘à  „°á“ð‘B¥¸¤²Ð$𑉢áOð‘A£¸¢Ðð‘€0B¥.¤$Ø…Ð$ð‘¼jðð‘A£µ¢ôÀð‘@¡¸ ­³¬âL„°áð‘Ðð‘ðð‘E„°á‰ð‘Ðð‘ðð‘A£µ¢ôÀð‘@¡¸ D„°á§ð‘Ðð‘@¡, è­i¬´ð]ð‘­µ¬lð]ð‘­µ¬¶ð]ð‘­³¬âðð‘­µ¬òð]ð‘­³¬âðð‘A£µ¢ôÀð‘@¡¸ X„°á—ð‘ Ðð‘@¡- Ò­i¬´ð]ð‘­³¬âðð‘A£µ¢ôÀð‘@¡¸ ­³¬âO„°á‹ð‘ Ðð‘àÐð‘ðð‘A£µ¢ôÀð‘@¡¸ ­³¬âA„°á‹ð‘Ðð‘àÐð‘ðð‘A£¸¢€0Àð‘­µ¬¦ðð‘­³¬âðð‘E«¸ª°À1À:ð‘Àºð‘Á:ð‘Áºð‘Â:ð‘ºð‘Ã:ð‘úð‘Äð‘E«¸ªÊÀð‘ðÑð‘­¬Þð]ð‘­¬ðð‘A£µ¢ðþÀð‘­g¬&ð]ð‘A£µ¢ðþÀð‘­g¬&ð]ð‘ðÑð‘E«¸ªÀ1À:ð‘ðÑð‘C§¸¦Â­¶¬zÐ&ð‘‰"ñð‘C§¸¦ÀÀð‘€ á¡ð‘Àð‘C§µ¦ôÀð‘B¥¸¤ÄÀð‘ðÑð‘AC§¸¦Äà𑉒ˆRð‰+AC§µ¦ôÀð‘€€) C§µ¦ôÀð‘C§¸¦Â€0Àð‘­¶¬¨ðð‘C§µ¦ôÀð‘aˆ2áŸð‘C§¸¦ÂÀð‘C§¸¦À€0Àð‘ðÑð‘B¥¸¤°Ð$ð‘­·¬ØÉôð‘Éñð‘A£¸¢”ÕƒC§µ¦ôÀð‘Àð‘ÁsÐ4ð‘­¸¬²Êôð‘@¡- D©¸¨”Â(ð‘²h­i¬´ð]ð‘@¡- ¨ð‘²h­i¬´ð]ð‘@¡- Ã(ð‘²h­i¬´ð]ð‘@¡- èð‘²h­i¬´ð]ð‘@¡- Ä(ð‘²h­i¬´ð]ð‘@¡- Ĩð‘²h­i¬´ð]ð‘@¡- Å(ð‘²h­i¬´ð]ð‘@¡- Ũð‘²h­i¬´ð]ð‘@¡- &­i¬´ð]ð‘­µ¬¶ð]ð‘­¹¬ÄÀ¨ð‘ÁA‰2Äôð‘A£.¢@ÔƒÀ"ð‘²hAðð‘@¡¸ ¶­¸¬²À ð‘À!áð‘Ѐ𑄡ñð‘@¡¸ ¶À ð‘À!á›ð‘ßqÀ0ð‘Ѐ𑄡áŸqÐð‘à ð‘ßqÀ0ð‘A£¸¢¼jТð‘À"ð‘´jRIÊ5ÅÀ À2ð‘вð‘A£µ¢ôÀð‘Àð‘A£¸¢²À"ð‘ÁqÀ2ð‘ÿ­¸¬ˆªñð‘­µ¬¶ð]ð‘.A£µ¢ðÀð‘­g¬&ð]ð‘A£¸¢¶À"ð‘„!á•ð‘Ђ𑄡á‹ð‘­¸¬¶ðð‘ðÑð‘A£µ¢ðýÀð‘­g¬&ð]ð‘A£µ¢ðýÀð‘­g¬&ð]ð‘A£µ¢ð Àð‘­g¬&ð]ð‘A£µ¢ð Àð‘­g¬&ð]ð‘A£¸¢€0Àð‘A£¸¢”À¢ð‘Ä3á³ð‘ @¡ «ÍÀ0ð‘G¯®þ Q@¡_ üÀ0ð‘­¬¸ðð‘­µ¬¦ðð‘@¡¸ ¼À1À0ð‘€À°ð‘@¡¸ ”àð‘A£¸¢¶À2ð‘à ð‘Ð’ð‘ðÑð‘@¡¸ ¼À1À0ð‘À°ð‘àIð‘@¡- ,­i¬´ð]ð‘­¬ðð‘@¡- RÀa²h­i¬´ð]ð‘­¬ðð‘Áð‘­¼¬úð]ð‘ðÑð‘B¥/¤F@¡/ ÈÁð‘€ áð‘­¹¬Þð]ð‘ðÑð‘­º¬Âð]ð‘Ñð‘„¡á ð‘Ô„ð‘„¡á7ð‘À”ð‘Àð‘€ áð‘­½¬:ð]ð‘à ð‘­¼¬úð]ð‘€0Âð‘­º¬˜ðð‘­r¬¬ð]ð‘­¾¬ð]ð‘Æ¤ð‘ßqá ð‘Æ´ð‘àð‘Ç$ð‘Æ´ð‘­»¬ ð]ð‘Á”ð‘­¼¬¨ð]ð‘­¿¬ð]ð‘€ áð‘­Å¬Tð]ð‘­Å¬^ð]ð‘ðÑð‘­ž¬6ð]ð‘ƒ9á€0Àð‘­ž¬6ð]ð‘ƒ9ᄱԔð‘Õ”ð‘Ñð‘„¡á € áÀ1Дð‘ðÑð‘B¥/¤FÄ„ð‘Ñ𑀠ᇄ¡á‹ð‘­»¬Vðð‘Òð‘A£¼¢ €0ÀÔƒÀ"ð‘¶hCE«¼ªœÀð‘ð€ ðÑð‘E«¼ªœÀð‘€ á¥ð‘­¼¬úð]ð‘Âð‘€ á…€0Âð‘€0Ôð‘ðð‘­½¬:ð]ð‘Âð‘€1áÂð‘E«¼ªœðð‘€ áð‘­½¬‚ð]ð‘€ á'ð‘Âð‘pÂð‘ðÒð‘qÒð‘­½¬:ð]ð‘ððÑ€0€ áð‘Âð‘pÂð‘­½¬:ð]ð‘𭽬‚ð]ð‘€ áð‘Âð‘pÂð‘ððÑ€0€ áð‘­½¬‚ð]ð‘€ á§ð‘Âð‘pÂð‘ðÒð‘qÒð‘­¼¬úð]ð‘ððÑ€0€ áð‘Âð‘€0Âð‘­¼¬úð]ð‘𭽬‚ð]ð‘€ á‘ð‘Âð‘€0Âð‘ððÑ€0ðÑ»¬»è¼$¼`Àð‘Òð‘€ áð‘„¡á“€0à ð‘€°á…€0Åð‘Òð‘­¼¬ì€ ñð‘­`¬Jð]ðÑð‘­`¬†ð]ðÑð‘€0”ð‘ãð‘Rä„ð‘„"­ž¬Vð]ð‘ðÑð‘€0Ãð‘â„ð‘€Rä„ð‘„"­ž¬Vð]ð‘ðÑð‘”ð‘ãð‘…R€ ä„ð‘„"­ž¬Vð]ð‘ðÑð‘Ãð‘…Pâ„ð‘€R€ ä„ð‘„"­ž¬Vð]ð‘ðÑð‘­ž¬6ð]ð‘„9á€0Ôð‘ðÑð‘­ž¬6ð]ð‘…9á€0Äð‘ðÑð‘B¥/¤FÆð‘ɤ𑭾¬ßqÉ´ð‘À!ñð‘É´ð‘@¡@ JÀð‘€ á§ð‘Ȥð‘Ù$ð‘Å!áð‘À!á ð‘­¬¬:ðð‘­¬¬Vðð‘ðÑð‘B¥/¤FÆð‘­¾¬î€ ñ€0Æð‘­¾¬‚@¡/ ~À ð‘À!ñð‘ZÀ ð‘ÁqÀ°ð‘Äòð‘À1À0ð‘À°ð‘ń𑀠ñÅ”ð‘Àð‘€ á­¾¬òðð‘Ǥð‘á„ð‘‰"áÁqÀ1Ç´ð‘Ø$ð‘­¾¬îÄ3ñð‘ń𑀠áŸÅ”ð‘Àð‘€ á­¾¬òð]ð‘à!ð‘Ą𑀠á—ð‘Ä”ð‘@¡) F­i¬´ð]ð‘À1Ç´ð‘ðÑð‘­ž¬Vð]ð‘ðÑð‘B¥/¤FÅð‘ðÑ€ B¥/¤F­½¬ð]ð‘(Ê4ð‘ðÑð‘B¥/¤Fôð‘­½¬œð]ð‘£áð‘€ á ð‘Ú”ð‘Ê$ð‘ßqÀ!á ð‘Ê4ð‘àð‘(Ê4ð‘­½¬^ð]ð‘ðÑð‘@¡@ 8À1À0ð‘À°ð‘@¡@  A£¢Ò­¥¬”ð]ð‘@¡@ $A£¢Ø­¥¬”ð]ð‘@¡@ "A£¢­¥¬”ð]ð‘@¡@ (A£¢­¥¬”ð]ð‘@¡@ ,A£¢Ò­¦¬Âð]ð‘@¡@ 0A£¢Ø­¦¬Âð]ð‘@¡@ .A£¢­¦¬Âð]ð‘@¡@ 4A£¢­¦¬Âð]ð‘@¡@  À ð‘$hÅ1áð‘@¡) ’²h­i¬´ð]ð‘­Ã¬ðð‘­Ä¬6ð]ð‘­Ä¬‚ð]ð‘À!áð‘@¡* Ô­i¬´ð]ð‘­Ã¬ðð‘@¡) Ä­i¬´ð]ð‘@¡@ "À ð‘$hÅ1áð‘@¡) æ²h­i¬´ð]ð‘­Ã¬ðð‘­Ä¬Ìð]ð‘­Ä¬èð]ð‘À!áð‘@¡+ ­i¬´ð]ð‘­Ã¬ðð‘@¡* ­i¬´ð]ð‘@¡@ $À ð‘hРð‘j@¡@ (À ð‘Рð‘Ê1Ï3Ï5áð‘@¡* j­i¬´ð]ð‘­Ã¬ðð‘@¡+ T­i¬´ð]ð‘@¡@ $À ð‘hРð‘j@¡@ FÀ ð‘Рð‘ÍÈâð‘à'ð‘@¡+ "­i¬´ð]ð‘@¡@ RÀ0ð‘­Ã¬ðð‘@¡@ 8À0ð‘@¡ ÐÀ ð‘À!á%ð‘@¡+ €­i¬´ð]ð‘­Å¬&ð]ð‘­Ã¬ðð‘@¡@ $À ð‘hРð‘j@¡@ 0À ð‘Рð‘Ê1Ï3Ï5á™ð‘@¡+ Ð­i¬´ð]ð‘­Â¬\ðð‘@¡* <²h­i¬´ð]ð‘­Å¬&ð]ð‘àð‘@¡* Ô­i¬´ð]ð‘­Ä¬Ìð]ð‘@¡@ 4À ð‘Рð‘hj@¡@ (À ð‘Рð‘­Â¬ÌÂ1Ç3Ä#ñð‘@¡+ ®­i¬´ð]ð‘­Ç¬ºð]ð‘Ê5Ï7@¡ ð­Ä¬ð]ð‘­Ã¬Ë5ñð‘àð‘@¡, ­i¬´ð]ð‘àð‘@¡ À1À0ð‘@¡, (­i¬´ð]ð‘­Å¬&ð]ð‘àð‘@¡/ Èà ð‘À!á‡ð‘ðÑð‘@¡+ ò­i¬´ð]ð‘­Ç¬ºð]ð‘Ê5Ï7@¡ ð­Ä¬ð]ð‘Ë5áð‘@¡ À1À0ð‘@¡@ 4À ð‘Рð‘hj@¡@ 0À ð‘Рð‘­Ä¬Â1Ç3Ä#ñð‘@¡@ .À ð‘@¡@ ,Ð ð‘$hÀ5ñð‘Å5ñð‘@¡@ :À0ð‘@¡@ 8­Ä¬À ð‘À!ñð‘@¡@ RÀ ð‘À!á“ð‘@¡/ HÀ ð‘À!ñð‘@¡ ÐÀ ð‘À!ñð‘­Å¬ð]ð‘@¡@ JÁ°ð‘ðÑð‘À ð‘È5À ð‘Ì7ÄñÜsáïð‘ðÑð‘ðÑð‘A£¢@¡€ €­¥¬ ð]ð‘A£€¢@¡ €­¥¬ ð]ð‘A£€¢@¡€ €­¥¬ ð]ð‘ðÑð‘Ê5Ï7@¡€ €­Ä¬ð]ð‘@¡ €­Ä¬ð]ð‘@¡€ €­Ä¬ð]ð‘@¡@ <Ã%À0ð‘ðÑð‘A£¢@¡ ð­¥¬ ð]ð‘ðÑð‘Ê5Ï7@¡ ð­Ä¬ð]ð‘@¡@ >Ã%À0ð‘ðÑð‘@¡, F­i¬´ð]ð‘D©@¨àð‘@¡, P­i¬´ð]ð‘D©@¨Ð(ð‘Ä#Ð8ð‘@¡@ JÀð‘ðÑð‘D©@¨à ð‘D©@¨Á(ð‘Ѩð‘­Ç¬ÒÁ!ñð‘@¡( Â­i¬´ð]ð‘Á(ð‘Ѩð‘²hQK@¡Æ €Ð(ð‘Åâð‘Шð‘Å#á ð‘àð‘À(ð‘@xÉ5áð‘­¥¬ ð]ð‘à ð‘­¦¬Âð]ð‘Á(ð‘Ѩð‘²hQK@¡Æ €À(ð‘H€0Àâð‘À(ð‘À!á‹ð‘à ð‘Ð(ð‘J‰2@xÈ5áð‘­¨¬˜ð]ð‘à ð‘­¨¬Žð]ð‘Á(ð‘ÀÁ8ð‘À!áð‘Á¨ð‘ÁqÁ¸ð‘À(ð‘À!áð‘Шð‘Å#ßsиð‘Ð(ð‘Å5á‡ð‘à!ð‘ÁÀ8ð‘À!áð‘Шð‘Å#áð‘ðÑð‘­Ê¬bð]ð‘À1À8ð‘À¸ð‘Á8ð‘Á¸ð‘¨ð‘À!ᇉ2à ³ÿÿÅ1À1¸ð‘Â(ð‘Á)Â8ð‘­É¬`ð]ð‘Â(ð‘À!áð‘@¡@ J€0Àð‘­Ç¬˜@¡@ JÀ ð‘À!ñð‘Á ð‘À!á‡ð‘ðÑð‘Á ð‘€ á)€0Á°ð‘­Ä¬6ð]ð‘­Ä¬‚ð]ð‘­Ç¬vÀ!ñð‘­Ç¬ºð]ð‘x@Å1áð‘@¡/ jÀ0ð‘ðÑð‘@¡/ hÀ0ð‘ðÑð‘@¡* Ô­i¬´ð]ð‘€0­©¬dð]ð‘­Ç¬ºð]ð‘À1@¡@ JÁ0ð‘@¡ úÀ0ð‘­É¬´ð]ð‘ðÑð‘A£¢@¡ ð­¦¬Âðð‘Â(ð‘À!á‡ð‘ðÑð‘xÀ>ð‘ÿ¯DÀ>ð‘ÿ¯­É¬Èð]ð‘ð¯À.ð‘THð¯À.ð‘¸h­Ê¬Pð]ð‘­É¬Rð]ð‘@¡@ JÀð‘Â(ð‘­È¬TÀ9ñð‘­È¬˜Ä9ñð‘­È¬ÆÂ9ñð‘­É¬Á9ñð‘ðÑð‘À1À°ð‘Á0ð‘À8ð‘иð‘¸ð‘Â(ð‘À#Â8ð‘Á8ð‘Ѹð‘­Å¬vðð‘€Å3À8ð‘иð‘¸ð‘€Á8ð‘Ѹð‘­Å¬vðð‘Á ð‘À!á ð‘À1À°ð‘Å3À8ð‘иð‘¸ð‘Á8ð‘Ѹð‘­Å¬vðð‘Ñ0ð‘ðÅ3À8ð‘иð‘¸ð‘Á8ð‘Ѹð‘­Å¬vðð‘€ áð‘Ã(ð‘ÁqÃ8ð‘Ó¸ð‘ðÑð‘À1Ã8ð‘øð‘ðÑð‘Ã(ð‘À!á‡ð‘ðÑð‘@¡@ JÀ°ð‘@¡) ²h­i¬´ð]ð‘èð‘@¡) 0²h­i¬´ð]ð‘@xÁ1á€0­©¬dðð‘@¡ *À ð‘­Ê¬ ðð‘Â(ð‘Á1á—ð‘@¡@ JÁ ð‘À!á‡ð‘ðÑð‘@¡ À ð‘­Ê¬LÀ!ñð‘@¡ |À ð‘@¡/ Hàð‘‰"á‡ð‘ðÑð‘­Ó¬¦ð]ð‘@¡@ @2À0ð‘­Ë¬êð]ð‘@¡@ @À ð‘ßqáçð‘ðÑð‘@¡# Ð0ð‘ðÑð‘@¡# Ð0ð‘ðÑð‘B¥N¤lÀ$ð‘À!á­Ê¬Úð]ð‘á‡ð‘ðÑð‘@¡Ž p­Ñ¬ð]ð‘@¡P *­Ê¬®à ð‘È5á ð‘ÂñðÁsK­Ó¬`ð]ð‘@¡N lÐÇ0ð‘ðÑð‘ðÑ9ªª­Î¬Æð]ð‘­Ï¬Üð]G­Ð¬pð]𑪥N¤l„°áB""Ð4ð‘Ò´ð‘­Ë¬æðð‘¤ð‘À!á“ð‘Ò´ð‘­Ì¬šð]ð‘@¡N lÀ ð‘D‰0á¡ð‘CÐ0ð‘Ò°ð‘@¡] ð­i¬´ð]²h­Ë¬æÀ!ñð‘À ð‘ßqÀ°ð‘À!á§²hÀ°ð‘@¡N là ð‘Á1Ã0ð‘­Ó¬`ð]@¡N ŽÀð‘@¡N lÇ ð‘ßqÇ0ð‘À!á‹ð‘­Þ¬2ð]ð‘Á ð‘À!á ð‘­Ô¬ð]ð‘ðÑð‘B¥N¤lÀ$ð‘­Ì¬–À!ñð‘@¡Ž bÀ ð‘ßqÀ0ð‘À!á¡2Ð0ð‘@¡N Àð‘@¡Ž `À0ð‘@¡N Àð‘­Ì¬–€ ñð‘@¡Ž `Ð ð‘@Áâ—ð‘Ð0ð‘@¡N Àð‘@¡A ŠÑ2­Ï¬ð]ð‘@¡Ž `À ð‘2ÁÀ0ð‘ðÑð‘­Í¬ð]ð‘­Ì¬®ð]ð‘ðÑð‘B¥N¤lÀ4ð‘ À´ð‘Pa@¡ à ð‘Ê%á @¡ *À ð‘­Ó¬¦ð]ð‘2@¡Ž bÀ0ð‘­Ý¬úð]ð‘ðÑð‘@¡4 0À ð‘@¡N À0ð‘­Í¬ˆð]ð‘­Í¬èð]ð‘­Î¬Dð]ð‘­Î¬Xð]ð‘­Î¬lð]ð‘­Ï¬¶ð]ð‘ÿ@­Ï¬¶ð]ð‘Å3­Î¬Æð]ð‘­Î¬æð]ð‘­Î¬€ð]ð‘­Ï¬Üð]L­Ï¬ð]ð‘ðÑð‘­Ï¬Üð]@­Ð¬&ð]0­Ð¬&ð]­Ð¬&ð]­Ð¬&ð]@¡N À ð‘¡N ’ÐÐð‘­Ð¬&ð]ð‘­Ð¬&ð]O­Ð¬&ð]­Ð¬&ð]ðÑð‘­Ï¬Üð]D­Ð¬&ð]­Ð¬&ð]­Ð¬&ð]P­Ð¬&ð]@­Ð¬&ð]­Ð¬&ð]P­Ð¬&ð]­Ð¬&ð]­Ð¬&ð]ÿ­Ð¬&ð]ÿðÑð‘­Ï¬Üð]Z­Ð¬&ð]ðÑð‘­Ï¬Üð][­Ð¬&ð] ðÑð‘­Ï¬Üð]X­Ð¬&ð]ðÑð‘­Ï¬Üð]Y­Ð¬&ð]ðÑð‘­Ï¬Üð]Y­Ð¬&ð]ðÑð‘­Ï¬Üð]Y@¡N ŒÐð‘­Ð¬&ð]ð‘ðÑð‘­Ï¬Üð]FK­Ð¬&ð]ð‘J­Ð¬&ð]ð‘ðÑð‘­Ï¬Üð]]­Ð¬&ð]­Ð¬&ð]†ðÑð‘A­Ï¬†ð]ð‘ðÑð‘Ê%á%ð‘­Î¬Æð]ð‘­Ï¬Üð]BÐð‘­Ð¬&ð]ð‘ßuáñða@¡N ŽÀð‘ðÑð‘A£A¢ŠÕƒÊ%­Ï¬vñð‘Àð‘Àð‘ßuðc­Ï¬bñða@¡N Àð‘ðÑð‘Ê%­Ï¬¦ñð‘A£A¢ŠÕƒÀð‘­Ï¬˜ßuñðc@¡N Àð‘ðÑð‘­Î¬Æð]ð‘@­Ï¬Üð]BL­Ð¬&ð]ð‘á÷ßsðÑð‘E«NªŽÀ ð‘ŸpÀð‘€ á‹ð‘­Ð¬”ð]ð‘ ·3I8 = < ?­?¬4ð]ð‘ ?­?¬4ð]ð‘ðÑð‘E«NªŽÀ ð‘ŸpÀð‘€ á‹ð‘­Ð¬”ð]ð‘ ·3I8 = < ?­?¬4ð]ð‘ ?­?¬4ð]ð‘ðÑð‘­Ð¬”ð]ð‘ = <­_¬Øð]ð‘­?¬4ð]ð‘ðÑð‘Ð>ð‘ÿ¯ ´3 = < ?­?¬4ð]ð‘ßsá;ð‘†>ásð‘ßsá'ð‘†>áóð‘ ?E«NªŽÀð‘ð¯Ð.ð‘ðÑð‘E«NªlDÀð‘à_ ´3 = < ?­?¬4ð]ð‘­?¬4ð]ð‘?, <­?¬4ð]ð‘…, <­?¬4ð]ð‘ ?À0ð‘ðÑð‘ð‘ÁAÂAÃAÀQÁQÂQÃQIð‘…A†A‡A„Q…Q†Q‡Q#..„BCtv..Œ´pð¥Ð ð‘ŸsKž)˜‚š.—–-ÀaÀaÀa-@¡Ñ X¶p€0OÁA܇À&ð‘­Ò¬DÀ<ð‘­Ò¬^À<ð‘¶p€0‡”ÁA܇À&ð‘­Ò¬VÀ<ð‘­Ò¬zÀ<ð‘¶p€0MÁA܇À&ð‘­Ò¬œÀ<ð‘§Ñ¦j€0†”‡)ÁA܇À&ð‘­Ò¬šÀ<ð‘à )ÊqÊq-¶r܇JŸ§á ð‘Ðð‘ÀAJø…©áð‘Ðð‘ðeÀAÀð‘ðgÀAàg˜s£á)ð‘Ðð‘ðe“”šä ð‘ÀAÀð‘ðgŽ£á ð‘ŸsáýÁA–¥áð‘Ðð‘„AÀAÀð‘­Ò¬.õ)*Œ*RJSK´l¶n*„ðÑ*ÿ/Ÿ·h Áäð‘àyw›&á…ð‘ E«Óª6Ðð‘„¡ñ›&ñðeŸvNÀžð‘­Ó¬<ð]ð‘áaPð@𑟃„—â¥l­Ñ¬€ð]ð‘ÀŽð‘HŸsK åÿÈ­Ò¬Þðð‘­Ò¬ÞðPñ/ðÑð‘‡9á „â€0ÁA@¡U äÐÀ ð‘ð1ðÑÀ!ðÑÀ1@¡N lÐ ð‘Å#áðÑð‘€ä€0ðÑð‘Á ð9ÂAÐÒð‘€0­Ó¬¢À!ñÅA ð‘­Ù¬Lð]ð‘ðÑð‘@¡N lÑ ð‘Ñ0ð‘Á°ð‘Å#á'ð‘ð3ñð‘‰2Å#áÅCÁ ð‘­Ù¬Lð]ð‘@¡N lÁ ð‘ð1ðð‘‰2Å#áÅCÀ ð‘­Ù¬Lð]ð‘@¡N lÁ ð‘­Ô¬ð]ð‘ðÑð‘þ¯ð1XÀ@áð‘À¾ð‘áð‘TJ¸hðð‘­Ô¬Xÿ°ñÅCÀ¨ð‘­Ù¬Lð]ð‘À®ð‘­Ô¬"ðÄqñ¯ðÑð‘À!á'ð1ÀÀð‘RHÁ ð‘´hA£A¢ŠÀ€ð‘HÀ ð‘­Ò¬¼ð]ð‘ðÑð‘À!áò1À¢ð9À"ð‘A£A¢Š­Ñ¬€ð]ð‘ðÑð‘@¡ rÐ ð‘¶jCB¥¤pÐ$ð‘Å1á‘ðFð‘s’á…ð‘À4ð‘À¶ð‘ðVð‘²hAÕƒàð‘àð‘B¥¤lÀ$ð‘@¡ ÌÐàð‘àPð‘B¥Ž¤jÐ4ð‘­Ö¬.ð]ð‘ðÑð‘B¥Ž¤j­Õ¬ˆÐ$ð‘Å#ñð‘B¥¤lÐ$ð‘ÁsÁâ3ð‘Ð4ð‘B¥¤rÐ$ð‘ÄsÐ4ð‘B¥¤pÐ4ð‘B¥Ž¤j""Ð4ð‘­Ö¬.ð]ð‘ðÑð‘B¥¤lÐ$ð‘ßsÅ#ä7ð‘Ð4ð‘B¥¤ÌÙ…ÀTð‘B¥¤rÐ$ð‘ÜsÐ4ð‘B¥¤pÐ4ð‘ðÑð‘@¡ Ì SÀ0ð‘åûð¡@¡Ž j33À0ð‘ðÑð‘@¡ Ì SÀ0ð‘åûð¡@¡Ž j33À0ð‘­Ö¬.ð]ð‘ðÑð‘@¡O ~À0ð‘@¡N lİð‘6Å0ð‘ðÑ𑥤̭~¬âð]BB¥¤~À$ð‘B¥N¤lôð‘ðÑð‘ò1­×¬ð]ð‘À;á­Ö¬Êðð‘À¢ð‘Á)á@¡N lÓ ð‘­Ö¬ÊðÀÁ"ð‘Á)á ­Ö¬Êðð‘Ò¢ð‘°j@ÐÀ ð‘À!áð‘ð1À"ð‘£A¢Š­Ñ¬€ð]AðÑð‘ò1­×¬ð]ð‘­Ö¬”ðð‘þ/À¾ù3Ã"ð‘ÁA@¡N üÐÀ ð‘¼hâð‘IHð]Ð ð‘À®ò9ò/ðÑð‘´hBÀ>ð‘ÿ¯À¤ð‘ÁA@¡N üÐÀ ð‘¼hÑ$ð‘ðDð‘Àð‘ð]HÐ ð‘‰2ÅCð¯À.ð‘´hBÁ¤ò9ÕƒÀ"ð‘À!áð‘ð1Â$ð‘£A¢Š­Ñ¬€ð]AðÑð‘­Ø¬Fð]ð‘­Ø¬À;ñð‘Â"ð‘É)Ê1Ó ð‘ÿÿÏ1Ç+Á%Á!C§N¦lÑ¢ð‘Ê%á…ð‘ÂsÔ¶ð‘C§O¦–Á¶ð‘pÂ6ð‘4À6ð‘­Ø¬"ð]ð‘ðÑð‘@¡O – ð‘²hAÁ ð‘Ã2ð‘ðÑð‘@¡N lÑ ð‘Ó°ð‘@¡ tÀ ð‘­Ó¬¦ð]ð‘ðÑð‘ò1­×¬ð]ð‘ðÑð‘@¡4 0À ð‘@¡N À0ð‘ðÑð‘@¡N À ð‘Åá‡ÁqÀ0ð‘­Í¬ˆð]ð‘­Î¬€ð]ð‘@¡O ¢À0ð‘@¡N lİð‘ðÑð‘@¡N À ð‘@¡4 0À0ð‘­§¬€ð]ð‘ðÑð‘@¡Ž dÐ ð‘Áá‡ÁsÐ0ð‘@¡O ÒÀ0ð‘@¡N lŰð‘ðÑð‘@¡Ž dà@ð‘­}¬@ð]ð‘ðÑð‘¡Ž dðÑ@@¡4 ,Ðð‘@¡Ž dÀ0ð‘ðÑð‘A£N¢üÕƒÐ"ð‘Å#á ð‘¼jð]ð‘ðÑð‘ö1À&ð‘²hAÀ¦ð‘´hBÀ4ð‘À¢ð‘À9á Ôƒ­z¬tð]ð‘ðÑð‘²hAB¥¤­z¬2ð]ðÑð‘´hA£À¢ÞÂ2ð‘A£4¢ Àð‘€ á‰ð‘A£À¢Ì­z¬tð]BðÑð‘ò1ô1­×¬ð]ð‘à¢ð‘Â"ð‘²hAÀð‘­Ú¬ZÀ;ñð‘É-áð‘´r£b¢t­z¬tð]Aà9ð‘¤ð‘Ððð‘­k¬Äð]ð‘B¥Ž¤hÐð‘­z¬2ð]´r£b¢|­z¬tð]AðÑð‘@¡N lÿÿÃ0ð‘­Î¬”ð]ð‘ðÑð‘@¡N lÃ0ð‘­Î¬€ð]ð‘ðÑð‘ÿA­Ï¬†ð]ð‘ðÑð‘ªA­Ï¬†ð]ð‘ðÑð‘þ¯­ß¬¤ð]ð‘@¡N l­Û¬xÄ ð‘À!ñB¥O¤|À$ð‘A£O¢~ÔƒÀ"ð‘ÿÿÅ1á«ð‘À4ð‘Ä0ð‘àð‘­Ó¬¦ð]ð‘­Û¬~ð]ð‘­Û¬xðð‘­Û¬hÀ!ñð‘À¢ð‘À!á'ð‘Ñ ð‘C§¦|À&ð‘Å1áð‘­Ó¬¦ð]ð‘­Û¬xðð‘Á"ð‘¼hÁ¢ð‘ð]ð‘B¥O¤|À$ð‘ÌqÀ4ð‘ñ¯ðÑð‘@¡O ~À ð‘ÿÿÅ1áð‘À0ð‘àió!ðÑð‘@¡N l4Ä0ð‘@¡O |À0ð‘ðÑð‘­Û¬~ð]ð‘@¡N làð‘­Ó¬¦ð]ð‘ðÑð‘ò1á"ð‘Ò"ð‘¶jáÂð‘SJÐ&ð‘Ê+áð‘C§N¦lÓ&ð‘­Ö¬ÊðÀ­Ö¬Êðð‘@¡/ Fðð‘­‹¬Èð]À ð‘Ä+@¡Ž fÐ0ð‘ðÑð‘@¡O ÆÀ0ð‘¡O ºÀ0ð‘@¡Ž fÀ ð‘Á1À0ð‘¡O ÆÁ1á‡@¡O ºÀ0ð‘@¡N lÅ0ð‘ðÑð‘­Ü¬ð]ð‘­Ù¬2ð]ð‘­Ø¬Tð]ð‘­Ý¬úð]ð‘ðÑð‘@¡O ~Ð ð‘ÿÿÉ5á!ð‘Å#áoó!@¡N lÑ ð‘Ó°ð‘@¡ tÀ ð‘­Ó¬¦ð]ð‘ðÑð‘@¡N lÀ°ð‘ðÑð‘@¡ lÀ ð‘þ€â‹ð‘þ„ IåÿÆ@¡í °Ð0ð‘ðÑð‘@¡N lÄ ð‘A£O¢à؃RAÀ$ð‘B¥m¤0Á4ð‘Å ð‘ØƒRAÀ$ð‘B¥m¤@Á4ð‘Å ð‘ØƒRAÀ$ð‘B¥m¤PÁ4ð‘Æ ð‘ØƒRAÀ$ð‘B¥m¤`Á4ð‘ðÑð‘@¡N lİð‘Å0ð‘Űð‘Æ0ð‘ðÑð‘@¡N lÆ ð‘Å1Ö°ð‘@ÅCÁÆ0ð‘@¡O ®À0ð‘ðÑð‘@¡4 2À ð‘@¡N lưð‘ðÑð‘@¡N lÆ ð‘@¡4 2À0ð‘­§¬€ð]ð‘ðÑð‘A£#¢‚À"ð‘À!á•ð‘£¢€B¥4¤2À$ð‘À!á‡A£¢~À"ð‘­Ó¬¦ð]ð‘@¡N lÐÇ0ð‘ðÑð‘@¡ð àÀ ð‘"<ÁÿÁ)À0ð‘Óq@¡ð ðÀ0ð‘@¡N lаð‘A£#¢‚€þÀ"ð‘È-áð‘×0ð‘ðÑð‘@¡A ‰Àð‘@¡Ž lÀð‘ðÑð‘@¡Ž lÀð‘„°Ðð‘@¡N lDÁAÁİð‘@¡O ŠÀ0ð‘ðÑð‘@¡Ž lÀð‘@¡A ‰Àð‘@¡4 4ÀPð‘­§¬€ð]ð‘­ß¬Jð]ð‘ðÑð‘¡^ P^(A£Ž¢lÀð‘€ á‡@^0Ñ0ð‘ðÑð‘­Ø¬Fð]ð‘­ß¬ À;ñ@Â"ð‘°hÁÂð‘Àð‘@¡ „À ð‘­Ó¬¦ðð‘ðÑð‘­à¬£Ž¢¶@¡/ FÀ ð‘À!áA£Ž¢·€À ð‘À!áð‘Àð‘€ ñ@¡Ž ¸Ðð‘„¡áð‘­à¬‡8ñð‘àð‘­«¬ô€8á­¬¬8áð‘Ðð‘àð‘ð]ð‘ðÑ¡Ž ¸Àð‘àuð‘­à¬ZA£/¢FÐ"𑣎¢€Å#áA£Ž¢ ð] £Ž¢Å#á𑣎¢°ð] ðÑð‘  À2ð‘"Á2ð‘&<À²ð‘ðÑð‘ò1ô1à¢ð‘ö5Â"ð‘²hAÀð‘Â¤ð‘Ø‡RC­z¬2ð]ðÑð‘ò1À"ð‘´hBÐ$ð‘à¢ð‘Á¢ð‘Å-áð‘Â"ð‘À!áð‘Ñ"ð‘ÅC@¡N üÑÐ ð‘¼jð]ð‘ðÑð‘B¥¨¤Àü‚@‰2HÙ…ÿ³Ê5Ð4ð‘à´ð‘ñ%Ÿqáóð‘ðÑð‘B¥¤^À$ð‘À!á‹ð‘­â¬¸ðð‘ßqÀ4ð‘ð¥À¤ö9À$ð‘­á¬¤Å1ñð‘­á¬\Å1ñð‘­â¬¸ðð‘D©–¨À҈𑠀¨áð‘@¡ ÿÀPð‘ÀÐð‘ÂÈð‘­â¬F„¨ñð‘E«˜ªÀ­â¬¼ð]ð‘­â¬Fðð‘Á$ø9ð©°xD©–¨À²x ­ü¬hð]ð‘A£—¢À*­ü¬œð]ð‘ÂÈ𑄨á™ð‘­â¬„¨ñð‘Á–ð‘à ð‘Á–ð‘E«˜ªÀ­â¬¼ð]ð‘­â¬FÅ1ñð‘àð‘Á–ð‘E«˜ªÀÊ5à:ð‘E«˜ªÀà*ð‘ç¨ð‘­â¬žðð‘B¥—¤ÀƄ𑀠á'ð‘pæð‘ çÔð‘âÔð‘â”ð‘Ô´ð‘*E«˜ªÀÐ:ð‘°t²zð£­ü¬hð]ð‘˜ÁA£¢hÐ2ð‘ð£ó7ÿÿÔð‘ðÑð‘óð‘@¡ À`ð‘À!áÀ1À0ð‘­ã¬²ðð‘­â¬ú‰3ñð‘­ã¬æð]ð‘­ã¬¸À!ñð‘÷(ð‘ç¨ð‘óð‘‰3á“ð‘­ä¬Ôð]ð‘­ã¬²ðð‘‰3á“ð‘­å¬xð]ð‘­ã¬²ðð‘‰3á“ð‘­å¬˜ð]ð‘­ã¬²ðð‘‰3á“ð‘­å¬žð]ð‘­ã¬²ðð‘‰3á“ð‘­ê¬èð]ð‘­ã¬²ðð‘;‰3á“ð‘­ì¬Ðð]ð‘­ã¬²ðð‘<‰3á“ð‘­ð¬.ð]ð‘­ã¬²ðð‘ À!áð‘B¥—¤ÀÆ”ð‘Ùð‘àð‘âÈ𑉪áð‘ðÑð‘B¥4¤-Àð‘€°á—ð‘~­ä¬:ð]ð‘­ä¬6ðð‘Іð‘…9á—ð‘~­ä¬:ð]ð‘­ä¬6ðð‘~~­ä¬:ð]ð‘ðÑð‘B¥¨¤À‚@À>ð‘ÿ¯‰2HÙ…Õ¦ð‘æ&ð‘ð$ð‘Í7áð‘ð¤ð‘Î7á“ð‘ð¯À.ð‘À1­ä¬Ððð‘ñ%Ÿqá×ð‘ð¯À.ð‘B¥¨¤À‰2HÙ…ÿÕ¦ð‘æ&ð‘ð$ð‘˜6áŸð‘Ð4ð‘à´ð‘@¡ Ðð‘­ä¬Ððð‘ñ%ŸqáÕð‘DðÑð‘€Áâ‹ð‘ÿþÈ-lÐ:ð‘׸ð‘ð«²z­ü¬œð]ð‘ Àð‘ÀZð‘Àšð‘ÀÚð‘{Áð‘Ášð‘B¥1¤°t²zò!ò#­ü¬hð]ð‘@¡ ­ü¬hð]ð‘²z1èð‘09زð‘`Õƒ@¡4   ­ü¬hð]ð‘À1ðÑð‘Áâ‹ð‘ÿþÈ-lÐ:ð‘׸ð‘À1ðÑð‘À1ðÑð‘´zð«þÁâ‹ð‘ÿþÈ-l²z­ü¬œð]ð‘Ð4ð‘׸ð‘ӈ𑀰áð‘­æ¬†ð]ð‘­æ¬~À!ñð‘­æ¬xðð‘ӈ𑀰áð‘­æ¬Äð]ð‘­æ¬~À!ñð‘­æ¬xðð‘ӈ𑀰áð‘­ç¬ìð]ð‘­æ¬~À!ñð‘­æ¬xðð‘ӈ𑀰áð‘­é¬ð]ð‘­æ¬~À!ñð‘­æ¬xðð‘ӈ𑀰á—ð‘­é¬žð]ð‘À!á ð‘À1àð‘$ðÑð‘Äâ1ð‘Íкð‘àð‘Ëâð‘@¡ "²zñ#­ü¬hð]ð‘nàð‘À1ðÑð‘à>ð‘ÿ¯­ç¬àÄòð‘Ï7B¥#¤{Àð‘€ áð‘@ÄwÍŸpáùð‘,Íðºð‘àð‘Ì­ç¬âËòð‘²zñ#0вð‘$áÒð‘@¡# {àð‘á’ð‘ò#1.Ø2ð‘09زð‘@¡ ­ü¬hð]ð‘@¡1 ò!­ü¬hð]ð‘ñ#@¡2 <­ü¬hð]ð‘²z,Õƒñ#@¡# {Àð‘­ç¬â€ ñð‘­ð¬4ð]ð‘‰2à’ð‘ñ#Ÿpáíð‘@¡5 B¥#¤{Àð‘@­ü¬hð]ð‘Ÿpáõð‘nàð‘À1ð¯à.ð‘ðÑð‘EÀ>ð‘ÿ¯zÀ>ð‘ÿ¯DÀ>ð‘ÿ¯xÀ>ð‘ÿ¯­è¬ÜÄòð‘@¡2 B¥#¤{Àð‘Hà@ð‘…ñ!Ÿpáõð‘Ï7ÍŸqáûð‘Íðºð‘àð‘Ì­è¬ÞËòð‘²zñ#0вð‘ñ#@¡2 B¥#¤{Àð‘D©¨Å3àð‘´pºrñ#à ð‘–¥á!𑳭‹¬Èð]ð‘­ð¬Nð]ð‘ñ#sŸuáéð‘àð‘àð‘°tñ!­è¬ŒŸpñð‘nàð‘À1ð¯À.ð‘¸hð¯À.ð‘THð¯À.ð‘ºhð¯À.ð‘UHðÑð‘­é¬˜Äòð‘$ÌwÈwÈwðºð‘àð‘Äw­é¬šËòð‘@¡4 ´p²zñ#àð‘ð!ñ#­ü¬hð]ð‘àð‘°tÒ ð‘Ñ2ð‘Ò ð‘Ѳð‘ò#àð‘ ó!ñ#­ü¬hð]ð‘àð‘°tëð‘áÒð‘nàð‘À1ðÑð‘­ê¬âÄòð‘@¡2 B¥#¤{Àð‘HÏ7ÍŸqáûð‘à@ð‘Ÿr…ñ!Ÿpáóð‘ÍŸqáûð‘Íðºð‘àð‘Ì­ê¬äËòð‘²zñ#0вð‘ñ#@¡2 B¥#¤{àð‘´pñ#à 𑳭ꬺ‚0ñð‘‚0ñð‘‚0ñð‘ ‚0ñð‘‚0ñð‘‚0ñð‘À²ð‘ñ#­„¬æð]ð‘À ð‘­ê¬ÀÀ9ñð‘À ð‘0€€Á’ð‘@¡8 @‚0á ð‘@¡8 j­ü¬hð]ð‘hò£à ð‘ñ#àð‘ô#sŸu­ê¬0ñð‘°tñ!­ê¬&Ÿrñð‘nàð‘À1ðÑð‘ð«­ë¬.Åòð‘ðªð‘Ï'ñð‘Ð ð‘€°áð‘­ë¬6ð]ð‘àð‘€°áð‘­ë¬Ìð]ð‘àð‘ðÑð‘­ë¬ÄÅòð‘ðªð‘Ï'ñð‘ÅÅòð‘²zñ#ñ#@¡2 B¥#¤{Àð‘D©¨Ðð‘Ðð‘ÐÂð‘ÐØð‘´pñ#à ð‘–¥á𑳭‹¬Èð]ð‘­ó¬nð]ð‘ñ#sŸuáéð‘°tñ!­ë¬vŸpñð‘À1àð‘ðÑð‘­ì¬´ÅòÀ1ðªð‘Ï'ñÀ1ÅÅòÀ1­ì¬´A£4¢´r°zñ!Àð‘„°á§ð‘ ÍòÀ1ñ!ð#­ü¬hð]ð‘­ì¬´Ï'ñÀ1Àð‘„°á§ð‘ÍòÀ1´rÑ ð‘Ò2ð‘Ñ ð‘Ò²ð‘ò!Ï'ñÀ1Àð‘„°á§ð‘$ÍòÀ1 ñ!ó#­ü¬hð]ð‘­ì¬´Ï'ñÀ1Àð‘„°á›À1ÍòÀ1²tÑàð‘Û2ð‘Ï'á ð‘à ð‘­§¬Šð]ð‘À1ðÑð‘ð«Óˆð‘„¨­î¬z„°ñð‘ÃÈð‘Ôð‘­í¬ÿÄòð‘Åòð‘­ô¬Üð]ð‘ãH𑉪‰²á/ð‘@¡N lUUÐ0ð‘Á€Å°z­ô¬¾ð]ð‘­î¬,ðð‘ÁŰzÐ>ð‘ÿ¯­¦¬Þð]ð‘ð¯Ð.ð‘­î¬,€ ñð‘Ÿv›&áÛð‘D­ð¬*ðð‘­ï¬‚ÃÈð‘Ôð‘Äòð‘Åòð‘­ô¬Üð]ð‘ãH𑉪‰²á!ð‘Á€Å°z­ô¬¾ð]ð‘­î¬,ðð‘Á€Å°zÐ>ð‘ÿ¯­¦¬Þð]ð‘ð¯Ð.ð‘­î¬,€ ñð‘Ÿv›&áÛð‘D­ð¬*ðð‘ÃÈð‘Ôð‘­ð¬(Ä3ñð‘@¡ üÀ ð‘€Ä3á›ð‘@¡ þÀ ð‘Рð‘­ï¬ŽÄ3ñð‘,­ð¬*ðð‘ӈ𑄨­ï¬‚„°ñð‘ÃÈð‘Ôð‘­ï¬‚ÿÄòð‘Åòð‘­ô¬Üð]ð‘ãH𑉪‰²á/ð‘@¡N lUUÐ0ð‘ÁŰz­ô¬¾ð]ð‘­ï¬4ðð‘ÁŰzÐ>ð‘ÿ¯­¦¬Þð]ð‘ð¯Ð.ð‘€ áð‘Ÿv›&áßð‘D­ð¬*ðð‘ÃÈð‘Ôð‘ÿ­ð¬(Ä3ñð‘@¡ üÀ ð‘Ä3á›ð‘@¡ þÀ ð‘Рð‘­ï¬ŽÄ3ñð‘,­ð¬*ðð‘$­ð¬*ðð‘ÃH𑀨­ï¬â„°ñð‘ӈ𑄨„°­ð¬(ñð‘?@¡?  Ðð‘­Å¬ð]ð‘@¡ úÀPð‘­ð¬(ðð‘@¡ ?Ðð‘@¡N lÐ0ð‘@¡_ üÐ0ð‘ӈ𑄨„°áð‘@¡ ÿÀ0ð‘À1ðÑð‘À1ðÑð‘‰2ðð‘@¡ 0Ñðð‘ðð‘ðÑð‘À>ð‘ÿ¯Ð>ð‘ÿ¯à>ð‘ÿ¯ð>ð‘ÿ¯EÀ>ð‘ÿ¯zÀ>ð‘ÿ¯€0Àð‘ÀRð‘À’ð‘ÀÒð‘À 𑟷­ð¬¤–5ñð‘­ò¬ÞHðð‘­ð¬º–5ñð‘­ò¬ÞHðð‘­ð¬Þ–5ñð‘­ò¬ÞÅ)ñð‘H@Ÿ'ðð‘­ñ¬"–5ñð‘­ò¬ÞÇ9á ð‘ðð‘Å)ñð‘@ÄcŸ£Å)á ð‘àð‘­ò¬Þðð‘­ñ¬x–5ñð‘Ç9á§ð‘Å)á#ð‘@ÄcŸ£Å)áð‘àð‘ø¯àð‘ø¯Å)á§­ò¬Þðð‘Š2á«ð‘ Ÿ(FÅ)á›6@Ÿ¦ Å)á›6 Ÿ¦­ò¬Þðð‘Š2á½ð‘E«/ªFà 𑉲á‰ð‘ð’ð‘Ÿ)œg­ò¬ÞÅ)ñð‘@Ÿ¦àð‘­ò¬Þð@¡# ˆà@ð‘J–5áð‘­ò¬b–5ñð‘›&á…à ð‘›&á…E«4ª,à ð‘‰R#ðRð‘)ð’ð‘Ÿ( Å)á›6@Ÿ¦@Å)á›6 Ÿ¦­ò¬Þðð‘­ò¬®–5ñð‘à†ð‘…:á…ý‰ª•5á‰ð‘³ð’ð‘Ç9á‡ð‘­ò¬ÞÅ)ñð‘@'­ò¬Þðð‘–5áð‘ ­ò¬Þ–5ñð‘Á9á…@Ÿ·À’𑈪'€0àð‘À9á!Ç9áð‘Ÿ'OàÒð‘†?á‹Ç9á…ðð‘£á‡ð‘àð‘ðð‘£á#𑟳á𑟳á𑟲á 𑟲á ð‘àð‘àð‘ð¯À.ð‘ºhð¯À.ð‘UHð¯ð.ð‘ð¯à.ð‘ð¯Ð.ð‘ð¯À.ð‘ðÑð‘À>ð‘ÿ¯Ð>ð‘ÿ¯à>ð‘ÿ¯ð>ð‘ÿ¯EÀ>ð‘ÿ¯zÀ>ð‘ÿ¯ÀÈð‘Ðð‘­ó¬î‡9ñð‘ÀÂð‘Ðð‘­ô¬Ž‡9ñð‘–5á¯ð‘Å3ƒ8áÊ5Æ#‚8áÊ5Æ#Æ#Ô°ð‘­ô¬Žðð‘–5áð‘­ô¬Ž–5ñð‘Å3 À­ô¬T…8ñð‘­ô¬T €„8ñð‘­ô¬<ä ð‘Ç=ñð‘á ð‘ Ë%á°ð‘Å3ƒ8áÊ5Æ#‚8áÊ5Æ#Æ#Ô°ð‘À‚ð‘…(€0ô ð‘ÿñÍ/„¡áð‘Рð‘À;á…÷û…)Ì'ô°ð‘ð¯À.ð‘ºhð¯À.ð‘UHð¯ð.ð‘ð¯à.ð‘ð¯Ð.ð‘ð¯À.ð‘ðÑð‘ðÑð‘QJK³²j ÿÀð‘Àð‘ðaðcåóð‘ðÑð‘À>ð‘ÿ¯Í1á¥ð‘@¡ üÀ0ð‘Ï7@¡ þð0ð‘ð°ð‘ñ0ð‘ñ°ð‘A£¢þ@¡ üð ð‘ÁqÇ1áð‘Áwð0ð‘Ð"ð‘ð¢ð‘Ñ2ð‘ñ²ð‘à ð‘Ñ"ð‘ñ¢ð‘²z ?À"ð‘Ä3À¢ð‘Ì7ñ#åñð‘@¡ þÐ0ð‘ð°ð‘ð¯À.ð‘ðÑð‘@¡ úÀ ð‘„¡á ð‘­õ¬Þð@¡ hÀ ð‘À!­õ¬Þñð‘ßqÀ0ð‘ÑÀ ð‘A£¢€Ð"ð‘Å1á¥ð‘ö1À ð‘­õ¬âÅ1ñð‘­ö¬xÅ1ñð‘ðÑð‘ñ7À†ð‘…8á Á ð‘À!á›ð‘ÆÆð‘Þ€¨ÆÖð‘­%¬\ð]ð‘ðÑð‘ÆÆð‘߀¨á†ð‘²á)þ€¨ÆÖð‘Á ð‘A£¢ðÂ2ð‘À1Á2ð‘­8¬Òð]ð‘ðÑð‘ÆÖð‘ÇVð‘Ô–ð‘Á ð‘A£¢ðÂ2ð‘À1Á2ð‘­ö¬¤ðð‘ñ7À†ð‘…8á ÆÆð‘€ ¿€¨ÆÖð‘Ô–ð‘Á ò9Ã"ð‘À"ð‘¶ð‘À1öð‘È6ð‘ɶð‘Ê6ð‘T­%¬æ#ðð‘Á€ð‘€ áð‘­à¬äð]ð‘Âð‘ðÑð‘@¡/ ÈÂð‘€(áð‘­ö¬Êð]ð‘ðÑð‘B¥¤ á$ð‘Ê%á+ð‘Фð‘Å#á‹ð‘­¬¬Vðð‘Íâð‘@¡ ú€0ÀPð‘B¥¤À$ð‘€ áð‘­¬Þð]ð‘­¬ðð‘„¡áð‘B¥/¤hÀ´ð‘B¥¤ À$ð‘À!á›ð‘À4ð‘­÷¬ªð]ð‘­ú¬^ð]ð‘­á¬ð]ð‘­õ¬rð]ð‘ðÑð‘­„¬æð]ð‘­û¬Zð]ð‘È ð‘Ú ð‘Ä+Á1Â)B¥¤À4ð‘­û¬xð]ð‘­„¬æð]ð‘­û¬Zð]ð‘È ð‘Ú ð‘Ä+Á1Â)B¥¤À4ð‘­û¬xð]ð‘B¥¤À$ð‘B¥¤Ð$ð‘­ø¬ŠÁ!ñð‘@¡ Àð‘­ø¬Ò€ ñð‘Àð‘B¥4¤4À$ð‘À!á ð‘­³¬Šð]ð‘@¡ Àð‘­ø¬Ò€ ñð‘­ù¬Zð]ð‘­ø¬Òðð‘@¡ À ð‘€ áð‘„¡á5ð‘­ù¬¦ð]ð‘­³¬žð]ð‘à!ð‘@¡ Ðð‘„¡áð‘€0Àð‘­³¬žð]ð‘ðÑð‘­„¬æð]ð‘­û¬Zð]ð‘­„¬æð]ð‘ ð‘ Ã!°ð‘ô°ð‘s­ø¬îõð‘­„¬æð]ð‘­û¬Zð]ð‘­„¬æð]ð‘ ð‘ Ã!°ð‘ô°ð‘s­ù¬.õð‘ðÑð‘@¡# aÀð‘ ·3A£#¢aÀð‘ =H:­_¬Äð]ð‘Àð‘@¡# zÀð‘@¡ À0ð‘ðÑð‘@¡# aÀð‘€  ·3A£#¢aÀð‘ =H:­_¬Äð]ð‘Àð‘@¡# zÀð‘@¡ €0Àð‘ðÑð‘0B¥/¤Jð$ð‘›&á‡ð‘@¡ úð 𑟧á‡ð‘ B¥¤ дð‘ÿñ4ð‘ÿá´ð‘À1@¡/ hÀ0ð‘À°ð‘@¡ À0ð‘@¡@ JÀð‘ðÑð‘­„¬æð]ð‘­û¬Zð]ð‘­„¬æð]ð‘¸pÀ¨ð‘À9­ú¬Ðñð‘Ç9ñð‘B¥/¤FÐð‘IB¥/¤Jàð‘Á¨ð‘–¥á‘ð‘‰"á•À1à ð‘‰"á‡À1Á¸ð‘s­ú¬võð‘­„¬æð]ð‘­û¬Zð]ð‘­„¬æð]ð‘¸pÀ¨ð‘­û¬LÀ9ñð‘Ç9ñð‘B¥/¤FÐð‘IB¥/¤Jàð‘Á¨ð‘–¥á‘ð‘‰"á•À1à ð‘‰"á‡À1Á¸ð‘s­ú¬òõð‘ðÑð‘ÿÀ ð‘„°á  ŸrJðÑð‘­„¬æð]ð‘¸pÀ¨ð‘Ä9á­ð‘Ç9áð‘LÿÿË1À$ð‘Â)À4ð‘JÍGsåÍð‘­ü¬2ðð‘À9ámð‘Á¨ð‘ÿïÁ)Á¸ð‘ðð‘B¥/¤Fðð‘B¥/¤Jàð‘Á¨ð‘£á‘ð‘‰"á•À1à ð‘‰"á‡À1Á¸ð‘ @¡# ~Àð‘„°á‡ð‘B¥¤ Ð4ð‘ðÑð‘A£¢ À"ð‘À!á ð‘ßqÀ2ð‘À¢ð‘À!á ð‘ßqÀ²ð‘­‹¬€ð]ð‘ðÑð‘Å#á-ð‘Ð>ð‘ÿ¯À>ð‘ÿ¯Àð‘Àð‘ðaðcßsáñð‘ð¯À.ð‘ð¯Ð.ð‘ðÑð‘Å#á-ð‘Ð>ð‘ÿ¯À>ð‘ÿ¯À1Àð‘ðcßsð‘ð‘áóð‘ð¯À.ð‘ð¯Ð.ð‘ðÑð‘Q‘ÑúæöA@ÿÿÿÿ\ÿÿ:0ÖBð:0š|:0 T»ÌÝî† €† €† €† €† €† €† €† €† €ÿÿ† €† €† €† €† €† €† €† €† €† €† €† €~~ªUÿ>>žž~~ÿÿ H( L@bP²Tà X @ b *********** Begin POST ************** p POST finished. Return Code = %x POST: Starting XRAM test. POST: Starting SOC+ test. POST: Starting Internal SOC+ Loopback test. POST: Starting SERDES Loopback test. tPOST: Interface Board/Backplane Loopback test complete. %x 6POST: Starting SOC+ HCB test. POST Not Available. Overlay with DIAG/POST t Restore code from EEPROM... ...Done dPASSED. FAILED. SOC+ test running...PSOC+ test complete. %x SOC+ HCB test running...SOC+ HCB test complete. %x XRAM test running...eXRAM test complete. %x xSOC+ Internal Loopback test running... SOC+ Internal Loopback Complete %x . Loss of Sync - Test FAILED. Time Out - Test FAILED. Special Signal Error - Test FAILED. Receiver Error - Test FAILED. Compare Error - Test FAILED. Testing Port 0: Testing Port 1: PASSED. SERDES Loopback test running... SERDES Loopback Complete %x Manual Loopback test running... Manual Loopback test complete. %x Interface Board Loopback test running... Interface Board Loopback Complete %x .IB / BP Loopback test running... IB / BP Loopback Complete %x .Serial Port Diag Request Complete %x @@@@@ Start Photon Specific POST @@@@@@ Testing ESI 0 Bus 0 pTesting ESI 1 Bus 0 pIIB Communications test running... IIB Communications test complete. %x Retry Loopback test. %x %x n IB Backplane Test... IB External Loopback Test... e In Test Fixture, Continuing IB NOT in Test Fixture, Test Cancelled Test pattern = %x : *** Pattern %x FAILED. *** c ---------- Photon Vital Information ------------- Firmware Date: %s VFirmware Date Code: tSOC+ Revision: Port 0 WWN: Port 1 WWN: %xr rBox ID: %x Box Name: %s Product Revision: -0 ---------- Photon State Information ------------- %On Board Control: %x Loop Bypass Control: %x Fan Tray Control: %x LED Control: %x Power Supply Control: %x Reset Control: %x Polling Bus Status: %x On Board Status: %x Fan Tray Status: %x Power Supply Status: %x Power Supply2 Status: %x fBP0 DDs Present: %x BP0 DDs Spunup: %x BP1 DDs Present: %x BP1 DDs Spunup: %x %BP0 DDs Loop A Bypass Control: %x iBP0 DDs Loop B Bypass Control: %x iBP0 DDs Fault LEDs Control: %x iBP0 DDs Loop A Bypass Status: %x iBP0 DDs Loop B Bypass Status: %x iBP0 DDs Fault LEDs Status: %x BP1 DDs Loop A Bypass Control: %x BP1 DDs Loop B Bypass Control: %x BP1 DDs Fault LEDs Control: %x BP1 DDs Loop A Bypass Status: %x BP1 DDs Loop B Bypass Status: %x BP1 DDs Fault LEDs Status: %x -------- Photon Temperature Information --------- %@@@@@@@@ HALT ON ERROR @@@@@@@@@@@@@ JOURNAL: %x LDO ERROR: %x stopdiag absboxstate echonpordieledonledoffrundiagdumphwtimerbypasson bypassoffmuxchgofflinersterrssptestboxinfodiagerrEnter a value: Enter the diagnostic code: Loop until error? 0=No 1=Yes ...@Choose ports to test: 0=Port 0, 1=Port1, 2=Both ...Value entered: %x t------------- Stopping Diagnostics. ---------------- Cannot run DIAGNOSTICS right now. Try later. -Diagnostic Error Status: %x nDebug #0. %x Debug #1. %x Debug #2. %x Debug #3. %x Debug #4. %x Debug #5. %x Debug #6. %x Debug #7. %x Debug #8. %x Debug #9. %x Time since power on: %x%x HIT PORT ASSERT!!! DRASTIC RECOVERY!!! %LIP MON Port 0, LIP complete!!! Nodes = %x LIP MON Port 1, LIP complete!!! Nodes = %x LIP0 %x oOID0 %x oTSM0 %x oOFF0 %x o LIP1 %x t OID1 %x t TSM1 %x t OFF1 %x tLT0(%x) LT1(%x) tIW0(%x) IW1(%x) tBANG 0! BANG 1! tTIMEOUT 0! TIMEOUT 1! ====== Dumping some HW regs: ====== ALU_FLAGS|OPTOSTAT: %x OPTOSTAT: %x ERR_A|STACK_PTR: %x xSTACK: %x FW_Q_PTR|HOST_Q_PTR: %x gHOST_Q_PTR: %x HWREV: %x TCREDIT|HCB_DMA: %x %HCB_DMA: %x MSBUS_ERR: %x RX_PRAMS|RX_PRAM_ADDR: %x :RX_PRAM_ADDR: %x RX_SPEC_SIG: %x RX_DMA_STAT: %x RX_BPTR: %x %TFG_STAT: %x TDMA_TODO: %x ALSTATE: %x CQ_TODO|RDMA_Q_COUNT: %x RDMA_Q_COUNT: %x RX_LIP: %x RDMA_FW_PTR: %x RDMA_HW_PTR: %x RDMA_I_PTR: %x RX_PRAM_ADDR|RX_PRAM: %x RX_BPTR: %x #%&')*+,-.1234569:> unknownNULL formatOvertemp - power has being turned off oOvertemp - check the the fan trays Overtemp - check the the power supplies fCommand line too long: 255 char max e%s bad adb magic: %x%x PA2? PA3? Data? Data read: 0x%x SLOT FRONT BACK Box Temperatures %d n %dC %dC setwwn, setname helpncommands: status, split, single, setboxid e0=No, 1=Yes? Turn On=1/Off=0? Yellow LED On=1/Off=0? Bypass Yes=1/No=0? Which Power Supply 0/1/2? nWhich Fan Tray Front=0/Rear=1? Power Supply fan Speed Low=0/High=1? Disk Drive fan Speed Low=0/High=1? Which side Front=0/Rear=1? Which DD slot 0-9? iBypass %x Yes=1/No=0? Which Backplane Front=0/Rear=1? 1Which IB A=0/B=1? nWhich OE 0/1? 1splitsinglesetboxid0infonboxid value [0-3]? MBEPROM uIBEPROM uSct %x:OK Sct %x:failed 3IBeprom HDR is not valid MBeeprom is not valid dMBeeprom is disabled Header checksum failed Header checksum ok setwwnset WWN digits %x-%x: nsetnameEnter 1-16 AlphaNumeric chars followed by a . NO spaces : +statusasdfn.* %x ^ %x + %x = %x & %x - %x # %x ! %x $ %x @ %x ~?,There were %d eeprom programming errors. Last block was: 0x%x Other ib is insane Will not reset box or IB. mGot NEW BOXINFO via IIB MB DL Data does not contain valid DL Magic: 0x%x MB Eprom contains valid DL Data. MB FPM Image does not contain valid Magic: 0x%x MB Eprom contains valid FPM Data. MB Eprom DL Data datecode does not match IBs MB Eprom DL Data datecode does not match MB FPM datecode MB Eprom FPM Data datecode does not match IBs MB Eprom DL text and data did not checksum MB Eprom DL fpm did not checksum Will NOT program IB Eprom. MB Image is too old! aMBs FPM datecode and DL datecode matched. oGOLD RUNNING: valid MB image. Start download IB and MB FPM datecodes matched. IB and MB DL datecodes matched. Reading IB Eeprom FPM data FPM dates did not match aIB FPM data did not checksum MB UL: t IB DL: t$B$< $NpÐ 0%Î'‚(J(l(´$X$^`'Œp't'zNônF¬V¬:¬6zˆ«¬¬`«ä|4}}Ú~j|T³°³°©x©x¬|î|èÌšpìo$o$pðororpðp|pðpðpðpðp¤pÊpðpðpoÀpoÀpðpðpð Ph>Starting Loader... Ph>DOWNLOAD(0x%x%x, n0x%xn) r download cmd not implemented yet Ph>Unknown command sent to loader (%x) o Ph>Type any key to begin download... Ph>Type to execute from address 0 Ph>Executing from 0x600... a P>Download Failed. Bad check sum: 0x%x o%xr´4´l´°´À´ôµ"µP¹Ä¹^¹®¹®µ¦¹”¹Ä¹Ä¹Ästate %x rev %x spec %x i´ †#`i´ ¢#ai´ ¾#bi´ Ú#ci´ ö#di´ J#ri´ f#ti´ ‚#vi´ ž#xi´ ¼ i´ Ò¨i´ èài´ þèi´ªi´:¬i´^®i´‚¢i´¦¤i´Ê¦i´îêi´ìi´6îi´Zâi´~äi´¢æÿZ(º!ÀQÄqÀQ¾A¼1Âa¾ASUN SENA 1.09@@@@@@@@ @@@@unknownFRONT DISKSREAR DISKS0Power Supplies (0,2 in front, 1 in rear) Fans (0 in front, 1 in rear) ESI Interface board(IB) (A top, B bottom)GBIC module (1 on left, 0 on right in IB)Disk backplane (0 in front, 1 in rear)BTemperature sensors (on front backplane)Temperature sensors (on rear backplane)Interconnect assemblyLoop configurationLanguage USA Englishrev.-00mod.-000 ­¾ï13‚l 3à“š°Ì±V±R±Z±Ô±ª±è² ±ø²*²>²^²~² ²Ž²¸²Ì²ì³ ³(³³4³H³D³L³X³T³\³d³`ÁqÁ!€@A€@@!@A@a@@¡@Á@á@@!@A@a@@¡@Á@á@@!@A@a@@¡@SUN PHOTONaabcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ 0123456789Lÿÿÿÿÿÿÿÿÿÿ8`€ÀÀÀðÀÆrdfcnrdfdnwrcwrpwrdfpmstopfpmstartrfpmresetrfpminitÔŽÔ`Ó¦Öz‹È×:× ØlØØÙ*Ù2ÖôÖ.ÙœØFÙ²Û¢ÛàÛÂÜJÜÀÙäÜþݪÝBÝÈÏÚ’ÞxÚ¨Ô®ÕÚÚ^ÚxàvßnÕ.ÙhÕ”ÜÜœÖÝ «äÞàßJÞÈà¢ÖVߨظÞ|î|èÙÿÿmfmhmtm‚n€nnœmÈmÖmämònn$n2n>m’m’mžmžmþn mªmºnLndnXnrÌn¦n¾n²nÌnÚnênúo    PÑÿPáUMþþ@è¨øð~þˆpø¨?€¸>?€0" €?€1€¸?€¨ðèðH>À"À>†0~>@>ƒàþ@ÀˆÀ€$@.Ð<@*Ð<À:þ<Àþ<€À:@*@> Í€>@ú> à€<ú p€À>9€?ŸÀø<?„@ø"À•>€?Ÿ?žø‡ðø?‡ð?€ø>ø"> @ø>@ð*À.€8: ð*Àð>Àð<>ð"À8?À>?€@"è?€¨?€øðøøpø¨¸0$h@¡ <0À0ð‘¡ p­i¬´ð]@­|¬hð]ð‘ HS HS@¡÷ ˆ÷ŠÀ0ð‘²hAÀ"ð‘ÿÿ­à¬ÂÅ1ñð‘@¡ 8À ð‘Тð‘À#À0ð‘@¡ :À ð‘À#À0ð‘À"ð‘¼hð]ð‘@¡÷ ˆ­à¬°À!ñð‘À ð‘²hAÀ¢ð‘A£¢8Ð"ð‘Á1À2ð‘À ð‘ÄqÀ0ð‘­à¬@ðð‘­|¬ªð]ð‘@¡ 8À ð‘@¡  ­i¬´ð]²h@¡ <0À0ð‘ðÑð‘à>ð‘ÿ¯­á¬F@¡ <à ð‘Ë-á‘ð‘0Å%Ð0ð‘à ð‘Ê3ñð‘@¡ 6À0ð‘@¡ >ð¯à.ð‘à0ð‘€0ðÑ€ ð¯à.ð‘àu@¡ 6À ð‘^…Á)­â¬”À!ñð‘@¡÷ fÀ ð‘²hAÀ"ð‘ÿÿ­á¬ Å1ñð‘@¡÷ f÷hÀ0ð‘­á¬tðð‘B¥¤6À$ð‘Тð‘­â¬8Á)ñð‘@¡ 8À ð‘À#À0ð‘À"ð‘¼hð]ð‘@¡÷ fÐ ð‘²jAТð‘­â¬À!ñð‘A£¢8À"ð‘Á1À2ð‘B¥¤<À$ð‘­â¬8À-ñð‘B¥¤<À$ð‘þÿÀ-À4𑥤6À$ð‘Å1Ð4ð‘À ð‘ÄqÀ0ð‘­á¬t@¡÷ †À ð‘ÁqÀ0ð‘@¡ 6À ð‘­â¬”À!ñð‘@¡ >À ð‘À!á¼hð]ð‘@¡ >À1À0ð‘@¡÷ †À0ð‘ðÑð‘@¡ <À ð‘Ã)Â1áð‘3Ç+Á!À0ð‘ðÑð‘@¡ <À ð‘Â)á ð‘À1À0ð‘ðÑð‘CÀ&ð‘²hAÀ¦ð‘Ѧð‘à"ð‘Â)á@Ñ&ð‘­©¬dð]ð‘°j­i¬´ð]²hÒ&ð‘°j­i¬´ð]@ðÑð‘­i¬´ð]@ =­_¬øð]ð‘¡  òƒ9á‡ð‘¡  Ò­i¬´ð]@ðу9@¡ hÀ0ð‘Á*ð‘°h­i¬´ð]@@¡ <Ð ð‘­ã¬àÌ;ñð‘Àªð‘°h@€Ð0ð‘zÐ>ð‘ÿ¯ ­ð¬ð]ð‘à ð‘J­è¬ð]ð‘ð¯Ð.ð‘ºjEЪð‘°j@À0ð‘A£¢hÀ2ð‘À!áð‘­©¬dð]ð‘@¡ <Ð ð‘­ä¬`Í;ñð‘Àªð‘Âq°h@€Ð0ð‘zÐ>ð‘ÿ¯ ­ð¬ð]ð‘à ð‘J­è¬ð]ð‘ð¯Ð.ð‘ºjEЪð‘Âs°j@À0ð‘A£¢hÐ"ð‘Å!Ð2ð‘À!áð‘­©¬dð]ð‘Áªð‘°h@­i¬´ð]²jðÑÁ#@¡# aÀð‘@¡† Àð‘ðÑð‘À>ð‘ÿ¯@¡† àð‘­`¬ð]ð¯À.ð‘ðÑð‘­ä¬tð]ð‘­`¬ð]]«ª@­ã¬Nð]E­ä¬Œð]ð‘ðÑð‘­ä¬tð]ð‘­`¬ð]]«ªH­ã¬Nð]E­ä¬Œð]ð‘ðÑð‘¡  ²­ã¬ ð]ð‘­å¬<ñÀ1­ä¬tð]ð‘­`¬ð]L«ªP­ã¬Nð]E­ä¬Œð]ð‘ðÑ𑪪UUÿÿ @@€€¡ À­i¬´ð]@@¡ \€À0ð‘Á0ð‘@¡„ ­ô¬6ð]ð‘€ áð‘A£¢\­ó¬Nð]­æ¬âðð‘@¡ò À>ð‘ÿ¯À>ù1ÿ¯A£„¢­ç¬ð]ð‘ð¯À.ð9À>ù1ÿ¯­ç¬pð]ð‘ð¯À.ð9À>ù1ÿ¯­ç¬Àð]ð‘A£å¢@ð¯À.ð9À>ù1ÿ¯­ç¬ ð]ð‘ÂóåZʳáßð‘ð¯À.ò9À>ù3ÿ¯@¡„ ­ç¬ð]ð‘ð¯À.ð9Ñð¯À.ð‘ßq­å¬¶À!ñð‘A£¢\Ð"ð‘Ê+áð‘@¡ \Ð ð‘Ê#à0ð‘­æ¬âðð‘@¡ €­õ¬ð]ð‘@¡ €­õ¬ð]ð‘@¡ €­õ¬ð]ð‘@¡ €­õ¬ð]ð‘A£¢\­ó¬\ð]ÿ­â¬Ø§¦ð]ð‘ðÑð‘ÜÐ ð‘Ð2ð‘ÂñÂóvϱáïð‘ðÑð‘¸pÜÐ"ð‘E«çªÐ0ð‘ÂñpÏ·áõð‘°xà ð‘Î3á‘ð‘ÂñpÏ·áïð‘ðÑð‘A£¢\­ó¬Nð]À²ù1àg¸pܪªÐ0ð‘ÁsÂñpÏ·áóð‘°xªªà ð‘Î3á‘ÁsÂñpÏ·áïð‘ðÑð‘A£¢\­ó¬Nð]À²ù1àg¸pܪªUUÐ0ð‘à°ð‘ÄñpÏ·áñð‘°xð ð‘Ï3á™ð‘ð ð‘Ï5áÄñpÏ·áçð‘ðÑð‘A£¢\­ó¬Nð]À²ù1àgM@¡† Àð‘@¡† À0ð‘@¡† £¢(rÀ0ð‘­è¬²À ð‘°hÀ ð‘ÿÿÅ1ñ@¡†  ­ð¬zð]@@¡† àð‘J¡ ê‡@¡ ­i¬´ð]ð‘@¡  ­i¬´ð]²h­è¬öð]@¡† À!áð‘À ð‘­è¬>ðÂq@¡† À ð‘ðÑÀ!A£†¢Ð"ð‘Á!À2ð‘À ð‘°hÀ ð‘²h@¡  0­i¬´ð]𑡆 ­è¬¦ð@@¡ &Àð‘@¡† À0ð‘À°ð‘Á0ð‘Á°ð‘Â0𑡆 Àð‘@¡ DÀ0ð‘À°ð‘ X­ ¬Òð]ð‘ ^­ ¬Òð]ð‘MS­ ¬Òð]ð‘­í¬Êð]ð‘ Y­?¬4ð]ð‘"­é¬œÂ9ñð‘¡ N­i¬´ð]@@¡† @Ð0ð‘­ì¬šðð‘­?¬4ð]ð‘ Y­?¬Pð]ð‘­ê¬."­?¬4ð]ð‘­ê¬.Ç9ñð‘ Y­?¬Pð]ð‘"­ê¬.Æ9ñð‘ Y­?¬Pð]ð‘"­ê¬.Å9ñð‘ Y­?¬Pð]ð‘"­ê¬.Ä9ñð‘ Y­?¬Pð]ð‘"ð„¨­ê¬N‰1ñð‘¡ Ž­i¬´ð]@@¡† À ð‘Á!À0ð‘­6¬0ð]¸pC§†¦À6ù1Á°ð‘ \ ]@¡†  À0ð‘#C§¦Ðà&ð‘ÿÿ­ê¬¾Æ3ñð‘²là¦ð‘D©†¨À(ð9­ï¬ð]A­ê¬Œðñ' XÂ@¡†  ÐÀ0ð‘&<@¡† À0ð‘­?¬4ð]ð‘­ë¬véð‘öð‘­ë¬(ðð‘@¡† À ð‘Á!À0ð‘¡ ¸­i¬´ð]@­ì¬šð­ ¬Òð]ð‘­ê¬ä@¡† À ð‘ßqÀ0ð‘À!ñð‘¡ p­i¬´ð]@&<@¡† À ð‘Á!À0ð‘­ì¬šðð‘#­ë¬‚úð‘# C‰0áð‘@¡†  à ð‘°là ð‘ Ê¡†  À ð‘@¡„ ­¬pð]ð‘­'¬Æð]ð‘02Å1áð‘b@¡†  À ð‘°hà ð‘ÈeÀ ð‘°h@A£„¢ À ð‘Ð"ð‘­í¬DÍ1ñð‘ÂñÂóßu­ë¬ìÊ%ñð‘:Á$Åäð‘j@¡†  Ð ð‘À0ð‘­ì¬JÅòð‘@¡† Àð‘c­?¬Pð]ð‘c@¡†  À ð‘ÄqÀ0ð‘°hÀ ð‘ÿÿ­ê¬ÖÅ1ñð‘@¡† À ø9C§†¦Àð‘­ê¬„€ ñð‘c­ð¬dð]ð‘­1¬àê‡ð‘­1¬ðð]ð‘ S ­ð¬ð]ð‘ X­ ¬Òð]ð‘­9¬Ìð]ð‘­:¬îð]ð‘@¡† À ð‘À!áð‘À ô9­7¬Öð]ð‘ X­ ¬Òð]ð‘@¡† À ð‘À!áð‘­í¬€ð]¶hÀ!á‹v­é¬ðð‘À!áð‘¡ (­i¬´ð]@ðÑÀ!pr~@¡ DÀ0ð‘аð‘@¡† À ð‘Á!À0ð‘¡ Ü­i¬´ð]@­ì¬šðÿÿ­í¬Æ@¡ &Àð‘pÀð‘ˆòð‘@¡† Ðð‘I@¡  z­i¬´ð]²h­ð¬ð]ð‘ðÑÂ%  € áð‘ À@¡†  À0ð‘N ­?¬Pð]ð‘á÷ßq‚ HS­?¬4ð]ð‘á÷ßqMSM ^ d­?¬4ð]ð‘å÷ð‘­ð¬"ð]ð‘ R­?¬4ð]ð‘  ­?¬Pð]ð‘&< X­?¬Pð]ð‘ Y­?¬Pð]ð‘ ^­?¬Pð]ð‘­î¬Ž–¥ñð‘  ­?¬Pð]ð‘ ð‘&<­î¬ÜÁ1ñð‘ È­?¬Pð]ð‘å÷ð‘ÿ"­ï¬Â9ñð‘hHI­?¬Pð]ð‘­î¬¸ßsñð‘­ð¬ð]ð‘­ï¬–ð]ð‘@¡† Àð‘H­í¬è@¡† À ð‘ßqÀ0ð‘ñð‘ðÑð‘À>ù1ÿ¯­ ¬Úð]À1l€. B¥¤°tB,C-DrA., ,,Ç­[¬Dð]A²p"! ð‘²pð¯À.ð9Áñ3²pºpñ!Ð ð‘ð#ô#Å#á“ñ;ߪð‘²jA°rñ!ÂðÑð‘ ¨Z­ ¬Òð]ð‘ (Z X­?¬Pð]ð‘ S X­ ¬Òð]ð‘­?¬Pð]ð‘ Y­ ¬Òð]ð‘ \ ] X­ ¬Òð]ð‘    YaðÑð‘­ï¬–ð]ð‘ _­ð¬"ð]ð‘­«¬Fð]ð‘&ðÑð‘­/¬æð]ð‘ ^c­ ¬Òð]ð‘c­ ¬Òð]ð‘HÿIÿc­ ¬Òð]ð‘c­ ¬Òð]ð‘b DðÑð‘@¡„ ­ð¬zðð‘À0ð‘ÂñŸtá÷ð‘ðÑð‘¡ €­i¬´ð]@#­ñ¬ð]ð‘áð‘A£¢B­ó¬Nð]#­ñ¬ð]ð‘áð‘A£¢B­ó¬Nð] #­ñ¬ð]ð‘áð‘A£¢B­ó¬Nð]@#­ñ¬ð]ð‘áð‘A£¢B­ó¬Nð]€­â¬Ø§¦šð]ð‘ðÑð‘A£„¢"!@ ð‘A£ó¢p­ò¬.ð]ð‘­ñ¬˜ñð‘Âó§ó¦Švųáåð‘@¡ó p­ñ¬Àð]ð‘­ñ¬˜ñð‘Âñ§ó¦Švűáåð‘@¡ BÀ ð‘Á9á—ð‘€0A£„¢"!@ ð‘ðÑ€ àmA£„¢"!@ ð‘ðÑð‘A£„¢"!@ ð‘ðÑð‘À ð‘A£„¢€@݃À2ð‘ÂórÅ·áõð‘A£„¢€"!@ ð‘A£…¢"!@ ð‘A£„¢€B¥…¤@܃À"ð‘Ð$ð‘Á1á“ð‘ÂóÂõrÀ·áé€0ðÑð‘àÀ"ð‘h.... ..... .$.(.,.0.4.8.<­ò¬`ð]ð‘ðÑð‘­ó¬J*€Ê1ñð‘Ï3ñð‘*„Ê1ñð‘Ï3ñð‘*ˆÊ1ñð‘Ï3ñð‘*ŒÊ1ñð‘Ï3ñð‘*Ê1ñð‘Ï3ñð‘*”Ê1ñð‘Ï3ñð‘*˜Ê1ñð‘Ï3ñð‘*œÊ1ñð‘Ï3ñð‘* Ê1ñð‘Ï3ñð‘*¤Ê1ñð‘Ï3ñð‘*¨Ê1ñð‘Ï3ñð‘*¬Ê1ñð‘Ï3ñð‘*°Ê1ñð‘Ï3ñð‘*´Ê1ñð‘Ï3ñð‘*¸Ê1ñð‘Ï3ñð‘*¼Ê1ñð‘Ï3ñð‘€0ðÑð‘à{à"ð‘Å%Ð2ð‘ðÑð‘à"ð‘Å-Ð2ð‘ðÑð‘Ì3ªªUUÿÿ @@€€A£ó¢ŒÀ"ð‘­ô¬À!ñð‘A£¢\€À2ð‘A£ó¢ŠÀ"ð9­õ¬ð]ð‘A£ó¢ŒÀ"ð‘ßqÀ2ð‘A£ó¢ŠÀ"ð9Ðâ‘ð‘@p„âð‘PHÀ2ù1ðÑ€ @¡ \À ð‘@¡ Ö­i¬´ð]²hA£¢\­ó¬\ð]ÿàSÿþÑ©E«ôª2À:ù1Àºð‘­ö¬ˆð]ð‘À*ð9Àªð‘­ö¬òð]ð‘A£ó¢pÀ*ð9Àªð‘­ö¬$ð]ð‘ÂóóŠ­ô¬hʳñð‘A£¢\Ð"ð‘Ê+á‡ðÑð‘à{ÜÐ ð‘Ð2ð‘ÂñÂóvϱáïð‘ðÑð‘ÜA£„¢Ð ð‘Ð2ð‘ÂñÂóvϱáéð‘ðÑð‘ÜA£„¢Ð"ð‘Ð0ð‘ÂñÂóvϱáéð‘ðÑð‘%x nE«ôªþÀ:ù1Àºð‘­õ¬6B¥„¤B@‰3ñð‘­õ¬€tűñð‘­õ¬VB¥„¤B@‰3ñð‘­õ¬€tűñð‘@­õ¬Ž‰"ñð‘Ý¥÷¤ftÅ‘âð‘¥ó¤jvÅ•â‘ð‘Ñ­õ¬âðð‘A£„¢­ô¬¤ð]ð‘E«ôªþÀ*ð9­ô¬6ð]ð‘@¡„ E«ôªþÀ*ò9­ô¬¤ð]ð‘E«ôªþÀ*ð9ÑE«ôªþÀªð‘ßqÀ:ù1Àºð‘­õ¬À!ñð‘A£¢\Ð"ð‘­ö¬Ê+ñðÑð‘­ö¬ð¸pT@ÜÐ"ð‘Ð0ð‘ÂñpÏ·áõð‘°xPDà ð‘Î3á‘ð‘ÂñpÏ·áïð‘ðÑð‘B¥¤\ð$ð‘À'À4ð‘À´ù1Á$ð‘ÁqÁ4ð‘Ñ´ð‘â4ð‘àQ¸pT@ܪªÐ0ð‘ÁsÂñpÏ·áóð‘°xPDªªà ð‘Î3á‘ÁsÂñpÏ·áïð‘ðÑð‘B¥¤\ð$ð‘À'À4ð‘À´ù1Á$ð‘ÁqÁ4ð‘Ñ´ð‘â4ð‘àQ¸pT@ܪªUUÐ0ð‘à°ð‘ÄñpÏ·áñð‘°xPDð ð‘Ï3á™ð‘ð ð‘Ï5áÄñpÏ·áçð‘ðÑð‘B¥¤\ð$ð‘À'À4ð‘À´ù1Á$ð‘ÁqÁ4ð‘Ñ´ð‘â4ð‘àQ÷hðŠ€åZä®äØå÷¬øÎÿÿðŠ€åZä®äØøÎ÷¬øøåÿÿ¡  0­i¬´ð]@­`¬Jð]@­`¬ð]0 =­_¬øð]ð‘…9á“ð‘A£¢|­ó¬Nð]„9á“ð‘A£¢|­ó¬Nð]­`¬†ð]0 =­_¬øð]ð‘…9áð‘A£¢|­ó¬Nð]„9áð‘A£¢|­ó¬Nð]­c¬nð]ð‘C§ó¦pÀð‘@¡± A£µ¢ðÀð‘­g¬,ð]ð‘@¡± ­g¬„ð]ð‘Ðð‘­ø¬¶ˆ°ñð‘Â÷óŠ­ø¬TÅ·ñð‘­`¬†ð]@­â¬Ø§¦¤ð]ð‘ðÑð‘A£¢|­ó¬Nð]­ø¬œðð‘­ä¬tð]ð‘­`¬ð]]«ªX­ã¬Nð]E­ä¬Œð]ð‘ðÑð‘¡  š­ã¬ ð]ð‘­ù¬2ñÀ1­ä¬tð]ð‘­`¬ð]«ª`­ã¬Nð]E­ä¬Œð]ð‘ðÑð‘æÁççAççÁèèAèèÁééAééÁêêAêêÁëëAëëÁììAììÁííAííÁîîAîîÁïïAïïÁððAððÁññAññÁòòAòòÁóóAóóÁôôAôôÁõõAõõÁööA÷÷øøùùúúûûüüýýþSUN SENA 1.09@@@@@@@@ @@@@unknownFRONT DISKSREAR DISKS Power Supplies (0,2 in front, 1 in rear)*Fans (0 in front, 1 in rear) ESI Interface board(IB) (A top, B bottom)GBIC module (1 on left, 0 on right in IB)Disk backplane (0 in front, 1 in rear)BTemperature sensors (on front backplane)Temperature sensors (on rear backplane)Interconnect assemblyLoop configurationLanguage USA Englishrev.-00mod.-000rÌŽÁ ­¾ï1$hÎUG6ݪh@(#)Wed Mar 3 13:32:24 1999 #AaBbCc1DdEeFf2GgHhIi3JjKkLl4MmNnOo5PpQqRr6SsTtUu7VvWwXx8YyZz##9-._0-._abc1abcdef2def33333334444444555555566666667777777888888899999990000000ìó;KópÃ?#PãKƒS%ƒPãPãPãPãPãPãPãPãPãPãPãPãPãPãPãPãPãPãPã ^sÿPãPãPãPãPãPãPãPãPãPãPãPãPãPãPãPãPãPã“ !ÿPãPãPãPãPãPãPãPãPãPãPãPãPãPãPãPãPãPã³ ÿ mmðm#m3mCmSmcÿ86S5#Pã 7^C^S^ca_3o“ÿ“C;Pã kƒk“o#ao“o3oCoSocØSØcïãÿ؃óCPã kƒk“o£o³oÓk£al£o“oãØ“Ø£سØsíÓ؃ö3ö#øšÿØÓ““Pã kƒk“o£o³oÓk£al£o“oóØãØóÙØÃíãØÓöSöCø¤ÿÙSÙc“Pã kƒk“a3aCasaƒao“aSa#ÙÙ#ÙSÙcÿÙsÙƒCPã kƒk“a3aCasaƒao“aca#Ù3ÙCÙsÙƒÿÞÓÞã(ãPã ``#asaƒao“a“bSٓ٣ٳÞÓÞãÿÞóß)£Pã ``#asaƒao“bSa£ÙÃÙÓÙãÞóßÿßß#*cPã ``#asaƒao“bSa³ÙóÚÚßß#ÿß3ßC+#Pã ``#asaƒao“bSaÃÚ#Ú3ÚCß3ßCÿßSßc+ãPã ``#asaƒao“bSaÓÚSÚcÚsßSßcÿßs߃,£Pã ``#asaƒao“bSaãÚƒÚ“Ú£ßs߃ÿß“ߣ-cPã ``#asaƒao“bSaóÚ³ÚÃÚÓß“ߣÿÔãÔó.#Pã ``#asaƒao“bSbÔ³ÔÃÔÓÔãÔóÿÕ3ÕC.ãPã ``#asaƒao“bSbÕÕÕ#Õ3ÕCÿÕƒÕ“/£Pã ``#asaƒao“bSb#ÕSÕcÕsÕƒÕ“ÿÕÓÕã0cPã ``#asaƒao“bSb3bCÕ£Õ³ÕÃÕÓÕãÿß³ßÃCCPã ``3asaƒao“a“bSÚãÚóÛß³ßÃÿßÓßãDPã ``3asaƒao“bSa£ÛÛ#Û3ßÓßãÿßóàDÃPã ``3asaƒao“bSa³ÛCÛSÛcßóàÿàà#EƒPã ``3asaƒao“bSaÃÛsÛƒÛ“àà#ÿà3àCFCPã ``3asaƒao“bSaÓÛ£Û³ÛÃà3àCÿàSàcGPã ``3asaƒao“bSaãÛÓÛãÛóàSàcÿàsàƒGÃPã ``3asaƒao“bSaóÜÜÜ#àsàƒÿÖ#Ö3HƒPã ``3asaƒao“bSbÕóÖÖÖ#Ö3ÿÖsÖƒICPã ``3asaƒao“bSbÖCÖSÖcÖsÖƒÿÖÃÖÓJPã ``3asaƒao“bSb#Ö“Ö£Ö³ÖÃÖÓÿ××#JÃPã ``3asaƒao“bSb3bCÖãÖó×××#ÿ*èƒ*ès*è£*è“S4“Pã [Sjj#j3jCèsèƒè“è£a_3o“ÿS$ó [c[sÿ&ƒ'3;Pã jãjóo#ao“o3oCoSocç“ç£ïÃÿè%ó'3Pã jãjóo£o³oÃkal£o“oãçóèç³çÓçãçÃíóørÿèc%ó&ƒPã jãjóo£o³oÃkal£o“oóèSèè3èCè#ècîø|ÿ(ã)£*c+#+ã,£-c9É#9É39ÉC9ÉS;Pã ``#`C`S`c`s`ƒ`“`£9Çc9Çs9ǃ9Ç“9Ç£9ÇÓ9È9È39dz9Çã9È9ÈCà“à£à³àÃàÓàãàó ó“ óà óó ô# ôS ôƒ ô³ao“ï“ÿã33'ã)£Pã ``#o£o³oÓbsal£o“oãásáãã3ää3äCä#î³ ó£ññÿãCÓ'ã*cPã ``#o£o³oÓbsal£o“oóáƒáóãCäSäsäƒäcîà óÓñ3ñ#ÿãSs'ã+#Pã ``#o£o³oÓbsal£o“pá“âãSä“ä³äÃä£îÓ ôñSñCÿãc'ã+ãPã ``#o£o³oÓbsal£o“pá£âãcäÓäóåäãîã ô3ñsñcÿãs³'ã,£Pã ``#o£o³oÓbsal£o“p#á³â#ãsåå3åCå#îó ôcñ“ñƒÿãƒS'ã-cPã ``#o£o³oÓbsal£o“p3áÃâ3ãƒåSåsåƒåcï ô“ñ³ñ£ÿã“ó'ã9ÂPã ``#o£o³oÓbsal£o“pCáÓâCã“å“å³åÃå£ï ôÃñÓñÃÿÊ#“'ã.ãPã ``#o£o³oÓbsal£o“pSÉ£ÉãÊ#Ë3ËSËcËCÍ£ ÍÃñóñãÿÊ33'ã/£Pã ``#o£o³oÓbsal£o“pcɳÉóÊ3˃Ë£˳Ë“ÍÓ ÍóòòÿÊCÓ'ã0cPã ``#o£o³oÓbsal£o“psÉÃÊÊCËÓËóÌËãÎ Î#ò3ò#ÿÊSs'ã(ãPã ``#o£o³oÓbsal£o“pƒp“ÉÓÊÊSÌ#ÌCÌSÌ3Î3 ÎSÏ3Ï#ÿ%ó8ƒ;Ã;1ÃPã b“b£b³bÃbÓbãal£_Cbóccc#ÿKó'ãBC?“;2cPã b“b£fCfSfcfsal£_Cc3cCcSccÿ:s;1#Pã b“b£csiCal£_CÿTãTã3s f#aaf3o#Wee#e3eCeSecÿTã2ã4 f#aaf3o#Weseƒe“e£e³eÃÿTã3sPã f#aao“o#W#eÓeãeóffÿ$ó ao#V³YSYcYsYƒY“Y£Y³ÿƒƒ5³ aaf3o#VÓZSZcZsZƒZ“Z£Z³ÿƒ5#5# aaf3o#VãZSZÃZÓZãZóÿSS6Ó aaf3o#WXXX#X3XCXSÿS6C7s aaf3o#XWXcXsXƒX“X£X³XÃÿS6Ó6C aaf3o#W#XXÓXãXóÿ&L£Pã ÀÌao“lão#_s_ƒÿ99Ã;Pã kk#o#ao“k3kCééïÓÿ-N¡é38ƒ9ÃPã kk#o£o³oÃksal£o“p£kSéCécéSé#é3îø†ÿ-N±éƒ8ƒ9Pã kk#o£o³oÃksal£o“p³kcé“é³é£éséƒî#øÿ;Pã i£i³o£o³oÃiÃao“iãiÓêêê#î3ø"ïóÿKó'ãBC?“%ó8ƒ;Ã:s1#Pã ÀÌÀÞ^ƒ_oƒð#ð3ðSðcðsðƒðCð“ð£_3_C_S_cÿ=s=Ã;Pã iójo#ê3êCêSêcjj#j3jCao“ðÿ;Ãê“;Ã=Pã iójo£o³oÃjSjcal£o“êsê³ê£êƒê“îCø,ÿ;Ãë;Ã=ÃPã iójo£o³oÃjSjsal£o“êóêÓêÃêãëîSø6ÿ;ÃëS;Ã>sPã iójo£o³oÃjSjƒal£o“ëCë#ëë3ëSîcø@ÿ;Ãë£;âޝsrŠX¬ó>§sŽš³Press Nameebutton to enteruser-definedename up to 16alpha-numericcharactersi-Press keypadbutton 1 to 7times to displayldesired letter ornumber.-Use forward-arrow to movecursor to nextospace.-Use underscorefor spaces.-Use back-arrow to deletepreviousdcharacter.l-Exit screentto store name.¦ctšc€Žc‚cžvc¬jcº¦cÆšcÔŽcâ‚côvdjd¦dšd*Žd:‚dBvdRjd^¦djšdzŽd„‚dvdž&·“!ÀˆÓ ¯ï‰CÕ¬Cº¨ì £à ÃÔ¡cÈ¡sÌ À ´ ¨ ((Á°(Á¸(ÁÀ(Áȱq3 Qq3ñq3‘q31q3Ñq3%qq3+q3£q3 Cq3ãq3ƒq3#q3Ãq3%cq3+q3³Ì SÍóΓÏ3ÐÓÑ%sÒ+Ó¥Ô EÕåÖ…×%ØÅÙ%eÚ+Û ™s„†ó-D†óº…Ó ÀÞÀ櫚³$ËšS‹šSЕ³Ζã«¢'P§CŒ Ã%ì £I¡s%©¡cÖ§C* £* Ã*¡c*¡sšºs«§s$ΧS’§S«‡“$É‹cì‹c«“%mŽ£S}³:‚c‰ ÀÀ‰ ÀÆðŽ£«~“$(€ƒN€ƒ«¯s#†°Ã#†± ›ÃL€Ó"*~óモ1™# "“ 3c!õ~ó!Úºsºw³þ}c€ˆÓ"~ó¦Ã!Ú~ó$¿Óþ°S‡|#†¾C ‚sõmfæmf×mfÈmf Save Box IDSave Box NameSave Loop Conf>Reset IB AoReset IB BoSpin Down DriveSpin Up DriveFront Fan OffFront Fan OnRear Fan OffRear Fan OnBypass GBICConnect GBICBypass BP 0Connect BP 0Bypass BP 1Connect BP 1Bypass DD ABypass DD BConnect DD AConnect DD BSave BrightnessEEPROM offnEEPROM onBypass BP ABypass BP BConnect BP AsConnect BP BsScreen Save OffScreen Save OnAutobypass OffAutobypass On$­c‰ó"4©ÃHvC)w£ x#¸š“!ÀŒ³Ô’˜ š“!Ú‡#EvCEw£Ex#Ex£Ey#Ey£Ez#E×SE×cE{óew£ %vCE}³E‚cr¼#____n________________f pÄ.pÊ$pÒ2Ì$Ô@@@@@@@ÀÀÀÀÀÀÀ€€€€€~VjVn~ €@ @€ @à @   À @   À €`à  à    À   @     `  À   À  À   À €`€  €€ à  À à €@   @  €€€ à   @€   à à   €€ à  €à €@   @ H€E?€ àà ð€€ à °  à @@?° à€@ ð € à €à€€à€ ð àÀÀà €€€€€ à€à €€€ €@   @€ €€  à  À  €€ € @ @ @`@_€€ € € à  À €€€ À  €€ €  à €À€€ àà  €€ àà €€ à € à €€ `€€` €€ `€€` C€|€     ` €€€€?ÿÿ`€À€À€À€À€À€À€À€ÇÀ€Ïà€È €È €Ïà€ÇÀ€À€À€À€À€À€À€À€à€ÿÿÿÿþ >I>?ÿÿ`€À€À€À€À€À€À@€Ïà€Ïà€À€ÇÀ€Ïà€È €È €Ïà€ÇÀ€À€À€À€À€À€à€ÿÿÿÿþ?ÿÿ`€À€À€À€À€À€À@€Ïà€Ïà€À€À€À€À@€Ïà€Ïà€À€À€À€À€À€À€à€ÿÿÿÿþ?ÿÿ`€À€À€À€À€À€À€À€À€À@€Ïà€Ïà€À€À€À€À€À€À€À€À€À€à€ÿÿÿÿþ ?ÿÿ`€À€À€À€À€À€À€À€È@€Ì`€Î €Ë €Éà€ÈÀ€À€À€À€À€À€À€À€à€ÿÿÿÿþ cqYOF?ÿÿ`€À€À€À€À€À€À€À€Ä €Í €É €Éà€Ï`€Æ €À€À€À€À€À€À€À€à€ÿÿÿÿþ !aEe;?ÿÿ`€À€À€À€À€À€À€Ã€Ã€€ÂÀ€Ïà€Ïà€Â€À€À€À€À€À€À€À€À€à€ÿÿÿÿþ ?ÿÿ`€À€À€À€À€À€À€À€À€Åà€Íà€É €Ï €Æ €À€À€À€À€À€À€À€à€ÿÿÿÿþ 'gEE}9?ÿÿ`€À€À€À€À€À€À€À€ÇÀ€Ïà€È €Ï €Ç@€À€À€À€À€À€À€À€À€à€ÿÿÿÿþ <~KIy0?ÿÿ`€À€À€À€À€À€À€À€À€Ç€ÇЀÀð€À0€À€À€À€À€À€À€À€À€à€ÿÿÿÿþ?ÿÿ`€À€À€À€À€À€À€À€À €Î €Ï €Áà€À`€À€À€À€À€À€À€À€À€à€ÿÿÿÿþ?ÿÿ`€À€À€À€À€À€À€À€À€ÆÀ€Ïà€É €Ïà€ÆÀ€À€À€À€À€À€À€À€à€ÿÿÿÿþ?ÿÿ`€À€À€À€À€À€À€À€À€ÅÀ€Ëà€Ê €Ïà€ÇÀ€À€À€À€À€À€À€À€à€ÿÿÿÿþ OIi? x~€€~x€€€<~Jn,~~?€€B!p|ocÀ`ð`<``À`ð`<`@ƒÀYÿÀðYÿÀð@ƒÀ``<`ð`À``<`ðcÀo|p!øŽƒ€àœ8ŸŸÃ€ŸðàŸü8ŸÿŸÿÀŸÿðà¿à|8¦?¦?¿à|8ŸÿðàŸÿÀŸÿŸü8ŸðàŸÃ€Ÿœ8àƒ€Žøþpþ|€€€|pþ<þ|@þ|þ|? DÌ8Ì|D|8àü^^üà?ÿþ`À€À€À€À€À"€ÀA€À€€€Á@€Â €Ä€È€ß|€Á@€Á@€Á@€ÁÿÀ€À€À€À€À€à€ÿÿ?ÿþ>ŸÀ>ŸÀ@>À> €>>><:*>À<Àœ¾¢þ~>*.?ŸÀ?ŸÀ’@’@À €€?ˆ?:*><>> >À<À>*. ?ÿþ`À€À€À€Çþ8€Ïþ<€Ì €Ì €Ì €Ì €Ì €Ì €Ì €Ì €Ì €Ì €Ì €Ïÿü€Çÿø€À€À€à€ÿÿÿÿþþþIþIþ‚6Æ|88|D|Ì8ÌDl88lD?ÿÿ`€Ãÿø€Â€Âª¨€Â€Áÿð€À€Ãÿø€Â€Âª¨€Â€Áÿð€À€Ãÿø€Â€Âª¨€Â€Áÿð€À€Ãÿø€Â€à€ÿÿÿÿþ?ÿÿÿÿ€ü€ýÿ÷€ýUW€ýÿ÷€þ€ÿÿÿ€ü€ýÿ÷€ýUW€ýÿ÷€þ€ÿÿÿ€ü€ýÿ÷€ýUW€ýÿ÷€þ€ÿÿÿ€ü€ýÿ÷€ÿÿÿ€ÿÿÿÿþÿ@UU@?þÿ@UU@?þÿ@UU@?þ€ºD‚ƒà‚Dº€?ÿÿ`€À€À€À€À€À€À€À€À€À€À€À€À€À€À€À€À€À€À€À€À€à€ÿÿÿÿþ?ÿÿ`€À€À€Ïÿü€Â€Â€Â€Â€ÏŸ>€Ï›>€ÏŸ>€Ï•>€ÏŸ>€Ï›>€ÏŸ>€Â€Â€Â€Â€Ïÿü€À€à€ÿÿÿ€ÿÿ )?€?€$€?€†þø>??">*. &.::†þø>>>><>"6þþ’þlO?ÿÿ`€À€À€À|€Àþ€ÀÆ€À‚€À†€À„€ÀH€Àè€À¨€Àø€Àð€À€Àø€Àø€À€Àø€Àð€À€Àp€Àø€Àˆ€ÀØ€ÀP€À€Àp€Àø€À¨€À¸€À0€À€Àþ€Àþ€À€À€À€À€À€À€À€À€À€À€À€À€€ÀÀÀ€Á€`€Ãp€Æø€Ì̀Ȅ€È€È€È€È8€Èp€Ìà €ÇÀ€Ã€0€Á€`€ÀÀÀ€À€€À€À€À€À€À€À€À€À€À€À€à€ÿÿÿÿþÿÿ€0À`@`@`@`@`@`€@`?à@`pp@`@@`@@`@@``0@` @`@`@`@`@`@`@`@pÀÿÿ€?ÿÿ?ÿÿ`€À€Ïÿþ€Ã€Ã€Ã€Ã€ÏÏ΀ÏÏ΀ÏÏ΀ÏÏ΀ÏÏ΀ÏÏ΀ÏÏ΀ÏÏ΀ÀÀÀÀÏÿþ€À€à€ÿÿÿ€ÿÿO?ÿÿ`€À€À€À€Àø€Áü€ÁŒ€Á€Á €Á€Àà€Áð€Á€Áð€Àà€À€Áð€Áð€À€Áð€Áà€À€Áø€Áø€Á€À€Áô€Áô€À€Áð€Áð€À€Áð€Áà€À€Àð€Áð€Á€Áð€Áð€À€Àà€Áð€ÁP€Áp€À`€À€À€À€À€À€À€À€À€À€À€ÁÿÀ€Á@€Á@€Á@€ß|€È€Ä€Â €Á@€À€€€ÀA€À"€À€À€À€À€À€À€à€ÿÿÿÿþ4€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€">AA>~~}}|||x8|T\>AA>|||x}}|||x8|T\þþþþ>€àøþþþþþþ‚‚þþ‚‚‚‚‚‚‚‚‚‚‚‚‚þþþþþþþþþþþþþþþþDxÈ€”€ä@”À¤@`˜€ÿÿà0``€`€`€`€`ø`` `@`€a`€`@` ``ø`€`€`€`€pÿÿà?ÿÿàŸÀŸÀ?‚@?‚@€@€>>:*><¾ þ~$.*:ÿÿ€0À`@` @`Q@`ˆˆ@a@b€@`@b¢@a@`* @`ED@`‚*@a@` @a@`ˆˆ@`DP@`(@`@`@pÀÿÿ€?ÿÿ?ÿÿÿÿ€ÿÿÿ€ð€öI'€öI'€öI'€öI'€öI'€öI'€ô€õÿÿ€ÿÿÿ€õÿÿ€þª«€÷]w€þ므÷]w€þ므÷]w€úª«€ÿÿÿ€ÿÿÿ€ÿÿÿ?ÿÿ?ÿþ`À€À€À€À€ÁÿÀ€Á@€Á@€Á@€ß|€È€Ä€Â €Á@€À€€€ÀA€À"€À€À€À€À€à€ÿÿÿÿþ?ÿÿ`€À€Ïÿü€É¶Ø€É¶Ø€É¶Ø€É¶Ø€É¶Ø€É¶Ø€Ëÿü€Ê€À€Ê€ÁUT€È¢ˆ€ÁP€È¢ˆ€ÁP€È¢ˆ€ÅUT€À€à€ÿÿÿÿþÿÿÀ›m€›m€›m€›m€›m€›m€¿ÿÀ  U@Š(€EŠ(€EŠ(€UU@þþøøpøˆøpøøøð~þˆ$?ŸÀ?ŸÀ ‚@1‚@@>>>‘>Ÿ<<>À*À. $.*:?ÿÿ`€À€Àà€Áò0€Ã€Æ €Ä€Ä€ÅÄ€Æ.0€Àÿà€ÁŽŒ€Ãt€Â €Â€Â €Ã€Á‰ð€Àø€À€À€à€ÿÿÿÿþ?ÿÿÿÿ€ÿÿÿ€ÿü€þ Ï€üæç€ùò÷€ûú÷€ûù÷€ú;ç€ùÑÏ€ÿ€þqs€üû‹€ýóû€ýëû€ýéó€üìç€þv€ÿÿ€ÿÿÿ€ÿÿÿ€ÿÿÿ€ÿÿÿÿþ|>Fc#Á¡€¡€Á¸ƒÅÆü1Ñ€`Ž€A€€B€€BÁ€bc1>?ÿÿ`€À€À€À€À€Àp€À˜€ÀŒ€Àä€Ç¾4€Ä£€Ä¡´€Ç¼ä€À €À€Àð€À€À€À€À€À€à€ÿÿÿÿþ €€÷Æ€”b€”6€÷œ€Á€c>!?ŸÀ?ŸÀÀÀ?€?Ž>*. @À>À>><> >>?ÿÿ`€À€Ïÿü€È’H€É¶Ø€É¶Ø€É¶Ø€É¶Ø€È’H€Ëÿü€Ê€Ê€Ëÿü€È’H€É¶Ø€É¶Ø€É¶Ø€É¶Ø€È’H€Ïÿü€À€à€ÿÿÿÿþ?ÿÿÿÿ€ÿÿÿ€ÿÿÿ€þ?€þÿ¿€þ¢¿€þã¿€þ¢¿€þã¿€þ¾¿€þÿ¿€þÏ¿€þÈ¿€þÿ¿€þÿ¿€þˆ¿€þˆ¿€þˆ¿€þˆ¿€þ?€ÿˆÿ€ÿÿÿ€ÿÿÿÿþ1ÀÀII68|DÀ|À8 tT|x|| 8€|ÀD@@H\Tt$ ?ÿÿ`€À€Àÿà€À€ €À® €ÀŠ €Àª €ÀŒ €À€ €À˜ €À› €À€ €À€ €À€ €À» €À» €À» €À» €Àÿà€À;€€À€à€ÿÿÿÿþ ÿà€ ® Š ª Œ € ˜ › € € € » » » » ÿà;€<xx```````````````````````````````````````````````````````xxÀÀÀÀÀGÿÿÿÿÿÿÿÿüÿÿÿÿÿÿÿÿüààààà?ÿÿ`€Àª¨€Â€À€Â€ÁUP€À€Àª¨€Â€À€Â€ÁUP€À€Àª¨€Â€À€Â€ÁUP€À€Àª¨€Â€à€ÿÿÿÿþ!"€&†€oÆàIfàI6à{6à6à~6à~fàDfà ÆàtÆàTÆà|Æàxfà6à~€~€D<ˆ@|ˆ@@||\TtDD?ÿþÿÿÿÿÿ€ÿýÿ€ÿýÿ€ÿýÿ€ÿùÿ€ÿùÿ€ÿùÿ€ÿñÿ€ÿñÿ€ÿíÿ€ÿý¿€ÿü€ÿü€ÿüÿ€ÿüÿ€ÿüÿ€ÿýÿ€ÿýÿ€ÿýÿ€ÿÿÿ€ÿÿÿ€ÿÿÿÿþ?ÿþ`À€À€À€À€À€À€À€À €À€À€À@€À€€À€À€À€À€À€À€À€À€à€ÿÿÿÿþ% ?ƒø?ƒø€ˆ€øpÀ>à" >àÀ@@>à>>àü Âü >?ð@?ð@" ?ƒ€?ƒð$x$x?ƒð€ "  " 2NÿÿÿÿÿÀ€€€€€€€€€€€€€€€€€€€€€€€€@€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€€ÿÿÿÿÿÿÿÿÿÿÿþ!ÄÀÍàI É `8@|€DÀ|À8€|€| €€€~À~ÀD€€€€€I ÀI Ë€Š€6€D€D€ .8D8D |8TTLTt8TT|xD!ð˜2ñ¼x‘$ÿÀQ$þ ÁìÿÀÈx2ÁøøÀ€DAÐDPðÁà€ÁøAøA€ÀðAðÁðAðÀpPÁÐ@+IIIIIIn>cAc>DD ?€?€€€:*><>€>€?€?€>*. >"?€ )>>><>">&.::>€>€œ¾¢þ~>>><:*><?€?€ >">?€?€6" &.::>€>€œ¾¢þ~>>><:*><?€?€ÄÀÍà‰  `†€ÏÀÏÀ€€ €€€ÀÀ€Ç€Ï€€€ € €€€€ 0>"><<>*. >>€?€">*. >>>>><þþ">(`0@`@` 8@`|`ÿø` ÿÄ`ÿø`0|`08@`@` @`@@"@@"ÿÿÿÀ` `ÿÿÿÀÿÿÿ€?ÿþ`À€À€Àþ€Áÿ€ÁÇ€Áƒ€Áƒ€Áƒ€Áƒ€Áƒ€Áƒ€Áƒ€Áƒ€Áƒ€Áƒ€Áƒ€ÁÇ€Áÿ€Àþ€À€à€ÿÿÿÿþ €€ÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀ€€€ŸÀ?ŸÀ?¾ þ~þþ">>*. 33?ÿÿ`€À€À€Ãÿü€Â€Â€ÂëÔ€ÂëĀ ԀÂëÄ€Âè€ÂÄ€ÂԀ¸€Î€È>¤€È€È€Ïÿü€À€À€à€ÿÿÿÿþÿÿÿÿÿ€ÿÿÿ€ÿÿÿ€ü€ýÿû€ýÿû€ý+€ý;€ýô+€ý;€ýë€ýü;€ýü+€ýGû€ñÿû€÷Á[€÷ÿû€÷ÿû€ð€ÿÿÿ€ÿÿÿ€ÿÿÿ€ÿÿ?ÿþ?ÿÀ @ @.½@.¼@ ½@.¼@.@ <@ =@+€@à@ƒê@€@€@ÿÿÀ€€€€€€€€€€€€€€€€€€€€€€€€€€08À>À € €>8$.*:À$À.*:>*. >>>>> <?Ÿ?‘">Ÿ?Ÿ?¾ þ~?ÿÿ`€À€À€À€À€À€À€À€ÇÀ€ÏကÈ!€€È €Ïà€ÇÁ€À€À€À€À€À€À€À€à€ÿÿÿÿþO?ÿÿ`€À€À€Àþ€Àþ€À€Àx€Àþ€Àþ€À€À@€Àè€À¨€Àø€Àð€À€Àø€Àø€À€Àø€Àø€À€Àø€Àð€À€Àp€Àø€À¨€À¸€À0€À€À€À€À€À€À€À€À€À€À€À€À€À€À€À€À€À€À€À€À€Áÿ€Á€Áy€Á€Áy€Á€Á}€ÁU€Á9€Á€Á9€ÁE€ÁE€Á€À‚€ÀD€À8€À€À €À€À€À€À€À€à€ÿÿÿÿþNN?ÿÿÿÿÃÿÿð`˜fÀ°`,<À<°à,?À$°€, ÈÀ$°€, ÈÀì°ÿ,?ÀȰ,<À°,À °À,?ÈÀ °àÿ,?ÈÎ#ü°°ÿ,þ"HÏ£ü³ø<,þ"HÁà³øf,?ÈÀ`°€Ã,ˆÀ°,Àü°,ˆÀü°ÿ,?ÈÀ°ÿ, HÀ°€, HÀü°€,0ÈÀü°€,ˆà¸nÿÿÿ?ÿÿÏÿÿðÿþÿÿ‡ÿÿà?ÿÿÿÿÃÿÿð`˜fÀ °ÿ,À|°ÿ,Àð°,?ÈÀð° ,?ÈÀ|°, HÀ °ÿ,0ÈÀ°ÿ,„ˆÀ|±8,ÆÆÃü³8ÿ,âÏãà²(,²?ÈÉ x²(x,ž?ÈÉ#à³èÿ,Œ"HÏãü±Èÿ,"HÆÀ|°, HÀ°~,À °ÿ,?ÈÀܰ,?ÈÀð°,HÀܰÿ,HÀ °~,Hà¸nÿÿÿ?ÿÿÏÿÿðÿþÿÿ‡ÿÿà?ÿÿÿÿÃÿÿð`˜fÀ °ÿ,À<°ÿ,Àð°,ˆÀð°,?ÈÀ<°, HÀ °,$HÀ°,<ÈÀñà~,BˆÉㄳðÿ,ÒÉ"ä²XÁ,š?ÈÍ"t²HÁ,ž?ÈÇâ³Éÿ,öà±~,bÀ@°,?ÈÀаÿ,?ÈÀp°ÿ,Àذ1,Àp°q,?ÈÀX°ß,?ÈÀ°Ž,à¸nÿÿÿ?ÿÿÏÿÿðÿþÿÿ‡ÿÿàþþ8`þþpøˆøppøˆþþpøèø0˜¸èèÿÿ€0À`@`@`oÀ@`† @a@b@b@d@f@o@o@d@d@b@b@a@`† @`oÀ@`@`@pÀÿÿ€?ÿÿÀø..øÀ|þ‚‚þ|€P*¨@Tª‚T( Àø..øÀþþ €P*¨@ªT&þþ?€ € €þ1€þLÞ>’ ’>ö>dLÞ’8’>ö €d €>þ8þ‚?€Æ?€|8|þ?€‚?€‚Æ?€D?€€€€þþ’’þl|þ‚‚þ| þþ’’þlþþ&?€ € €1€> >>?€?€ €1€?€?€$€$€?€'€$€4€€ >cI{zI6>cACB,@ >  AA$>€<~KIy0BcqYOF?€?€' g E E€}€9><><A>I€{€II(BcqY O F @@$€BcqYOF'gE?€E?€} 9 €>€>A<I{<>€I€I,@ >  AA$>€<~KIy0BcqYO7€F$€$€'=€gEE€}€9><><A>I€{€II(BcqY O F @@$€BcqYOF'g7€E$€E$€}=€9€>€>A<I{<>€I€I?ÿÿ`€À€Ãàp€Çðˆ€Ä€Ä€Çðˆ€Ãàp€À€ÀA€Çà€€Çð@€ÀP €À€À@€Çà€Çð€ÀP€Àü€À€À€à€ÿÿÿÿþ|þ‚‚þ|üþ üþ !ðüüþ  þüüðÿÿÿÿÿÿÿÿ@`áñëǃ?ÿÿ`€À€Àp€Àˆ€À€ÇÁ€Ïàˆ€È p€È"€Ïá€ÇÀ€€À@€Ï€ €Ï€€À€€Ï€€Ï€À€Àü€À€À€à€ÿÿÿÿþ )?€ € €?€>>><?€?€>€>€>>><>*. *ªª@€€@€€@…€J‚ @€@•H€J€€*€UŠ€AŠ€T €€@€€@ €UUU*ªª|þÆ‚Æþ|øøøð?ÿÿ`€À€À€À€À€À €À €À €À€À€À$€À€€À€À€À€À€À€À€À€À€À€à€ÿÿÿÿþ ``à 800 †Æf6666ffÆÆÆÆf6,À7ŸÀ$‚@$‚@=ƒÀ€> >>þþ">þþ">•?—?†>Ÿ>ƒ>*. $.*:?ÿÿ`€À€À€ÀC€Àc€À3€À€À€À€À€À3€À3€Àc€Àc€Àc€Àc€À3€À€À €À€À€à€ÿÿÿÿþ?ÿÿÿÿ€ÿÿÿ€ÿyÿ€ÿ9ÿ€ÿ™ÿ€ÿÉÿ€ÿÉÿ€ÿÉÿ€ÿÉÿ€ÿ‰ÿ€ÿ™ÿ€ÿÿ€ÿ9ÿ€ÿ9ÿ€ÿ9ÿ€ÿ™ÿ€ÿÉÿ€ÿéÿ€ÿÿÿ€ÿÿÿ€ÿÿÿ€ÿÿÿ€ÿÿÿÿþ?ÿÿ`€À€À€ÀA€À"€À€À €À€À €À€À"€À€À"€ÀA€À"€ÀA€À"€À€À €À€À€à€ÿÿÿÿþ?ÿþÿÿÿÿÿ€ÿÿÿ€úª«€÷]w€þ므÷]w€þ므÷]w€þª«€õÿÿ€ÿÿÿ€õÿÿ€ô€öI'€öI'€öI'€öI'€öI'€öI'€ð€ÿÿÿ€ÿÿ?ÿþþþ2rÞŒpø¨¸0@è¨øðøø?ÿÿà€Ï€€Ï€€À€€Ç€Ï€€Êƒà€Ë„€Ã€Éˆ€Ëˆ€Îˆ~€Ìˆ€Ç€Ï„€Ê„€Ëƒà€Ã€À€€ÏÀ€ÏÀ€è€€ÿÿÿÿþ?ÿÿ`€À€À€À$€ÀB€À€Á€€Â@€ÃçÀ€À$€À$€À$€À$€À$€À$€À$€À'À€À @€À @€À?À€À€à€ÿÿÿÿþ$øðpø¨¸08ðð8ÀÀ|þ‚þ||þ‚þ|!øðpø¨¸08ðð8ÀÀ|þ‚þ|þþ$øðpø¨¸08ðð8ÀÀ|þ‚þ|„Æâ²žŒ$øðpø¨¸08ðð8ÀÀ|þ‚þ|BÒšžöb$øðpø¨¸08ðð8ÀÀ|þ‚þ|08,þþ $øðpø¨¸08ðð8ÀÀ|þ‚þ|NΊŠúr$øðpø¨¸08ðð8ÀÀ|þ‚þ|xü–’ò`$øðpø¨¸08ðð8ÀÀ|þ‚þ|âú?ÿÿ`€À€ÅUT€È¢ˆ€ÁP€È¢ˆ€ÁP€È¢ˆ€ÁUT€Ê€À€Ê€Ëÿü€É¶Ø€É¶Ø€É¶Ø€É¶Ø€É¶Ø€É¶Ø€Ïÿü€À€à€ÿÿÿÿþUU@Š(€EŠ(€EŠ(€U@  ¿ÿÀ›m€›m€›m€›m€›m€›m€ÿÿÀ$?ŸÀ?ŸÀ †@1Ž@À€>>>>•<<>*. $.*:O@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@O?ÿÿ`€À€À€À˜€Á¼€Á$€Á$€Áì€ÀÈ€À€À€ÁЀÁP€Áð€Áà€À€Àð€ÁÀ€Áà€Àð€À€À€Àà€Áð€ÁP€Áp€À`€À€À€À€Àø€Áü€ÁŒ€Á€Á €Àˆ€À€Áü€Áü€À€Áð€Áà€À€À€ÁЀÁP€Áð€Áà€À€Áð€Áð€À€Áð€Áà€À€Äà€Åð€Å€Çð€Ãð€À€Àà€Áð€ÁP€Áp€À`€À€Á0€Áp€ÁЀÁЀÀ€À€À€à€ÿÿÿÿþ?ÿÿ`€À€À€Ãÿð€Â€ÂP€ÎP€ÊP€ÊP€Ê€Ê€ÊÀ€Êà€Ëçp€È¸€Èü€Ïüä€Àl€À8€À€À€à€ÿÿÿÿþ! €À@@À €€€?ÿÿ`€À€€À€€ÀÀÀ€ÀÀÀ€ÀÀÀ€ÀÀÀ€ÀÀÀ€À€€À€€À€À€À€€À€€ÀÀÀ€ÀÀÀ€ÀÀÀ€ÀÀÀ€ÀÀÀ€À€€À€€à€ÿÿÿ€ÿÿ!L&Þo’I’Id2@8è|¨Dølð(|8|ð 88p|øT¨\¸08ø|øT\||ˆˆ|xÿþ€•R€•S€•R€•R€•Rà€ ÿþ        àÿþ€•R€•S€•R€•R€•Rà€ ÿþ    B c q YàOF PÀ±ŒøáãxÌc±ŒŒc£?|Lc 1Œ#˜!† Lc1Œ#Œ!† Lc1Œþ!ÄÇ!† Lc±ŒŒ lÁ1† LcŸüøùìçxOÿxpûÌnxG½ð ø @ü@þÿŸ€À|À?üOÇàü€ðÿÿçãðþ€€ðø€óñøþ€ÿ€øÀÀùøüþÿ€ÿø€Àüü~þƒÿçø€À~~?8þ?‡Ÿƒƒð?À??€qþ?‡ð~ÀŸaþŽðþÀÏÆAü œàþ€Ççàpü~?8áü€Çãóðøøþ?páü€ãñùñøøþ?àáüáøüãðøüÀÁüÀü~Gãðü€ÁüŒ~>Ç€ðø€Áþ??>Àðøÿþ~?þ?€àøÿ?ÿü~þ~?àðþ?ÿ€øüüü~xÀðþÿÀñùóùøüüÀàüÿÀãóùóñùþ?ÀàüþÿàÇçüãóÿ?€?àøþðÏþÇçÿ?€?Àøþ?ðŸþÏÏÏÀGðü?ø??>ÿŸÿÀÇðüüþ~>ÿ?߇àø0þüü~þ~?~Ÿƒàø`ÿùøüyüü~þ?‡àðàÿóñøüùøüü?àñÀÿ€çãñþñøü?Àã€ÿ€Çãÿãðüx?¸€çÿÀÇÿÇàÿð?ð€þÿÀ?‡ÏÇÀÿà?à?€üÀ?Çã€ÿÀÀ?ø?À ~'ãð?€ðÀüsñø~Àøùøü|Àðüü~88Àà~~?8ÀF??€8ÀŸÀ8€ÏÇ€<€Ççã|?ãóð|>ñùø~|øüøøü~p?ÿð~? ÿÀ?ÿŸÿÿþüG?„À?à  ?`?†@€> €* €. €À?À?ˆ€þþ">€€€€?€?€€€ €À@{ã@J1@J@{Î@`À1€ øþ8   8þø ?þ?þ 8<&#!!‚ Æ | 8 0C A A A A0ã¾ €€ÀÀÀÀÀÀÀÀÀÀ€€€€ÀÀÀÀÀÀÀÀÀÀ€€?ÿÿ`€À€À€À€À€À€À€À€À>€À€Àÿ€€ÁÿÀ€À€À€À€À€À€À€À€À€À€à€ÿÿÿÿþ?ÿÿ`€À€À€À€À€À€À€À€À€À€ÁÿÀ€Àÿ€€À€À>€À€À€À€À€À€À€À€à€ÿÿÿÿþ@@8@|ÿøÿÄÿø|8@@@@@?ÿÿ`€À €À!$€Ïçþ€Ïä€À$€Ç$À€Ï„`€Ê„0€Ë„`€ÃÀ€À`€É0€Ë„€Î„ €Ä„€À0€À„`€Çä€Ïä€È€€à€ÿÿÿÿþ?ÿÿ`€À€Èø€Ä¨€Â¨€Á€À‚€ÀB¨€À"¨€Àø€À€À€É"€Ä‘€À€€É @€Ä €À€É €Ä€À€à€ÿÿÿÿþ )€€?€?€€€1€;€;€1€?€?€€€€:*><> >>€?€?€€?€"?ÿÿ`€À€À €À0€À(€À$€Ãâ€Â€Â€€Â@€Â €Â€Â €Â@€Â€€Â€Ãâ€À$€À(€À0€À €à€ÿÿ€?ÿÿ>C ÿÀÿø?€|€8àà|ÀðT€8\‚8 pÒ €t`%€Tà!@À|ÁCÕ"àx€>T`€!¡¤`H‰/oJ€p\RZX0T%ÿÒ€0t_U48$ "ÿåOÀ08º€<|%ÏÿþT_È<\Bˆ0ÈkÈ8ÜÈ0ˆ0€™Hp€"`€‚È`|À àxàÀ|`>€xp€8 8tÀðTàà||€x?€ÿøÿÀ}}?DðüßÇ€ÁàÀxÀÀÀÀÀp€~·ÿ ·ÿ €~ÀpÀÀÀÀÀxÁàÇ€ßüðO?ÿÿ`€À€À€À€À€Àx€À?€À€À?€Àx€À€À€À€À€À€À€Àx€À?€À€À?€Àx€À€À€À€À€À€À€À€À<€À€À€À€À€À€À€À€À€À€À€À€À€À€À€À€À€À€À€À€À€À€Àÿ€€À€€€À‚€€À¾€€À€€€À€€€À¦€€À²€€À¬€€À€€€À¢€€Àª€€Àœ€€À€€€ÀA€À"€À€À€À€À€À€À€À€À€à€ÿÿÿÿþOÀxÃøÀÁøÀ8ÁøÀÃøÀ8ÀCàB àÀàÃàÀ øøÀà øøÀÀÀÀÀ ÿ}MeYEU9‚D8 0.00n0.00n0123456789abcdef C C C C C C C C C C C C C C C C C C C C C C C C Ø-AØ€iSÁÓ€icÁã€(ã.#€Ü3Â3  €×0€ óƒÂS ×:€ÝÂs¡.×D€݃“2×D€ÜC³ y €×0€ ó³ÂÓ y×:€Ý#Âó›.×D€Ý“Ã{2×D€ÜSÃ3 s €×0€ óãÃS s×:€Ý3Ãs•.×D€ݣÓu2×D€Ücó m €×0€ ôÃÓ m×:€ÝCÃó.×D€ݳÄo2×D€ÜsÄ3 g €×0€ ôCÄS g×:€ÝSÄs‰.×D€ÝÃÄ“i2×D€܃ij a €×0€ ôsÄÓ a×:€ÝcÄóƒ.×D€ÝÓÅc2×D€Ü“Å3 [ €×0€ ô£ÅS [×:€ÝsÅs}.×D€ÝãÅ“]2×D€Ë#€ Åà U×:€Åãw.×D€ÆW2×D€Ës€ Æ3 O×:€ÆSq.×D€ÆsQ2×D€ËÀ Æ£ I×: €ÆÃk.×D €ÆãK2×D €Ì€ Ç C×: €Ç3e.×D €ÇSE2×D €`³€`À`Ó€`ã€ÇÀ ͳD €ö¦€Çó€ Íã%$ €ö¦€È#€ ÎH €ö¦ €ÈS€ ÎC( €ö¦ ÀȃÀ ÎsD €ö¦ÀȳÀ Σ%$ €ö¦ÀÈãÀ ÎÓH €ö¦ ÀÉÀ Ï( €ö¦ €.#€.ã€/£€0c€Hƒ€IC€J€JÃ2 €ö¦2 €ö¦2 €ö¦ 2 €ö¦ ¬€÷¬€÷¬€÷ ¬€÷ º€*€÷º€*€÷º€*€÷ º€*€÷ 2 €ö¦2 €ö¦2 €ö¦ 2 €ö¦ º€*€÷º€*€÷º€*€÷ º€*€÷ ¬€÷¬€÷¬€÷ ¬€÷ U €×0ÇöÄ öö÷÷ O €×0ÇöÄ öö÷÷ I €×0 ÇöÄ  öö ÷ ÷ C €×0 ÇöÄ  öö ÷ ÷ U €×0ÇöÄ öö÷÷O €×0ÇöÄ öö÷÷I €×0 ÇöÄ  öö ÷ ÷ C €×0 ÇöÄ  öö ÷ ÷ "H €öìDö°2ö°"H €öì%$ö°2ö°"H €öì Hö° 2ö° "H €öì (ö° 2ö° "H €öìDö°2ö°"H €öì%$ö°2ö°"H €öì Hö° 2ö° "H €öì (ö° 2ö° 9Á@9Á@ 9Á˜9Á˜ ÀCCHƒÀܣσ €×0À ôÓÏ£×:ÀÝóÏÃ(.×DÀÞcÏã¡2×DÀܳÐy €×0À õÐ#y×:ÀÞÐC({.×DÀÞsÐc›2×DÀÜÃЃs €×0À õ3Уs×:ÀÞÐÃ(u.×DÀÞƒÐã•2×DÀÜÓÑm €×0À õcÑ#m×:ÀÞ#ÑC(o.×DÀÞ“Ñc2×DÀÜãуg €×0À õ“Ñ£g×:ÀÞ3ÑÃ(i.×DÀÞ£Ñã‰2×DÀÜóÒa €×0À õÃÒ#a×:ÀÞCÒC(c.×DÀÞ³Òcƒ2×DÀÝÒƒ[ €×0À õóÒ£[×:ÀÞSÒÃ(].×DÀÞÃÒã}2×DÀÌcÀ ÓU×:ÀÓ3(W.×DÀÓSw2×DÀ̳À ÓƒO×:ÀÓ£(Q.×DÀÓÃq2×DÀÍÀ ÓóI×: ÀÔ(K.×D ÀÔ3k2×D ÀÍSÀ ÔcC×: ÀÔƒ(E.×D ÀÔ£e2×D S €ö¦u.öº U2öºÕ€.ö~!õ€2ö~S €ö¦u.öº U2öºÕ€.ö~!õ€2ö~S €ö¦ u.öº U2öº Õ€.ö~ !õ€2ö~ S €ö¦ u.öº U2öº Õ€.ö~ !õ€2ö~ S €ö¦u.öº U2öºÕ€.ö~!õ€2ö~S €ö¦u.öº U2öºÕ€.ö~!õ€2ö~S €ö¦ u.öº U2öº Õ€.ö~ !õ€2ö~ S €ö¦ u.öº U2öº Õ€.ö~ !õ€2ö~ ×Ã׃×ãףף׃×ã×s×s×s q} 6II6ÀÀÀÀÀxxxxxxxxxxxxxxxxxxxx8@`pxxxxxHHHHxxHHHHHHHHHHHHHxE~°Àð<P€°BPøB° €ð<ïF€ö`"F€ö`¬€÷º€€÷·ötöjöj¬€÷º€€÷·ötöjöj4öj(öj4öj(öjÕ€8ö~!õ€<ö~Õ€8ö~!õ€<ö~S €ö¦u.öº U2öºS €ö¦u.öº U2öºS €ö¦u.öº U2öºS €ö¦u.öº U2öºS €ö¦u.öº U2öºS €ö¦u.öº U2öºS €ö¦u.öº U2öºS €ö¦u.öº U2öºS €ö¦u.öº U2öºS €ö¦u.öº U2öºS €ö¦u.öº U2öºS €ö¦u.öº U2öºS €ö¦u.öº U2öºS €ö¦u.öº U2öº  €ö¦ u €ö¦ k €ö¦ a €ö¦ W €ö¦ M €ö¦ C €ö¦ €ö¦u €ö¦k €ö¦a €ö¦W €ö¦M €ö¦C €ö¦¡.öº—.öº.öºƒ.öºy.öºo.öºe.öº2öºw2öºm2öºc2öºY2öºO2öºE2öº(.öº(w.öº(m.öº(c.öº(Y.öº(O.öº(E.öº¡2öº—2öº2öºƒ2öºy2öºo2öºe2öºÕ€.ö~!õ€2ö~Õ€.ö~!õ€2ö~Õ€.ö~!õ€2ö~Õ€.ö~!õ€2ö~Õ€.ö~!õ€2ö~Õ€.ö~!õ€2ö~Õ€.ö~!õ€2ö~Õ€.ö~!õ€2ö~Õ€.ö~!õ€2ö~Õ€.ö~!õ€2ö~Õ€.ö~!õ€2ö~Õ€.ö~!õ€2ö~Õ€.ö~!õ€2ö~Õ€.ö~!õ€2ö~˜ €ö¦x €ö¦%X €ö¦~ €ö¦^ €ö¦%> €ö¦d €ö¦˜ €ö¦x €ö¦%X €ö¦~ €ö¦^ €ö¦%> €ö¦d €ö¦2 €ö¦2 €ö¦2 €ö¦2 €ö¦2 €ö¦2 €ö¦2 €ö¦¬€÷¬€÷¬€÷¬€÷¬€÷¬€÷¬€÷2 €ö¦2 €ö¦2 €ö¦2 €ö¦2 €ö¦2 €ö¦2 €ö¦¬€÷¬€÷¬€÷¬€÷¬€÷¬€÷¬€÷º€*€÷º€*€÷º€*€÷º€*€÷º€*€÷º€*€÷º€*€÷º€*€÷º€*€÷º€*€÷º€*€÷º€*€÷º€*€÷º€*€÷ÇöÄ öö÷÷ÇöÄ öö÷÷ÇöÄ öö÷÷ÇöÄ öö÷÷ÇöÄ öö÷÷ÇöÄ öö÷÷ÇöÄ öö÷÷ÇöÄ öö÷÷ÇöÄ öö÷÷ÇöÄ öö÷÷ÇöÄ öö÷÷ÇöÄ öö÷÷ÇöÄ öö÷÷ÇöÄ öö÷÷ï€öØ"€öØ\öâ;ööFööSöö¬€÷º€€÷\öâ;ööFööSöö¬€÷º€€÷"޶è°Ï޶è°!õŽ·è°µ‚Ž·è°¦Ó¦Ó€÷<* ÷< ÷<€÷<"€÷2!õ€÷2¬€÷º€ ÷(Á÷n@øVöö¬€÷º€" ÷(Á÷n@øVööÁ°$Á¸%ÁÀ$ÁÈ%¬€÷|€€÷xXöö"€÷–Ï€÷–!õ€÷–µ€÷–$÷欀÷º€&€÷.÷ª.÷´.÷ª.÷´¬€÷$÷満&€÷.÷ª.÷´¬€÷$÷満&€÷.÷ª.÷´¬€÷$÷満&€÷í÷ &­÷ -÷ m÷ T÷¾'T÷È4÷Ò÷Üï€÷ð"€÷ðÕ€÷ð¬€÷ù÷ú7öö,ööøº€€ø¬€÷ù÷ú7öö,ööøº€€ø¬€÷ù÷ú7öö,ööøº€€ø"÷d{÷P÷ZíÀqC"HF€öì"HF€öì"H€öì"H€öì"H€öì"H€öì"H€€öì"H€öì"H€öì"H€öì"H€öì"H€öì"H€öì"H€öì"H €öì"H €öì"H €öì"H €öì"H €öì"H €öì"H €öì"H €öì"H €öì"H €öì"H €öì"H €öì"H €öì"H €öì"H#‚öìÿ"H #‚öìÿ"H#‚öìÿ"H#‚öìÿ"H@#‚öìÿ"H#‚öìÿ"H€#‚öìÿ"H€#‚öìÿ ÿÿO–öÎÿ#‚ö’ÿ"D #‚öœÿÏ€#‚÷–ÿ #‚÷ðÿê#‚öØÿ"*#‚ö`ÿï@#‚÷2ÿ"€#‚÷‚ÿЀþ#‚÷Œÿ¼€þ#‚÷Œÿ—ŽföˆÿN†øÇÀÞºÀæ9ÀðÀð9ÀøÀø9ÁÁ9ÁÁ9ÁÁ9ÁÁ9Á Á 9Á(Á(9Á0Á09Á8Á8 9ÁHÁH 9ÁPÁP 9ÁXÁX 9Á`Á` 9ÁhÁh 9ÁpÁp 9ÁxÁx 9Á€Á€ 9ÁˆÁˆ 9ÁÁ ö°˜ö°2ö° uö°xö°2ö° kö°%Xö°2ö° aö°~ö°2ö° Wö°^ö°2ö° Mö°%>ö°2ö° Cö°dö°2ö°ö°˜ö°2ö°uö°xö°2ö°kö°%Xö°2ö°aö°~ö°2ö°Wö°^ö°2ö°Mö°%>ö°2ö°Cö°dö°2ö°ùÁ Á .ùÁ¨Á¨.#£S€£†C†•ã•ã”ÑS‘S‘S“„#˜ó¹3¹3‰C‰Cˆc¬C¬C©S†“†Ó†³†s†s†Ó†³CCC”Ô3”3”3­Ã„“„“#Šƒ‡óŠóŠƒ”ÃÃÃþC–ƒ•ã•ã¦Ã¤Ó¦Ã¦Ã†C††¤c¥ƒ¤c¤c†C††C†C©ã#Ž3##Ž3####˜ó¹3¹3ŽÓ¯ã˜ƒ˜ƒ”Õ#•#•#–ƒ¤Ó~3~3™s™s™ã¤ó|Ó|C#¦Óãs¦Ó§C¥ó»S»S–£–#‚‚ £ Ã¡c¡s”Öã#¨¨ã¨s¨”׳—³—³–ƒ—C—C¤c¦S¤c¤c¤Ó¦Ã¦ÃùS¸ùƒ›ùƒ›ùƒ›ùƒ›ùS¸ùS¸ùS¸ùS¸ùS¸ùS¸ùS¸ùS¸ùS¸ùS¸ùS¸ùS¸ùS¸ùS¸ùS¸ùS¸ùS¸ùS¸ùS¸ùS¸ùS¸ùS¸ùS¸ ùs¸ªÃªó«#«S«ƒ«³«ã¬¸s¸£¸Ó¹¢C ã¢Ó¡ƒ£S¢C£ã $ -8PBRNTZVc€l€wÀ‚¡ª*±>¸XÀXÉÖæõ(( @X €/Ð>ÐGÒQÔ[ØhÜqü}ˆ“œ¬¼ÐØàëõû*BTn'‚0Œ;®KäRîbo |R‹^˜h¢€«Œº¸ÅÊ<Ó`ß„è¨ñ ÿ $ H H- l= H Z 0n 8‚ @• €  ª  ´ °À ÀË ÒÖ Òß Úé ò ÿ   *0 *B >W Xi q  y ª€ º† Ê Ò” ê£ ° Â Ö å *í >ý r  † ®& Â5 ì@ H NP ŽX Æg Ìt Ü‚ ä“ ì¢ ü®¸&Ä:Õ‚ß”ì–÷®¶¾*È9ÔGÜXäfüs &‹R™Z¨€¶ŠÁžÌ²×âÝüë*ø,BV ^-‚=ÞIæWîhös’" B®J¿RÌ^ÚfënõrþŒŒ ¬°&°3°CÀKÐSÚZb.m<uR^†f†˜’¥Ê®ì´¾,ÄBÌPÓXÚzæŠð˜÷ þø   & 0$ :, D4 Q4 ^: gR oz {º ‹Ô žÔ ± ·$ Á* Ë6 Ör ܺ è¾ ùÔ Ø * 2 #6 0R 6X =` D PÊ Xô ^ mh yp ƒš ‰¸ •ô › ¥T ±\ »† Á  Êô Ö æ ÷. 2 \ v $¨ *¾ 8Ø >ò G M T [: dP vv ƒœ ‰¦ ® —Ö §` ´n Èv Ùî ä, ô< L | ¨ (ì 9þ D< Ol ZŠ i– t  ‡V p ¡t ¯€ ºŠ Ç’ Óº Ù çÆ øà ä ü  & 7 ?& MP S¢ _¢ g® wÀ ‡Ê ’ø œ  ¥ @ ³ ^ ¹ ´ ¿ Ê Í ì Ó! ß!( å!B ï!^ õ!d ü!l!x !!¦'!Ì5!ØB!þH"O"V"4e"8n"@|"B‹"€›"²¡"į"̽"îÉ#"×#0ã#@î#Nú#^#š#¶#ä+$5$B$J$RS$Re$`m$€~$Œ‰$Ò$æž%¥%­%2µ%\Ê%ŠÞ%Òì%æó& ü&&>&p&t$&Ž,&4&Æ?&òJ'.W'Fh'|p'Ž}'ŽŽ'¤—'°¢'´­'´º'´Ä'ÆÍ'ÆÛ'Îì'àó( ú((2(6(8.(<;(RO(ZX(`a(pj(xr(†ƒ(šŠ(¬˜(â (ò«(òº(òÌ(òÖ)è)ò)ú)P)`)h)~%)†+)”;)ÂM)êS*`*m*x*(…*NŒ*`œ*p¬*xº*ˆÁ*šÏ*¶Ö*àÜ*ðç+ò+û+(+:+V+¨+À0+ÐA+ØP+øV, f,8l,Py,`†,h‘,ˆ—,¸¦,Ƹ,ôÀ-&È-@×-Pæ-Xó-lü-Š -¬-Â$-Î5-ò=. E.P.>W.F^.°f.ºn.Âv/ ~/4‰/J‘/d™/l­/p¹/æÅ0Ò0>Û0Bí0Lÿ0T0œ0ª+0º<0ðK0þT1c1$q1,18Œ1>–1B¤1L²1T¾1ŒÅ1ŽÌ1žÓ1¬Ú1°ã1¼ê1Ö÷1Ö1à1ð1ø20&2:-2L42`>2¨E2´M2¸V2Êd2Ìp2à|2ôŒ2üœ3®3µ3(Â3lÉ3pÐ3z×3Æä3Ìî4Dõ4Hü4R4¨4Ä4È4Ì*4Ð:4ÔD4ØM4äV5`5\o5r{5‚†5ŠŽ5žŸ5¼ª5̵5Ô½5èÎ5üØ6$æ60õ606<6D6d#6Â+6à37;7>G7>S7h[7c7ªk7®s7Æ|7Ј7Ö”7è›8®8&º84Ç8>Ï8P×8Šä8˜ì8¶ô8¾ü8Î8Ò8ö8þ 9(9859D@9ZH9|P9¢Y9¦a9¦l9ª}9¬‹9Ę9̦9Ø­9Þº:È:Õ:Râ:hð:‚÷:Š :–:Ê:Ô$:è-:î=;D;K;Z;&h;do;†v;Ž€;î;î™;ð¦;ò±< º<¼Ã<ÀÑ<êÝ=é=ö=R=š=¨=Æ*=ä2=ø9=üE>L>(S>N^>žn>¸u>Ê|?‡?4?@•?Pž?|¨?¨±?¸¶?¼¼?àÅ?ðÊ?ôÐ@Þ@æ@&ó@~ü@ÞAFAFAF'An4A :B2EB>QB>aB@iBðqC yDPDöDø™Dú¥Dü±Dþ»EÅEÔEâEðEþE4E`E~EŠ#EÔ*Eä1F=FIFSF<[FtgFˆwFF F°F¸©GµG¿GHÆGTÍG`àGpóGxG¢Gª$GÀ5GÈCGÜKH SH[H0hH@uHH€HœŒH´˜HØ¡I«I4´I<½IHÆI~ÐI’ÜI ìI°üI¸ IàJJ)J@9JPIJXWJrbJªmJÈuJÐ}Jè…KK0•K`ŸKp©Kx±K”½K¬ÉKÜÔKäßLìL ùL4 LP LT "Ln /Lü 7M ?M JMb SMj \Mp hM€ tMŽ M” Mœ žM¨ ©MÞ µMî ÄN( ÊNF ÕNN áN` èNh ïNr þNœ!NÀ!NÐ!NØ!*Nì!4O*!?O4!JOH!UOT!`O^!kO`!wOp!‡Ox!“O|!ŸOÊ!ªOü!µP!ÁP !ÏP!ÛP(!äP0!íPL!üP`"Ph"Pl"!P°"/PÀ"<Pà"IQ"VQ "cQ@"pQ€"}Qº"„Qð"’R"¥R"®R "·RP"ÅR`"ÒR€"ßR "ìRÄ"üRÐ# RÚ#Rö#%S #2S@#ESL#RS~#YS#gS˜#uS¤#ƒS²#ŠS¶#˜SÐ#ŸSø#¦Sü#´T*#»T.#ÉTP#ÙTT#ìTT#ôTd#ûT|$T†$TŒ$TÄ$TÚ$ Tð$/Tú$9U$CU$QU*$YU2$aUN$hUj$mUž$tU $yUª$~U´$ƒU¼$ˆUØ$Uì$˜V$§V$$³V8$¿VL$ÍV^$ÙVr$åV†$ôVš$ûVª% V¶%VÎ%VÔ%!Vâ%+Væ%8Vü%CW %OW%`W:%gWT%nWZ%zWj%…Wz%ŒWˆ%“W¢%žW¶%¯WÎ%ÀWÞ%ÑWò%ÞWö%åWú%ìWü%ûX& X&X>&XX&+Xd&5Xš&<X¤&CX¸&MXð&TXü&\Y&hY&xYJ&‡Y~&’YÂ&YÒ&¦YÖ&´Yà&¾Yð&ÈYø&ÑZ0&ÝZ@&âZª&ëZÆ&ðZÎ&ùZÞ'Zâ' Zæ'Zè'$Zð'6Zø'?[('F[B'V[B'`[Z'h[j'w[Â'\ 'ˆ\'\'\n'«\r'¶\~'¿\Ž'Ì\¨'Ù\Ò'à\Ò'î\â'õ\ê(\þ(\þ( \þ(/](>](I](S]"(b]0(m]>(€]X(‹]l(”]‚(ž]À(¥]Ä(¯]È(»]ò(Ä^(Ï^(×^L(ä^Z(ï^r(÷^v)^v) ^v)^z)+^~)6^~)H^~)T^‚)_^„)k^œ)u^¤)„^°)Œ^¸)”^Ð) _¸)­_Ä)½_Ä)Ë_Ä)Ø_Ä)æ_Ø)ñ_ø)ü`*`J*`†*1`Æ*<`Þ*Ea *Pa *Ya *ea$*pah*~aœ*…aœ*Œa¤*•a°*¡c*¨c*µcj*¼cn*Çcª*Ócª*Ûcô*çcô*ïd*ýdN+d‚+d¬+dò+&dö+3dü+?eF+Ke+Xež+ae²+jeÂ+seÊ+|eÒ+…eÔ+eè+™eü+¡eü+¬f +·f&+Âf,+Íf6+ØfJ+ãf`+îfx+ùf–,fž,f¢,fÂ,(fò,3fú,;g&,Ag,,FgL,Ng~,Tg„,Yg¨,dg´,qgø,yh,h,‰hT,‘hV,™hn,¡h–,©h®,±hº,¹h¾,Æi,Îi<,Öif,ßij,æij,òij,ùi-i´- j$-jd-jz-jÞ-#jö-*jö-1k -8k-?k8-FkJ-MkV-Tkf-[k~-bk–-ikš-qk¤-zk®-ƒk°-‹kÄ-’kî-›l- l4-§l>-­lj-³l€-½l€-Êl€-ÚlŽ-âl¼-êlà-òlê-úmR.mV.m„.m’.m¾.%mÐ.,mè.4mè.?mú.Fn.Mn.Xn.cn$.jnF.sn”.znœ.n¦.ˆn®.nÆ.–nî.žnò.¨o .­o$.µor.½oÀ.Æp.Îp|.Öp¤.ßp².äpÊ.ípì.öpð/q / q/q/q&/q./$q:/*qB//qJ/9qP/Aq^/Gqt/Nqž/Uqª/\q¼/cqÔ/jqø/qqü/{r/ƒr/Šrr/‘r‚/˜r˜/Ÿrœ/©r /³r¤/½r¨/Èr¬/Õr¬/är´/ðrÄ/ýrÈ0 rú0s0$s"0-s206sp0?s0Gsª0Rsâ0at&0qt.0€tD0‘tn0¡t„0±t’0½tè0Ëu0×u0åu:0íuP0úud1ux1u1uÎ1uØ1&v 13v$1;v61Cv>1KvD1Sv~1cv¬1svì1wR1wš1w¢1«wª1¹wì1Áwô1Éwø1Ûx~1çx‚1öxœ2x 2 x´2xÌ2y’2-yª29yè2Dyè2Ryè2Yyè2az2iz 2qz2yz,2z22z22”zB2›zp2£zt2¬zˆ2¸zˆ2Åzš2Ñz¾2Ýzô2é{2õ{<3{<3 {n3{ˆ3{š3"{¶3){ä30{þ37|3>|03E|43N|T3Y|h3d|ª3p|è3{|î3…|ò3‘}3ž}@3¨}j3²}„3¼}¨3Æ}Î3Ð}Ú3Û~3å~,3ï~j3û~‚4~”4 ~Ì4~Ð4~Ü4#~â4,~ê444;4F4Y4kN4rŽ4¢4‹Ê4“Î4Þ4¬ô4½ô4Çô4Ѐz4Þ€~4怌4í€Ò4û85 B5h5$51ð5A‚5M‚D5]‚n5i‚r5w‚€5‚‚˜5Ž‚œ5ž‚À5®‚È5¾‚Ì5È‚þ5Ѓ5؃5áƒ25çƒ<5îƒd5öƒp5ÿƒ¤6ƒÒ6 ƒÖ6ƒô6ƒø6(„61„68„6E„"6N„26\„F6h„\6w„„6~„ˆ6‡„˜6„Â6™„Ê6¨„â6¶„æ6Â…6Ë…L6Õ…j6Þ… 6è…¾6ö…Ð7…Ú7†7 †"73†b7@†j7S†˜7`† 7s†Î7€†Ö7“‡7 ‡ 7³‡:7À‡B7Ó‡p7à‡x7ó‡æ8ˆ8ˆ8'ˆ~8;ˆž8Hˆ¨8WˆÂ8eˆò8t‰8†‰ž8”‰ö8¨‰ú8³Š8ÁŠ48ËŠˆ8ÔŠŒ8⊠8ðŠ®8ÿŠº9ŠÎ9ŠÒ9Šä9#Šè9-‹94‹49@‹\9H‹€9W‹–9e‹š9v‹ª9„‹®9•‹È9‹È9°‹È9¸‹È9À‹æ9ÌŒ9ÝŒ9êŒ<9öŒP:ŒP:Œ\:Œ|:%Œ:.Œ¬::Œ¾:BŒà:NŒø:]:j :v:„8:Œ<:˜l:¤¨:°Ò:¾æ:ËŽ:ØŽ2:äŽH:îŽh:üŽx;Ž‚;ŽŒ; ަ;)ް;5ŽÒ;AŽþ;Q$;b<;sH;Z;“d;¡x;°º;ÁÎ;ÑÖ;Þì;ê;û*<.<B< ª<.®<:Ð ”„>”¦>-”â>:•>G•>S•T>`•r>q•Œ>•´>‰•¼>˜•È>¨•è>³•ò>¿–>Ì–:>Ý–T>í–j>ü–~? –Œ?– ?%–¨?3–Â?A–Ü?O–ö?^—?k— ?{—`?ˆ—d?”—Ž?§— ?µ—Ö?Á˜?И,?ߘB?똆?ù˜Š@˜¬@˜Æ@˜Î@+˜Ö@8™@D™V@P™v@^™–@g™¦@t™¼@}™ö@Šš@˜š@§š@´š0@ÚB@ÓšL@çšX@õšnAšžA šÀAšÐA#šØA0šàA=šîAJ› AV›$Ac›6Ap›VA~›ŠA‹›’A˜›šA£›¨A³›¼AÀ›ÀAË›æAØ›üAäœAòœ(Aÿœ:B œ>BœZB!œpB,œ B9œ°BEœºBPB_Bn&By6B„ZB•nB£xB°œB¿ÊBÎÚBÙžBåž Bñž6CžVCžnC"žšC1ž¼C>žÐCKžðCYžþCfŸnCtŸrCƒŸšCŸÐCœŸÒC«ŸêCºŸôCÉ C× Cå FCò „D ŒD ¨D ºD- ¾D:¡DI¡*DZ¡6Dn¡~D~¡ D¡¨D ¡¶D®¡ÒD¼¢ D΢Dà¢4Dñ¢VE¢hE¢rE"¢†E0¢–E>¢üEP£Ea£8Er£tE£„E£¶E™£ÒE¤£æE²¤E¿¤NEФdEᤂEEú¤ºF¤ÆF¤âF#¤îF3¥FC¥FV¥ Fg¥ Ft¥@F}¥LF†¥VF¥xF˜¥‚F¡¥F¬¥”F¹¥žFÊ¥¶FÒ¥ÐFÚ¥ØFè¥ÞFû¦,G¦HG¦nG¦xG"¦ G-¦´G5¦ÂGB¦ÄGM¦ÞG`¦æGn§(Gx§BG‚§rG•§xG¢§€Gµ§†GƧŠG×§¦G䧸Gñ§ÒH¨H¨H#¨.H0¨0H=¨^HM¨|HV¨‚H_¨ŽHq¨˜Hƒ¨žH–¨öHŸ©H¨©&H¼©dHÈ©xHÔ©xHàª<HíªDHóª”Hùª¢Hÿª¼I ªÌI«I«I!«(I(«:I/«BI7«FIB«IO«ÌI[«äIg«ôIv¬I…¬I‘¬I¬I¤¬6I¬¬:I´¬VI¾¬`Iɬ˜IÒ¬˜IÛ¬ºI⬼Ié¬ÄIð¬ÜJ¬øJ­J­J$­<J,­dJ:­†JJ­”JX­˜Jb­œJr­°Jz­´J‚­ÌJŠ­ÔJ’­ÖJš­òJ§­þJ¶®J¾®JÆ®(Jή,JÖ®@JÞ®BJæ®JJî®XJø®\K®‚K®˜K¯K¯"K&¯JK-¯VKA¯hKO¯|KW¯„Ke¯ŒKu¯˜Kƒ¯ºKНØK“¯ÜK¤¯êK¬°K¹°Kư$KÓ°:Ká°BKî°PKü°ZL °lL°|L)°šL9°¢LH°°LX°ºLh°ÌLs±L~± L†±>L‘±JL™±RL§±VL²±ZL½±lLű„LбLر¢L౪Lî±ÐLö±ÔM±ÜM ±èM±øM"² M-²&M5²*M@²>MK²^MY²rMa²zMi²~Mt²ŽM‚² M²¸M˜²ÌM£²ìM±³M¹³MÁ³ M̳MÚ³$Mâ³(Mí³0Mõ³4N³DN³HN³LN$³TN2³XN=³\NH³`NV³dNa³hNm³ŠNw³žN‚³°N‰³°N–³°N³âN¥³þN­´Nµ´N½´4N´ZNÊ´hNÒ´lN×´¨Nß´°Nä´ÀNé´ìNñ´ôNöµNþµOµ"O µFOµLOµPO µlO*µ¦O4µ¶O=µâOGµòOP¶OV¶4O\¶zOb¶¨Oh¶ÊOq·ØOz·öOƒ¸OŒ¸$O•¸JOž¸O§¸²O±¸¶O¿¹VOȹ^OعtOå¹”Oô¹®P¹®P ¹ÄP¹ÞP¹ÞP'¹ÞP0¹ìP>¹ðPGºPVº.PeºLPmºVPxºbP‡º„P’º˜PŸº¾P­ºÂPººÔPºòPÊ»PÒ»Pß» Pñ»$Pø»,Pÿ»VQ»zQ»ˆQ»žQ»¬Q%»ÎQ-»äQ5»èQ;¼QC¼ QK¼$QQ¼FQY¼\Qa¼`Qg¼|Qo¼˜Qw¼œQ¼ Qˆ¼¨Qœ¼ÂQ¢¼ÌQ¨¼ÞQ´¼ìQº¼úQǽQ×½:Qâ½^Qð½‚Qû½”R½œR½®R½¶R)¾R6¾ RE¾RS¾Ra¾zRo¾‚R~¾’R‡¾¤R¾¾R™¾ÊR¢¾èR«¾îR¸¾òRÿRÏ¿RÜ¿(Ré¿LR÷¿`S¿pS¿tS¿tS-¿tS:ÀpSBÀœSJÀÖSRÁSZÁPSbÁŠSjÁ®SrÁîSzÂ.S‚ÂNSŠÂ\SšÂÌS£ÂÞS¬ÂøSµÃSÆÃSÔÃZSÝÃîSçÄSñÄSÿÄ2TÄ6TÄ‚T+ÄÌT7ÄèTFÅTWÅ&TjÅ:TxÅTT‡Å^T˜ÅdT¨ÅvT²ŶTÀźTÎÅÒTÜÅÚTêÆTôÆTþÆ0U Æ8UÆ@U)ÆVU2ÆlU:Æ~UFƘUNÆœU[ÆÄUfÆÊUqÆøU|ÇU„ÇJUŒÇfU”ÇvUœǘU§ǺU´ÇÒUÃÇàUÎÈTUÚȘUæÈÆUïÈÖUúÉVÉ:VÉNVÉRV"É`V/ÉnV7ɪVBÉ´VPÉÈV`ÉêViÉþVzÊ V‹ÊV˜Ê0V¨ÊLV²ÊPVÃÊbVÒÊtVßÊtVéÊtVùÊŽWÊ’WÊ®W ʾWÊÚWÊâW-Ë"W4Ë<W;ËlWB˪WIËÔWPËæWYËêWgËþWnÌ2WuÌnW{Ì–WƒÌšWŒÌšW•̪WŸÌ®W®ÌàWµÍWÁ͈WÐÍèWÛÎDWèÎXWòÎlX΀XΔX#ΨX0ÎÆX9ÎæXIÏXVÏXhÏXwÏ.X‚Ï<XÏ@X—ÏPX«ÏbX²ÏvXºφXÍϘXÔϦXÜ϶XèÏÌXïÏÜXýÏúYÐ&YÐDYÐpY!ДY1жY6ÐÊY<ÐàYBÐêYIÐôYPÑY_ÑXYmÑjYzÑ€YÒ.YšÒ4Y¢ÒDY®ÒFY¶ÒHYÀÒVYÎÒ^YÚÒdYèÒzYöÒ„YþÒŠZÒZÒšZÒœZ*Ò¢Z2Ò¼Z;Ò¼ZNÒÆZVÒÐZ^ÒØZfÒÞZpÓ"ZxÓ.Z†Ó6ZÓ<Z¢Ó\Z¯Ó`ZÁÓtZÈÓ~ZÏÓ¢ZÖÓ¦ZäÓâZëÔZòÔ[Ô"[ÔX[Ô`[!ÔŠ[*ÔŽ[;Ôª[DÔ®[SÔÚ[ZÔÜ[aÕ.[rÕˆ[{Õ”[‹ÕÖ[”ÕÚ[¢Õæ[«Ö[ºÖ [ÃÖ.[ÓÖV[ãÖz[ðÖ”[øÖ²\ÖÆ\ÖÊ\Öð\Öô\*×\9×:\Iל\Q× \]×à\cØ\kØ\vØ"\€ØF\‘ØT\¡Øl\±Ø„\¹ظ\ÇØØ\ØØð\áÙ\ïÙ*\ýÙ2] ÙL]Ùd]%Ùh]4Ù˜];Ùœ]KÙ²]\ÙØ]dÙä]rÚ$]yÚZ]Ú^]Úx]šÚ’]¨Ú¨]µÚ¾]ÅÚê]ÍÛ"]ÕÛZ]ÝÛh]æÛx]ïÛ~]ýÛ„^Ûž^Û¢^ÛÂ^-Ûà^:Ü^AÜ^PÜJ^aÜ~^iÜ‚^qÜœ^~ÜÀ^‘ÜÆ^˜ÜÚ^ Üò^¨Üþ^¶Ý ^ÅÝ*^ÊÝ0^ÐÝB^àݪ^òÝÈ_Ýú_Þ_ Þ2_)ÞT_1ÞZ_9Þx_GÞŽ_NÞÄ_VÞÈ_bÞà_pß_{ßJ_‡ßf_ßn_ß _¥ߤ_µßÐ_»ßö_Áà _Çà_Íà_Ôà_àà$_ëà@_òàR_ùàZ`àv`àž`à¢`*àÂ`0àà`7àä`?àä`Nàä`]àü`já`sá(`á\`Žá~`›á¤`©áô`µáú`Áâ`Îâ,`ÚâF`çâ~`óâž`ÿâ¸a â¼aâÜa'âúa5ãa=ãaGã6aOãNa\ãfajã~auã–a€ã®aã²ažã¸aªãÎa¶ãâaÃãæaÓä aÞä*aêä6aûä:b äVbäzb#äžb1äÄbCäÐbTäÔb`äæbjåtbsåxbåŠbå˜b•åžb¢å´b®åÆb¼åìbÊæbØæ8bææ^bôæxcæ~c æ‚cæ†c(æ¦c5æ¾cBæÀcPæÄc]æîcjæøcwçc„ç¢c‘çÌcžçàc«çâc¹çìcÆè,cÕè@câèHcïèŒdè¦dèÀd&èÖd2èÜd?èÞdMédZé’dfé˜dséšdéždŽéÄdéÌd¬éàd¹éèdÆê&dØê0dêê¤düêºe êÀeêÂe0êÜe<êâeIêäeWêèeeëetë.e‚ë2e‘ë6ežëve«ë–eºë°eÇë¾eÓëÄeàëÈeîëÌeûìfì0fì`f%ìf2ì´f?ìÂfKìÌfYìÐfdìÒfpìæf~íNfí\fíf«íêfºíøfÊî,fÖînfãîzfîîŽfûîög ïgï4g#ïvg/ï‚g:ïŽgFïâgUð(g_ð*gkð.gvð0g‚ð4gðNgŸðŽg¬ð¤g¹ðºgÆðÞgÓðúgßñgíñ"gúñ.hñXhñ^h"ñnh0ñxh=ñhOñžh]ñ¨hjñÆhzñêh‡òh•òh£òh¬òJh¾òXhÌòbhÙòzhéòŠhòò˜hÿò®i òÂiòÊi#òÞi1òÞi@òäiRòîi_òúiróióiói›ó:i¬óBi»óniÊóºi×óÎiäóÚiñóîiþôj ôjô<j&ôHj3ôTj@ô†jLôŠj[ôŽjjôºj~ô¾jˆôÈjôÜj›õ j¨õ<j²õDjÀõHjËõrjØõrjèõrjòõˆjÿõÞk õâkõðkök%öLk+öxk:ö†k@ö¤kKöÊkYöÊkcöÊklöâkzöækƒ÷k’÷$kž÷:k©÷Zk·÷nkÄ÷–kÒ÷¦kà÷ªkëøfkýøŠlø´l"øÒl.øÖl;øîlOù.lcùZlnù¦lzùðl†úl‘úlœúZl©ú^l´úvlÆú”l×úÂläúÌlôúÐmúòmû>m"ûHm2ûLmAûZmMûpm[ûxmiû~mzû¬m‡û¼m—üm£ü m²ü(mÂü2mÕü6mäüLmóü\nühn üznü˜nüœn&ü°n.üÌn6üÐn>üÐnLüÐnTn[nhnrþn}n‹n™n©n¹nÆPnÓnàÐnínùoooo$o/o>oOo` oq"oƒ$oŒ$oš&o¨(o²*oÁ6oÑ6oÞ8oî:oü<p>p@p!Bp+Dp8FpEHpTJpcLpqNpPpŒRp™Tp¥Vp±Xp¿ZpÍ\pØ^pç`põbqdqfqtq%vq2xq<zqF|qP~qXŽqhqpšqw¤q~°q†Ðq“ðqžôq¦&q´(qÆ@qÕHqåPqôXr`rhrjr*pr9 rFÐrVðrerv@rˆpr™°r¨Ðr·èrÃrÑ rá0rï:rýDs Zs€s"šs/Às<ÖsJsX(sgNsups‚Žs¸sœÜsªs·sÄ(sÏ@sÞbsîsü²t àt t& @t5 btE tT Àtb ðtp t~ 0tŽ TtŸ zt± ”tº štÆ ²tÒ Òtß òtï tû 0u `u ˜u$ ®u2 Æu@ ØuN èu\ øuj üux u† u• u¤ Ju³ LuÀ †uÎ ¢uÙ ¾uå Úuñ öuü v .v Jv% fv2 ‚v> žvK ¼vW Òvc èvo þv{vˆ:v•^v¢‚v°¦v¾ÊvÌîvÙvæ6vóZw~w¢wÆw)w30w?@wLPwX`w_pwk€wswz w°wŠÀw”ÐwŸàw©ðw²w»wÅ wÏ0wÚ@wåPwï`wúpx€xx°x+àx8 xB@xO€x\Àxhàxoðxvx}x„ x‹0x’@x™Px `x§px®~x¸–x xÇÀxÌàxÐxÔ@xÜPxå`xípxô€xüy y °yÀyÐyày&ðy.y4y: y?0yD@yMpyXyb ykÀyuÐy€ðyŠy”y 0y«@yµPyÁpyÍyÖ°yáÐyìàyøðzzz0z)Pz3`zA€zO z\°zdÐzlÞzzÞzˆÞz”]z¢^z²^z¿hzÍ€zÝzë°{Ð{ð{&ú{2ü{=þ{H{X{b{l {z{ˆ{–{ {¬{»{Ë{Ú"{è0{÷B|B|P|p|%|-°|5Ð|=ð|E|M0|UP|]€|eÀ|m|v |@|ˆ`|‘€|š |£À|¬à|µ|¾ |Ç@|Ñ`|Ú€|ã |ìÀ|õà|þ} }@}`}"€}+ }5À}=ð}E }M@}U`}]€}e }nÀ}wà}€}‰ }’@}›`}¤€}­ }¶À}¿à}É }Ò }Û @}ä `}í €}ö  }ÿ À~ à~!~! ~#!@~-!`~7!p~A!€~K!~U! ~`!À~k!à~u!ð~"~‰"~“" ~ž"@~©"`~²"~½"”~Ì"¸~Û"à~ê"ð~ù### &#06#@F#`T#aa#bl#cw#d#eŽ#fž#r©#t²#vº#xÃ#zÑ#{Þ#|ï#}€#~€ #€#€€&#‚€3#„€E#†€S#ˆ€^#Š€p#Œ€…#Ž€#€›#€©#‘€¸#’€Å#”€Ó#–€ã#˜€÷#²#Î#Ü##ê0#ø>$L$[$e$n$(w$<€$B‰$H’$Nž$X¦$^²$hº$lÅ$†Ñ$ŽÙ$šå$Âó$æ‚%‚%6‚%:‚%N‚!%N‚(%T‚/%\‚6%d‚>%n‚H%‚‚O%”‚V%¨‚]%®‚d%´‚k%¼‚q%΂y%Ô‚&‚…&‚Œ& ‚”&8‚ž&L‚¤&h‚«&ˆ‚²&®‚¹&Ò‚Á&î‚Ç'‚Ò'.‚Ø'P‚Þ'd‚ä't‚í'z‚÷'‚ƒ'Œƒ '’ƒ'¦ƒ'°ƒ*'ºƒ0'ƃ8'ÖƒD'ðƒP(ƒ](ƒj(6ƒu(Jƒ(Rƒ‡(fƒ(lƒš(tƒ¤(´ƒ®(¼ƒ¶(ƒÀ(ăÌ(ʃÖ(ЃÞ(Öƒç(܃ô(âƒü(è„(î„(ô„(ú„&)„/)„;)„D)„N)0„X)F„f)\„v)x„€)’„Œ)Ä„š)æ„§*„¶*<„Å*j„Õ*¤„ã*Ô„ñ+…+"…+T…!+€…-+®…<+Ð…J+ò…U,…b,(…n,F…v,P…~,\…†,Š…,º…,è…¤-…«-…²-…¹-&…À-,…Ç-R…Î-~…Õ-¨…Ü-Ò…ä-ò…ì.…ó.$…û.@†.R† .\†.d†.p†".t†..|†</F†I/F†Y/F†a/F†g/H†p/J†y/L†/N†„/P†‹/R†’/T†œ/V†¦/X†¶/Z†Ã/\†Ò/^†ß/`†ê/b†õ/d‡/f‡ /h‡/j‡(/l‡8/n‡H/p‡Y/r‡h/s‡v/t‡ƒ/v‡/x‡–/z‡£/|‡°/~‡½/€‡Ê/‡Ö/°‡á/ȇì/ȇú/ʈ/̈/Έ'/Ј7/ÒˆH/ÔˆS/Öˆ]/؈k/؈z0ˆˆ0ˆ•0ˆ1ˆ©1ˆ´1ˆ¾1ˆÆ1 ˆÏ2ˆÜ2ˆè3ˆõ3ˆþ4‰ 4‰4‰4 ‰'4,‰.4-‰74.‰D40‰O42‰Z44‰a48‰j5‰x5‰5@‰Š5€‰’5À‰š6‰¢6@‰ª6€‰²6À‰»7‰Ä7@‰Ì7€‰Ô7À‰Ü8‰å8@‰î?‰û?Š?Š?Š? Š.?ÈŠ:?ÌŠC?ЊN?Њ]?ÔŠk@Šx@Љ@Š–@Š¢@Ь@ е@ ŠÂ@ŠÍ@ŠÚ@Šæ@Šð@Šù@‹@‹@ ‹@"‹*@$‹9@(‹I@,‹U@.‹b@0‹q@4‹@8‹@:‹@<‹¬@>‹º@@‹Å@B‹Ð@F‹Ü@J‹é@J‹ò@L‹ÿ@NŒ @PŒ@RŒ&@TŒ.@XŒ=@XŒL@XŒY@ZŒa@ZŒj@bŒs@jŒ‡@¦Œ@®Œ“@¶Œš@¾Œ¡@ÆŒ¨@ÎŒ¯@ÖŒ¶A.Œ½A†ŒÈA‡ŒÓAˆŒÖAˆŒåA‰ŒðAŠŒýAŠAŠAŠ+GÊ=NIN8UNTaN`mNlqNŒNNŽœN«N’¼N ÌN°ÜNÀäNÆìNÌóNÐúNÔŽNØŽ NàŽNêŽ"NôŽ-NüŽ:O|ŽKO|ŽYO~ŽgO~ŽsOŠŽO–ŽŠO¢Ž•O®ŽŸOºŽ©OÆŽ´OÒŽ¾OàŽÊOàŽÚP*ŽèPNŽôPVŽýP` PÐPà'T26_ü?_þL`V`a€n€u€„€@“€€¡€„ª€œ¹€ Å€ðÐ@ØBçDódä‚‚$&‚$1‚d<‚¤G‚äRƒ$^„i„€t……€Š†—†Ÿ†¨†³†¾†Æ† І ܆é†ô†‘†‘ †‘†‘†‘)† ‘6ˆ ‘Gˆ ‘Rˆ ‘[Ž`‘jŽb‘tŽd‘‚Žf‘Žh‘Žj‘«Žl‘·Žp‘ÀŽq‘ÉŽ€‘ÖŽ‚‘㎄‘üŽ’’ Ž”’Ž ’"Ž¢’/ޤ’;ް’H޲’UŽ´’a޶’nŽ·’{ޏ’‡Žº’–Žº’¦ŽÀ’®–À’¶—À’¾˜À’ƨÀ’Ô¬À’â¬À’ñ¬À’õ±’ùµ`“µp“µð“µô“µø“%µú“1µü“;µþ“F¶“Q¶“]¶“j¶“t¶“}¶ “‡¶“‘¶“™¶ “¡¶ “§¶$“¬¶(“²¶,“¸¶0“¾¶4“¶8“ʶ<“Ò¶@“Ú¶D“â¶H“ê¶L“ò¶P“ú¶T”¸T”¸X”¸\”¸`”¸d”%¸h”/¸l”6¸p”>¸t”F¸x”N¸|”V¸€”^¸„”f¸ˆ”l¸Œ”r¸”ƒ¸”ޏ””¸°”—¸²” ¸¶”¥¸¼”©¸À”´¸Â”»¸Ä”¿¸Å”ŸƔ˸Ȕڸʔà¸Î”í¸Î”÷¸Ò•¸Þ• ¸æ•¸ô• ¹•*¹•7¹•D¹•Q¹•^¹•k¹•wº •„¼0•¾@• ¾@•©ÀP•²Â`•¿Äp•ÌÆ€•×怕å怕ð怕ùö€–ö€–þ€–€–(–4–C–S–^–m–{–ˆ–“ –Ÿ–¯–¾–Ζږì–÷— —,—-—%.—50—C2—Q4—[8—g—x—„@—€—›À—¦—±@—¼€—ÇÀ—Ó—ß@—ꀗõÀ˜˜ @˜˜(˜5˜E˜U ˜gȘv̘‚ИИ¢Ô˜³˜¼˜Æ˜Ð˜Ú˜ç ˜ó*™,™ 4™<™D™#L™+T™3\™;d™Cl™Kt™S|™\„™eŒ™n”™wœ™€¤™‰¬™’´™›¼™¤Ä™­Ì™·ì™Àl™Ên™Ôp™âr™ìt™üvš xšzš(|š:~šL€š^‚šn„š†šŒ¦šž°š¦ š®š¶ðšÂ€šÐšÜšê@šøð››0›*Л<p›N›`°›rP›„ð›–›¨0›ºЛÌp›ß›ñ°œPœðœ' œ9!0œK!М]"pœo#œ#°œ“$Pœ¦$ðœ·%€œÊ%ðœÖ&€œä'0œò'à(à) #*`4+ E+àV, g-`x. ‰.àš/ «0`½1 Ê1À×2`ä2àö3pž4ž4ž.5 žB5°žV6@ži6О|7pž8ž›8€ž§9žµ9ÀžÃ:pžÏ;žÚ;Àžæ<`žõ=Ÿ=ÀŸ>pŸ"? Ÿ1?Ÿ=@0ŸK@àŸYAŸgB@ŸvC@Ÿ‡DŸ˜DÀŸ©E€ŸºF@ŸËGŸÜGÀŸíH€ŸþI@ J  JÀ 2K€ @Kð NL  \M0 fM  uN ƒPà ‘S ¡S  ®T »Tp ÈTà ÕUä åUä ùUä¡V¤¡V¤¡#V¤¡-V°¡8V¶¡BV¾¡LVСWVà¡bVæ¡lVî¡vVö¡€W¡‹W¡–W ¡¡W&¡¯W8¡½WD¡ËWP¡ÙW^¡çWf¡õWx¢W‚¢WŒ¢W”¢-W¢¢;W²¢IW¢WWÒ¢eWâ¢sWî¢X¢X¢ŸX ¢®X0¢½X@¢ÌXP¢ÛX`¢êXp¢ùX€£X£X £&X°£5XÀ£DXУSXà£bXð£qXö£Y£Y£›Y£©Y(£·Y0£ÅY<£ÓYP£âY`£ñYp¤Y€¤Y¤Y ¤-Y°¤<Y¶¤JYƤXYÔ¤fYä¤tYð¤‚Z¤Z¤žZ¤¬Z$¤ºZ*¤ÈZ:¤ÖZP¤åZ`¤ôZp¥Z€¥Z¥!Z ¥0Z°¥?ZÀ¥NZÐ¥]Zà¥lZð¥{Zö¥ŠZþ¥—[¥¤[ ¥±[&¥¹[4¥Å[B¥Ñ[H¥à[P¥ì[`¥ù[p¦[v¦[‚¦[Ц"[’¦+[˜¦4[œ¦>[°¦E[À¦L[ЦY[à¦e[ð¦q\¦\¦\ ¦š\0¦¨\@¦¶\P¦Ã\V¦Ð\`¦Ý\p¦ê\€¦ö\§\ §\°§\À§)\Ч6\à§B\ð§O]§\]§h] §s]0§€]@§]P§™]`§¦]p§³]€§¿]§Ì] §Ù]°§å]À§ò]Чÿ]ਠ]ð¨^¨)^(¨5^0¨B^@¨N^P¨\^`¨e^p¨p^€¨{^¨ˆ^ ¨•^°¨ ^À¨©^Ш¶^ਾ^ð¨Ç_¨Ï_¨Ú_ ¨å_0¨ð_@¨ú_P© _`©_p©'_€©4_©A_ ©N_°©Z_À©f_Щq_à©|_ð©‰`©”`©Ÿ` ©©`0©³`@©À`P©Í``©Ú`p©ç`€©ô`ª` ª`°ª`Àª*`Ъ8`àªG`ðªVaªaaªla ªza0ª‰a@ª˜aPª§a`ª¶apªÅa€ªÔaªáa ªîa°ªûaÀ«aЫaà«"að«/b«<b«Ib «Vb0«eb@«tbP«‚bV«Œbp«šbt«¥b|«­b«¹b «Çb°«ÕbÀ«âbЫïbà«ýbð¬ c¬c¬'c ¬5c0¬Cc@¬TcP¬ec`¬scp¬ct¬c€¬Ÿc¬®cž¬½c¬¬Ìcº¬ÛcƬêcÔ¬ùcâ­cô­d­&d­5d­Dd*­Sd:­bdB­qdR­€d^­dj­ždz­­d„­¼d­Ëdž­Úd°­êdÀ­údЮ dà®dð®*e®:e®Je ®Ze0®je@®zeP®Še`®šep®ªe€®ºe®Êe ®Úe°®êeÀ®úeЯ eà¯eð¯*f¯:f¯Jf ¯Uf0¯af@¯qfP¯f`¯fp¯œf€¯ªf¯¸f ¯Æf°¯ÔfÀ¯ãfЯòfà°fð°g°g°(g °4g0°@g@°LgP°Xg`°dgp°pg€°|g°ˆg °”g°° gÀ°¬gа¸gà°Ågð°Òh°ßh°ìh °ùh0±h@±hP±"h`±0hp±>h€±Lh±Zh ±hh°±vhÀ±„hб’hౡhð±°i±¿i±Îi ±Ýi0±ìi@±ùiP²i`²ip²i€²,i²;i ²Gi°²OiÀ²Xiвeià²rið²~j²†j²“j ² j0²®j@²¼jP²Äj`²Ðjp²Üj€²èj²ôj ²ÿj°³ jÀ³jгjà³%jð³.k³7k³Ak ³Jk0³Xk@³fkP³rk`³~kp³‡k€³‘k³šk ³£k°³°kÀ³ºkгÄkà³Ðkð³Ûl³ål³îl ³øl0´l@´lP´l`´'lp´2l€´?l´Jl ´Tl°´clÀ´qlдlà´‹lð´”m´£m´°m ´¾m0´Ìm@´ÚmP´èm`´ömfµmhµmtµ m‚µ.m’µ<mžµJmªµYmºµgmȵtmÖµ€mäµmòµ™mþµ¤n µ®nµºn$µÅn2µÑn>µÜnLµénXµönd¶nr¶n€¶n¶(nœ¶2n¦¶?n²¶Ln¾¶Xn̶dnÚ¶rnê¶nú¶Šo ¶”o ¶£o0¶°o@¶¾oP¶Éo`¶Ôop¶áo€¶ño¶üo ·o°·oÀ·oз(oà·4oð·@p·Lp·Xp ·dp0·pp@·|pP·ˆp`·”pp· p€·®p·¼p ·Èp°·ÔpÀ·àpÄ·ëpÊ·ôpà·ÿpð¸ q¸q¸%q ¸3q0¸?q@¸KqP¸SqX¸]qX¸iqX¸tqX¸€qX¸qX¸œqX¸¦qX¸²qX¸¾qX¸ÉqX¸ÓqX¸ÞqX¸éqX¸ôqX¹qX¹ qX¹qX¹"qX¹0qX¹8qX¹FqX¹RqX¹`qX¹mq`¹{q`¹‚qh¹qh¹™qh¹£qh¹¯qh¹ºq€¹Âq¹Êq ¹Òq°¹ÚqÀ¹âqйêqà¹òqð¹úrºrº r ºr0ºr@º rPº(r`º/rpº7r€º>rºHr ºPr°ºWrÀº_rкfràºnrðºusº}sº„s ºŒs0º“s@º›sPº¢s`ºªspº±s€º¹sºÀs ºÉs°ºÑsÀºØsкàsðºçtºïtºöt0ºþt@»tP»t`»tp» t»(t »/t°»7tÀ»>tлFtà»Mtð»Uu»\u»lu »tu0»{u@»ƒuP»Šu`»’up»™u€»¡u»¨u »°u°»·uÀ»¿uлÉv@»ÒvP»ÝvÀ»èw0»ñw »úw°¼x ¼ x0¼x ¼x°¼'y ¼0y0¼9y ¼By°¼Kz ¼Tz0¼]z ¼g{¼q{€¼{{ð¼„|¼’|@¼Ÿ|м¬}`¼¹}°¼Ã}À¼Ð~0¼á~¼ò~ð½`½ ½€½-€€½7€Ð½F ½U½d‚½u‚`½‚p½Žƒ°½œ„ ½¬„½½…нΆ½á†@½ó†p¾†¾†°¾†Ð¾/†ð¾?‡ ¾K‡¾X‡ð¾hˆ`¾wˆÐ¾‡‰@¾”‰°¾ ‰ð¾®Š¾ÀŠ€¾ËŠð¾Ù‹`¾ã‹ ¾ïŒ¾ûŒ@¿Œ°¿ ¿#¿.Ž0¿>Ž ¿PŽÐ¿^¿m ¿{@¿ŠP¿œÀ¿±p¿Âà¿Ô‘P¿é’¿ö”0À ”ÀÀ• À2•°ÀG•àÀ\– Àp–€À– À“–àÀ¨—@À¼—°ÀјÀݘ€Àê˜ðÀö™ Á™pÁ™àÁ šPÁ*šÁ9š°ÁK›PÁZ›ÀÁgÁx Á† 0Á“  Áž °Á­ ÀÁ¸ ÐÁÇ àÁÖ¡`Áá¡pÁì¡€Áû¢Â¢@¢ÐÂ$£PÂ3£àÂB¤`ÂN¤ÐÂZ¤ðÂk¥€Âv¥ðÂ…¦P”¦ÀŸ¦Ð°§@¾§PÂ˧pÂÙ¨Âä¨pÂñ¨àéPéÀéàÃ*ªPÃ9ªÀÃDªðÃO« ÃZ«PÃe«€Ãp«°Ã{«àƬѬ@Þ¬°Ãª¬ðü­`ÃÆ­ÀÃÓ¯Ãà¯pÃî¯àÃü°PİÀıı@Ä,·Ä=¸pÄG¸ ÄQ¸ÐÄ[¹Äe¹0Äs¹`ă¹ÐÄ–º@Ä¢ºpįºàÄûPÄÓ»°ÄÞ¼ Äè¾@Äú¾Å¿ÐÅÀÀÅ%ÀÀÅ3ÀÀÅCÀÆÅSÀÌÅaÀÞÅmÀðÅyÀøÅ…ÁÅ‘ÁÅÁÅ©ÁŵÁ ÅÁÁ(ÅÍÁ0ÅÙÁ8ÅåÁ@ÅòÁHÅþÁPÆ ÁXÆÁ`Æ"ÁhÆ.ÁpÆ:ÁxÆFÁ€ÆRÁˆÆ^ÁÆjÁ˜ÆwÁ Æ‚Á¨ÆÁ°ÆšÁ¸Æ§ÁÀÆ´ÁÈÆÁÁÐÆÏÁÐÆÝÁàÆëÁðÆúÂÇ ÂÇ Ç&Â0Ç5Â@ÇHÂPÇZÂ`ÇhÂpÇx€džÂÇ– ǣ°DzÂÀÇÅÂÐÇ×ÂàÇåÂðÇõÃÈÃÈÃ È Ã0È/Ã@ÈBÃPÈTÃ`ÈbÃpÈrÀȀÃÈàÈðȬÃÀÈ¿ÃÐÈÑÃàÈßÃðÈïÄÈýÄÉ Ä ÉÄ0É)Ä@É<ÄPÉNÄ`É\ÄpÉlÄ€ÉzÄÉŠÄ É—İɦÄÀɹÄÐÉËÄàÉÙÄðÉéÅÉ÷ÅÊÅ ÊÅ0Ê#Å@Ê6ÅPÊHÅ`ÊVÅpÊfÅ€ÊtÅʄŠʑŰʤÅÀÊ·ÅÐÊÅÅàÊÓÅðÊáÆÊïÆÊüÆ ËÆ0Ë"Æ@Ë0ÆPË>Æ`ËLÆpËZÆ€ËgÆËzÆ Ëư˛ÆÀË©ÆÐË·ÆàËÅÆðËÓÇËçÇËûÇ Ì Ç0ÌÇ@Ì(ÇPÌ7Ç`ÌBÇpÌMÇ€ÌXÇÌdÇ Ìpǰ̂ÇÀÌŽÇÐÌšÇà̬Çð̸ÈÌÄÈÌÖÈ ÌâÈ0ÌïÈ@ÍÈPÍÈ`ÍÈpÍ-È€Í9ÈÍEÈ ÍWȰÍcÈÀÍoÈÐÍÈàÍÈðÍšÉÍ­ÉͺÉ ÍÍÉ0ÍàÉ@ÍóÉPÎÉ`ÎÉpÎ-É€Î@ÉÎTÉ Î`ɰÎlÉÀÎxÉÐÎ…ÉàΔÉðΣÊβÊÎÂÊ ÎÔÊ0ÎæÊ@ÎøÊPÏ Ê`ÏÊpÏ#Ê€Ï/ÊÏ<Ê ÏNʰÏ`ÊÀÏrÊÐÏ…ÊàÏ”ÊðÏ£ËϲËÏÂË ÏÏË0ÏßË@ÏïËPÐË`ÐËpÐË€Ð.ËÐ>Ë ÐO˰Ð`ËÀÐmËÐÐ}ËàÐËðОÌЯÌнÌ ÐÎÌ0ÐßÌ@ÐñÌPÑÌ`ÑÌpÑ Ì€Ñ0ÌÑAÌ ÑR̰Ñ_ÌÀÑoÌÐÑÌàÑÌðÑ¡ÍÑ®ÍѾÍ ÑÎÍ0ÑßÍ@ÑðÍPÑþÍ`ÒÍpÒ Í€Ò2ÍÒDÍ ÒTͰÒfÍÀÒxÍÐÒˆÍàÒšÍðÒ¬ÎÒ¼ÎÒÎÎ ÒàÎ0ÒñÎ@ÓÎPÓÎ`Ó'ÎpÓ9΀ÓKÎÓ[ΠÓmΰÓÎÀÓÎÐÓ¡ÎàÓ³ÎðÓÄÏÓ×ÏÓêÏ Ó÷Ï0ÔÏ@ÔÏPÔÏ`Ô.ÏpÔ;Ï€ÔJÏÔ]Ï ÔoϰÔ}ÏÀÔÏÐÔ›ÏàÔ«ÏðÔ¸ÐÔÇÐÔÚÐ ÔìÐ0ÔúÐ@Õ ÐPÕÐ`Õ(ÐpÕ5ЀÕDÐÕWРÕiаÕwÐÀÕ‡ÐÐÕ•ÐàÕ¥ÐðÕ²ÑÕÁÑÕÔÑ ÕæÑ0ÕôÑ@ÖÑPÖÑ`Ö"ÑpÖ/Ñ€Ö>ÑÖQÑ ÖcѰÖqÑÀÖÑÐÖÑàÖŸÑðÖ¬ÒÖ»ÒÖÎÒ ÖàÒ0ÖîÒ@ÖþÒP× Ò`×Òp×)Ò€×8Ò×KÒ ×]Ò°×kÒÀ×{ÒÐ׉Òà×™ÒðצÓ×¹Ó×ÌÓ ×ÚÓ0×èÓ@×öÓPØÓ`ØÓpØ$Ó€Ø7ÓØEÓ ØSÓ°ØaÓÀØoÓÐØ|ÓàØÓðØ¢ÔØ°ÔؾÔ ØÌÔ0ØÚÔ@ØèÔPØüÔ`ÙÔpÙÔ€Ù.ÔÙ=Ô ÙLÔ°ÙYÔÀÙgÔÐÙuÔàÙ‡ÔðÙ™ÕÙ¦ÕÙ´Õ ÙÂÕ0ÙÔÕ@ÙæÕPÙóÕ`ÚÕpÚÕ€Ú!ÕÚ3Õ ÚAÕ°ÚPÕÀÚ_ÕÐÚrÕàÚ…ÕðÚ’ÖÚ ÖÚ®Ö ÚÀÖ0ÚÒÖ@ÚßÖPÚíÖ`ÚûÖpÛ Ö€ÛÖÛ,Ö Û:Ö°ÛHÖÀÛZÖÐÛlÖàÛzÖðÛ‰×Û˜×Û«× Û¾×0ÛÊ×:ÛØ×DÛé×PÛò×`Ûû×pÜ ×€Ü× Ü"×ÀÜ/×àÜ<ØÜJØBÜVØPÜaØ`ÜlØpÜz؀܋ØÜšؠܪذܺØÀÜÈØÐÜÙØàÜèØðÜøÙÝÙÝÙ Ý*Ù0Ý;Ù@ÝLÙPÝ]Ù`ÝnÙpÝÙ€ÝÙÝÙ Ý«ٰݹÙÀÝÆÙÐÝÔÙàÝâÙðÝïÚÝýÚÞ Ú ÞÚ0Þ&Ú@Þ4ÚPÞAÚ`ÞOÚpÞ]Ú€ÞjÚÞxÚ Þ†Ú°Þ“ÚÀÞ¡ÚÐÞ¯ÚàÞ¼ÚðÞÊÛÞØÛÞåÛ ÞóÛ0ßÛ@ßÛPßÛ`ß*Ûpß7Û€ßEÛßSÛ ß`Û°ßnÛÀß|ÛÐ߉Ûàß—ÛðߥÜß²ÜßÀÜ ßÎÜ0ßÛÜ@ßèÜPßõÜ`àÜpàÜ€àÜà)Ü à6ܰàCÜÀàPÜÐà]ÜààjÜðàwÝà„Ýà’Ý à Ý0à®Ý@à¼ÝPàÊÝ`àØÝpàæÝ€àôÝáÝ áݰáÝÀá,ÝÐá:ÝàáHÝðáVÞádÞárÞ á€Þ0áŽÞ@áœÞPáªÞ`á¸ÞpáÆÞ€áÔÞáâÞ áðÞ°áþÞÀâ ÞÐâÞàâ0ÞðâBßâTßâfß âxß0âŠß@âœßPâ®ß`âÀßpâÒ߀âäßâöß ãß°ãßÀã,ßÐã>ßàãPßðãbàãtàã†à ã˜à0ãªà@ã¼àPãÎà`ãààpãòà€äàäà äà°ä(àÀä4àÐä@ààäLàðäXáädáäpá ä|á0äˆá@ä”áPä á`ä¬ápä¸á€äÄáäÐá äÜá°äèáÀäôáÐåáàåáðåâå-âå<â åKâ0åZâ@åiâPåuâ`åâpåâ€å™âå¥â å±â°å½âÀåÌâÐåÛâàåêâðåùãæãæã æ&ã0æ8ã@æJãPæ\ã`ænãpæ€ã€æ’ãæ¤ã æ¶ã°æÈãÀæÚãÐæìãàæþãðçäç"äç2ä çBä0çSä@çdäPçtä`ç„äpç•ä€ç¦äç¶ä çÆä°ç×äÀçèäÐçøäàèäðèåè*åè:å èJå0è[å@èlåPè|å`èŒåpèå€è®åè¾å èÎå°èßåÀèðåÐéåàéåðé!æé2æéBæ éRæ0écæ@étæP鄿`锿p饿€é¶æéÆæ éÖæ°éçæÀéøæÐêæàêæðê)çê:çêJç êZç0êkç@ê|çPêŒç`êœçpê­ç€ê¾çêÉç êÔç°êãçÀêóçÐëçàëçðë èë1èë@è ëPè0ë`è@ëoèPë}è`ëŽèpëœè€ëªèë¸è ëÆè°ëÕèÀëãèÐëñèàëÿèðì éìéì#é ì1é0ìBé@ìQéPì`é`ìpépì~é€ìéìžé ì­é°ì½éÀìÍéÐìÝéàìíéðìýêí êíê í$ê0í0ê@í<êPíHê`íTêpícê€írêí„ê í”ê°í¤êÀí´êÐíÄêàíÓêðíâëíôëîë îë0î#ë@î2ëPîDë`îTëpîdë€îsëî‚ë î”ë°î¥ëÀî¶ëÐîÇëàîØëðîéìîúìï ì ïì0ï'ì@ï2ìPï=ì`ïKìpïZì€ïhìïvì ï„ì°ï•ìÀï£ìÐï²ìàïÀìðïÎíïÜíïíí ïûí0ð í@ðíPð&í`ð4ípðEí€ðSíðdí ðuí°ðíÀð‰íÐð˜íàð§íðð¶îðÅîðÔî ðãî0ððî@ñîPñî`ñ îpñ0î€ñ?îñNî ñ]î°ñmîÀñ}îÐñîàñîðñ­ïñ½ïñÍï ñÝï0ñíï@ñýïPò ï`òïpò-ï€ò=ïòGï òQï°òZïÀòcïÐòlïàòuïðò~ðò‡ðò”ð òžð0ò¨ð@ò±ðPòºð`òÃðpòÌð€òÕðòÞð òçð°òñðÀóðÐóðàó#ððó3ñó?ñóKñ óWñ0ócñ@óoñPó{ñ`ó‡ñpó“ñ€óŸñó«ñ ó·ñ°óÃñÀóÏñÐóÛñàóçñðóóòóÿòô ò ôò0ô#ò@ô/òPô;ò`ôGòpôSò€ô_òôkò ôwò°ôƒòÀôòÐô›òàô§òðô³óô¿óôËó ô×ó0ôãó@ôïóPôûó`õópõó€õ&óõ8ó õJó°õ]óÀõoóÐõóàõ”óðõ¦ôõ¸ôõËô õÝô0õïô@öôPöô`ö&ôpö9ô€öKôö]ô öpô°ö‚ôÀö”ôÐö§ôàö¹ôðöËõöÞõöðõ ÷õ0÷õ@÷'õP÷9õ`÷Lõp÷^õ€÷põ÷ƒõ ÷•õ°÷§õÀ÷ºõÐ÷Ìõà÷Þõð÷ñöøöøö ø#ö0ø1ö@ø?öPøMö`øVöjø_ötølö~ø{öˆø‹ö’ø•öœøŸö¦ø©ö°øµöºøÄöÄøÑöÎøÝöØøæöâøóöìùööù÷ù÷ ù*÷ù:÷ùI÷(ùY÷2ùb÷<ùl÷Fùz÷Pù‹÷Zùœ÷dùª÷nù·÷xùÄ÷‚ùÍ÷ŒùÖ÷–ùß÷ ùé÷ªùø÷´ú÷¾ú÷Èú)÷Òú;÷ÜúM÷æúY÷ðúb÷úúoøú{øúŠøú™ø"ú£ø,ú°ø6ú½ø@úÊøJú×øTúãø^úïøhúûørûø|ûø†ûøû+øšû7ø¤ûCø®ûPø¸û]øÂûjøÌûwøÖû„øàû‘øêûžøôû«øþû¸ùûÅùûÒùûßù&ûìù0ûùù:üùPü ùpüù€ü&ù’ü7ÿþüDtextlocore_begininitsaved_pcsaved_a0start_trapsoc_alivetimeout_cntoffline_cntinit_cntper_portper_port_0per_port_1per_port_endcopy_dload_and_excde_loopcde_1fcde_2fcde_endgrep_reveeprom_cksumeeprom_datecodeeeprom_datestreeprom_hdr_endlesb_0lesb_1locore_unusedservice_paramsserv_parms_endpower_onsoc_magicsoc_cksumfw_date_codedate_strhw_revisionport_0_wwnport_1_wwnnode_wwnbackdoor_alpa_0backdoor_alpa_1backdoor_frame_sizerx0_dmarx1_dmalocore_endsoc_beginstarthcb_fillprom_start_begincpdltextcpdldatacpdldonecpchkmagicdlt_copy_eepromdce_1fdl_copy_invalidnot_power_ontest_fpm_suminvalidate_fpmfpm_chk_doneclr_udataclr_restprom_start_endfpm_loadedmainiib_wertserial_wertesi_wertfcp_wertfpm_disp_wertfpm_keypad_wertfpm_getesi_wertfpm_poll_donefpm_boxset_wertpoll_tablerx_hdr_poll_tablespec_sig_poll_tableal_state_poll_tabletx_poll_poll_tablepoll_resetal_state0al_state1serial_portsbus_slavemisc_begindo_nop_8hcb_clearmisc_endrx_hdr_beginrxh_do_bad_d_idrxh_bad_stoprxh_check_open_failrxh_do_invalid_idrxh_do_my_id_invalidrxh_not_loop_initrx_hdr1rx_hdr0rx_hdrxlooprx139wrx139drxh_check_s_idrxh_bad_d_idrxh_my_id_invalidrxh_well_known_s_idrxh_check_x_idrxh_rsprxh_unsolicitedrxh_unexp_ackrxh_check_xrrxh_bad_f_ctlrxh_good_f_ctlrxh_x_initrxh_30frxh_31frxh_32frxh_wait_unsolrxh_wait_eofwait_again168wait_eof_done168rxh_unsol_abtsrxh_ua_looprxh_ua_10rxh_ua_nextrxh_ua_not_foundrxh_ua_05rxh_ua_foundrxh_ua_eofwait_again180wait_eof_done180rxh_ua_free_discardrxh_ua_discardwait_again183wait_eof_done183rxh_solicitedrxh_sol_uchkrxh_val_hdrrxh_sol_uokrxh_sol_udatarxh_sol_udata1rxh_sol_ucontrxh_sol_u2rxh_sol_u1rxh_sol_u3rx195rxh_sol_reqiprxh_exch_errrxe_ee_stoprxh_rjt_xchg_errrxh_hdr_okrxh_check_lcrxh_lc_seq_initrxh_good_lcwait_again208wait_eof_done208rxh_not_lcwait_again210wait_eof_done210rxh_not_lc_siwait_again212wait_eof_done212rxh_wait_solwait_again214wait_eof_done214rxh_s_dmarxh_saverxh_19frxh_1frxh_save_exitrx_hdr_endrx_eof_beginsof_2_class_tabrx_eof1rx_eof0rx_eofrxe_eofrxe_eof_okrxe_errrxe_of_okrx230wrx230drx_discardrxe_truncaterxet_retrx236rx_ignorerx239rx_busyrx241wrx241dsel_hcb1243rx_rejectrx246wrx246dsel_hcb1248rx_send_ackrx_link_controlrxe_p_rjtrxe_f_rjtrxe_p_bsyrxe_f_bsy_dfrxe_f_bsy_lcrxe_busyrxe_rjtrxe_rjt_tabrxe_retire_xchgrxe_invalid_reasonrxe_no_retire_xchgrx267rxe_ack_1rxe_ack_nrxe_do_ackrx272rxe_ack_retrxe_no_more_datarnmd_10rxe_send_more_datarxe_smrxe_lcrrxe_xfer_rdyrx281rx282wrx282dsel_hcb1284rxe_xr1rx287rxe_unsol_abtssel_hcb1290rxe_ua_70rx293rxe_abortedrx295rxe_ab_10sel_hcb1298rxe_ab_20rx301rxe_logirxe_cred_okrxe_logi_txb_okrxe_logi_bb_donerxe_logi_retrxe_unsol_fcprxe_new_fcprx309rx310rxe_unsol_elsrx313rxe_u_2frx315rx316wrx316drxe_u_3frxe_unsol_els_tabrxe_logi_reqrx321rx322wrx322drxe_unsolicitedrxe_els_donerxe_to_payload_donerxe_handle_plogirxe_els_10rxe_handle_logorxe_send_logorxe_els_12rxe_els_13rxe_handle_prlirxe_handle_adiscrxe_els_15rxe_els_20rxe_els_30rxe_handle_rlsrxe_els_40rxe_rcv_datarx347rx348rxe_payload_to_xramrxe_xram_looprxe_to_hcbrxe_wait_hcbrxe_to_xramrx355rxe_xram_donerxe_payload_donerxe_xram_retrxe_u_dmarxe_u_donesel_hcb1361rxe_got_seq_initrxe_20frxe_no_creditrx366sel_hcb1367rxe_nc1rxe_unsol_freexrxe_u_dont_freerxe_u_resprxe_classrxe_bcntrxe_sol_udatarx377rx378rxe_all_udonerx380rxe_sol_elsrx382rxe_se_2frx384rx385wrx385drxe_se_4frxe_se_3frxe_sol_els_tabrxe_flogi_rsprxe_logi_rsprx392rx393wrx393drxe_logi_rsp_1rxe_datarxe_frame_dmarxe_frame_donerxe_check_delayrx401rxe_c3_no_ackrxe_check_ackrxe_no_crdtrxe_ack_only1sel_hcb1408rxe_no_ackrxe_did_ackrxe_next_seqrxe_21frxe_last_datarxe_next_abtsrxe_na_10rxe_next_tabrxe_tbdrxe_outbrxe_outb_completerxe_inbrxe_inb_completerxe_simplerxe_s1rxe_simple_txrxe_s2rxe_iowrxe_iorrxe_notify_data_donerxe_send_first_datarxe_send_datarxe_txrxe_tx_1rxe_tx_2rxe_tx_5sel_hcb1438rxe_bpoolrxe_22frxe_23frxe_bpool1rxe_bpool2rxe_no_bpoolrxe_abts_cleanuprxe_ac3rxe_completerxe_request_donerxe_freerxe_returnrx_eof_endrx_dma_beginrxd_flushrx_flushwait_again457wait_eof_done457rx_dmarxd_00rxd_q1rx0_sbus_errorrx1_sbus_errorrxd_sbus_errorrxd_sbe_looprxd_found_call_backrxd_donerx_rdma1rx_rdma0rx_rdmarx_dma_completedrxd_s1rx_none_availrxrd_00rx_dma_endspec_sig_beginss_goto_offline_1ss_init_1ss_goto_offline_0ss_init_0ss_initss_offline_1ss_offline_0ss_offliness_1fss_2fss_goto_nolightss_look_for_lightss_3fss_nolight_1ss_nolight_0ss_nolightss_see_lightss_35fss_light_wait_1ss_light_wait_0ss_light_waitss_37fss_assert_ltrss_40fss_4fss_light_1ss_light_0ss_lightss_25fss_goto_ltr_recss_50fss_5fss_ltr_recover_1ss_ltr_recover_0ss_ltr_recoverss_6fss_goto_rxresetss_7fss_rxreset_1ss_rxreset_0ss_rxresetss_8fss_goto_linkupss_goto_lp_onlinesslp_10sslp_20ss_lp_online_1ss_lp_online_0ss_lp_onlinesslpo_00rx_update_lesbrx_status_changerxsc_2fss_force_offlinessfo_1fssfo_2frx_offliness_12fss_13foffi_30rxol_05rxol_10rxol_20rx_spec_alrxsa_02rxsa_05ss_goto_tcredit_adjss_reset_rxss_null_dmaport_offlinepoff_retcheck_oe_bypass_1check_oe_bypass_0check_oe_bypasschkoe_lci_waitchkoe_cut_inchkoe_non_bypasschkoe_lco_waitchkoe_oechkoe_oco_waitchkoe_cut_outchkoe_offlinechkoe_no_cutchkoe_retflash_laser_1flash_laser_0flash_laserfla_10fla_20fla_70fla_90inc_lesbilb_00spec_sig_endscavange_tsdstx_poll1tx_poll0tx_polltxp_00txp_01txp_05txp_done0txp_20txp_retnext_segtx_dec_segcnttx_dseg_dmatx_next_reqnot_enough_CQEsnot_enough_segstx_routines_begintx_acktx_ack_do_ittx_50ftx_51ftx_52fetsd_done620tx_ba_acctx_70ftx_71ftx_72fetsd_done627tx_75ftx_rjttx_from_hcbtx_ack_receivedtx_logouttx_logintxl_looptxl_storetxl_next_classinstall_tfqtxit_port1txit_1ftxit_hash_tab_oktx_get_tfqtxgt_port1txgt_1ftxgt_hash_tab_oktxgt_looptxgt_no_matchtxgt_not_foundtx_create_tfqtxcq_alloc_failtxct_1ftxct_2ftxct_3ftxct_4ftxct_5ftxct_class1txct_class2txct_6ftxct_7ftxct_8ftxct_9ftxct_10ftxct_class3tx_free_tfqtxf_05tx_frame_from_xramtxfx_no_tsdtxfx_got_tsdtxfx_1ftxfx_22etsd_done681txfx_23txfx_25txfx_30txfx_35tx_next_seqtxn_20ftxn_21ftxn_25ftxn_next_tabtxn_simpletxn_iowtxn_iortxn_outbtxn_inbtxn_returntxn_completed_cbtxn_completedtxn_goto_rxeport_free_tfqpft_00pft_tfq_looppft_tfq_foundpft_tsd_looppft_tsd_donepft_tsd_foundpft_05port_free_tsd_done_1ptsd_05ptsd_10ptsd_15ptsd_retport_clean_hashpch_20pch_22pch_hash_foundpch_hash_looppch_30pch_40hash_inittx_routines_endsw_timerovfs_per_sectimer_initdo_timerports_okdo_timer_exitlink_fail_1link_fail_2ports_asserttm_another_secskip_ab_timerto_loopto_to_not_zeroto_nextto_retto_unretiretou_00tou_05to_timeoutto_abts_timeouttat_00tat_05to_abts_00wait1micwaw5wait5micwait25micwait1secw1s5w1s10wait5secw5s5w5s10rx_init_beginrx_initrx_init_loopw822fillw823fillrx_init_endtx_init_begintx_inittx_init_porttxi00txi_clr_pptx_init_endfcal_init_beginfbuf1_0fbuf2_0fbuf1_1fbuf2_1lip_rx_fp_0lip_tx_fp_0lip_rx_fp_1lip_tx_fp_1lip_tfq_0lip_tfq_1lism_hdr_platelip_rx_proc_0lip_rx_proc_1lip_form_alpalfa_00lip_initlip_int2lip_try_liplip_t0lip_t1lip_timer_0lip_timer_1lip_timerlip_tm0lip_timeoutlip_timeout_liplip_to_sslip_oi_rcvd_0lip_oi_rcvd_1lip_oi_rcvdlip_oi_idlelip_oi_00lip_l0lip_l1lip_oi_idle_wait_0lip_oi_idle_wait_1lip_oi_idle_waitlip_oi_loss_synclip_oi_iw_donelip_iw_loss_synclip_iw_no_liplip_iw0lip_iw1lip_iw3lip_oi_tsm_0lip_oi_tsm_1lip_oi_tsmlip_tsm_sp0lip_tsm_sp1lip_tsm1lip_tsm01lip_tsm2lip_tsm3lip_tsm4lip_tsm10lip_bad_tfqlip_oi_alpa_s_0lip_oi_alpa_s_1lip_oi_alpa_slip_as_sp1lip_as2lip_as_busylip_oi_alpa_m_0lip_oi_alpa_m_1lip_oi_alpa_mlip_am_sp0lip_am_sp1lip_am2lip_am3lip_am4lip_am5lip_am7lip_mon_0lip_mon_1lip_monfairness_onlip_mon_tfqlip_mon_05lip_mon_10mon_to_lip_1mon_to_lip_0mon_to_liplip_ignore_eoflip_init_lportrx_loop_initrxli_05rxli_10rx_oi_rcvdrxli2_05rxli2_10lip_rx_hdr1lip_rx_hdr0lip_rx_hdrwait_again958wait_eof_done958lip_rx_eoflip_rxe_eoflip_rxe_eof_okrx963lip_rh_sp1lip_rxe_errrx966wrx966dlip_rx_discardrx969lip_tx_poll1lip_tx_poll0lip_tx_polllip_tp_00lip_txp_00lip_txp_01lip_txp_10lip_txp_20lip_txp_30lip_txp_retlip_rx_proc_tsmlip_rx_tsm0lip_rx_tsm1lip_tsm_e1lip_rt_winlip_rt_loselip_rt_masterlip_rt_busylip_rtm1lip_rtm2lip_lism_errorlip_rx_proc_alpa_slip_pas0lip_pas1lip_pas_tablelip_pas_lifalip_pas_lipalip_pas_lihalip_pas_lisalip_pas_lirplip_pas_lilplpl_10lip_pas_errorlip_rx_proc_alpa_mlip_pam0lip_pam1lip_pam_tablelip_pam_lipalip_pam_lihalip_pam_lisalip_pam_no_lirplip_pam_lirplip_pam_do_lirplip_pam_rp1lip_pam_lilplip_pam_store_lilplip_pam_donelpd_10lip_pam_errorlip_alpa_lifalip_alpa_lipalippa1lip_alpa_lihalipha0lipha1lip_alpa_lisalipsa1lip_alpa_retxlip_rx_proc_nullip_swap_tx_and_rxlip_sw0lip_1flip_tx_frameft_0fft_1fft_2fft_3flip_retx_framelip_retx0lip_retx1frame_to_xramrx1071wrx1071drx1072ftx4rx1075ftx5ftx6ftx7ftx8rx1080ftx_exitlip_lism_enterlip_lism_e0lip_lism_e1lip_lism_donelip_lism_d0lip_lism_d1check_lport_idchkid1chkid_invalidchkid_matchlpbm1lpbm2chkid_retget_lport_idglpid_mineglpid_hosedget_any_lport_idgalid1galid2galid_hosedgalid_freegalid4galid5galid_exitlip_goto_offlinelip_goto_oi_rcvdlip_goto_try_liplip_rx_flushlrf_10lrf_20wait_again1119wait_eof_done1119lrf_30rx1121lip_discard_tsdldt_done1ldt_00ldt_01ldt_done0ldt_25ldt_retlip_drasticlip_ab_disabledlip_do_drasticlip_bang_0lip_bang_1lip_exitfcal_init_enddo_error1do_error0do_errorerr_offlineerr1err_fcalerr2err_oflwoflw_loopoflw_retoflw_hdrwait_again1157wait_eof_done1157oflw_eofrx1159b64_alloc_beginb64_allocb64_popb64_alloc_failb64af10b64_freeb64_f2b64_free_listb64_not_emptyb64_fl_retb64_initb64_clr_loopb64_clr_doneb64_5fb64_pool_loopb64_6fend_b64_pool_loopb64_alloc_endxchg_beginXCHG_free_headXCHG_free_tailXCHG_availXCHG_initXCHG_pool_loopXCHG_stuffend_XCHG_pool_loopXCHG_allocXCHG_popXCHG_freeXf_retxr_statusXCHG_retirexr_port0xr_to_loopxr_loopxr_pend_loopxr_endlistxr_donexchg_endtx_err_begintx0_sbus_errortx1_sbus_errortx_err_endput_hw_regs_beginput_hw_regsput_rpramsput_rp_loopput_rxbufput_rxbuf_looprx1222wrx1222dhalt_on_errloop_foreverput_hw_regs_endjournal_beginphoton_begintoggle_strobeib_rd_dataib_rd_statib_wr_control_allib_control_bitonib_control_bitoffib_wr_dataib_wr_dtphoton_endsp_beginsp_ptr_initsp_fw_initsp_chip_resetsp_nopnop_16sp_nop_8sp_hw_resetshr_20sp_hw_enableshe_20sp_hw_initserial_initsp_initserial_pollsp_pollsp_poll_checksp_rx_spbsp_no_rxsp_tx_spbsp_chk_exitsp_rx_readyasp_rx_readysp_tx_readysp_puts_leafsp_pl_20sp_pl_30sp_pl_40sp_pl_50sp_putscsp_psc_00sp_psc_10sp_putssp_puts_00sp_puts_10sp_puts_20sp_puts_40sp_puts_50sp_puts_60sp_puts_70sp_puts_80sp_puts_90sp_puts_endsp_put_nextssp_put_n10sp_put_n20putcharputcaputcgetchargetcagetcpre_sp_g2csp_get_2charsg2c_05sg2c_10sg2c_11sg2c_20sg2c_21sg2c_30sg2c_40sg2c_50sg2c_60sp_get_4charsg4c_20sg4c_80sg4c_100sp_endprint_beginprintffp_savefprintffp_10fp_20fp_enddoprntdop_10dop_20dop_21dop_22dop_30dop_31dop_40dop_50dop_60dop_90dop_100dop_endwdecdivbydcdv_10decdivprintn10dd10printnpn_10pn_20print_endcmd_if_begincmd_if_char_enqcice_10cice_20cicd_30cice_40cice_endcmd_if_parsecip_05cip_10cip_15cip_55cip_endclr_cmd_incci_10cci_99cmd_if_enddebug_initdbi_10do_debugdbg_10dbg_20dbg_25dbg_30dbg_90dbg_100do_ptracedp10pt_peekpt_pokept_writept_readpt_contpt_gregsptg1pt_sregspt_breakpt_invalidaccess_sizepokelpokepokecpeeklpeekcpeekt_put_intt_put_mtpm_5tpm_10tpm_11tpm_12tpm_13tpm_14tpm_40t_get_intt_get_mtgm_10tgm_20tgm_30tgm_40pp_magic1pp_magic2adb_replypp_waitingsp_iib_beginiib_check2sendiib_nxt_sndiib_snd_exitiib_fnd_sndiib_xmt_busyiib_send_dataseibd_01seibd_05seibd_10ics2_20sp_iib_enqiib_chk_preambiib_preamb_exitiib_preamb_adjiib_preamb_startiib_chk_payloadiib_calc_chksumcalc_chksumiib_reset_cntsp_iib_exitiib_check2rcvic2r_10valid_wwnchkiib_chk_chgcf2c_10cf2c_12cf2c_20cf2c_30chk_chg_exitc4ch_03c4ch_04c4ch_05c4ch_10cmd_iib_boxi_01cmd_iib_boxi_05cmp_iib_bi_10cmp_iib_bi_15cmp_iib_bi_20cmp_iib_bi_25cmp_iib_bi_30rcbx_1frcbx_2freally_ch_boxinforchwwn_exitcheck_setboxidcsbidexitiib_snd_chgsf2c_10sf2c_12set_vals_in_ibxicmp_ack_bufsp_iib_endstrings_beginstrcmpscmp_10scmp_20scmp_30strncmpstrn_20hex_2_asciih2a_10h2a_20h2a_retstr_copystrings_endcmd_esiprobeesiprobe_10esiprobe_15esiprobe_25esiprobe_30esiprobe_50sp_scp_testswr_10swr_20swr_30set_rdsrd_10srd_20srd_30srd_40cmd_helpcmd_statusall_ledsonall_ledsoffcmd_singlecmd_splitchg_loopcfgcmd_setboxidcsbid_fpmsetbox_idcmdsbi_10cmdsbi_20cmdsbi_30cmd_setwwncswwn_fpmget_spwwncmd_setnamecsnm_10csnm_20csnm_25csnm_26csnm_30csnm_fpmcsnm_40cmd_lfsp_big_enddiag_overlay_startdiag_post_overlaydpo_10cmd_callpostcmd_restoredpo_retdpo_namsgdiag_no_postoldiag_overlay_endesi_beginesi_initesi_init_exitinit_psrd_cfgmbeprom_validmbeprom_checkmbeprom_disablerd_mbepromrd_mbep_contmbeprom_invalidibe_inv_05fibeprom_invalidibe_inv_10fibeprom_validrd_ibepromrd_cfg_exitcmp_eprom_magicrd_mbhdr_4cksumrd_ibhdr_4cksumrd_4cksumr4cs_10r4cs_20cfg_loopid_10setwwnckcf_10copy_wwncwwn05addwd6incwd6cwwn20cnt_fru_grpscnt_grpscfg_1fset_num_grpsesi_pollesi_poll_initesi_pi_contesi_poll_starteps_1fpoll_grppoll_frupoll_nxtesi_poll_checkesi_poll_exitget_esi_ptresi_peekpeek_exitesi_pokepoke_exitesi_blink_genblink_cntesi_overtemp_checkovertemp_ft0check_overtemp_ft1overtemp_ft1check_overtemp_ib0overtemp_ib0check_overtemp_ib1overtemp_ib1check_overtemp_ps0overtemp_ps0check_overtemp_ps1overtemp_ps1check_overtemp_ps2overtemp_ps2check_overtemp_bp0overtemp_bp0_hspeedovertemp_bp0check_overtemp_bp1overtemp_bp1_hspeedovertemp_bp1overtemp_checkovertemp_timeovertemp_timerovertemp_shutdownovertemp_goneovertemp_check_exitrst_dm_ctresi_exch_infoexch_infoeexin_1fexch_info_clrexch_data_clrexch_info_exitloopb_to_nportltn_01ltn_10ltn_20bypass_oeboe_00unbypass_oeuboe_00esi_1sec_timeresi_1sec_exitesi_set_overtempesi_no_changeesi_clr_overtempesi_endesi_routines_beginget_esiset_esiesi_req_accacc_req_not_sameacc_req_sameacc_fcp_reqacc_new_reqacc_req_startacc_reqesi_req_maccmacc_reqesi_req_clrclr_reqesi_peek_lppeek_lp_singlepeek_lp_presesi_poke_lppoke_lp_stateplps_1fesi_peek_mbpeek_mb_setesi_poke_mbpoke_mb_statepoke_mb_yledpoke_mb_gledesi_peek_pspeek_ps01peek_ps_statepeek_ps_dcfpeek_ps_otspeek_ps_otwpeek_ps2peek_ps_acfpeek_ps_revpeek_ps_presentpeek_ps_no_countpeek_ps_no_faultpeek_ps_faultpeek_ps_off_checkpeek_ps_prechps_prech_checkps_prech_disableps_prech_changepeek_ps_exitesi_poke_psps_state_changedps_state_onps_unit_cntps_state_setesi_poke_exitesi_peek_ftpeek_ft_statepeek_ft_revpeek_ft_prespeek_ft_state_onpeek_ft_no_revesi_poke_ftft_state_changedft_state_onpoke_ft_yledpoke_ft_onbrdpoke_ft_fanesi_peek_bppeek_bp_sendpeek_bp_startpeek_bp_frontpeek_bp_presentpeek_bp_typepeek_bp_ts_startpeek_bp_nxt_cyclepeek_bp_ts_readpeek_bp_ts_numpeek_bp_ts_refpeek_bp_ts_7drvspeek_bp_ts_endpeek_bp_get_typepeek_bp_stateesi_peek_ddpeek_dd_bptypepeek_ddpeek_dd_presentpeek_dd_bpapeek_dd_bpbpeek_dd_yledpeek_dd_insertedpeek_dd_identifypeek_dd_nextpeek_dd_exitesi_poke_bppoke_bp_maskbp_def_no_changepoke_bp_statepoke_bp_bpoke_bp_bypasspoke_bp0_bypasspoke_bp_ddesi_poke_ddpoke_dd_maskdd_def_no_changedd_state_changedd_state_frontdd_state_cntdd_state_setdd_state_byleddd_state_yleddd_state_bbeadd_state_bbebdd_state_spndnbp_state_setdd_bp_state_setpoke_dd_exitesi_peek_ibpeek_other_ib_prespeek_ib_stateib_overtempstore_p0_nodesstore_p1_nodesesi_poke_ibpoke_no_resetpoke_ibpoke_ib_statepoke_ib_setpoke_ib_disablepoke_ib_yledpoke_ib_offesi_peek_oepeek_oe_statepeek_oe1peek_oe_donepeek_oe0peek_oe_prespeek_oe_faultpeek_oe_rxlosspeek_oe_syncpeek_oe_onlinepeek_oe_offlinepeek_oe_not_presentpeek_oe_txdblesi_poke_oepoke_oepoke_oe_statepoke_oe_setpoke_oe_yledpoke_oe_gledpoke_oe_ledspoke_oe_byppoke_oe_nbyppoke_oe_modepoke_oe_loopbpoke_oe_optcpoke_oe_portpoke_oe_hwpoke_oe_offlinepoke_oe_exitesi_req_mbreq_mb_blinkreq_mb_statreq_mb_enablereq_mb_validreq_mb_exitesi_req_bpreq_bp_setesi_req_ddreq_dd_blinkreq_dd_exitesi_req_ibib_update_gledib_update_yledib_no_failesi_req_oeoe_check_controloe_check_bypsoe_check_offoe_update_gledoe_update_yledesi_req_ftft_req_gledft_req_yledesi_rd_local_busesi_wr_local_busesi_rd_esi_busesi_wr_esi_busesi_set_statset_stat_bitset_stat_exitesi_rcv_peekrcv_peek_IB_Arcv_peek_nodesrcv_peek_bprcv_peek_bp0rcv_peek_bp_tsrcv_peek_bp_okrcv_peek_bp_otrcv_peek_exitesi_send_peeksend_peek_ibsend_peek_IB_Asend_peek_bpsend_peek_bp_tssend_peek_exitesi_rcv_pokercv_poke_startrcv_poke_bp_typercv_poke_nxt_spinuprcv_poke_spinuprcv_poke_bp_type1rcv_poke_nxt_ddrcv_poke_presrcv_poke_nreqrcv_poke_clr_nreqrcv_poke_chk_nreqrcv_poke_chk_reqrcv_poke_dd_endrcv_poke_dd_statercv_poke_npresrcv_poke_exitesi_send_pokesend_poke_bp_typesend_poke_nxt_ddsend_poke_no_esisend_poke_exitget_iib_ptresi_offlineoffline_p1esi_temp_cnvtesi_temp_setpeek_bp_ts_errorpeek_bp_ts_checkpeek_bp_failpeek_bp_setpeek_bp_otwpeek_bp_aver_tpeek_bp_max_tpeek_bp_ts_dscrpeek_bp_ts_donepeek_bp_preset_a2desi_routines_endmbeprom_copymbecp_10mbecp_20mbecp_30mbecp_35mbecp_50mbecp_exitmbeprom_readmbeprom_read_scteerd_10eerd_20mbeprom_writembeprom_write_sectmbeewr_10mbeewr_25eewr_cmpmbeewr_30mbeewr_erreewr_40ibeprom_copyib_eerd_10ibeprom_write_sectibeprom_writeibeewr_10ibeewr_25prog_eepriib_noporprog_eepriibprog_eeproms_noporprog_eeproms_porprog_eeproms_hdrprog_eepromsprog_ibepromibeprom_nxt_sctcalc_xram_hdrcksumcalc_hdr_cksummbe_chksum05mbe_chksum10check_write_respreep_10preep_20genr_prog_mbepromgenr_prog_ibepromgenr_prog_anyeprommgpie_10mgpie_20mbeprom_set_step1n2set_esi_errdiag_ext_spcmd_boxinfodiag_print_xdgw10dgw60dgw70print_zerofpr_listfpr_05fpr_10fpr_20fpr_30fpr_retreset_errscmd_boxstatecmd_rsterrscmd_offlineport_0_offlineport_1_offlinecmd_rundiagcmd_diagerrcderr1cmd_diecmd_porcmd_resetcmd_muxchgab_beginab_timerabt_0fabt_2fabt_1fablt_chk_onlineablt_6fablt_notsplitab_timer_stepabns_2fab_lp_init_toablt_not_onlineablt_no_tout2ablt_exitab_port_offlineablo_8fablo_4fablo_5fablo_1fablo_2fablo_do_initab_port_onlineabls_8fabls_6fabls_1fabls_2fabls_3fabls_4fabls_5fabls_exitab_initabi_1fabi_2fabi_loopabi_init_stateabi_6fab_loopinit_timeoutlpto_do_retrylpto_foab_next_stateab_restart_loopab_retry_looprlp_1frlp_exitab_force_offlineabfo_1fab_bypass_oeab_bypass_bpab_do_bypassab_bypass_ddfab_bypass_ddab_bypass_ddrab_unbypass_oeab_unbypass_bpab_do_unbypassab_unbypass_ddfab_unbypass_ddab_unbypass_ddrab_is_splitloopab_s0_initabs0_loop0abs0_1fabs0_loop1abs0_2fab_s0_successab_s0_failab_s1_initabs1_lpabs1_loop0abs1_1fabs1_2fab_s1_successabs1_3fab_s1_failabs1f_5ab_s2_initab_s2_successab_s2_failabs2_1fab_s3_initab_s3_failab_s3_successabs3_2fabs3_1fab_s4_initab_s4_successab_s4_failab_s5_initab_s5_failab_s5_successabs5_2fabs5_1fab_s6_initab_s6_successabs6_1fab_s6_failabs6_2fab_s7_initab_s7_successab_s7_failab_rc_initab_rc_successab_rc_failab_st_initab_st_successab_st_failab_set_failab_enableab_disableab_endloader_beginloaderdl_loopdl_lp10dl_lp30dl_lp50dl_0dl_0_10dl_0_20dl_adl_a_20dl_ddl_edl_e_20dl_ldl_l_10dl_l_20dl_odl_o_10dl_o_20dl_xload_initexec_loadput2acksload_exitload_rcvrcv10rcv20rcv30rcv40ldr_thenldr_elseldr_e101ldr_e111ldr_e112ldr_e120ldr_el10ldr_endifdownload_donedldun_10dl_cmd_downloaddl_cmd_dl100dl_downloadfpmdl_cmd_no_waycmd_filldl_badloader_endiib_beginiib_initiib_init_doneiib_polliib_poll_startiib_poll_aloneiib_ibaiib_set_tsiib_poll_shareiib_ts_busiib_poll_busiib_poll_exitiib_sel_mstrsmst_10smst_20smst_30sel_mstr_endiib_ts_transitionts_x05ts_x10ts_x100ts_x105ts_x110ts_x115ts_t0ts_t010ts_t011ts_t1ts_t110ts_t111ts_t2ts_t210ts_t211ts_t3ts_t310ts_t311ts_tbrkts_tcaseset_esi_bus_controloeb10oeb15iib_bus_offoeb20iib_clear_hbiib_clear_tokeniib_set_hbiib_set_tokeniib_get_hbgohb_10iib_get_tokengotkn_10iib_1sec_timeriib_1sec_poriib_1sec_resetiib_1sec_exitiib_timer_srviib_tmr_resetiib_tmr_chk_tsiib1s_30iib1s_35iib1s_40iib1s_60iib1s_65tmr_srv_exitreset_otibown_esi_busiib_clr_flagiib_chk_flagchk_flag_exitchk_sp_cts_setchk_sp_cts_exitiib_enddownload_beginchk_mb_dltxtcmdt_05cmdt_10cmdt_15cmdt_20cmdt_25cmdt_35cmdt_36cmdt_26cmdt_30cmdt_40check_fpm_imagerlfpm_20rlfpm_30rlfpm_40reload_ib_fpm_ckreload_ib_fpmribf_endrbif_nextribf_exitgenr_checksumchk_mb_fpmdataread_mb_dltdcalc_dltd_cksumread_mb_fpmcalc_fpm_cksumstart_mbe_uploadstart_ibe_downloadcont_start_dlupload_mbepromdownload_ibepromdownload_2epromcmdl_progcmdl_prog_00fcmdl_prog_01fcmdl_prog_05fcmdl_prog_06fcmdl_p_05cmdl_p_10cmdl_prog_07fcmdl_prog_08fcmdl_prog_09ffcmdl_10fcmdl_15cmdl_15_regcmdl_16cmdl_endbankcmdl_eb_10cmdl_eb_20cmdl_eb_30cmdl_2fcmdl_4fcmdl_1fcmdl_5fcmdl_exit2get_fpm_datacmdl_checkbankcmdl_cb_10cmdl_dltextcmdl_dldatacmdl_hdrcmdl_hdr20cmdl_fpmincr_ep_errieer_10clr_ep_errcheck_ep_errceer_05eewrerr_ibset_fpm_startgo_disp_plzwaitgdpzw_10go_disp_plzwaitrgo_disp_pw_setupgo_disp_contgo_disp_pw_loopgdpw_exitstart_slow_blinkend_slow_blinkdownload_endfpm_beginfpm_keypad_pollfkp_1ffkp5fkp20fkp25fpm_new_keyfpm_getesi_pollfgep10fgep20fgep25fgep30fgep40fgep_retfpm_disp_pollfdp_1afdp_1ffdp10fdp_retfpm_initfinit_10finit_retfpm_state_initfsi_10fpm_hw_initfpm_system_setfpm_scrollfpm_hdot_scrfpm_ovlayfpm_display_offfpm_display_onfpm_display_flashrestore_dispfpm_csrwfpm_csrform_setfill_L2blankfpm_write_disp_L2copy_xram2vramfwdL2_loopfwdL2_testfwdL2_retfpm_write_disp_xramfwdx10fwdxretfpm_fill_disp_xramffdx10ffdxretfpm_fill_L2ffill5fpm_write_cmdfwc10fpm_write_parmfwp10fpm_readfpm_wait_for_d6fwf5fwf15fwf20fwfretfwfdisfpm_keypad_newd01_lshft_tabd1_lshft_tabfpm_icon_to_screenfpm_i2x_loopfi2x_4flshft_boff1fi2x_1ffi2x_looplshft_8_boff1lshft_boff2fi2x_loop_endlshft_8_boff2fi2x_2ffi2x_2bfi2x_do_endlshft_8_eofflshft_eofffi2x_3ffi2x_endfpm_text_to_screenftts_1bftts_1fftts_2fftts_loopftts_2bftts_row_fullftts_donefpm_ascii_to_iconfati_no_iconfpm_state_machinefsm_1ffsm_2ffsm_3ffpm_new_statefns_1ffns_2ffpm_exec_tasksfet_10fet_retfpm_text_displayftd_exitfpm_icon_displayfid_exitfpm_text_inputfti_30fti_40fpm_next_text_infnxt_retfpm_backsp_textfbst_retfpm_text_initftini_10fpm_text_clearftclr_10fpm_set_boxnamebsu_set_boxnamefruicon_dispfrid_20frid_30frid_40frid_100frid_retfpm_frid_nopresfpm_fi_rout_exdisp_list_indexdli_retfpm_set_esifse10fse_retbsu_setesifpm_ss_gafpm_exec_routinefpm_init_brightfpm_bright_ctrlfbrc_10bsu_setbrightfpm_choose_boxidfsbid_10bsu_set_boxidfpm_get_boxidfpm_init_boxidfpm_call_routinefcr_retfpm_copy_fwrevfcfr10fpm_wwn_2_asciifpm_copy_boxnamefcbn_10fpm_get_tempeftd_10ftd_retfdbug_fl_onfdbug_fl_offfdbug_L2solidfdbug_L2horzfpm_boxset_pollfbsu_10fbsu_20fbsu_60fbsu_100fbsu_retfpm_clear_bsufclb_10fclb_retfpm_request_bsufpm_cancel_bsufpm_grp_dispfgd_10fpm_init_loopcfpm_choose_loopcfclc_10fclc_20fpm_init_su1fpm_cond_new_statefcns_5fcns_10fcns_50fpm_set_timerfpm_flash_cursffc5ffc10fpm_get_bsu_msgfpm_clear_bsu_msgfpm_choose_scrsvfpm_init_scrsvbsu_set_scrsvfpm_idlefidl_10fidl_20fpm_upd_scrsvfms_10fms_retfpm_init_abfpm_choose_abfpm_set_abfpm_ab_dispfab10fpm_foff_buttonffb_retfpm_ib_requestsfib10fib15fib20fib25fibretfib_rst_finfpm_getallfga_10fga_12gethw_regsfpm_print_hex2bfph_retvar_icon_dispvid10vidretfpm_endfcp_targ_beginfcp_uattn_initinit_set_sidfcp_targcmd_new_entrycmd_xfr_donecmd_no_resetcmd_availablecmd_data_incmd_no_datacmd_data_outcmd_xfr_rdycmd_send_rspcmd_rsp_rdycmd_que_outcmd_poll_exitfcp_cmd_execmd_exe_uattncmd_exe_startexe_inqexe_senseexe_turexe_rcv_diagexe_send_diagexe_wr_bufexe_rd_bufcmd_exe_invalidcmd_exe_checkcmd_exe_errcmd_exe_msgcmd_exe_exitfcp_check_uattncheck_portcheck_port1check_uattn_exitfcp_check_uatblcheck_sidcheck_nxt_sidcheck_set_sidcheck_set_nxt_sidcheck_uatbl_exitfcp_inquiryinq_startinq_exitfcp_req_sensesense_startfcp_turfcp_rcv_diagrcv_clr_bufrcv_diag_pg00rcv_diag_pg01rcv_diag_pg02rcv_diag_pg04rcv_diag_pg07rcv_diag_okrcv_diag_errrcv_diag_exitfcp_get_pg00get_pg00_setget_pg00_errget_pg00_exitfcp_get_pg01get_pg01_lenget_pg01_hdrget_pg01_setget_pg01_grpget_pg01_txtget_pg01_errget_pg01_exitfcp_get_pg02get_pg02_nfrusget_pg02_lenget_pg02_hdrget_pg02_grp_stateget_pg02_fru_stateget_pg02_nxt_grpget_pg02_okget_pg02_errget_pg02_exitfcp_get_pg04get_pg04_okget_pg04_errget_pg04_exitfcp_get_pg07get_pg07_ngrpsget_pg07_nfrusget_pg07_lenget_pg07_hdrget_pg07_grp_dscrget_pg07_fru_dscrget_pg07_desc_strget_pg07_no_strget_pg07_empty_strget_pg07_nxt_fruget_pg07_okget_pg07_errget_pg07_exitfcp_send_diagsend_diag_pg04send_diag_errsend_diag_exitfcp_set_pg02set_pg02_grpset_pg02_stateset_pg02_nxtset_pg02_okset_pg02_errset_pg02_exitfcp_set_pg04set_pg04_wwnset_pg04_pswdset_pg04_bnameset_pg04_bidset_pg04_errset_pg04_okset_pg04_exitfcp_wr_bufwr_buf_codebuf_code_textcode_text_savecode_text_writebuf_code_datacode_data_savecode_data_writebuf_code_okbuf_code_errwr_buf_fpmbuf_fpm_datafpm_data_savefpm_data_writebuf_fpm_okbuf_fpm_errwr_buf_errwr_buf_donewr_buf_no_savewr_buf_okwr_buf_exitfcp_rd_bufrd_buf_exitfcp_get_htypefcp_get_hstateget_state_lgget_state_lpget_state_mbget_state_psstate_ps_onstate_ps_doneget_state_ftstate_ft_onstate_ft_offstate_ft_speedstate_ft_doneget_state_bpstate_bp_no_faultstate_bp_doneget_state_ibstate_ib_reportget_state_ddget_state_ddrget_state_ddfstate_ddstate_dd_no_faultstate_dd_doneget_state_flstate_fl_reportstate_flstate_fl_offget_state_tsget_state_tsfstate_tsget_state_errget_state_doneget_state_presentget_state_onget_state_no_faultget_state_okget_state_setget_grp_stateget_state_updateget_state_exitfcp_set_hstateset_state_bpstate_bp_bybstate_bp_setset_state_ddset_state_ddfstate_dd_offstate_dd_byastate_dd_bybstate_dd_setstate_dd_inset_state_doneset_state_exitfcp_set_hunit_statefcp_scopys_copyfcp_sct_srvsct_in_rangesct_retrysct_chk_startsct_chksumfcp_targ_endfcp_xface_beginfcp_xfacefcp_no_delayxface_exitxface_xfer_rdyxf_00xf_02xf_05xface_responsexr_00xface_sendfcp_xface_endfcp_beginfcp_initfcp_init_exitfcp_pollfcp_poll_startfcp_chk_rspfcp_chk_dlfcp_chk_resetfcp_poll_allfcp_poll_contfcp_poll_exitfcp_spinupspinup_fcp_enablespinup_fcp_disablespinup_ab_disablespinup_exitfcp_spindownspindown_ddf_searchspindown_ddr_searchfcp_enablefcp_disablefcp_cmd_porfcp_cmd_ibfcp_cmd_dlfcp_cmd_exitfcp_bypassbypass_ddf_searchbypass_ddf_startbypass_ddf_Bbypass_ddf_donebypass_ddf_offbypass_ddr_searchbypass_ddr_Bbypass_ddr_donebypass_ddr_offfcp_bp_typefcp_bp_type11fcp_spinup_ddspinup_dd_searchspinup_dd_onspinup_dd_startspinup_dd_Bspinup_dd_donespinup_dd_delayfcp_spinup_dd_exitfcp_1sec_timerfcp_spin_timerfcp_timer_exitfcp_bcopybc_loopbc_exitfcp_bzerobz_loopbz_exitfcp_endsoc_ucode_endsoc_endi_datai_data_beginstack_topstack_basetx_data_beginhash_tab_ptrshash_tab_ptrs_0hash_tab_ptrs_1hashtab_0_c2hashtab_0_c3hashtab_1_c2hashtab_1_c3tx_data_endserial_timeriib_timerfcp_timeresi_timerdiag_timerfpm_disp_timerfpm_keypad_timerfpm_getesi_timerfpm_boxset_timerport_assert_countb64_listb64_free_headb64_free_tailb64_availba_acc_payloaddiag_data_startdiag_controldiag_err_statusdiag_POST_randiag_statediag_callbackdiag_sr_cqesoc_dstatsoc_last_expsoc_last_rcvsocport0_dstatsocport1_dstatserdes0_dstatserdes1_dstatextoe0_dstatextoe1_dstatiblb0_dstatiblb1_dstatiblbbp0_dstatiblbbp1_dstatxram_dstatxram_addr_failxram_fail_cntxram_last_expxram_last_rcvbp_dstatfcal_dstatfeprom_dstatfeprom_ibfeprom_mbiib_dstattest_lbrestore_ol_eptrdf_xramdf_hcbdf_iibdiag_fhslb_frame_plslb_frame8slb_endslb_retry_cntslb_data_patternssoclb_glb_listserdes_glb_listextoe_glb_listiblb_glb_listiblbbp_glb_listglb_errdiag_msgs_startpost_start_msgpost_end_msgpost_xram_startpost_soc_startpost_soclb_startpost_serdes_startpost_iblbbp_donepost_hcb_startdp_post_na_msgpost_ol_msgpost_rstr_msgpost_rsdone_msgdiag_pass_msgdiag_fail_msgsoc_run_msgsoc_done_msghcb_run_msghcb_done_msgxram_run_msgxram_done_msgsoclb_run_msgsoclb_done_msgsoclb_los_msgsoclb_to_msgsoclb_ss_msgsoclb_rx_msgsoclb_cmp_msgsoclb_p0_msgsoclb_p1_msgsoclb_passserdes_run_msgserdes_done_msgextoe_run_msgextoe_done_msgiblb_run_msgiblb_done_msgiblbbp_run_msgiblbbp_done_msgsp_enddiag_msgph_post_startesi0_test_msgesi1_test_msgrun_iibtest_msgdone_iibtest_msgdiag_retryslb_msgattt_msgibbp_tm_msgibex_tm_msgtest_fix_msgno_test_fix_msgspt_pat_msgspt_fail_msgsp_test_text1sp_test_text2sp_test_text3sp_test_text4sp_test_text5sp_test_text6sp_test_text7sp_test_text8sp_test_text9sp_test_text10sp_test_text11sp_test_text12ib_state_msgonbrd_ctl_msglp_ctl_msgfan_ctl_msgled_ctl_msgps_ctl_msgrst_ctl_msgpbus_stat_msgonbrd_stat_msgfan_stat_msgps_stat_msgps2_stat_msgbp0_ddp_msgbp0_dds_msgbp1_ddp_msgbp1_dds_msgbp0_actl_msgbp0_bctl_msgbp0_lctl_msgbp0_astat_msgbp0_bstat_msgbp0_lstat_msgbp1_actl_msgbp1_bctl_msgbp1_lctl_msgbp1_astat_msgbp1_bstat_msgbp1_lstat_msgsp_temp_msghoerr_msgjournal_msgdo_error_msgst_stopdiagst_absst_boxstatest_echost_porst_diest_ledonst_ledoffst_rundiagst_dumphwst_timerst_byponst_bypoffst_muxchgst_offlinest_rsterrsst_sptestst_boxinfost_diagerrprompt0_msgrundiag1_msgrundiag2_msgrundiag3_msgdisp0_msgstopdiag_msgdiagbusy_msgdiagerr_msgdebug0debug1debug2debug3debug4debug5debug6debug7debug8debug9time_msg0time_msg1lassdraslm0lm1to_lip0oi_idle0to_tsm0off_w0to_lip1oi_idle1to_tsm1off_w1lto0lto1idle_w0idle_w1bang0bang1tmo0tmo1dreg_msgalu_fl_msgoptos_msgerra_msgstack_msgfwqptr_msghqptr_msghwrev_msgtcredit_msghcbdma_msgsberr_msgrxprams_msgrxprama_msgrxss_msgrxdmas_msgrxbptr_msgtfgstat_msgtdmatodo_msgalstate_msgcqtodo_msgrdmaqcnt_msgrxlip_msgrdmafwptr_msgrdmahwptr_msgrmdaiptr_msgrx0_msgrx1_msgdiag_msgs_enddiag_data_endvalid_alpasend_val_alpasfcp_idata_beginfcp_in_queuefcp_out_queueactive_fcp_xchgbusy_templategood_status_templatecheck_cond_templatexfer_rdy_templatefcp_rsp_dlyfcp_dl_cntfcp_chksumfcp_chksum_prevfcp_dl_exfcp_resetfcp_timer_cntfcp_bp0_statefcp_bp1_statefcp_readyfcp_enabledfcp_uattn_codefcp_grp_controlfcp_grp_statusfcp_esi_pagesfcp_hgrp_typesfcp_idata_endesi_idata_beginesi_lg0esi_lp0esi_lp1esi_mb0esi_ps0esi_ps1esi_ps2esi_ft0esi_ft1esi_bp0esi_bp1esi_ddf0esi_ddf1esi_ddf2esi_ddf3esi_ddf4esi_ddf5esi_ddf6esi_ddf7esi_ddf8esi_ddf9esi_ddf10esi_ddr0esi_ddr1esi_ddr2esi_ddr3esi_ddr4esi_ddr5esi_ddr6esi_ddr7esi_ddr8esi_ddr9esi_ddr10esi_ib0esi_ib1esi_oe0esi_oe1esi_oe2esi_oe3esi_tsf0esi_tsf1esi_tsf2esi_tsf3esi_tsf4esi_tsf5esi_tsf6esi_tsf7esi_tsf8esi_tsf9esi_tsf10esi_tsr0esi_tsr1esi_tsr2esi_tsr3esi_tsr4esi_tsr5esi_tsr6esi_tsr7esi_tsr8esi_tsr9esi_tsr10esi_lg_stesi_lp_stesi_mb_stesi_bp_stesi_ddf_stesi_ddr_stesi_ps_stesi_ft_stesi_ib_stesi_oe_stesi_tsf_stesi_tsr_stesi_rtblesi_tablesesi_peek_classesi_poke_classesi_oe_offsetsesi_ps_offsetsesi_ft_offsetsesi_ib_offsetsesi_bp_offsetsesi_nxt_offsetsesi_iib_offsetson_brd_shadowloopb_shadowfan_shadowled_shadowps_shadowreset_shadowesi_shadow_ptrsonbrd_statfan_statps_statps2_statloopb_controlesi_num_grpsesi_ps_prechargeesi_overtemp_clockesi_num_psesi_num_ddesi_timer_cntesi_grp_statesi_overtemp_statesi_post_statesi_mb_revesi_mbeprom_validesi_mbeprom_disabledesi_ts_cntesi_ts_numesi_blink_cntesi_blink_rateesi_exch_cntesi_exch_rateesi_par_changedesi_temperature_msgesi_shutdown_msgesi_peek_msgesi_peek1_msgesi_poke_msgesi_poke1_msgesi_idata_endsp_idata_beginst_printnst_introst_charrst_resetst_debugst_scopest_esiprobest_loadst_loadprepst_execst_unknownst_unknown2st_nullst_shutdownst_ft_warningst_ps_warningci_st1ci_st2dbg_bdmgse_conf4st_valse_pa2se_pa3se_datase_datardte_hdrte_st1te_st2te_st4te_st3st_h2st_helpst_h1se_ynse_offse_yledse_bypassse_psse_fanse_psfse_ddfse_ddfrse_ddse_pbypassse_bpse_ibse_oest_splitst_singlest_setboxidst_infost_boxidst_mbepromst_ibepromst_okst_failst_noiepromst_noeepromst_diseepromst_hdrcsfailst_hdrcsokst_setwwnst_wwnxst_wwnyst_setnamest_setnmgst_statusst_asdfst_periodst_asterickst_carrotst_plusst_equalst_ampersandst_dashst_poundst_exclpointst_dollarst_atsignst_tildast_questionst_commast_ceerr1st_ceerr2st_turnoffoibst_willnotresetst_gotnewst_mbdltxivst_mbdlmgcok2st_mbfpmtxivst_mbfpmmgcok2st_nomatchdatest_nomatchdate2st_fpmnomdatest_badmbdlcksst_badmbfpmcksst_toooldcodembst_mbfpmdldcmtchst_goldstdlst_ibmbfpmmtchst_ibmbdlmtchst_rdibfpmst_fpmdtsnomst_fpmibncsst_mbulst_ibdlcmd_tblcmd_execptrace_switchst_lo1st_lo2st_lo3st_lo4st_lo5st_lo6st_lo7st_lo8st_lo9st_lo10st_lo11st_loxdl_caseldr_caseasdfstasdfreasdfspasdfasdfsp_saveregsfpr_stat_listsp_idata_endiib_idata_beginiib_tblib_idimmasterother_ibts_xrestsmy_hb0my_hb1other_hb0other_hb1other_ib_insaneiib_bus_freeiib_reset_onceiib_srv_timeiib_ts_cntiib_ts_intiib_num_chkiib_max_chkiib_box_resetiib_ib_resetiib_reset_delayiib_sp_cts_polliib_sp_tx_creditboxinfo_changechng_via_otibdidisetboxidminusflagplusflagiib_ipkt_cntiib_opkt_cntiib_miss_pktiib_tmr_mpktiib_out_tbliib_in_tblinit_tableneed_fpm_initneed_mb_initiib_initializedesi_initializedfcp_initializedlast_initializedinit_retryinit_bitsiib_idata_endbox_info_beginxram_box_infobox_info_wwnorg_wwnbox_info_idlogical_idvendor_idprod_idprod_revbox_info_cfgbox_grp_cfgbox_info_logbox_failbox_info_setupdup_wwnpasswordbox_namebox_idloop_cfgiibp_versionfpm_brightfpm_scr_svab_ctlreservedbox_info_descddf_descddr_descps_descft_descib_descoe_descbp_desctsf_desctsr_descmb_desclp_desclg_descrev_descmod_descbox_info_hdrhdr_statehdr_gen_codehdr_languagehdr_uattn_codembehdrcksummbemagicmbedatestrmbefwdate_codembehwrevisionbox_info_endload_idata_beginul_bytecountul_curraddrul_bankswul_curswul_numerrorsul_lastsecdl_bytecountdl_curraddrdl_bankswdl_curswdl_numerrorsdl_lastsecmb_dl_magicmb_fpm_magicmb_dl_datecodemb_fpm_datecodeib_dl_magicib_fpm_magicib_dl_datecodeib_fpm_datecodemb_valid_copyib_valid_copydltd_cksum_resfpm_cksum_resfloop_cntrdatecode16datecode18piib_dl_flagsdoing_dldo_not_resetreset_on_donedo_mb_cksummbim_too_oldsave_a4load_idata_endab_idata_beginab_timer_cntab_loopab_loop0ab_loop1ab_loop_state_tableab_ibab_lpab_bp0ab_bp1ab_oe0ab_oe1ab_ddfab_ddrab_num_ddfab_num_ddrabab_initializedab_enabledab_idata_endfpm_i_data_beginfpm_i_datafpm_buff_image_L2fpm_buff_image_L3fpm_temp_d0fpm_temp_d1fpm_temp_d2fpm_temp_d4fpmfpm_disp_parmfpm_disp_controlfpm_creditsfpm_bright_idxfpm_bright_tablefpm_ib0_fwrevdsfpm_ib1_fwrevdsst_rdfcst_rdfdst_wrcst_wrpst_wrdst_fpstopst_fpstartst_fpmresetst_fpminitfpm_rout_tabfpm_rout_tab_endbsu_offset_svfpm_start_bsubsu_boxnamebsu_autobypbsu_fruesibsu_brightbsu_scrsvbsu_splitbsu_singlebsu_boxidfpm_end_bsufpm_bsu_msg_tabfpm_key_tablepswd_bufferpswd_cntstate_idatais_message_lbicon_message_lbfpm_i_data_endstop_fpmpost_controlpost_loadi_data_endu_data_beginu_datanport_0_paramsnport_1_paramsbuf_pool_listreq_listlast_stack_ptrremote_cosplocal_cospsw_halthalt_on_fc_errdeath_aregsdeath_hwregsdeath_rprams0death_rprams1death_hcbdeath_hcb0death_hcb1death_hcb2death_hcb3death_stackdiag_buff0diag_buff1diag_buff2diag_buff3diag_buf_enda7_savediag_tmpibmux_savebpbyp_saveslb_tfqslb_rxbufslb_cur_rxfslb_err_saveslb_to_cntslb_rx_wrapabs_countslb_optspt_pat_ptrspt_statusdiag_tx_bufffpm_u_data_beginfpm_u_dataL2_imagefpm_update_ctrfpm_timerfpm_boxid_buffpm_loopc_buffpm_temp_buffpm_curs_nextfpm_buff_abfpm_Xrowfpm_Xcolfd_opstat_a0fd_alstat_a0fd_spsig_a0fd_opstat_a1fd_alstat_a1fd_spsig_a1fd_opstat_b0fd_alstat_b0fd_spsig_b0fd_opstat_b1fd_alstat_b1fd_spsig_b1fpm_iib_Actlfpm_iib_Bctlfpm_iib_finfpm_u_data_endfcp_udata_beginels_buffcp_cmdfcp_rspfcp_buffcp_uattn_tblfcp_udata_endsp_udata_beginspaspbsp_aceprtbufchar2putchar2getsp_char2getsp_char4getsp_scp_onsp_scp_pa2sp_scp_pa3sp_scp_datasp_scp_1shotse_datainrtest_onrtest_pa2rtest_pa3sp_statregsaver_psrr_pcr_npcr_tbrr_wimr_yr_glob1r_glob2r_glob3r_glob4r_glob5r_glob6r_glob7rwindowmagictg_storittg_cnttg_c1tg_c2tp_storittp_cnttgi_valtgi_dattpi_valtpi_datti_addrti_dataerrnodorunload_udata_beginload_statebcmd_ixchar_cntbcntbufnibble_cntescapenibspotxbcnthload_udata_endbcntxsp_udata_endsp_esi_pssp_esi_fansp_esi_bpsp_esi_ddsp_esi_ibsp_esi_oemeprom_save1meprom_save2meprom_save3meprom_save4meprom_save5eetest_dataesi_send_bufesi_rcv_bufiib_udata_beginiib_ipktiib_opktiib_fpm_ipktiib_fpm_opktupload_bufiib_udata_endu_data_endb64_poolb64_pool_endXCHG_poolXCHG_pool_enddload_bufmbebox_infoeprom_box_infombebox_info_wwnmbeorg_wwnmbebox_info_idmbelogical_idmbevendor_idmbeprod_idmbeprod_revmbebox_info_cfgmbebox_grp_cfgmbebox_info_logmbebox_failmbebox_info_setupmbedup_wwnmbepasswordmbebox_namembebox_idmbeloop_cfgmbeiibp_versionmbefpm_brightmbefpm_scr_svmbeab_ctlmbereservedmbebox_info_descmbeddf_descmbeddr_descmbeps_descmbeft_descmbeib_descmbeoe_descmbebp_descmbetsf_descmbetsr_descmbemb_descmbelp_descmbelg_descmberev_descmbemod_descmbebox_info_hdrmbehdr_statembehdr_gen_codembehdr_languagembehdr_uattn_codembembehdrcksummbembemagicmbembedatestrmbembefwdate_codembembehwrevisionfpm_datafpm_validfpm_magicfpm_cksumfpm_datecodefpm_datestrfpm_start_statekp_cg_1kp_cg_2kp_cg_3kp_cg_4kp_cg_5kp_cg_6kp_cg_7kp_cg_8kp_cg_9kp_cg_0kp_hex_1kp_hex_2kp_hex_3kp_hex_4kp_hex_5kp_hex_6kp_hex_7kp_hex_8kp_hex_9kp_hex_0kp_in_bfrkp_in_llkp_in_offkp_ch_offlast_char_grpkp_ll_ptrfpm_alert_statefpm_menu_statefpm_setup1_statefpm_plswaitfpm_plswait_statefpm_sysview_statefpm_scrsave_statefpm_testm_statefpm_foffst_statefpm_reservedfpm_screens_beginstate_0state_1state_2state_alertstate_ab_dispstate_bp_l2state_bp_0_l3state_bp_1_l3state_byps_bp_0state_byps_bp_1state_byps_frdd_0state_byps_frdd_1state_byps_frdd_2state_byps_frdd_3state_byps_frdd_4state_byps_frdd_5state_byps_frdd_6state_byps_frdd_7state_byps_frdd_8state_byps_frdd_9state_byps_frdd_10state_byps_rrdd_0state_byps_rrdd_1state_byps_rrdd_2state_byps_rrdd_3state_byps_rrdd_4state_byps_rrdd_5state_byps_rrdd_6state_byps_rrdd_7state_byps_rrdd_8state_byps_rrdd_9state_byps_rrdd_10state_force_offlstate_for_off_statstate_ft_l2state_ft_0_l3state_ft_1_l3state_fr_dd_l2state_fr_dd_0_l3state_fr_dd_1_l3state_fr_dd_2_l3state_fr_dd_3_l3state_fr_dd_4_l3state_fr_dd_5_l3state_fr_dd_6_l3state_fr_dd_7_l3state_fr_dd_8_l3state_fr_dd_9_l3state_fr_dd_10_l3state_help_1state_help_2state_help_3state_help_name_2state_help_name_3state_help_name_4state_help_tfoff_p1state_help_tauby_p1state_help_tauby_p2state_help_test_p1state_help_test_p2state_help_test_p3state_hexinstate_ib_l2state_ib_0_l3state_ib_1_l3state_mb_l2state_menustate_oe_l2state_oe_a0_l3state_oe_a1_l3state_oe_b0_l3state_oe_b1_l3state_pls_waitstate_ps_l2state_ps_0_l3state_ps_1_l3state_ps_2_l3state_rr_dd_l2state_rr_dd_0_l3state_rr_dd_1_l3state_rr_dd_2_l3state_rr_dd_3_l3state_rr_dd_4_l3state_rr_dd_5_l3state_rr_dd_6_l3state_rr_dd_7_l3state_rr_dd_8_l3state_rr_dd_9_l3state_rr_dd_10_l3state_scrsavestate_setup_1state_setup_2state_sunstate_sysdebugstate_sysloopstate_sysviewstate_test_mainstate_test_1state_test_2state_test_9state_textinfpm_screens_endfpm_ascii_tab_beginfpm_ascii_tabfpm_ascii_tab_endfpm_iconst_h_1p_p1ts_h_1p_p1t_h_2p_p1t_h_2p_p2ts_h_2p_p1ts_h_2p_p2t_h_3p_p1t_h_3p_p2t_h_3p_p3ts_h_3p_p1ts_h_3p_p2ts_h_3p_p3t_h_tdisp_labt_h_tdisp_1l1t_h_tdisp_1l2t_h_tdisp_1l4t_h_tdisp_1l5t_h_tdisp_1l6t_h_tdisp_2l1t_h_tdisp_2l2t_h_tdisp_2l3t_h_tdisp_2l4t_h_tdisp_2l5t_h_tdisp_2l6t_h_tdisp_2l7t_h_tdisp_3l1t_h_tdisp_3l2t_h_tdisp_3l3ts_h_tdisp_labts_h_tdisp_1l1ts_h_tdisp_1l2ts_h_tdisp_1l4ts_h_tdisp_1l5ts_h_tdisp_1l6ts_h_tdisp_2l1ts_h_tdisp_2l2ts_h_tdisp_2l3ts_h_tdisp_2l4ts_h_tdisp_2l5ts_h_tdisp_2l6ts_h_tdisp_2l7ts_h_tdisp_3l1ts_h_tdisp_3l2ts_h_tdisp_3l3t_h_tfoff_labt_h_tfoff_1l1t_h_tfoff_1l2t_h_tfoff_1l3t_h_tfoff_1l4t_h_tfoff_1l5t_h_tfoff_1l6ts_h_tfoff_labts_h_tfoff_1l1ts_h_tfoff_1l2ts_h_tfoff_1l3ts_h_tfoff_1l4ts_h_tfoff_1l5ts_h_tfoff_1l6t_h_tauby_labt_h_tauby_1l1t_h_tauby_1l2t_h_tauby_1l3t_h_tauby_1l4t_h_tauby_1l5t_h_tauby_1l6t_h_tauby_2l1t_h_tauby_2l2t_h_tauby_2l3t_h_tauby_2l4ts_h_tauby_labts_h_tauby_1l1ts_h_tauby_1l2ts_h_tauby_1l3ts_h_tauby_1l4ts_h_tauby_1l5ts_h_tauby_1l6ts_h_tauby_2l1ts_h_tauby_2l2ts_h_tauby_2l3ts_h_tauby_2l4t_test_displayt_test_debugts_test_dispts_test_dbugt_fofflt_offliningt_offl_donet_offl_notdonets_foffl_lbts_foff_exects_foff_donet_sochw_labt_port0t_port1t_opstatt_alstatt_specsigis_ibAis_ibBts_sochw_labts_port0_lbts_port1_lbts_opstat_lb0ts_alstat_lb0ts_spsig_lb0ts_opstat_lb1ts_alstat_lb1ts_spsig_lb1t_str_bufferts_opstat_a0ts_alstat_a0ts_spsig_a0ts_opstat_a1ts_alstat_a1ts_spsig_a1ts_opstat_b0ts_alstat_b0ts_spsig_b0ts_opstat_b1ts_alstat_b1ts_spsig_b1ts_erra_b1fi_opstat_a0fi_alstat_a0fi_spsig_a0fi_opstat_a1fi_alstat_a1fi_spsig_a1fi_opstat_b0fi_alstat_b0fi_spsig_b0fi_opstat_b1fi_alstat_b1fi_spsig_b1fpm_disabled_msgt_autobypasst_ab_enablet_ab_disablets_ab_titlets_ab_controlis_ab_btis_sunlogois_setup_0is_frdrive_1is_rrdrive_2is_power_3is_fan_4is_bkplane_5is_ib_6is_opt_7is_mb_8is_warn_10is_test_15is_help_16is_tog_17ts_bname_menu_0ts_bname_menu_1ts_wwn_cen_1ts_wwn_cen_2is_return_15is_return_17is_kpadin_9is_kpad0_13is_tabf_14is_tabb_12is_clrbut_17is_frd_lblis_rrd_lblis_frd_i2is_rrd_i2is_disk_0b_3is_disk_1b_4is_disk_2b_5is_disk_3b_6is_disk_4b_7is_disk_5b_8is_disk_6b_9is_disk_7b_10is_disk_8b_11is_disk_9b_12is_disk_10b_13is_disk_11b_14is_back_15is_left_16ts_byp_bp_stris_byp_bp_a_lbis_byp_bp_b_lbis_fru_0_bpbypis_fru_1_bpbypis_byp_dd_a_lbis_byp_dd_b_lbis_fru_0_bypis_fru_1_bypis_fru_2_bypis_fru_3_bypis_fru_4_bypis_fru_5_bypis_fru_6_bypis_fru_7_bypis_fru_8_bypis_fru_9_bypis_fru_10_1bypis_fru_10_0bypts_byp_dd_strt_byp_msgis_temp_lb_l3t_fail_msgt_C_msgis_help_lblis_help_lbl_2is_fan_help_3is_bp_help_6is_if_help_9is_oe_help_12is_help_ft_lbis_help_bp_lbis_help_ib_lbis_help_oe_lbis_help_su_lbis_help_fr_dd_lbis_help_rr_dd_lbis_help_ps_lbis_help_mb_lbt_h_su_nam_1l1t_h_su_nam_1l2t_h_su_nam_1l3t_h_su_nam_1l4t_h_su_nam_1l5t_h_su_nam_1l6t_h_su_nam_2l1t_h_su_nam_2l2t_h_su_nam_2l3t_h_su_nam_2l4t_h_su_nam_2l5t_h_su_nam_2l6t_h_su_nam_3l1t_h_su_nam_3l2t_h_su_nam_3l3t_h_su_nam_3l4t_h_su_nam_3l5t_h_su_nam_3l6t_h_su_nam_4l1t_h_su_nam_4l2t_h_su_nam_4l3t_h_su_nam_4l4t_h_su_nam_4l6ts_h_su_nam_1l1ts_h_su_nam_1l2ts_h_su_nam_1l3ts_h_su_nam_1l4ts_h_su_nam_1l5ts_h_su_nam_1l6ts_h_su_nam_2l1ts_h_su_nam_2l2ts_h_su_nam_2l3ts_h_su_nam_2l4ts_h_su_nam_2l5ts_h_su_nam_2l6ts_h_su_nam_3l1ts_h_su_nam_3l2ts_h_su_nam_3l3ts_h_su_nam_3l4ts_h_su_nam_3l5ts_h_su_nam_3l6ts_h_su_nam_4l1ts_h_su_nam_4l2ts_h_su_nam_4l3ts_h_su_nam_4l4ts_h_su_nam_4l6is_h_su_lbis_right_17is_setup_help_3is_frd_help_6is_rrd_help_9is_pwr_help_12is_a0_node_lbis_a1_node_lbis_b0_node_lbis_b1_node_lbis_a0_node1_lbis_a1_node1_lbis_b0_node1_lbis_b1_node1_lbts_nodes_a0ts_nodes_a1ts_nodes_b0ts_nodes_b1is_prompt_0is_prompt_1is_prompt_2is_prompt_3is_prompt_4is_prompt_5is_prompt_6is_prompt_7is_prompt_8is_prompt_9is_prompt_10is_prompt_11is_prompt_12is_prompt_13is_prompt_14is_prompt_15ts_disp_txt_0ts_disp_txt_1ts_disp_txt_2ts_disp_txt_3ts_disp_txt_4ts_disp_txt_5ts_disp_txt_6ts_disp_txt_7ts_disp_txt_8ts_disp_txt_9ts_disp_txt_10ts_disp_txt_11ts_disp_txt_12ts_disp_txt_13ts_disp_txt_14ts_disp_txt_15is_mb_help_3is_dr_num_0is_dr_num_1is_sys_rulets_bname_sys_1ts_bname_sys_0is_mb_lbl_0is_mb_2is_mb_idis_mb_eepromis_mb_statusis_oe_lbl_0is_oe_2is_oe_a1lb_7is_oe_a0lb_8is_oe_b1lb_13is_oe_b0lb_14is_oe_3is_oe_a0_idis_oe_a1_idis_oe_b0_idis_oe_b1_idis_test_13is_ps_lblis_ps_i2is_ps_i3is_ft_lblis_ft_i2is_ft_i3is_ib_lblis_ib_i2is_ib_lblt_l2is_ib_lblb_l2ts_ib_0_fw2ts_ib_1_fw2is_ib_i3is_bp_lblis_bp_i2is_bp_i3is_setup_lblis_su1_i2is_su2_i2is_namelb_3is_brite_3is_roll_5is_wwn_6is_loop_6is_nodelb_9is_nodes_11is_boxid_9is_boxid_11is_test_14is_fldemo_12is_alip_12is_fwd_16is_lp_choose_8is_demo_on_13is_ss_choose_14is_wwn_lbis_ss_lbis_alert_titleis_alert_symis_alert_cancts_alert_msg0ts_alert_msg1ts_alert_msg2ts_alert_msg3t_alert_msgbsu_boxid_msgbsu_boxname_msgbsu_loopc_msgbsu_reset_ib0bsu_reset_ib1bsu_spinoff_ddbsu_spinup_ddbsu_fanoff_0bsu_fanon_0bsu_fanoff_1bsu_fanon_1bsu_oe_offbsu_oe_onbsu_bp0_offbsu_bp0_onbsu_bp1_offbsu_bp1_onbsu_dd_byp_absu_dd_byp_bbsu_dd_on_absu_dd_on_bbsu_bright_msgbsu_mb_offbsu_mb_onbsu_bp_byp_absu_bp_byp_bbsu_bp_on_absu_bp_on_bbsu_scrsv_offbsu_scrsv_onbsu_ab_offbsu_ab_onis_fru_rule_l2is_frt_lb_l2is_rear_lb_l2is_0_lb_l2is_1_lb_l2is_ps2_lb_l2is_menu_rule_l2is_home_17is_l3_cardis_l3_tabis_l3_tdownis_l3_tarwis_fru_0_l3is_fru_1_l3is_fru_2_l3is_fru_3_l3is_fru_4_l3is_fru_5_l3is_fru_6_l3is_fru_7_l3is_fru_8_l3is_fru_9_l3is_fru_10_1l3is_fru_10_0l3is_fru_a_l3is_fru_b_l3is_pls_waitt_pswd_bfrt_bfr_10ts_prompt4ts_prompt_1ts_prompt_2ts_disp_bfr_1ts_disp_bfr_2icon_cursoricon_dblcuricon_spicon_bangicon_dquoteicon_poundicon_dollaricon_percenticon_ampersandicon_tickicon_lparenicon_rparenicon_splaticon_plusicon_commaicon_slashicon_colonicon_scolonicon_lessicon_equalicon_greatericon_questionicon_aticon_lbracketicon_bslashicon_rbracketicon_uparrowicon_underbaricon__icon_btickicon_lcurlyicon_moreicon_rcurlyicon_tildeicon_0ficon_1ficon_2ficon_3ficon_4ficon_5ficon_6ficon_7ficon_8ficon_9ficon_Aicon_asicon_Bicon_bsicon_Cicon_csicon_Dicon_dashicon_dsicon_Eicon_esicon_Ficon_fsicon_Gicon_gsicon_Hicon_hsicon_Iicon_isicon_Jicon_jsicon_Kicon_ksicon_Licon_lbficon_lsicon_Micon_msicon_Nicon_nsicon_Oicon_osicon_Picon_periodicon_psicon_Qicon_qsicon_Ricon_rsicon_Sicon_ssicon_Ticon_tsicon_Uicon_underscoreicon_usicon_Vicon_vsicon_Wicon_wsicon_Xicon_xsicon_Yicon_ysicon_Zicon_zsicon_0_bticon_0_iicon_10_bticon_11_bticon_1_bicon_1_iicon_2_bicon_2_iicon_3_bicon_3_iicon_4_bicon_4_iicon_5_bicon_5_iicon_6_bicon_6_iicon_7_bicon_7_bticon_8_bticon_9_bticon_9_iicon_Alert_lbicon_alert_1icon_alert_2icon_auto_lbicon_a_lbicon_back_bticon_badimage_lbicon_bk_plane_lbicon_boxid_bticon_boxid_lbicon_Bplne_bticon_Bplne_bt_inicon_bp_iicon_bright_lbicon_button_bticon_bypass_bticon_bytesync_lbicon_b_lbicon_cancel_bticon_clear_bticon_connect_bticon_continue_bticon_ddview_ruleicon_dd_offline_lbicon_dd_online_lbicon_dk_failedicon_dk_npresicon_dk_nreadyicon_dk_presenticon_dr_numbersicon_Dwntabicon_fans_lbicon_Fan_off_bticon_fdr_bt_inicon_forward_bticon_frdd_bticon_frdd_iicon_front_lbicon_fr_drives_lbicon_ft_bticon_ft_bt_inicon_ft_iicon_help_bicon_Help_iicon_help_lbicon_home_bticon_ib_bt_inicon_ib_lbicon_if_board_bicon_InterfaceB_iicon_l1_a_conicon_l1_b1_conicon_l1_bpa_licon_l1_dd_conicon_l2_bp_off_bticon_l2_ft_status_lbicon_l2_oe_bt_inicon_l2_oe_off_bticon_L3_bp_status_lbicon_l3_cardicon_L3_dd_status_lbicon_l3_fru_np_lbicon_l3_ib_status_lbicon_l3_mb_status_lbicon_l3_oe_failed_lbicon_l3_oe_nosig_lbicon_l3_oe_ok_lbicon_l3_oe_sig_lbicon_l3_oe_status_lbicon_l3_overtemp_lbicon_L3_pw_status_lbicon_l3_tabicon_loop_bticon_loop_iicon_loop_lbicon_m_board_bicon_mb_bt_inicon_mb_iicon_menu_ruleicon_motherbrd_lbicon_name_0_bticon_name_bticon_name_keypadicon_nodes_lbicon_node_bticon_oe_a0icon_oe_a0_officon_oe_a1icon_oe_a1_officon_oe_amp_lbicon_oe_b0icon_oe_b1icon_oe_db9_lbicon_oe_lbicon_oe_lw1_lbicon_oe_lw2_lbicon_oe_sw1_lbicon_oe_sw2_lbicon_off_bticon_off_lbicon_ok_status_iicon_on_bticon_online_lbicon_on_gry_bticon_on_lbicon_op_module_bicon_op_mod_iicon_Power_iicon_power_lbicon_ps_bticon_ps_f_bticon_ps_off_bticon_rdd_bt_inicon_rear_lbicon_reset_bticon_return_bticon_rev00icon_rev01icon_rev02icon_rev03icon_rev04icon_rev05icon_rev06icon_rev07icon_rrdd_bticon_rrdd_iicon_rr_drives_lbicon_ruleicon_save_bticon_setup_bicon_setup_lbicon_split_bticon_ss_lbicon_su1_lbicon_su2_lbicon_sunlogoicon_sup_help_lbicon_su_0icon_su_1icon_su_2icon_su_3icon_s_loop_iicon_tabback_bticon_tabforward_bticon_temp_iicon_test_bticon_tog_diskview_bicon_txfault_lbicon_up_bticon_waiticon_warning_sm_iicon_wwn_bticon_wwn_lbfpm_fruicons_beginfpm_fru_iconsfpm_ib0fwrevstrfpm_ib1fwrevstrfpm_wwn_asciifpm_boxnamefpm_tsf_0_afpm_tsf_1_afpm_tsf_2_afpm_tsf_3_afpm_tsf_4_afpm_tsf_5_afpm_tsf_6_afpm_tsf_7_afpm_tsf_8_afpm_tsf_9_afpm_tsf_10_afpm_tsr_0_afpm_tsr_1_afpm_tsr_2_afpm_tsr_3_afpm_tsr_4_afpm_tsr_5_afpm_tsr_6_afpm_tsr_7_afpm_tsr_8_afpm_tsr_9_afpm_tsr_10_afpm_tsbp_0fpm_tsbp_1fpm_nodes_a0fpm_nodes_a1fpm_nodes_b0fpm_nodes_b1fpm_11d_beginis_strip_11_0is_strip_11_1vi_is_drtemp_0vi_is_drtemp_1vi_fr_dd_6_nextvi_ddf_0_sysfi_ddf_0_11sysvi_ddf_0_blink_sysfi_ddf_0_bl_11sysvi_dfc_0a_sysfi_dfc_0a_11sysvi_dfc_0b_sysfi_dfc_0b_11sysvi_ddf_1_sysfi_ddf_1_11sysvi_ddf_1_blink_sysfi_ddf_1_bl_11sysvi_dfc_1a_sysfi_dfc_1a_11sysvi_dfc_1b_sysfi_dfc_1b_11sysvi_ddf_2_sysfi_ddf_2_11sysvi_ddf_2_blink_sysfi_ddf_2_bl_11sysvi_dfc_2a_sysfi_dfc_2a_11sysvi_dfc_2b_sysfi_dfc_2b_11sysvi_ddf_3_sysfi_ddf_3_11sysvi_ddf_3_blink_sysfi_ddf_3_bl_11sysvi_dfc_3a_sysfi_dfc_3a_11sysvi_dfc_3b_sysfi_dfc_3b_11sysvi_ddf_4_sysfi_ddf_4_11sysvi_ddf_4_blink_sysfi_ddf_4_bl_11sysvi_dfc_4a_sysfi_dfc_4a_11sysvi_dfc_4b_sysfi_dfc_4b_11sysvi_ddf_5_sysfi_ddf_5_11sysvi_ddf_5_blink_sysfi_ddf_5_bl_11sysvi_dfc_5a_sysfi_dfc_5a_11sysvi_dfc_5b_sysfi_dfc_5b_11sysvi_ddf_6_sysfi_ddf_6_11sysvi_ddf_6_blink_sysfi_ddf_6_bl_11sysvi_dfc_6a_sysfi_dfc_6a_11sysvi_dfc_6b_sysfi_dfc_6b_11sysvi_ddf_7_sysvi_ddf_7_blink_sysfi_ddf_7_blink_sysvi_dfc_7a_sysfi_dfc_7a_sysvi_dfc_7b_sysfi_dfc_7b_sysvi_ddf_8_sysvi_ddf_8_blink_sysfi_ddf_8_blink_sysvi_dfc_8a_sysfi_dfc_8a_sysvi_dfc_8b_sysfi_dfc_8b_sysvi_ddf_9_sysvi_ddf_9_blink_sysfi_ddf_9_blink_sysvi_dfc_9a_sysfi_dfc_9a_sysvi_dfc_9b_sysfi_dfc_9b_sysvi_ddf_10_sysvi_ddf_10_blink_sysfi_ddf_10_blink_sysvi_dfc_10a_sysfi_dfc_10a_sysvi_dfc_10b_sysfi_dfc_10b_sysvi_disk_7bvi_disk_8bvi_disk_9bvi_disk_10bvi_ddf_7_l2vi_ddf_7_blink_l2fi_ddf_7_l2vi_ddf_8_l2vi_ddf_8_blink_l2fi_ddf_8_l2vi_ddf_9_l2vi_ddf_9_blink_l2fi_ddf_9_l2vi_ddf_10_l2vi_ddf_10_blink_l2fi_ddf_10_l2vi_ddr_7_l2vi_ddr_7_blink_l2fi_ddr_7_l2vi_ddr_8_l2vi_ddr_8_blink_l2fi_ddr_8_l2vi_ddr_9_l2vi_ddr_9_blink_l2fi_ddr_9_l2vi_ddr_10_l2vi_ddr_10_blink_l2fi_ddr_10_l2vi_state_frdd_7_l3vi_state_frdd_8_l3vi_state_frdd_9_l3vi_state_frdd_10_l3vi_state_rrdd_7_l3vi_state_rrdd_8_l3vi_state_rrdd_9_l3vi_state_rrdd_10_l3fi_ddf_7_l3fi_ddf_8_l3fi_ddf_9_l3fi_ddf_10_l3fi_ddf_7_on_l3fi_ddf_8_on_l3fi_ddf_9_on_l3fi_ddf_10_on_l3fi_ddf_7_on_bt_l3fi_ddf_8_on_bt_l3fi_ddf_9_on_bt_l3fi_ddf_10_on_bt_l3fi_ddr_7_l3fi_ddr_8_l3fi_ddr_9_l3fi_ddr_10_l3fi_ddr_7_on_bt_l3fi_ddr_8_on_bt_l3fi_ddr_9_on_bt_l3fi_ddr_10_on_bt_l3fi_ddr_7_on_l3fi_ddr_8_on_l3fi_ddr_9_on_l3fi_ddr_10_on_l3fi_ddf_7_sysfi_ddf_7_pre_l3fi_ddf_7_okf_l3fi_ddf_7_rbea_l3fi_ddf_7_rbeb_l3fi_ddf_8_sysfi_ddf_8_pre_l3fi_ddf_8_okf_l3fi_ddf_8_rbea_l3fi_ddf_8_rbeb_l3fi_ddf_9_sysfi_ddf_9_pre_l3fi_ddf_9_okf_l3fi_ddf_9_rbea_l3fi_ddf_9_rbeb_l3fi_ddf_10_sysfi_ddf_10_pre_l3fi_ddf_10_okf_l3fi_ddf_10_rbea_l3fi_ddf_10_rbeb_l3fi_ddr_7_sysfi_ddr_7_pre_l3fi_ddr_7_okf_l3fi_ddr_7_rbea_l3fi_ddr_7_rbeb_l3fi_ddr_8_sysfi_ddr_8_pre_l3fi_ddr_8_okf_l3fi_ddr_8_rbea_l3fi_ddr_8_rbeb_l3fi_ddr_9_sysfi_ddr_9_pre_l3fi_ddr_9_okf_l3fi_ddr_9_rbea_l3fi_ddr_9_rbeb_l3fi_ddr_10_sysfi_ddr_10_pre_l3fi_ddr_10_okf_l3fi_ddr_10_rbea_l3fi_ddr_10_rbeb_l3fi_ddf_7_fle_l3fi_ddf_7_blink_l2fi_ddf_7_blink_l3fi_ddf_8_fle_l3fi_ddf_8_blink_l2fi_ddf_8_blink_l3fi_ddf_9_fle_l3fi_ddf_9_blink_l2fi_ddf_9_blink_l3fi_ddf_10_fle_l3fi_ddf_10_blink_l2fi_ddf_10_blink_l3fi_ddr_7_fle_l3fi_ddr_7_blink_l2fi_ddr_7_blink_l3fi_ddr_8_fle_l3fi_ddr_8_blink_l2fi_ddr_8_blink_l3fi_ddr_9_fle_l3fi_ddr_9_blink_l2fi_ddr_9_blink_l3fi_ddr_10_fle_l3fi_ddr_10_blink_l2fi_ddr_10_blink_l3ts_tsf_10_l3fi_tsf_10_l3ts_tsr_10_l3fi_tsr_10_l3vi_rr_dd_6_nextvi_ddr_0_sysfi_ddr_0_11sysvi_ddr_0_blink_sysfi_ddr_0_bl_11sysvi_drc_0a_sysfi_drc_0a_11sysvi_drc_0b_sysfi_drc_0b_11sysvi_ddr_1_sysfi_ddr_1_11sysvi_ddr_1_blink_sysfi_ddr_1_bl_11sysvi_drc_1a_sysfi_drc_1a_11sysvi_drc_1b_sysfi_drc_1b_11sysvi_ddr_2_sysfi_ddr_2_11sysvi_ddr_2_blink_sysfi_ddr_2_bl_11sysvi_drc_2a_sysfi_drc_2a_11sysvi_drc_2b_sysfi_drc_2b_11sysvi_ddr_3_sysfi_ddr_3_11sysvi_ddr_3_blink_sysfi_ddr_3_bl_11sysvi_drc_3a_sysfi_drc_3a_11sysvi_drc_3b_sysfi_drc_3b_11sysvi_ddr_4_sysfi_ddr_4_11sysvi_ddr_4_blink_sysfi_ddr_4_bl_11sysvi_drc_4a_sysfi_drc_4a_11sysvi_drc_4b_sysfi_drc_4b_11sysvi_ddr_5_sysfi_ddr_5_11sysvi_ddr_5_blink_sysfi_ddr_5_bl_11sysvi_drc_5a_sysfi_drc_5a_11sysvi_drc_5b_sysfi_drc_5b_11sysvi_ddr_6_sysfi_ddr_6_11sysvi_ddr_6_blink_sysfi_ddr_6_bl_11sysvi_drc_6a_sysfi_drc_6a_11sysvi_drc_6b_sysfi_drc_6b_11sysvi_ddr_7_sysvi_ddr_7_blink_sysfi_ddr_7_blink_sysvi_drc_7a_sysfi_drc_7a_sysvi_drc_7b_sysfi_drc_7b_sysvi_ddr_8_sysvi_ddr_8_blink_sysfi_ddr_8_blink_sysvi_drc_8a_sysfi_drc_8a_sysvi_drc_8b_sysfi_drc_8b_sysvi_ddr_9_sysvi_ddr_9_blink_sysfi_ddr_9_blink_sysvi_drc_9a_sysfi_drc_9a_sysvi_drc_9b_sysfi_drc_9b_sysvi_ddr_10_sysvi_ddr_10_blink_sysfi_ddr_10_blink_sysvi_drc_10a_sysfi_drc_10a_sysvi_drc_10b_sysfi_drc_10b_sysfi_ddf_7_bypfi_dfc_7a_bypfi_dfc_7b_bypfi_byps_dfc_7a_btfi_byps_dfc_7b_btfi_ddf_8_bypfi_dfc_8a_bypfi_dfc_8b_bypfi_byps_dfc_8a_btfi_byps_dfc_8b_btfi_ddf_9_bypfi_dfc_9a_bypfi_dfc_9b_bypfi_byps_dfc_9a_btfi_byps_dfc_9b_btfi_ddf_10_bypfi_dfc_10a_bypfi_dfc_10b_bypfi_byps_dfc_10a_btfi_byps_dfc_10b_btfi_ddr_7_bypfi_drc_7a_bypfi_drc_7b_bypfi_byps_drc_7a_btfi_byps_drc_7b_btfi_ddr_8_bypfi_drc_8a_bypfi_drc_8b_bypfi_byps_drc_8a_btfi_byps_drc_8b_btfi_ddr_9_bypfi_drc_9a_bypfi_drc_9b_bypfi_byps_drc_9a_btfi_byps_drc_9b_btfi_ddr_10_bypfi_drc_10a_bypfi_drc_10b_bypfi_byps_drc_10a_btfi_byps_drc_10b_btit_11dd_sysit_11dd_blinkit_11dd_conn_sysicon_7_iicon_8_iicon_connector_2icon_diskicon_disk_bicon_disk_npicon_disk_nsicon_strip_11fpm_11d_endfi_bp_0_l2fi_bp_1_l2fi_bp_0_on_l3fi_bp_0_on_bt_l3fi_bp_0_pre_l3fi_bp_0_bbea_l3fi_bp_0_bbeb_l3fi_bp_1_on_l3fi_bp_1_on_bt_l3fi_bp_1_pre_l3fi_bp_1_bbea_l3fi_bp_1_bbeb_l3fi_bp_0_bbea_bypfi_bp_0_bbeb_bypfi_bp_1_bbea_bypfi_bp_1_bbeb_bypfi_byps_bp0_a_btfi_byps_bp0_b_btfi_byps_bp1_a_btfi_byps_bp1_b_btfi_ddf_0_bypfi_dfc_0a_bypfi_dfc_0b_bypfi_ddf_1_bypfi_dfc_1a_bypfi_dfc_1b_bypfi_ddf_2_bypfi_dfc_2a_bypfi_dfc_2b_bypfi_ddf_3_bypfi_dfc_3a_bypfi_dfc_3b_bypfi_ddf_4_bypfi_dfc_4a_bypfi_dfc_4b_bypfi_ddf_5_bypfi_dfc_5a_bypfi_dfc_5b_bypfi_ddf_6_bypfi_dfc_6a_bypfi_dfc_6b_bypfi_ddr_0_bypfi_drc_0a_bypfi_drc_0b_bypfi_ddr_1_bypfi_drc_1a_bypfi_drc_1b_bypfi_ddr_2_bypfi_drc_2a_bypfi_drc_2b_bypfi_ddr_3_bypfi_drc_3a_bypfi_drc_3b_bypfi_ddr_4_bypfi_drc_4a_bypfi_drc_4b_bypfi_ddr_5_bypfi_drc_5a_bypfi_drc_5b_bypfi_ddr_6_bypfi_drc_6a_bypfi_drc_6b_bypfi_ddf_0_sysfi_ddf_1_sysfi_ddf_2_sysfi_ddf_3_sysfi_ddf_4_sysfi_ddf_5_sysfi_ddf_6_sysfi_ddr_0_sysfi_ddr_1_sysfi_ddr_2_sysfi_ddr_3_sysfi_ddr_4_sysfi_ddr_5_sysfi_ddr_6_sysfi_dfc_0a_sysfi_dfc_1a_sysfi_dfc_2a_sysfi_dfc_3a_sysfi_dfc_4a_sysfi_dfc_5a_sysfi_dfc_6a_sysfi_dfc_0b_sysfi_dfc_1b_sysfi_dfc_2b_sysfi_dfc_3b_sysfi_dfc_4b_sysfi_dfc_5b_sysfi_dfc_6b_sysfi_drc_0a_sysfi_drc_1a_sysfi_drc_2a_sysfi_drc_3a_sysfi_drc_4a_sysfi_drc_5a_sysfi_drc_6a_sysfi_drc_0b_sysfi_drc_1b_sysfi_drc_2b_sysfi_drc_3b_sysfi_drc_4b_sysfi_drc_5b_sysfi_drc_6b_sysfi_byps_dfc_0a_btfi_byps_dfc_0b_btfi_byps_dfc_1a_btfi_byps_dfc_1b_btfi_byps_dfc_2a_btfi_byps_dfc_2b_btfi_byps_dfc_3a_btfi_byps_dfc_3b_btfi_byps_dfc_4a_btfi_byps_dfc_4b_btfi_byps_dfc_5a_btfi_byps_dfc_5b_btfi_byps_dfc_6a_btfi_byps_dfc_6b_btfi_byps_drc_0a_btfi_byps_drc_0b_btfi_byps_drc_1a_btfi_byps_drc_1b_btfi_byps_drc_2a_btfi_byps_drc_2b_btfi_byps_drc_3a_btfi_byps_drc_3b_btfi_byps_drc_4a_btfi_byps_drc_4b_btfi_byps_drc_5a_btfi_byps_drc_5b_btfi_byps_drc_6a_btfi_byps_drc_6b_btfi_ddf_0_l2fi_ddf_1_l2fi_ddf_2_l2fi_ddf_3_l2fi_ddf_4_l2fi_ddf_5_l2fi_ddf_6_l2fi_ddr_0_l2fi_ddr_1_l2fi_ddr_2_l2fi_ddr_3_l2fi_ddr_4_l2fi_ddr_5_l2fi_ddr_6_l2fi_ddf_0_l3fi_ddf_1_l3fi_ddf_2_l3fi_ddf_3_l3fi_ddf_4_l3fi_ddf_5_l3fi_ddf_6_l3fi_ddf_0_on_l3fi_ddf_1_on_l3fi_ddf_2_on_l3fi_ddf_3_on_l3fi_ddf_4_on_l3fi_ddf_5_on_l3fi_ddf_6_on_l3fi_ddr_0_l3fi_ddr_1_l3fi_ddr_2_l3fi_ddr_3_l3fi_ddr_4_l3fi_ddr_5_l3fi_ddr_6_l3fi_ddr_0_on_l3fi_ddr_1_on_l3fi_ddr_2_on_l3fi_ddr_3_on_l3fi_ddr_4_on_l3fi_ddr_5_on_l3fi_ddr_6_on_l3fi_ddf_0_on_bt_l3fi_ddf_1_on_bt_l3fi_ddf_2_on_bt_l3fi_ddf_3_on_bt_l3fi_ddf_4_on_bt_l3fi_ddf_5_on_bt_l3fi_ddf_6_on_bt_l3fi_ddr_0_on_bt_l3fi_ddr_1_on_bt_l3fi_ddr_2_on_bt_l3fi_ddr_3_on_bt_l3fi_ddr_4_on_bt_l3fi_ddr_5_on_bt_l3fi_ddr_6_on_bt_l3fi_ddf_0_pre_l3fi_ddf_0_okf_l3fi_ddf_0_rbea_l3fi_ddf_0_rbeb_l3fi_ddf_1_pre_l3fi_ddf_1_okf_l3fi_ddf_1_rbea_l3fi_ddf_1_rbeb_l3fi_ddf_2_pre_l3fi_ddf_2_okf_l3fi_ddf_2_rbea_l3fi_ddf_2_rbeb_l3fi_ddf_3_pre_l3fi_ddf_3_okf_l3fi_ddf_3_rbea_l3fi_ddf_3_rbeb_l3fi_ddf_4_pre_l3fi_ddf_4_okf_l3fi_ddf_4_rbea_l3fi_ddf_4_rbeb_l3fi_ddf_5_pre_l3fi_ddf_5_okf_l3fi_ddf_5_rbea_l3fi_ddf_5_rbeb_l3fi_ddf_6_pre_l3fi_ddf_6_okf_l3fi_ddf_6_rbea_l3fi_ddf_6_rbeb_l3fi_ddr_0_pre_l3fi_ddr_0_okf_l3fi_ddr_0_rbea_l3fi_ddr_0_rbeb_l3fi_ddr_1_pre_l3fi_ddr_1_okf_l3fi_ddr_1_rbea_l3fi_ddr_1_rbeb_l3fi_ddr_2_pre_l3fi_ddr_2_okf_l3fi_ddr_2_rbea_l3fi_ddr_2_rbeb_l3fi_ddr_3_pre_l3fi_ddr_3_okf_l3fi_ddr_3_rbea_l3fi_ddr_3_rbeb_l3fi_ddr_4_pre_l3fi_ddr_4_okf_l3fi_ddr_4_rbea_l3fi_ddr_4_rbeb_l3fi_ddr_5_pre_l3fi_ddr_5_okf_l3fi_ddr_5_rbea_l3fi_ddr_5_rbeb_l3fi_ddr_6_pre_l3fi_ddr_6_okf_l3fi_ddr_6_rbea_l3fi_ddr_6_rbeb_l3fi_ft_0_l2fi_ft_1_l2fi_ft_0_pre_l3fi_ft_0_psff_l3fi_ft_0_ddff_l3fi_ft_0_cff_l3fi_ft_0_on_l3fi_ft_0_on_bt_l3fi_ft_1_pre_l3fi_ft_1_psff_l3fi_ft_1_ddff_l3fi_ft_1_cff_l3fi_ft_1_on_l3fi_ft_1_on_bt_l3fi_ib_0a_fofffi_ib_1a_fofffi_ib_0b_fofffi_ib_1b_foffit_foff_buttonfi_ib_0_sys_lfi_ib_0_sys_rfi_ib_1_sys_lfi_ib_1_sys_rfi_ib_0_l2fi_ib_1_l2fi_ib_0_on_l3fi_ib_0_on_bt_l3fi_ib_0_pre_l3fi_ib_0_otw_l3fi_ib_0_stat_l3fi_ib_1_on_l3fi_ib_1_on_bt_l3fi_ib_1_pre_l3fi_ib_1_otw_l3fi_ib_1_stat_l3fi_ib0_a0_nodesfi_ib0_a1_nodesfi_ib1_b0_nodesfi_ib1_b1_nodesfi_mb_on_l3fi_mb_err_l3fi_mb_stat_l3fi_oe_a0_l2fi_oe_a1_l2fi_oe_b0_l2fi_oe_b1_l2fi_oe_a0_pr_l3fi_oe_a0_on_l3fi_oe_a0_on_bt_l3fi_oe_a0_txf_l3fi_oe_a0_onb_l3fi_oe_a1_txf_l3fi_oe_a1_onb_l3fi_oe_a1_on_l3fi_oe_a1_pr_l3fi_oe_a1_on_bt_l3fi_oe_b0_txf_l3fi_oe_b0_onb_l3fi_oe_b0_on_l3fi_oe_b0_pr_l3fi_oe_b0_on_bt_l3fi_oe_b1_txf_l3fi_oe_b1_onb_l3fi_oe_b1_on_l3fi_oe_b1_pr_l3fi_oe_b1_on_bt_l3fi_ol_a0_pre_sysfi_ol_a1_pre_sysfi_ol_b0_pre_sysfi_ol_b1_pre_sysfi_oe_a0_pre_sysfi_oe_a1_pre_sysfi_oe_b0_pre_sysfi_oe_b1_pre_sysfi_ps_0_l2fi_ps_1_l2fi_ps_2_l2fi_ps_0_on_l3fi_ps_0_pre_l3fi_ps_0_ac_l3fi_ps_0_dc_l3fi_ps_0_ot_l3fi_ps_0_on_bt_l3fi_ps_1_on_l3fi_ps_1_pre_l3fi_ps_1_ac_l3fi_ps_1_dc_l3fi_ps_1_ot_l3fi_ps_1_on_bt_l3fi_ps_2_on_l3fi_ps_2_pre_l3fi_ps_2_ac_l3fi_ps_2_dc_l3fi_ps_2_ot_l3fi_ps_2_on_bt_l3fi_loop_bt_sufi_ib_0_conf_sysfi_ib_1_conf_sysfi_cursorit_cursorfi_bp_0_fle_l3fi_bp_1_fle_l3fi_ft_0_fle_l3fi_ft_1_fle_l3fi_ib_0_fle_l3fi_ib_1_fle_l3fi_mb_fle_l3fi_oe_a0_fle_l3fi_oe_a1_fle_l3fi_oe_b0_fle_l3fi_oe_b1_fle_l3fi_ps_0_fle_l3fi_ps_1_fle_l3fi_ps_2_fle_l3fi_ddf_0_fle_l3fi_ddf_1_fle_l3fi_ddf_2_fle_l3fi_ddf_3_fle_l3fi_ddf_4_fle_l3fi_ddf_5_fle_l3fi_ddf_6_fle_l3fi_ddr_0_fle_l3fi_ddr_1_fle_l3fi_ddr_2_fle_l3fi_ddr_3_fle_l3fi_ddr_4_fle_l3fi_ddr_5_fle_l3fi_ddr_6_fle_l3fi_ddf_l2fi_ddr_l2fi_ps_l2fi_ft_l2fi_ib_l2fi_bp_l2fi_mb_l2fi_oe_l2fi_save_contfi_ddf_mmfi_ddr_mmfi_oe_mmfi_ps_mmfi_ft_mmfi_bp_mmfi_ib_mmfi_mb_mmfi_ok_mmfi_ok_sysfi_choose_loopcfi_scr_save_on_btts_screen_sav_1ts_screen_sav_2ts_tsf_0_l3fi_tsf_0_l3ts_tsf_1_l3fi_tsf_1_l3ts_tsf_2_l3fi_tsf_2_l3ts_tsf_3_l3fi_tsf_3_l3ts_tsf_4_l3fi_tsf_4_l3ts_tsf_5_l3fi_tsf_5_l3ts_tsf_6_l3fi_tsf_6_l3ts_tsf_7_l3fi_tsf_7_l3ts_tsf_8_l3fi_tsf_8_l3ts_tsf_9_l3fi_tsf_9_l3ts_tsr_0_l3fi_tsr_0_l3ts_tsr_1_l3fi_tsr_1_l3ts_tsr_2_l3fi_tsr_2_l3ts_tsr_3_l3fi_tsr_3_l3ts_tsr_4_l3fi_tsr_4_l3ts_tsr_5_l3fi_tsr_5_l3ts_tsr_6_l3fi_tsr_6_l3ts_tsr_7_l3fi_tsr_7_l3ts_tsr_8_l3fi_tsr_8_l3ts_tsr_9_l3fi_tsr_9_l3fi_ddf_0_blink_sysfi_ddf_0_blink_l2fi_ddf_0_blink_l3fi_ddf_1_blink_sysfi_ddf_1_blink_l2fi_ddf_1_blink_l3fi_ddf_2_blink_sysfi_ddf_2_blink_l2fi_ddf_2_blink_l3fi_ddf_3_blink_sysfi_ddf_3_blink_l2fi_ddf_3_blink_l3fi_ddf_4_blink_sysfi_ddf_4_blink_l2fi_ddf_4_blink_l3fi_ddf_5_blink_sysfi_ddf_5_blink_l2fi_ddf_5_blink_l3fi_ddf_6_blink_sysfi_ddf_6_blink_l2fi_ddf_6_blink_l3fi_ddr_0_blink_sysfi_ddr_0_blink_l2fi_ddr_0_blink_l3fi_ddr_1_blink_sysfi_ddr_1_blink_l2fi_ddr_1_blink_l3fi_ddr_2_blink_sysfi_ddr_2_blink_l2fi_ddr_2_blink_l3fi_ddr_3_blink_sysfi_ddr_3_blink_l2fi_ddr_3_blink_l3fi_ddr_4_blink_sysfi_ddr_4_blink_l2fi_ddr_4_blink_l3fi_ddr_5_blink_sysfi_ddr_5_blink_l2fi_ddr_5_blink_l3fi_ddr_6_blink_sysfi_ddr_6_blink_l2fi_ddr_6_blink_l3ts_tsr_bp0_l3fi_tsr_bp0_l3ts_tsr_bp1_l3fi_tsr_bp1_l3it_bp_l2it_bp_l3it_bp_pre_l3it_bypass_portit_choose_loopcit_ddf_mmit_ddr_mmit_dd_sysit_dd_blinkit_dd_conn_sysit_dd_pre_l3it_esi_contit_ft_l2it_ft_pre_l3it_fru_wrn_l2it_fru_okf_l3it_fru_on_l3it_fru_byp_l3it_fru_on_bt_l3it_fru_onli_l3it_fru_reset_l3it_ib_l2it_ib_sysit_ib_conf_l3it_ib_0_conf_sysit_ib_1_conf_sysit_ib_conf_btit_ib_pre_l3it_mb_err_l3it_mb_mmit_ok_mmit_oe_l2it_ol_sysit_oe_txflt_l3it_oe_onb_l3it_oe_a0_pres_sysit_oe_a1_pres_sysit_oe_b0_pres_sysit_oe_b1_pres_sysit_oe_pr_l3it_ps_l2it_ps_pre_l3it_ps_ot_l3it_ps_on_bt_l3it_scrsv_on_btls_mb_revls_oe_a0_revls_oe_a1_revls_oe_b0_revls_oe_b1_revls_ps_0_revls_ps_1_revls_ps_2_revls_ft_0_revls_ft_1_revls_ib_0_revls_ib_1_revls_bp_0_revls_bp_1_revls_ddf_0_revls_ddf_1_revls_ddf_2_revls_ddf_3_revls_ddf_4_revls_ddf_5_revls_ddf_6_revls_ddr_0_revls_ddr_1_revls_ddr_2_revls_ddr_3_revls_ddr_4_revls_ddr_5_revls_ddr_6_revls_boxidil_rev_noil_boxid_noil_oemod_typefpm_fruicons_endfpm_data_end/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "common.h" #include "errorcodes.h" #define MAX_MODE_SENSE_LEN 0xffff #define MAXLEN 1000 #define RETRY_PATHLIST 1 #define BYTES_PER_LINE 16 #define SCMD_UNKNOWN 0xff #define SCSI_VHCI "/devices/scsi_vhci/" #define SLASH "/" #define DEV_PREFIX "/devices/" #define DEV_PREFIX_STRLEN strlen(DEV_PREFIX) #define DEVICES_DIR "/devices" extern char *dtype[]; /* from adm.c */ extern int rand_r(unsigned int *); static int cleanup_dotdot_path(char *path); static int wait_random_time(void); static char *scsi_find_command_name(int cmd); static void scsi_printerr(struct uscsi_cmd *ucmd, struct scsi_extended_sense *rq, int rqlen, char msg_string[], char *err_string); static void string_dump(char *hdr, uchar_t *src, int nbytes, int format, char msg_string[]); static int issue_uscsi_cmd(int file, struct uscsi_cmd *command, int flag); static int wait_random_time(void) { time_t timeval; struct tm *tmbuf = NULL; struct timeval tval; unsigned int seed; int random; pid_t pid; /* * Get the system time and use "system seconds" * as 'seed' to generate a random number. Then, * wait between 1/10 - 1/2 seconds before retry. * Get the current process id and ex-or it with * the seed so that the random number is always * different even in case of multiple processes * generate a random number at the same time. */ if ((timeval = time(NULL)) == -1) { return (errno); } if ((tmbuf = localtime(&timeval)) == NULL) { return (-1); /* L_LOCALTIME_ERROR */ } pid = getpid(); /* get a random number. */ seed = (unsigned int) tmbuf->tm_sec; seed ^= pid; random = rand_r(&seed); random = ((random % 500) + 100) * MILLISEC; tval.tv_sec = random / MICROSEC; tval.tv_usec = random % MICROSEC; if (select(0, NULL, NULL, NULL, &tval) == -1) { return (-1); /* L_SELECT_ERROR */ } return (0); } /* * Special string dump for error message */ static void string_dump(char *hdr, uchar_t *src, int nbytes, int format, char msg_string[]) { int i; int n; char *p; char s[256]; assert(format == HEX_ONLY || format == HEX_ASCII); (void) strcpy(s, hdr); for (p = s; *p; p++) { *p = ' '; } p = hdr; while (nbytes > 0) { (void) sprintf(&msg_string[strlen(msg_string)], "%s", p); p = s; n = MIN(nbytes, BYTES_PER_LINE); for (i = 0; i < n; i++) { (void) sprintf(&msg_string[strlen(msg_string)], "%02x ", src[i] & 0xff); } if (format == HEX_ASCII) { for (i = BYTES_PER_LINE-n; i > 0; i--) { (void) sprintf(&msg_string[strlen(msg_string)], " "); } (void) sprintf(&msg_string[strlen(msg_string)], " "); for (i = 0; i < n; i++) { (void) sprintf(&msg_string[strlen(msg_string)], "%c", isprint(src[i]) ? src[i] : '.'); } } (void) sprintf(&msg_string[strlen(msg_string)], "\n"); nbytes -= n; src += n; } } /* * Return a pointer to a string telling us the name of the command. */ static char * scsi_find_command_name(int cmd) { /* * Names of commands. Must have SCMD_UNKNOWN at end of list. */ struct scsi_command_name { int command; char *name; } scsi_command_names[29]; register struct scsi_command_name *c; scsi_command_names[0].command = SCMD_TEST_UNIT_READY; scsi_command_names[0].name = MSGSTR(61, "Test Unit Ready"); scsi_command_names[1].command = SCMD_FORMAT; scsi_command_names[1].name = MSGSTR(110, "Format"); scsi_command_names[2].command = SCMD_REASSIGN_BLOCK; scsi_command_names[2].name = MSGSTR(77, "Reassign Block"); scsi_command_names[3].command = SCMD_READ; scsi_command_names[3].name = MSGSTR(27, "Read"); scsi_command_names[4].command = SCMD_WRITE; scsi_command_names[4].name = MSGSTR(54, "Write"); scsi_command_names[5].command = SCMD_READ_G1; scsi_command_names[5].name = MSGSTR(79, "Read(10 Byte)"); scsi_command_names[6].command = SCMD_WRITE_G1; scsi_command_names[6].name = MSGSTR(51, "Write(10 Byte)"); scsi_command_names[7].command = SCMD_MODE_SELECT; scsi_command_names[7].name = MSGSTR(97, "Mode Select"); scsi_command_names[8].command = SCMD_MODE_SENSE; scsi_command_names[8].name = MSGSTR(95, "Mode Sense"); scsi_command_names[9].command = SCMD_REASSIGN_BLOCK; scsi_command_names[9].name = MSGSTR(77, "Reassign Block"); scsi_command_names[10].command = SCMD_REQUEST_SENSE; scsi_command_names[10].name = MSGSTR(74, "Request Sense"); scsi_command_names[11].command = SCMD_READ_DEFECT_LIST; scsi_command_names[11].name = MSGSTR(80, "Read Defect List"); scsi_command_names[12].command = SCMD_INQUIRY; scsi_command_names[12].name = MSGSTR(102, "Inquiry"); scsi_command_names[13].command = SCMD_WRITE_BUFFER; scsi_command_names[13].name = MSGSTR(53, "Write Buffer"); scsi_command_names[14].command = SCMD_READ_BUFFER; scsi_command_names[14].name = MSGSTR(82, "Read Buffer"); scsi_command_names[15].command = SCMD_START_STOP; scsi_command_names[15].name = MSGSTR(67, "Start/Stop"); scsi_command_names[16].command = SCMD_RESERVE; scsi_command_names[16].name = MSGSTR(72, "Reserve"); scsi_command_names[17].command = SCMD_RELEASE; scsi_command_names[17].name = MSGSTR(75, "Release"); scsi_command_names[18].command = SCMD_MODE_SENSE_G1; scsi_command_names[18].name = MSGSTR(94, "Mode Sense(10 Byte)"); scsi_command_names[19].command = SCMD_MODE_SELECT_G1; scsi_command_names[19].name = MSGSTR(96, "Mode Select(10 Byte)"); scsi_command_names[20].command = SCMD_READ_CAPACITY; scsi_command_names[20].name = MSGSTR(81, "Read Capacity"); scsi_command_names[21].command = SCMD_SYNC_CACHE; scsi_command_names[21].name = MSGSTR(64, "Synchronize Cache"); scsi_command_names[22].command = SCMD_READ_DEFECT_LIST; scsi_command_names[22].name = MSGSTR(80, "Read Defect List"); scsi_command_names[23].command = SCMD_GDIAG; scsi_command_names[23].name = MSGSTR(108, "Get Diagnostic"); scsi_command_names[24].command = SCMD_SDIAG; scsi_command_names[24].name = MSGSTR(69, "Set Diagnostic"); scsi_command_names[25].command = SCMD_PERS_RESERV_IN; scsi_command_names[25].name = MSGSTR(10500, "Persistent Reserve In"); scsi_command_names[26].command = SCMD_PERS_RESERV_OUT; scsi_command_names[26].name = MSGSTR(10501, "Persistent Reserve out"); scsi_command_names[27].command = SCMD_LOG_SENSE; scsi_command_names[27].name = MSGSTR(10502, "Log Sense"); scsi_command_names[28].command = SCMD_UNKNOWN; scsi_command_names[28].name = MSGSTR(25, "Unknown"); for (c = scsi_command_names; c->command != SCMD_UNKNOWN; c++) if (c->command == cmd) break; return (c->name); } /* * Function to create error message containing * scsi request sense information */ static void scsi_printerr(struct uscsi_cmd *ucmd, struct scsi_extended_sense *rq, int rqlen, char msg_string[], char *err_string) { int blkno; switch (rq->es_key) { case KEY_NO_SENSE: (void) sprintf(msg_string, MSGSTR(91, "No sense error")); break; case KEY_RECOVERABLE_ERROR: (void) sprintf(msg_string, MSGSTR(76, "Recoverable error")); break; case KEY_NOT_READY: (void) sprintf(msg_string, MSGSTR(10503, "Device Not ready. Error: Random Retry Failed: %s\n."), err_string); break; case KEY_MEDIUM_ERROR: (void) sprintf(msg_string, MSGSTR(99, "Medium error")); break; case KEY_HARDWARE_ERROR: (void) sprintf(msg_string, MSGSTR(106, "Hardware error")); break; case KEY_ILLEGAL_REQUEST: (void) sprintf(msg_string, MSGSTR(103, "Illegal request")); break; case KEY_UNIT_ATTENTION: (void) sprintf(msg_string, MSGSTR(10504, "Unit attention." "Error: Random Retry Failed.\n")); break; case KEY_WRITE_PROTECT: (void) sprintf(msg_string, MSGSTR(52, "Write protect error")); break; case KEY_BLANK_CHECK: (void) sprintf(msg_string, MSGSTR(131, "Blank check error")); break; case KEY_VENDOR_UNIQUE: (void) sprintf(msg_string, MSGSTR(58, "Vendor unique error")); break; case KEY_COPY_ABORTED: (void) sprintf(msg_string, MSGSTR(123, "Copy aborted error")); break; case KEY_ABORTED_COMMAND: (void) sprintf(msg_string, MSGSTR(10505, "Aborted command. Error: Random Retry Failed.\n")); break; case KEY_EQUAL: (void) sprintf(msg_string, MSGSTR(117, "Equal error")); break; case KEY_VOLUME_OVERFLOW: (void) sprintf(msg_string, MSGSTR(57, "Volume overflow")); break; case KEY_MISCOMPARE: (void) sprintf(msg_string, MSGSTR(98, "Miscompare error")); break; case KEY_RESERVED: (void) sprintf(msg_string, MSGSTR(10506, "Reserved value found")); break; default: (void) sprintf(msg_string, MSGSTR(59, "Unknown error")); break; } (void) sprintf(&msg_string[strlen(msg_string)], MSGSTR(10507, " during: %s"), scsi_find_command_name(ucmd->uscsi_cdb[0])); if (rq->es_valid) { blkno = (rq->es_info_1 << 24) | (rq->es_info_2 << 16) | (rq->es_info_3 << 8) | rq->es_info_4; (void) sprintf(&msg_string[strlen(msg_string)], MSGSTR(49, ": block %d (0x%x)"), blkno, blkno); } (void) sprintf(&msg_string[strlen(msg_string)], "\n"); if (rq->es_add_len >= 6) { (void) sprintf(&msg_string[strlen(msg_string)], MSGSTR(132, " Additional sense: 0x%x " "ASC Qualifier: 0x%x\n"), rq->es_add_code, rq->es_qual_code); /* * rq->es_add_info[ADD_SENSE_CODE], * rq->es_add_info[ADD_SENSE_QUAL_CODE]); */ } if (rq->es_key == KEY_ILLEGAL_REQUEST) { string_dump(MSGSTR(47, " cmd: "), (uchar_t *)ucmd, sizeof (struct uscsi_cmd), HEX_ONLY, msg_string); string_dump(MSGSTR(48, " cdb: "), (uchar_t *)ucmd->uscsi_cdb, ucmd->uscsi_cdblen, HEX_ONLY, msg_string); } string_dump(MSGSTR(43, " sense: "), (uchar_t *)rq, 8 + rq->es_add_len, HEX_ONLY, msg_string); rqlen = rqlen; /* not used */ } /* * Execute a command and determine the result. */ static int issue_uscsi_cmd(int file, struct uscsi_cmd *command, int flag) { struct scsi_extended_sense *rqbuf; int status, i, retry_cnt = 0, err; char errorMsg[MAXLEN]; /* * Set function flags for driver. * * Set Automatic request sense enable * */ command->uscsi_flags = USCSI_RQENABLE; command->uscsi_flags |= flag; /* intialize error message array */ errorMsg[0] = '\0'; /* print command for debug */ if (getenv("_LUX_S_DEBUG") != NULL) { if ((command->uscsi_cdb == NULL) || (flag & USCSI_RESET) || (flag & USCSI_RESET_ALL)) { if (flag & USCSI_RESET) { (void) printf(" Issuing a SCSI Reset.\n"); } if (flag & USCSI_RESET_ALL) { (void) printf(" Issuing a SCSI Reset All.\n"); } } else { (void) printf(" Issuing the following " "SCSI command: %s\n", scsi_find_command_name(command->uscsi_cdb[0])); (void) printf(" fd=0x%x cdb=", file); for (i = 0; i < (int)command->uscsi_cdblen; i++) { (void) printf("%x ", *(command->uscsi_cdb + i)); } (void) printf("\n\tlen=0x%x bufaddr=0x%x buflen=0x%x" " flags=0x%x\n", command->uscsi_cdblen, command->uscsi_bufaddr, command->uscsi_buflen, command->uscsi_flags); if ((command->uscsi_buflen > 0) && ((flag & USCSI_READ) == 0)) { (void) dump_hex_data(" Buffer data: ", (uchar_t *)command->uscsi_bufaddr, MIN(command->uscsi_buflen, 512), HEX_ASCII); } } (void) fflush(stdout); } /* * Default command timeout in case command left it 0 */ if (command->uscsi_timeout == 0) { command->uscsi_timeout = 60; } /* Issue command - finally */ retry: status = ioctl(file, USCSICMD, command); if (status == 0 && command->uscsi_status == 0) { if (getenv("_LUX_S_DEBUG") != NULL) { if ((command->uscsi_buflen > 0) && (flag & USCSI_READ)) { (void) dump_hex_data("\tData read:", (uchar_t *)command->uscsi_bufaddr, MIN(command->uscsi_buflen, 512), HEX_ASCII); } } return (status); } if ((status != 0) && (command->uscsi_status == 0)) { if ((getenv("_LUX_S_DEBUG") != NULL) || (getenv("_LUX_ER_DEBUG") != NULL)) { (void) printf("Unexpected USCSICMD ioctl error: %s\n", strerror(errno)); } return (status); } /* * Just a SCSI error, create error message * Retry once for Unit Attention, * Not Ready, and Aborted Command */ if ((command->uscsi_rqbuf != NULL) && (((char)command->uscsi_rqlen - (char)command->uscsi_rqresid) > 0)) { rqbuf = (struct scsi_extended_sense *)command->uscsi_rqbuf; switch (rqbuf->es_key) { case KEY_NOT_READY: if (retry_cnt++ < 1) { ER_DPRINTF("Note: Device Not Ready." " Retrying...\n"); if ((err = wait_random_time()) == 0) { goto retry; } else { return (err); } } break; case KEY_UNIT_ATTENTION: if (retry_cnt++ < 1) { ER_DPRINTF(" cmd():" " UNIT_ATTENTION: Retrying...\n"); goto retry; } break; case KEY_ABORTED_COMMAND: if (retry_cnt++ < 1) { ER_DPRINTF("Note: Command is aborted." " Retrying...\n"); goto retry; } break; } if ((getenv("_LUX_S_DEBUG") != NULL) || (getenv("_LUX_ER_DEBUG") != NULL)) { scsi_printerr(command, (struct scsi_extended_sense *)command->uscsi_rqbuf, (command->uscsi_rqlen - command->uscsi_rqresid), errorMsg, strerror(errno)); } } else { /* * Retry 5 times in case of BUSY, and only * once for Reservation-conflict, Command * Termination and Queue Full. Wait for * random amount of time (between 1/10 - 1/2 secs.) * between each retry. This random wait is to avoid * the multiple threads being executed at the same time * and also the constraint in Photon IB, where the * command queue has a depth of one command. */ switch ((uchar_t)command->uscsi_status & STATUS_MASK) { case STATUS_BUSY: if (retry_cnt++ < 5) { if ((err = wait_random_time()) == 0) { R_DPRINTF(" cmd(): No. of retries %d." " STATUS_BUSY: Retrying...\n", retry_cnt); goto retry; } else { return (err); } } break; case STATUS_RESERVATION_CONFLICT: if (retry_cnt++ < 1) { if ((err = wait_random_time()) == 0) { R_DPRINTF(" cmd():" " RESERVATION_CONFLICT:" " Retrying...\n"); goto retry; } else { return (err); } } break; case STATUS_TERMINATED: if (retry_cnt++ < 1) { R_DPRINTF("Note: Command Terminated." " Retrying...\n"); if ((err = wait_random_time()) == 0) { goto retry; } else { return (err); } } break; case STATUS_QFULL: if (retry_cnt++ < 1) { R_DPRINTF("Note: Command Queue is full." " Retrying...\n"); if ((err = wait_random_time()) == 0) { goto retry; } else { return (err); } } break; } } if (((getenv("_LUX_S_DEBUG") != NULL) || (getenv("_LUX_ER_DEBUG") != NULL)) && (errorMsg[0] != '\0')) { (void) fprintf(stdout, " %s\n", errorMsg); } return (L_SCSI_ERROR | command->uscsi_status); } /* * MODE SENSE USCSI command * * * pc = page control field * page_code = Pages to return */ int scsi_mode_sense_cmd(int fd, uchar_t *buf_ptr, int buf_len, uchar_t pc, uchar_t page_code) { struct uscsi_cmd ucmd; /* 10 byte Mode Select cmd */ union scsi_cdb cdb = {SCMD_MODE_SENSE_G1, 0, 0, 0, 0, 0, 0, 0, 0, 0}; struct scsi_extended_sense sense; int status; static int uscsi_count; if ((fd < 0) || (buf_ptr == NULL) || (buf_len < 0)) { return (-1); /* L_INVALID_ARG */ } (void) memset(buf_ptr, 0, buf_len); (void) memset((char *)&ucmd, 0, sizeof (ucmd)); /* Just for me - a sanity check */ if ((page_code > MODEPAGE_ALLPAGES) || (pc > 3) || (buf_len > MAX_MODE_SENSE_LEN)) { return (-1); /* L_ILLEGAL_MODE_SENSE_PAGE */ } cdb.g1_addr3 = (pc << 6) + page_code; cdb.g1_count1 = buf_len>>8; cdb.g1_count0 = buf_len & 0xff; ucmd.uscsi_cdb = (caddr_t)&cdb; ucmd.uscsi_cdblen = CDB_GROUP1; ucmd.uscsi_bufaddr = (caddr_t)buf_ptr; ucmd.uscsi_buflen = buf_len; ucmd.uscsi_rqbuf = (caddr_t)&sense; ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); ucmd.uscsi_timeout = 120; status = issue_uscsi_cmd(fd, &ucmd, USCSI_READ); /* Bytes actually transfered */ if (status == 0) { uscsi_count = buf_len - ucmd.uscsi_resid; S_DPRINTF(" Number of bytes read on " "Mode Sense 0x%x\n", uscsi_count); if (getenv("_LUX_D_DEBUG") != NULL) { (void) dump_hex_data(" Mode Sense data: ", buf_ptr, uscsi_count, HEX_ASCII); } } return (status); } int scsi_release(char *path) { struct uscsi_cmd ucmd; union scsi_cdb cdb = {SCMD_RELEASE, 0, 0, 0, 0, 0}; struct scsi_extended_sense sense; int fd, status; P_DPRINTF(" scsi_release: Release: Path %s\n", path); if ((fd = open(path, O_NDELAY | O_RDONLY)) == -1) return (1); (void) memset((char *)&ucmd, 0, sizeof (ucmd)); ucmd.uscsi_cdb = (caddr_t)&cdb; ucmd.uscsi_cdblen = CDB_GROUP0; ucmd.uscsi_bufaddr = NULL; ucmd.uscsi_buflen = 0; ucmd.uscsi_rqbuf = (caddr_t)&sense; ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); ucmd.uscsi_timeout = 60; status = (issue_uscsi_cmd(fd, &ucmd, 0)); (void) close(fd); return (status); } int scsi_reserve(char *path) { struct uscsi_cmd ucmd; union scsi_cdb cdb = {SCMD_RESERVE, 0, 0, 0, 0, 0}; struct scsi_extended_sense sense; int fd, status; P_DPRINTF(" scsi_reserve: Reserve: Path %s\n", path); if ((fd = open(path, O_NDELAY | O_RDONLY)) == -1) return (1); (void) memset((char *)&ucmd, 0, sizeof (ucmd)); ucmd.uscsi_cdb = (caddr_t)&cdb; ucmd.uscsi_cdblen = CDB_GROUP0; ucmd.uscsi_bufaddr = NULL; ucmd.uscsi_buflen = 0; ucmd.uscsi_rqbuf = (caddr_t)&sense; ucmd.uscsi_rqlen = sizeof (struct scsi_extended_sense); ucmd.uscsi_timeout = 60; status = (issue_uscsi_cmd(fd, &ucmd, 0)); (void) close(fd); return (status); } /* * Print out fabric dev dtype */ void print_fabric_dtype_prop(uchar_t *hba_port_wwn, uchar_t *port_wwn, uchar_t dtype_prop) { if ((dtype_prop & DTYPE_MASK) < 0x10) { (void) fprintf(stdout, " 0x%-2x (%s)\n", (dtype_prop & DTYPE_MASK), dtype[(dtype_prop & DTYPE_MASK)]); } else if ((dtype_prop & DTYPE_MASK) < 0x1f) { (void) fprintf(stdout, MSGSTR(2096, " 0x%-2x (Reserved)\n"), (dtype_prop & DTYPE_MASK)); } else { /* Check to see if this is the HBA */ if (wwnConversion(hba_port_wwn) != wwnConversion(port_wwn)) { (void) fprintf(stdout, MSGSTR(2097, " 0x%-2x (Unknown Type)\n"), (dtype_prop & DTYPE_MASK)); } else { /* MATCH */ (void) fprintf(stdout, MSGSTR(2241, " 0x%-2x (Unknown Type,Host Bus Adapter)\n"), (dtype_prop & DTYPE_MASK)); } } } void print_inq_data(char *arg_path, char *path, L_inquiry inq, uchar_t *serial, size_t serial_len) { char **p; uchar_t *v_parm; int scsi_3, length; char byte_number[MAXNAMELEN]; static char *scsi_inquiry_labels_2[21]; static char *scsi_inquiry_labels_3[22]; #define MAX_ANSI_VERSION 6 static char *ansi_version[MAX_ANSI_VERSION]; /* * Intialize scsi_inquiry_labels_2 with i18n strings */ scsi_inquiry_labels_2[0] = MSGSTR(138, "Vendor: "); scsi_inquiry_labels_2[1] = MSGSTR(149, "Product: "); scsi_inquiry_labels_2[2] = MSGSTR(139, "Revision: "); scsi_inquiry_labels_2[3] = MSGSTR(143, "Firmware Revision "); scsi_inquiry_labels_2[4] = MSGSTR(144, "Serial Number "); scsi_inquiry_labels_2[5] = MSGSTR(140, "Device type: "); scsi_inquiry_labels_2[6] = MSGSTR(145, "Removable media: "); scsi_inquiry_labels_2[7] = MSGSTR(146, "ISO version: "); scsi_inquiry_labels_2[8] = MSGSTR(147, "ECMA version: "); scsi_inquiry_labels_2[9] = MSGSTR(148, "ANSI version: "); scsi_inquiry_labels_2[10] = MSGSTR(2168, "Async event notification: "); scsi_inquiry_labels_2[11] = MSGSTR(2169, "Terminate i/o process msg: "); scsi_inquiry_labels_2[12] = MSGSTR(150, "Response data format: "); scsi_inquiry_labels_2[13] = MSGSTR(151, "Additional length: "); scsi_inquiry_labels_2[14] = MSGSTR(152, "Relative addressing: "); scsi_inquiry_labels_2[15] = MSGSTR(2170, "32 bit transfers: "); scsi_inquiry_labels_2[16] = MSGSTR(2171, "16 bit transfers: "); scsi_inquiry_labels_2[17] = MSGSTR(2172, "Synchronous transfers: "); scsi_inquiry_labels_2[18] = MSGSTR(153, "Linked commands: "); scsi_inquiry_labels_2[19] = MSGSTR(154, "Command queueing: "); scsi_inquiry_labels_2[20] = MSGSTR(2173, "Soft reset option: "); /* * Intialize scsi_inquiry_labels_3 with i18n strings */ scsi_inquiry_labels_3[0] = MSGSTR(138, "Vendor: "); scsi_inquiry_labels_3[1] = MSGSTR(149, "Product: "); scsi_inquiry_labels_3[2] = MSGSTR(139, "Revision: "); scsi_inquiry_labels_3[3] = MSGSTR(143, "Firmware Revision "); scsi_inquiry_labels_3[4] = MSGSTR(144, "Serial Number "); scsi_inquiry_labels_3[5] = MSGSTR(140, "Device type: "); scsi_inquiry_labels_3[6] = MSGSTR(145, "Removable media: "); scsi_inquiry_labels_3[7] = MSGSTR(2174, "Medium Changer Element: "); scsi_inquiry_labels_3[8] = MSGSTR(146, "ISO version: "); scsi_inquiry_labels_3[9] = MSGSTR(147, "ECMA version: "); scsi_inquiry_labels_3[10] = MSGSTR(148, "ANSI version: "); scsi_inquiry_labels_3[11] = MSGSTR(2175, "Async event reporting: "); scsi_inquiry_labels_3[12] = MSGSTR(2176, "Terminate task: "); scsi_inquiry_labels_3[13] = MSGSTR(2177, "Normal ACA Supported: "); scsi_inquiry_labels_3[14] = MSGSTR(150, "Response data format: "); scsi_inquiry_labels_3[15] = MSGSTR(151, "Additional length: "); scsi_inquiry_labels_3[16] = MSGSTR(2178, "Cmd received on port: "); scsi_inquiry_labels_3[17] = MSGSTR(2179, "SIP Bits: "); scsi_inquiry_labels_3[18] = MSGSTR(152, "Relative addressing: "); scsi_inquiry_labels_3[19] = MSGSTR(153, "Linked commands: "); scsi_inquiry_labels_3[20] = MSGSTR(2180, "Transfer Disable: "); scsi_inquiry_labels_3[21] = MSGSTR(154, "Command queueing: "); /* * Intialize scsi_inquiry_labels_3 with i18n strings */ ansi_version[0] = MSGSTR(2181, " (Device might or might not comply to an ANSI version)"); ansi_version[1] = MSGSTR(2182, " (This code is reserved for historical uses)"); ansi_version[2] = MSGSTR(2183, " (Device complies to ANSI X3.131-1994 (SCSI-2))"); ansi_version[3] = MSGSTR(2184, " (Device complies to ANSI INCITS 301-1997 (SPC))"); ansi_version[4] = MSGSTR(2226, " (Device complies to ANSI INCITS 351-2001 (SPC-2))"); ansi_version[5] = MSGSTR(2227, " (Device complies to ANSI INCITS 408-2005 (SPC-3))"); /* print inquiry information */ (void) fprintf(stdout, MSGSTR(2185, "\nINQUIRY:\n")); /* * arg_path is the path sent to luxadm by the user. if arg_path * is a /devices path, then we do not need to print out physical * path info */ if (strcmp(arg_path, path) != 0 && strstr(arg_path, "/devices/") == NULL) { (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(5, "Physical Path:")); (void) fprintf(stdout, "\n %s\n", path); } if (inq.inq_ansi < 3) { p = scsi_inquiry_labels_2; scsi_3 = 0; } else { p = scsi_inquiry_labels_3; scsi_3 = 1; } if (inq.inq_len < 11) { p += 1; } else { /* */ (void) fprintf(stdout, "%s", *p++); print_chars(inq.inq_vid, sizeof (inq.inq_vid), 0); (void) fprintf(stdout, "\n"); } if (inq.inq_len < 27) { p += 1; } else { (void) fprintf(stdout, "%s", *p++); print_chars(inq.inq_pid, sizeof (inq.inq_pid), 0); (void) fprintf(stdout, "\n"); } if (inq.inq_len < 31) { p += 1; } else { (void) fprintf(stdout, "%s", *p++); print_chars(inq.inq_revision, sizeof (inq.inq_revision), 0); (void) fprintf(stdout, "\n"); } if (inq.inq_len < 39) { p += 2; } else { /* * If Pluto then print * firmware rev & serial #. */ if (strstr((char *)inq.inq_pid, "SSA") != 0) { (void) fprintf(stdout, "%s", *p++); print_chars(inq.inq_firmware_rev, sizeof (inq.inq_firmware_rev), 0); (void) fprintf(stdout, "\n"); (void) fprintf(stdout, "%s", *p++); print_chars(serial, serial_len, 0); (void) fprintf(stdout, "\n"); } else if ((inq.inq_dtype & DTYPE_MASK) != DTYPE_ESI) { p++; (void) fprintf(stdout, "%s", *p++); print_chars(serial, serial_len, 0); (void) fprintf(stdout, "\n"); } else { /* if we miss both the above if's */ p += 2; } } (void) fprintf(stdout, "%s0x%x (", *p++, (inq.inq_dtype & DTYPE_MASK)); if ((inq.inq_dtype & DTYPE_MASK) < 0x10) { (void) fprintf(stdout, "%s", dtype[inq.inq_dtype & DTYPE_MASK]); } else if ((inq.inq_dtype & DTYPE_MASK) < 0x1f) { (void) fprintf(stdout, MSGSTR(71, "Reserved")); } else { (void) fprintf(stdout, MSGSTR(2186, "Unknown device")); } (void) fprintf(stdout, ")\n"); (void) fprintf(stdout, "%s", *p++); if (inq.inq_rmb != 0) { (void) fprintf(stdout, MSGSTR(40, "yes")); } else { (void) fprintf(stdout, MSGSTR(45, "no")); } (void) fprintf(stdout, "\n"); if (scsi_3) { (void) fprintf(stdout, "%s", *p++); if (inq.inq_mchngr != 0) { (void) fprintf(stdout, MSGSTR(40, "yes")); } else { (void) fprintf(stdout, MSGSTR(45, "no")); } (void) fprintf(stdout, "\n"); } (void) fprintf(stdout, "%s%d\n", *p++, inq.inq_iso); (void) fprintf(stdout, "%s%d\n", *p++, inq.inq_ecma); (void) fprintf(stdout, "%s%d", *p++, inq.inq_ansi); if (inq.inq_ansi < MAX_ANSI_VERSION) { (void) fprintf(stdout, "%s", ansi_version[inq.inq_ansi]); } else (void) fprintf(stdout, " (%s)", MSGSTR(71, "Reserved")); (void) fprintf(stdout, "\n"); if (inq.inq_aenc) { (void) fprintf(stdout, "%s", *p++); (void) fprintf(stdout, MSGSTR(40, "yes")); (void) fprintf(stdout, "\n"); } else { p++; } if (scsi_3) { (void) fprintf(stdout, "%s", *p++); if (inq.inq_normaca != 0) { (void) fprintf(stdout, MSGSTR(40, "yes")); } else { (void) fprintf(stdout, MSGSTR(45, "no")); } (void) fprintf(stdout, "\n"); } if (inq.inq_trmiop) { (void) fprintf(stdout, "%s", *p++); (void) fprintf(stdout, MSGSTR(40, "yes")); (void) fprintf(stdout, "\n"); } else { p++; } (void) fprintf(stdout, "%s%d\n", *p++, inq.inq_rdf); (void) fprintf(stdout, "%s0x%x\n", *p++, inq.inq_len); if (scsi_3) { if (inq.inq_dual_p) { if (inq.inq_port != 0) { (void) fprintf(stdout, MSGSTR(2187, "%sa\n"), *p++); } else { (void) fprintf(stdout, MSGSTR(2188, "%sb\n"), *p++); } } else { p++; } } if (scsi_3) { if (inq.inq_SIP_1 || inq.ui.inq_3.inq_SIP_2 || inq.ui.inq_3.inq_SIP_3) { (void) fprintf(stdout, "%s%d, %d, %d\n", *p, inq.inq_SIP_1, inq.ui.inq_3.inq_SIP_2, inq.ui.inq_3.inq_SIP_3); } p++; } if (inq.ui.inq_2.inq_2_reladdr) { (void) fprintf(stdout, "%s", *p); (void) fprintf(stdout, MSGSTR(40, "yes")); (void) fprintf(stdout, "\n"); } p++; if (!scsi_3) { if (inq.ui.inq_2.inq_wbus32) { (void) fprintf(stdout, "%s", *p); (void) fprintf(stdout, MSGSTR(40, "yes")); (void) fprintf(stdout, "\n"); } p++; if (inq.ui.inq_2.inq_wbus16) { (void) fprintf(stdout, "%s", *p); (void) fprintf(stdout, MSGSTR(40, "yes")); (void) fprintf(stdout, "\n"); } p++; if (inq.ui.inq_2.inq_sync) { (void) fprintf(stdout, "%s", *p); (void) fprintf(stdout, MSGSTR(40, "yes")); (void) fprintf(stdout, "\n"); } p++; } if (inq.ui.inq_2.inq_linked) { (void) fprintf(stdout, "%s", *p); (void) fprintf(stdout, MSGSTR(40, "yes")); (void) fprintf(stdout, "\n"); } p++; if (scsi_3) { (void) fprintf(stdout, "%s", *p++); if (inq.ui.inq_3.inq_trandis != 0) { (void) fprintf(stdout, MSGSTR(40, "yes")); } else { (void) fprintf(stdout, MSGSTR(45, "no")); } (void) fprintf(stdout, "\n"); } if (inq.ui.inq_2.inq_cmdque) { (void) fprintf(stdout, "%s", *p); (void) fprintf(stdout, MSGSTR(40, "yes")); (void) fprintf(stdout, "\n"); } p++; if (!scsi_3) { if (inq.ui.inq_2.inq_sftre) { (void) fprintf(stdout, "%s", *p); (void) fprintf(stdout, MSGSTR(40, "yes")); (void) fprintf(stdout, "\n"); } p++; } /* * Now print the vendor-specific data. */ v_parm = inq.inq_ven_specific_1; if (inq.inq_len >= 32) { length = inq.inq_len - 31; if (strstr((char *)inq.inq_pid, "SSA") != 0) { (void) fprintf(stdout, MSGSTR(2189, "Number of Ports, Targets: %d,%d\n"), inq.inq_ssa_ports, inq.inq_ssa_tgts); v_parm += 20; length -= 20; } else if ((strstr((char *)inq.inq_pid, "SUN") != 0) || (strncmp((char *)inq.inq_vid, "SUN ", sizeof (inq.inq_vid)) == 0)) { v_parm += 16; length -= 16; } /* * Do hex Dump of rest of the data. */ if (length > 0) { (void) fprintf(stdout, MSGSTR(2190, " VENDOR-SPECIFIC PARAMETERS\n")); (void) fprintf(stdout, MSGSTR(2191, "Byte# Hex Value " " ASCII\n")); (void) sprintf(byte_number, "%d ", inq.inq_len - length + 5); dump_hex_data(byte_number, v_parm, MIN(length, inq.inq_res3 - v_parm), HEX_ASCII); } /* * Skip reserved bytes 56-95. */ length -= (inq.inq_box_name - v_parm); if (length > 0) { (void) sprintf(byte_number, "%d ", inq.inq_len - length + 5); dump_hex_data(byte_number, inq.inq_box_name, MIN(length, sizeof (inq.inq_box_name) + sizeof (inq.inq_avu)), HEX_ASCII); } } if (getenv("_LUX_D_DEBUG") != NULL) { dump_hex_data("\nComplete Inquiry: ", (uchar_t *)&inq, MIN(inq.inq_len + 5, sizeof (inq)), HEX_ASCII); } } /* * Internal routine to clean up ../'s in paths. * returns 0 if no "../" are left. * * Wouldn't it be nice if there was a standard system library * routine to do this...? */ static int cleanup_dotdot_path(char *path) { char holder[MAXPATHLEN]; char *dotdot; char *previous_slash; /* Find the first "/../" in the string */ dotdot = strstr(path, "/../"); if (dotdot == NULL) { return (0); } /* * If the [0] character is '/' and "../" immediatly * follows it, then we can strip the ../ * * /../../foo/bar == /foo/bar * */ if (dotdot == path) { strcpy(holder, &path[3]); /* strip "/.." */ strcpy(path, holder); return (1); } /* * Now look for the LAST "/" before the "/../" * as this is the parent dir we can get rid of. * We do this by temporarily truncating the string * at the '/' just before "../" using the dotdot pointer. */ *dotdot = '\0'; previous_slash = strrchr(path, '/'); if (previous_slash == NULL) { /* * hmm, somethings wrong. path looks something * like "foo/../bar/" so we can't really deal with it. */ return (0); } /* * Now truncate the path just after the previous '/' * and slam everything after the "../" back on */ *(previous_slash+1) = '\0'; (void) strcat(path, dotdot+4); return (1); /* We may have more "../"s */ } /* * Follow symbolic links from the logical device name to * the /devfs physical device name. To be complete, we * handle the case of multiple links. This function * either returns NULL (no links, or some other error), * or the physical device name, alloc'ed on the heap. * * NOTE: If the path is relative, it will be forced into * an absolute path by pre-pending the pwd to it. */ char * get_slash_devices_from_osDevName(char *osDevName, int flag) { struct stat stbuf; char source[MAXPATHLEN]; char scratch[MAXPATHLEN]; char pwd[MAXPATHLEN]; char *tmp, *phys_path; int cnt; boolean_t is_lstat_failed = B_TRUE; /* return NULL if path is NULL */ if (osDevName == NULL) { return (NULL); } strcpy(source, osDevName); for (;;) { /* * First make sure the path is absolute. If not, make it. * If it's already an absolute path, we have no need * to determine the cwd, so the program should still * function within security-by-obscurity directories. */ if (source[0] != '/') { tmp = getcwd(pwd, MAXPATHLEN); if (tmp == NULL) { return (NULL); } /* * Handle special case of "./foo/bar" */ if (source[0] == '.' && source[1] == '/') { strcpy(scratch, source+2); } else { /* no "./" so just take everything */ strcpy(scratch, source); } strcpy(source, pwd); (void) strcat(source, "/"); (void) strcat(source, scratch); } /* * Clean up any "../"s that are in the path */ while (cleanup_dotdot_path(source)) ; /* * source is now an absolute path to the link we're * concerned with */ if (flag == NOT_IGNORE_DANGLING_LINK) { /* * In order not to ingore dangling links, check * the lstat. If lstat succeeds, return the path * from readlink. * Note: osDevName input with /devices path from * a dangling /dev link doesn't pass lstat so * NULL is returned. */ if (stat(source, &stbuf) == -1) { if (!is_lstat_failed && strstr(source, "/devices")) { /* * lstat succeeded previously and source * contains "/devices" then it is * dangling node. */ phys_path = (char *)calloc(1, strlen(source) + 1); if (phys_path != NULL) { (void) strncpy(phys_path, source, strlen(source) + 1); } return (phys_path); } else if (is_lstat_failed) { /* check lstat result. */ if (lstat(source, &stbuf) == -1) { return (NULL); } else { /* and continue */ is_lstat_failed = B_FALSE; } } else { /* * With algorithm that resolves a link * and then issues readlink(), should * not be reached here. */ return (NULL); } } else { if (lstat(source, &stbuf) == -1) { /* * when stat succeeds it is not * a dangling node so it is not * a special case. */ return (NULL); } } } else if (flag == STANDARD_DEVNAME_HANDLING) { /* * See if there's a real file out there. If not, * we have a dangling link and we ignore it. */ if (stat(source, &stbuf) == -1) { return (NULL); } if (lstat(source, &stbuf) == -1) { return (NULL); } } else { /* invalid flag */ return (NULL); } /* * If the file is not a link, we're done one * way or the other. If there were links, * return the full pathname of the resulting * file. * * Note: All of our temp's are on the stack, * so we have to copy the final result to the heap. */ if (!S_ISLNK(stbuf.st_mode)) { phys_path = (char *)calloc(1, strlen(source) + 1); if (phys_path != NULL) { (void) strncpy(phys_path, source, strlen(source) + 1); } return (phys_path); } cnt = readlink(source, scratch, sizeof (scratch)); if (cnt < 0) { return (NULL); } /* * scratch is on the heap, and for some reason readlink * doesn't always terminate things properly so we have * to make certain we're properly terminated */ scratch[cnt] = '\0'; /* * Now check to see if the link is relative. If so, * then we have to append it to the directory * which the source was in. (This is non trivial) */ if (scratch[0] != '/') { tmp = strrchr(source, '/'); if (tmp == NULL) { /* Whoa! Something's hosed! */ O_DPRINTF("Internal error... corrupt path.\n"); return (NULL); } /* Now strip off just the directory path */ *(tmp+1) = '\0'; /* Keeping the last '/' */ /* and append the new link */ (void) strcat(source, scratch); /* * Note: At this point, source should have "../"s * but we'll clean it up in the next pass through * the loop. */ } else { /* It's an absolute link so no worries */ strcpy(source, scratch); } } /* Never reach here */ } /* * Input - Space for client_path, phci_path and paddr fields of ioc structure * need to be allocated by the caller of this routine. */ int get_scsi_vhci_pathinfo(char *dev_path, sv_iocdata_t *ioc, int *path_count) { char *physical_path, *physical_path_s; int retval; int fd; int initial_path_count; int current_path_count; int i; char *delimiter; int malloc_error = 0; int prop_buf_size; int pathlist_retry_count = 0; if (strncmp(dev_path, SCSI_VHCI, strlen(SCSI_VHCI)) != 0) { if ((physical_path = get_slash_devices_from_osDevName( dev_path, STANDARD_DEVNAME_HANDLING)) == NULL) { return (L_INVALID_PATH); } if (strncmp(physical_path, SCSI_VHCI, strlen(SCSI_VHCI)) != 0) { free(physical_path); return (L_INVALID_PATH); } } else { if ((physical_path = calloc(1, MAXPATHLEN)) == NULL) { return (L_MALLOC_FAILED); } (void) strcpy(physical_path, dev_path); } physical_path_s = physical_path; /* move beyond "/devices" prefix */ physical_path += DEV_PREFIX_STRLEN-1; /* remove :c,raw suffix */ delimiter = strrchr(physical_path, ':'); /* if we didn't find the ':' fine, else truncate */ if (delimiter != NULL) { *delimiter = '\0'; } /* * We'll call ioctl SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO * at least twice. The first time will get the path count * and the size of the ioctl propoerty buffer. The second * time will get the path_info for each path. * * It's possible that additional paths are added while this * code is running. If the path count increases between the * 2 ioctl's above, then we'll retry (and assume all is well). */ (void) strcpy(ioc->client, physical_path); ioc->buf_elem = 1; ioc->ret_elem = (uint_t *)&(initial_path_count); ioc->ret_buf = NULL; /* free physical path */ free(physical_path_s); /* 0 buf_size asks driver to return actual size needed */ /* open the ioctl file descriptor */ if ((fd = open("/devices/scsi_vhci:devctl", O_RDWR)) < 0) { return (L_OPEN_PATH_FAIL); } retval = ioctl(fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, ioc); if (retval != 0) { close(fd); return (L_SCSI_VHCI_ERROR); } prop_buf_size = SV_PROP_MAX_BUF_SIZE; while (pathlist_retry_count <= RETRY_PATHLIST) { ioc->buf_elem = initial_path_count; /* Make driver put actual # paths in variable */ ioc->ret_elem = (uint_t *)&(current_path_count); /* * Allocate space for array of path_info structures. * Allocate enough space for # paths from get_pathcount */ ioc->ret_buf = (sv_path_info_t *) calloc(initial_path_count, sizeof (sv_path_info_t)); if (ioc->ret_buf == NULL) { close(fd); return (L_MALLOC_FAILED); } /* * Allocate space for path properties returned by driver */ malloc_error = 0; for (i = 0; i < initial_path_count; i++) { ioc->ret_buf[i].ret_prop.buf_size = prop_buf_size; if ((ioc->ret_buf[i].ret_prop.buf = (caddr_t)malloc(prop_buf_size)) == NULL) { malloc_error = 1; break; } if ((ioc->ret_buf[i].ret_prop.ret_buf_size = (uint_t *)malloc(sizeof (uint_t))) == NULL) { malloc_error = 1; break; } } if (malloc_error == 1) { for (i = 0; i < initial_path_count; i++) { free(ioc->ret_buf[i].ret_prop.buf); free(ioc->ret_buf[i].ret_prop.ret_buf_size); } free(ioc->ret_buf); close(fd); return (L_MALLOC_FAILED); } retval = ioctl(fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, ioc); if (retval != 0) { for (i = 0; i < initial_path_count; i++) { free(ioc->ret_buf[i].ret_prop.buf); free(ioc->ret_buf[i].ret_prop.ret_buf_size); } free(ioc->ret_buf); close(fd); return (L_SCSI_VHCI_ERROR); } if (initial_path_count < current_path_count) { /* then a new path was added */ pathlist_retry_count++; initial_path_count = current_path_count; } else { break; } } /* we are done with ioctl's, lose the fd */ close(fd); /* * Compare the length num elements from the ioctl response * and the caller's request - use smaller value. * * pathlist_p->path_count now has count returned from ioctl. * ioc.buf_elem has the value the caller provided. */ if (initial_path_count < current_path_count) { /* More paths exist than we allocated space for */ *path_count = initial_path_count; } else { *path_count = current_path_count; } return (0); } int get_mode_page(char *path, uchar_t **pg_buf) { struct mode_header_g1 *mode_header_ptr; int status, size, fd; /* open controller */ if ((fd = open(path, O_NDELAY | O_RDWR)) == -1) return (-1); /* L_OPEN_PATH_FAIL */ /* * Read the first part of the page to get the page size */ size = 20; if ((*pg_buf = (uchar_t *)calloc(1, size)) == NULL) { (void) close(fd); return (L_MALLOC_FAILED); } /* read page */ if (status = scsi_mode_sense_cmd(fd, *pg_buf, size, 0, MODEPAGE_ALLPAGES)) { (void) close(fd); (void) free(*pg_buf); return (status); } /* Now get the size for all pages */ mode_header_ptr = (struct mode_header_g1 *)(void *)*pg_buf; size = ntohs(mode_header_ptr->length) + sizeof (mode_header_ptr->length); (void) free(*pg_buf); if ((*pg_buf = (uchar_t *)calloc(1, size)) == NULL) { (void) close(fd); return (L_MALLOC_FAILED); } /* read all pages */ if (status = scsi_mode_sense_cmd(fd, *pg_buf, size, 0, MODEPAGE_ALLPAGES)) { (void) close(fd); (void) free(*pg_buf); return (status); } (void) close(fd); return (0); } /* * Dump a structure in hexadecimal. */ void dump_hex_data(char *hdr, uchar_t *src, int nbytes, int format) { int i; int n; char *p; char s[256]; assert(format == HEX_ONLY || format == HEX_ASCII); (void) strcpy(s, hdr); for (p = s; *p; p++) { *p = ' '; } p = hdr; while (nbytes > 0) { (void) fprintf(stdout, "%s", p); p = s; n = MIN(nbytes, BYTES_PER_LINE); for (i = 0; i < n; i++) { (void) fprintf(stdout, "%02x ", src[i] & 0xff); } if (format == HEX_ASCII) { for (i = BYTES_PER_LINE-n; i > 0; i--) { (void) fprintf(stdout, " "); } (void) fprintf(stdout, " "); for (i = 0; i < n; i++) { (void) fprintf(stdout, "%c", isprint(src[i]) ? src[i] : '.'); } } (void) fprintf(stdout, "\n"); nbytes -= n; src += n; } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * luxadm.h * * External functions and global variables needed for PHOTON */ /* * I18N message number ranges * This file: 13500 - 13999 * Shared common messages: 1 - 1999 */ #ifndef _LUXADM_H #define _LUXADM_H #ifdef __cplusplus extern "C" { #endif /* External functions */ extern int fc_update(unsigned, unsigned, char *); extern int fcal_update(unsigned, char *); extern int q_qlgc_update(unsigned, char *); extern int emulex_update(char *); extern int emulex_fcode_reader(int, char *, char *, uint32_t); extern int setboot(unsigned, unsigned, char *); extern int sysdump(int); extern int h_insertSena_fcdev(); extern int hotplug(int, char **, int, int); extern int hotplug_e(int, char **, int, int); extern void print_fabric_dtype_prop(uchar_t *, uchar_t *, uchar_t); /* SSA and RSM */ extern int p_download(char *, char *, int, int, uchar_t *); extern void ssa_fast_write(char *); extern void ssa_perf_statistics(char *); extern void ssa_cli_start(char **, int); extern void ssa_cli_stop(char **, int); extern void ssa_cli_display_config(char **argv, char *, int, int, int); extern void cli_display_envsen_data(char **, int); extern int p_sync_cache(char *); extern int p_purge(char *); extern void led(char **, int, int); extern void alarm_enable(char **, int, int); extern void alarm_set(char **, int); extern void power_off(char **, int); extern char *get_physical_name(char *); /* SSA LIB environment sense */ extern int scsi_get_envsen_data(int, char *, int); extern int scsi_put_envsen_data(int, char *, int); /* hotplug */ extern void print_errString(int, char *); extern int print_devState(char *, char *, int, int, int); extern void print_dev_state(char *, int); extern void print_bus_state(char *, int); extern int dev_handle_insert(char *, int); extern int dev_handle_remove(char *, int); extern int dev_handle_replace(char *, int); /* funct.c */ extern char ctoi(char); /* Functions for FC-HBA based operations */ extern int fchba_display_port(int verbose); extern int fchba_non_encl_probe(); extern int fchba_inquiry(char **argv); extern int fchba_dump_map(char **argv); extern int use_fchba(); extern int fchba_display_link_status(char **); extern int fchba_display_config(char **, int, int); extern int fchba_hotplug_e(int, char **, int, int); /* for g_adm.c & hotplug.c */ int print_devState(char *, char *, int, int, int); #ifdef __cplusplus } #endif #endif /* _LUXADM_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * I18N message number ranges * This file: 21000 - 21499 * Shared common messages: 1 - 1999 */ /* * Functions to support the download of FCode to PCI HBAs * Qlogic ISP21XX/22XX boards: FC100/P single port, ISP2200 dual port * and Emulex cards */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "luxadm.h" /* Error codes - used by the fcode_load_file routine */ #define FCODE_SUCCESS 0 /* successful completion */ #define FCODE_LOAD_FAILURE 1 /* general failure */ #define FCODE_IOCTL_FAILURE 2 /* FCODE ioctl download failure */ #define HBA_MAX 128 #define FCODE_HDR 200 #define MAX_RETRIES 3 #define MAX_WAIT_TIME 30 /* * EMULEX Fcode attributes */ #define EMULEX_FCODE_VERSION_LENGTH 16 #define EMULEX_READ_BUFFER_SIZE 128 /* Emulex specific error codes */ #define EMLX_ERRNO_START 0x100 /* Diagnostic error codes */ #define EMLX_TEST_FAILED (EMLX_ERRNO_START + 0) /* Download image contains bad data */ #define EMLX_IMAGE_BAD (EMLX_ERRNO_START + 1) /* Download image not compatible with current hardware */ #define EMLX_IMAGE_INCOMPATIBLE (EMLX_ERRNO_START + 2) /* Unable to take adapter offline */ #define EMLX_IMAGE_FAILED (EMLX_ERRNO_START + 3) /* Image download failed */ #define EMLX_OFFLINE_FAILED (EMLX_ERRNO_START + 4) /* * This is just a random value chosen to identify Sbus Fcodes. Sbus FCode * for Ivory is based on a 2200 chip but this value does not reflect that. */ #define SBUS_CHIP_ID 0x1969 #define IVORY_BUS "/sbus@" #define IVORY_DRVR "/SUNW,qlc@" /* Global variables */ static char fc_trans[] = "SUNW,ifp"; /* fibre channel transport */ static char fp_trans[] = "SUNW,qlc"; /* fca layer driver */ static char fp_trans_id[] = "fp@"; /* transport layer id */ static char qlgc2100[] = "FC100/P"; /* product name for 2100 */ static char qlgc2200[] = "ISP2200"; /* product name for 2200 */ static char qlgc2300[] = "ISP2300"; /* product name for 2300 */ static char qlgc2312[] = "ISP2312"; /* product name for 2312 */ /* * The variable qlgc2200Sbus represents the string which is always the * starting string of the version information in an ISP2200 Sbus Fcode. */ static char qlgc2200Sbus[] = "ISP2200 Sbus FC-AL Host Adapter Driver"; static char pcibus_list[HBA_MAX][PATH_MAX]; /* Internal functions */ static int q_load_file(int, char *); static int q_getbootdev(uchar_t *); static int q_getdevctlpath(char *, int *); static int q_warn(int); static int q_findversion(int, int, uchar_t *, uint16_t *); static int q_findfileversion(char *, uchar_t *, uint16_t *, int, int *); static int q_findSbusfile(int, int *); static int memstrstr(char *, char *, int, int); static int fcode_load_file(int, char *, int *); /* * Functions to support Fcode download for Emulex HBAs */ static int emulex_fcodeversion(di_node_t, uchar_t *); static void handle_emulex_error(int, char *); /* * Searches for and updates the cards. This is the "main" function * and will give the output to the user by calling the subfunctions. * args: FCode file; if NULL only the current FCode version is printed */ int q_qlgc_update(unsigned int verbose, char *file) /*ARGSUSED*/ { int fd, fcode_fd = -1, errnum = 0, devcnt = 0, retval = 0, isSbus = 0; int sbus_off; uint_t i, fflag = 0; uint16_t chip_id = 0, file_id = 0; uchar_t fcode_buf[FCODE_HDR]; static uchar_t bootpath[PATH_MAX]; static uchar_t version[MAXNAMELEN], version_file[MAXNAMELEN]; char devpath[PATH_MAX], tmppath[PATH_MAX]; void (*sigint)(); /* to store default SIGTERM setting */ static struct utmpx *utmpp = NULL; /* pointer for getutxent() */ char *ptr1, *ptr2; char phys_path[PATH_MAX]; /* * The variables port1 and port2 are used to store the bus id * e.g. the bus id for this path: * /devices/sbus@12,0/SUNW,qlc@2,30000/fp@0,0:devctl * is "sbus@12". They are initialized to a random value and are * set such that they are not equal initially. */ static char port1[MAXNAMELEN] = { 0 }; static char port2[MAXNAMELEN] = { 0 }; if (file) { fflag++; /* check for a valid file */ if ((fcode_fd = open(file, O_RDONLY)) < 0) { (void) fprintf(stderr, MSGSTR(21000, "Error: Could not open %s\n"), file); return (1); } if (read(fcode_fd, fcode_buf, FCODE_HDR) != FCODE_HDR) { perror(MSGSTR(21001, "read")); (void) close(fcode_fd); return (1); } /* * Check if it's SBUS FCode by calling q_findSbusfile * if it is then isSbus will be 1, if not it will be 0 * in case of an error, it will be -1 */ isSbus = q_findSbusfile(fcode_fd, &sbus_off); if (isSbus == -1) { (void) close(fcode_fd); return (1); } /* * FCode header check - make sure it's PCI FCode * Structure of FCode header (byte# refers to byte numbering * in FCode spec, not the byte# of our fcode_buf buffer): * header byte 00 0x55 prom signature byte one * byte 01 0xaa prom signature byte two * data byte 00-03 P C I R * OR * header byte 32 0x55 * byte 33 0xaa * data byte 60-63 P C I R * The second format with an offset of 32 is used for ifp prom */ if (!(((fcode_buf[0x00] == 0x55) && (fcode_buf[0x01] == 0xaa) && (fcode_buf[0x1c] == 'P') && (fcode_buf[0x1d] == 'C') && (fcode_buf[0x1e] == 'I') && (fcode_buf[0x1f] == 'R')) || ((fcode_buf[0x20] == 0x55) && (fcode_buf[0x21] == 0xaa) && (fcode_buf[0x3c] == 'P') && (fcode_buf[0x3d] == 'C') && (fcode_buf[0x3e] == 'I') && (fcode_buf[0x3f] == 'R')) || (isSbus))) { (void) fprintf(stderr, MSGSTR(21002, "Error: %s is not a valid FC100/P, " "ISP2200, ISP23xx FCode file.\n"), file); (void) close(fcode_fd); return (1); } /* check for single user mode */ while ((utmpp = getutxent()) != NULL) { if (strstr(utmpp->ut_line, "run-level") && (strcmp(utmpp->ut_line, "run-level S") && strcmp(utmpp->ut_line, "run-level 1"))) { if (q_warn(1)) { (void) endutxent(); (void) close(fcode_fd); return (1); } break; } } (void) endutxent(); /* get bootpath */ if (!q_getbootdev((uchar_t *)&bootpath[0]) && getenv("_LUX_D_DEBUG") != NULL) { (void) fprintf(stdout, " Bootpath: %s\n", bootpath); } } /* * Get count of, and names of PCI slots with ifp device control * (devctl) nodes. Search /devices. */ (void) strcpy(devpath, "/devices"); if (q_getdevctlpath(devpath, (int *)&devcnt) == 0) { (void) fprintf(stdout, MSGSTR(21003, "\n Found Path to %d FC100/P, ISP2200, ISP23xx Devices\n"), devcnt); } else { (void) fprintf(stderr, MSGSTR(21004, "Error: Could not get /devices path to FC100/P," "ISP2200, ISP23xx Cards.\n")); retval++; } for (i = 0; i < devcnt; i++) { (void) strncpy((char *)phys_path, &pcibus_list[i][0], strlen(&pcibus_list[i][0])); if (fflag && (strstr((char *)bootpath, strtok((char *)phys_path, ":")) != NULL)) { (void) fprintf(stderr, MSGSTR(21005, "Ignoring %s (bootpath)\n"), &pcibus_list[i][0]); continue; } (void) fprintf(stdout, MSGSTR(21006, "\n Opening Device: %s\n"), &pcibus_list[i][0]); /* Check if the device is valid */ if ((fd = open(&pcibus_list[i][0], O_RDWR)) < 0) { (void) fprintf(stderr, MSGSTR(21000, "Error: Could not open %s\n"), &pcibus_list[i][0]); retval++; continue; } (void) close(fd); /* * Check FCode version present on the adapter (at last boot) */ if (q_findversion(verbose, i, (uchar_t *)&version[0], &chip_id) == 0) { if (strlen((char *)version) == 0) { (void) fprintf(stdout, MSGSTR(21007, " Detected FCode Version:\tNo version available for this FCode\n")); } else { (void) fprintf(stdout, MSGSTR(21008, " Detected FCode Version:\t%s\n"), version); } } else { chip_id = 0x0; } if (fflag) { /* * For ISP2200, Sbus HBA, do just 1 download * for both the ports (dual port HBA) * Here it is assumed that readdir() always * returns the paths in pcibus_list[] in the * sorted order. */ (void) strcpy(tmppath, pcibus_list[i]); if (ptr1 = strstr(tmppath, IVORY_BUS)) { if (ptr2 = strstr(ptr1, IVORY_DRVR)) { ptr2 = strchr(ptr2, ','); if (ptr2 = strchr(++ptr2, ',')) { *ptr2 = '\0'; } } (void) strcpy(port2, ptr1); if (strcmp(port1, port2) == 0) { (void) fprintf(stdout, MSGSTR(21037, "/n New FCode has already been downloaded " "to this ISP2200 SBus HBA Card.\n" "It is sufficient to download to one " "port of the ISP2200 SBus HBA Card. " "Moving on...\n")); continue; } } /* * Check version of the supplied FCode file (once) */ if ((file_id != 0 && version_file != NULL) || (q_findfileversion((char *) &fcode_buf[0], (uchar_t *)&version_file[0], &file_id, isSbus, &sbus_off) == 0)) { (void) fprintf(stdout, MSGSTR(21009, " New FCode Version:\t\t%s\n"), version_file); } else { (void) close(fcode_fd); return (1); } /* * Load the New FCode * Give warning if file doesn't appear to be correct * */ if (chip_id == 0) { errnum = 2; /* can't get chip_id */ retval++; } else if (chip_id - file_id != 0) { errnum = 3; /* file/card mismatch */ retval++; } else { errnum = 0; /* everything is ok */ } if (!q_warn(errnum)) { /* Disable user-interrupt Control-C */ sigint = (void (*)(int)) signal(SIGINT, SIG_IGN); /* Load FCode */ (void) fprintf(stdout, MSGSTR(21010, " Loading FCode: %s\n"), file); if (q_load_file(fcode_fd, &pcibus_list[i][0]) == 0) { (void) fprintf(stdout, MSGSTR(21011, " Successful FCode download: %s\n"), &pcibus_list[i][0]); (void) strcpy(port1, port2); } else { (void) fprintf(stderr, MSGSTR(21012, "Error: FCode download failed: %s\n"), &pcibus_list[i][0]); retval++; } /* Restore SIGINT (user interrupt) setting */ (void) signal(SIGINT, sigint); } } } (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(125, "Complete\n")); if (fcode_fd != -1) (void) close(fcode_fd); return (retval); } /* * Retrieve the version banner from the card * uses ioctl: FCIO_FCODE_MCODE_VERSION FCode revision */ static int q_findversion(int verbose, int index, uchar_t *version, uint16_t *chip_id) /*ARGSUSED*/ { int fd = -1, ntries; struct ifp_fm_version *version_buffer = NULL; char prom_ver[100] = { 0 }; char mcode_ver[100] = { 0 }; fcio_t fcio; if (strstr(&pcibus_list[index][0], fc_trans)) { if ((fd = open(&pcibus_list[index][0], O_RDWR)) < 0) { (void) fprintf(stderr, MSGSTR(21000, "Error: Could not open %s\n"), &pcibus_list[index][0]); return (1); } if ((version_buffer = (struct ifp_fm_version *)malloc( sizeof (struct ifp_fm_version))) == NULL) { (void) fprintf(stderr, MSGSTR(21013, "Error: Memory allocation failed\n")); (void) close(fd); return (1); } version_buffer->fcode_ver = (char *)version; version_buffer->mcode_ver = mcode_ver; version_buffer->prom_ver = prom_ver; version_buffer->fcode_ver_len = MAXNAMELEN - 1; version_buffer->mcode_ver_len = 100; version_buffer->prom_ver_len = 100; if (ioctl(fd, FCIO_FCODE_MCODE_VERSION, version_buffer) < 0) { (void) fprintf(stderr, MSGSTR(21014, "Error: Driver interface FCIO_FCODE_MCODE_VERSION failed\n")); free(version_buffer); (void) close(fd); return (1); } version[version_buffer->fcode_ver_len] = '\0'; /* Need a way to get card MCODE (firmware) to track certain HW bugs */ if (getenv("_LUX_D_DEBUG") != NULL) { (void) fprintf(stdout, " Device %i: QLGC chip_id %x\n", index+1, *chip_id); (void) fprintf(stdout, " FCode:%s\n MCODE:%s\n PROM:%s\n", (char *)version, mcode_ver, prom_ver); } free(version_buffer); } else if (strstr(&pcibus_list[index][0], fp_trans)) { /* * Get the fcode and prom's fw version * using the fp ioctls. Currently, we pass * only the fcode version to the calling function * and ignore the FW version (using the existing * implementation). */ if ((fd = open(&pcibus_list[index][0], O_RDWR)) < 0) { (void) fprintf(stderr, MSGSTR(4511, "Could not open %s\n"), &pcibus_list[index][0]); (void) close(fd); return (1); } /* Get the fcode version */ bzero(version, sizeof (version)); fcio.fcio_cmd = FCIO_GET_FCODE_REV; /* Information read operation */ fcio.fcio_xfer = FCIO_XFER_READ; fcio.fcio_obuf = (caddr_t)version; fcio.fcio_olen = MAXNAMELEN; for (ntries = 0; ntries < MAX_RETRIES; ntries++) { if (ioctl(fd, FCIO_CMD, &fcio) != 0) { if ((errno == EAGAIN) && (ntries+1 < MAX_RETRIES)) { /* wait 30 secs */ (void) sleep(MAX_WAIT_TIME); continue; } (void) close(fd); return (L_FCIO_GET_FCODE_REV_FAIL); } break; } version[MAXNAMELEN-1] = '\0'; } /* Get type of card from product name in FCode version banner */ if (strstr((char *)version, qlgc2100)) { *chip_id = 0x2100; } else if (strstr((char *)version, qlgc2200)) { *chip_id = 0x2200; if (strstr((char *)version, "Sbus")) { *chip_id = SBUS_CHIP_ID; } } else if (strstr((char *)version, qlgc2300)) { *chip_id = 0x2300; } else if (strstr((char *)version, qlgc2312)) { *chip_id = 0x2312; } else { *chip_id = 0x0; } (void) close(fd); return (0); } /* * Retrieve the version banner and file type (2100 or 2200) from the file */ static int q_findfileversion(char *dl_fcode, uchar_t *version_file, uint16_t *file_id, int isSbus, int *sbus_offset) { int mark; int qlc_offset = 0; char temp[4] = { 0 }; /* * Get file version from FCode for 2100 or 2202 */ if (isSbus) { *file_id = SBUS_CHIP_ID; } else { if ((dl_fcode[0x23] == 0x22) || (dl_fcode[0x23] == 0x23)) { *file_id = dl_fcode[0x22] & 0xff; *file_id |= (dl_fcode[0x23] << 8) & 0xff00; } else { *file_id = dl_fcode[0x42] & 0xff; *file_id |= (dl_fcode[0x43] << 8) & 0xff00; } } /* * Ok, we're just checking for 2200 here. If it is we need * to offset to find the banner. */ if ((*file_id == 0x2200) || (*file_id == 0x2300) || (*file_id == 0x2312)) { qlc_offset = -32; } /* * If this is an ISP2200 Sbus Fcode file, then search for the string * "ISP2200 FC-AL Host Adapter Driver" in the whole fcode file */ if (isSbus) { *file_id = SBUS_CHIP_ID; qlc_offset = *sbus_offset; /* Subtract 111 from the offset we add below for PCI Fcodes */ qlc_offset -= 111; } /* Banner length varies; grab banner to end of date marker yr/mo/da */ version_file[0] = '\0'; for (mark = (111 + qlc_offset); mark < (191 + qlc_offset); mark++) { (void) strncpy(temp, (char *)&dl_fcode[mark], 4); if ((strncmp(&temp[0], "/", 1) == 0) && (strncmp(&temp[3], "/", 1) == 0)) { (void) strncat((char *)version_file, (char *)&dl_fcode[mark], 6); break; } (void) strncat((char *)version_file, temp, 1); } return (0); } /* * Find if the FCode file is a ISP2200 SBUS Fcode file */ static int q_findSbusfile(int fd, int *sbus_offset) { static int file_size; char *sbus_info; struct stat statinfo; if (lseek(fd, 0, SEEK_SET) == -1) { perror(MSGSTR(21022, "seek")); return (-1); } if (fstat(fd, &statinfo)) { perror(MSGSTR(21023, "fstat")); return (-1); } file_size = statinfo.st_size; if ((sbus_info = (char *)malloc(file_size)) == NULL) { (void) fprintf(stderr, MSGSTR(21013, "Error: Memory allocation failed\n")); return (-1); } if (read(fd, sbus_info, file_size) < 0) { perror(MSGSTR(21001, "read")); free(sbus_info); return (-1); } /* * Search for the version string in the whole file */ if ((*sbus_offset = memstrstr((char *)sbus_info, qlgc2200Sbus, file_size, strlen(qlgc2200Sbus))) != -1) { free(sbus_info); return (1); } else { free(sbus_info); return (0); } } /* * Build a list of all the devctl entries for all the 2100/2200 based adapters */ static int q_getdevctlpath(char *devpath, int *devcnt) { struct stat statbuf; struct dirent *dirp = NULL; DIR *dp = NULL; char *ptr = NULL; int err = 0; int testopen; if (lstat(devpath, &statbuf) < 0) { (void) fprintf(stderr, MSGSTR(21016, "Error: %s lstat() error\n"), devpath); return (1); } if ((strstr(devpath, fc_trans) || (strstr(devpath, fp_trans_id) && strstr(devpath, fp_trans))) && strstr(devpath, "devctl")) { /* Verify the path is valid */ if ((testopen = open(devpath, O_RDONLY)) >= 0) { (void) close(testopen); (void) strcpy(pcibus_list[*devcnt], devpath); *devcnt += 1; return (0); } } if (S_ISDIR(statbuf.st_mode) == 0) { /* * not a directory so * we don't care about it - return */ return (0); } /* * It's a directory. Call ourself to * traverse the path(s) */ ptr = devpath + strlen(devpath); *ptr++ = '/'; *ptr = 0; /* Forget the /devices/pseudo/ directory */ if (strcmp(devpath, "/devices/pseudo/") == 0) { return (0); } if ((dp = opendir(devpath)) == NULL) { (void) fprintf(stderr, MSGSTR(21017, "Error: %s Can't read directory\n"), devpath); return (1); } while ((dirp = readdir(dp)) != NULL) { if (strcmp(dirp->d_name, ".") == 0 || strcmp(dirp->d_name, "..") == 0) { continue; } (void) strcpy(ptr, dirp->d_name); /* append name */ err = q_getdevctlpath(devpath, devcnt); } if (closedir(dp) < 0) { (void) fprintf(stderr, MSGSTR(21018, "Error: Can't close directory %s\n"), devpath); return (1); } return (err); } /* * Get the boot device. Cannot load FCode to current boot device. * Boot devices under volume management will prompt a warning. */ static int q_getbootdev(uchar_t *bootpath) { struct mnttab mp; struct mnttab mpref; FILE *fp = NULL; static char buf[BUFSIZ]; char *p = NULL, *p1 = NULL; /* p = full device, p1 = chunk to rm */ char *slot = ":devctl"; char *root = "/"; if ((fp = fopen(MNTTAB, "r")) == NULL) { (void) fprintf(stderr, MSGSTR(21000, "Error: Could not open %s\n"), MNTTAB); return (1); } mntnull(&mpref); mpref.mnt_mountp = (char *)root; if (getmntany(fp, &mp, &mpref) != 0 || mpref.mnt_mountp == NULL) { (void) fprintf(stderr, MSGSTR(21019, "Error: Cannot get boot device, check %s.\n"), MNTTAB); (void) fclose(fp); return (1); } (void) fclose(fp); /* * If we can't get a link, we may be dealing with a volume mgr * so give a warning. If a colon is present, we likely have a * non-local disk or cd-rom, so no warning is necessary. * e.g. /devices/pci@1f,4000/scsi@3/sd@6,0:b (cdrom, no link) or * storage-e4:/blah/blah remote boot server */ if (readlink(mp.mnt_special, buf, BUFSIZ) < 0) { if (strstr(mp.mnt_special, ":") == NULL) { (void) fprintf(stderr, MSGSTR(21020, "\nWarning: Cannot read boot device link, check %s.\n"), MNTTAB); (void) fprintf(stderr, MSGSTR(21021, "Do not upgrade FCode on adapters controlling the boot device.\n")); } return (1); } /* * Copy boot device path to bootpath. First remove leading * path junk (../../..) then if it's an ifp device, chop off * the disk and add the devctl to the end of the path. */ if (p = strstr(buf, "/devices")) { if (strstr(buf, fc_trans) != NULL) { p1 = strrchr(p, '/'); *p1 = '\0'; } } (void) strcpy((char *)bootpath, (char *)p); if (p1) { (void) strcat((char *)bootpath, slot); } return (0); } /* * Load FCode to card. * uses ioctl: IFPIO_FCODE_DOWNLOAD */ static int q_load_file(int fcode_fd, char *device) { static int dev_fd, fcode_size; struct stat stat; ifp_download_t *download_p = NULL; fcio_t fcio; uint16_t file_id = 0; uchar_t *bin = NULL; if (lseek(fcode_fd, 0, SEEK_SET) == -1) { perror(MSGSTR(21022, "seek")); (void) close(fcode_fd); return (1); } if (fstat(fcode_fd, &stat) == -1) { perror(MSGSTR(21023, "fstat")); (void) close(fcode_fd); return (1); } fcode_size = stat.st_size; if (strstr(device, fc_trans)) { if ((download_p = (ifp_download_t *)malloc( sizeof (ifp_download_t) + fcode_size)) == NULL) { (void) fprintf(stderr, MSGSTR(21013, "Error: Memory allocation failed\n")); (void) close(fcode_fd); return (1); } } else { if ((bin = (uchar_t *)malloc(fcode_size)) == NULL) { (void) fprintf(stderr, MSGSTR(21013, "Error: Memory allocation failed\n")); (void) close(fcode_fd); return (1); } } if (strstr(device, fc_trans)) { if (read(fcode_fd, download_p->dl_fcode, fcode_size) != fcode_size) { perror(MSGSTR(21001, "read")); free(download_p); (void) close(fcode_fd); return (1); } } else { if (read(fcode_fd, bin, fcode_size) != fcode_size) { perror(MSGSTR(21001, "read")); free(bin); (void) close(fcode_fd); return (1); } } if ((dev_fd = open(device, O_RDWR|O_EXCL)) < 0) { (void) fprintf(stderr, MSGSTR(21000, "Error: Could not open %s\n"), device); free(download_p); return (1); } if (strstr(device, fc_trans)) { download_p->dl_fcode_len = fcode_size; file_id = download_p->dl_fcode[0x42] & 0xff; file_id |= (download_p->dl_fcode[0x43] << 8) & 0xff00; download_p->dl_chip_id = file_id; if (ioctl(dev_fd, IFPIO_FCODE_DOWNLOAD, download_p) < 0) { (void) fprintf(stderr, MSGSTR(21024, "Error: Driver interface IFPIO_FCODE_DOWNLOAD failed\n")); free(download_p); (void) close(dev_fd); return (1); } free(download_p); } else if (strstr(device, fp_trans)) { fcio.fcio_cmd = FCIO_DOWNLOAD_FCODE; /* Information read operation */ fcio.fcio_xfer = FCIO_XFER_WRITE; fcio.fcio_ibuf = (caddr_t)bin; fcio.fcio_ilen = fcode_size; if (ioctl(dev_fd, FCIO_CMD, &fcio) != 0) { (void) fprintf(stderr, MSGSTR(21036, "Error: Driver interface FCIO_DOWNLOAD_FCODE failed\n")); free(download_p); (void) close(dev_fd); return (1); } free(bin); } (void) close(dev_fd); return (0); } /* * Issue warning strings and loop for Yes/No user interaction * err# 0 -- we're ok, warn for pending FCode load * 1 -- not in single user mode * 2 -- can't get chip_id * 3 -- card and file do not have same type (2100/2200) */ static int q_warn(int errnum) { char input[1024]; input[0] = '\0'; if (errnum == 1) { (void) fprintf(stderr, MSGSTR(21025, "\nWarning: System is not in single-user mode.\n")); (void) fprintf(stderr, MSGSTR(21026, "Loading FCode will reset the adapter and terminate I/O activity\n")); } else { if (errnum == 2) { (void) fprintf(stderr, MSGSTR(21027, " Warning: FCode is missing or existing FCode has" " unrecognized version.\n")); return (1); } else if (errnum == 3) { (void) fprintf(stderr, MSGSTR(21028, " Warning: New FCode file version does not match this" " board type. Skipping...\n")); return (1); } (void) fprintf(stderr, MSGSTR(21029, "\nWARNING!! This program will update the FCode in this" " FC100/PCI, ISP2200/PCI, ISP23xx/PCI " " and Emulex devices.\n")); (void) fprintf(stderr, MSGSTR(21030, "This may take a few (5) minutes. Please be patient.\n")); } loop1: (void) fprintf(stderr, MSGSTR(21031, "Do you wish to continue ? (y/n) ")); (void) gets(input); if ((strcmp(input, MSGSTR(21032, "y")) == 0) || (strcmp(input, MSGSTR(40, "yes")) == 0)) { return (0); } else if ((strcmp(input, MSGSTR(21033, "n")) == 0) || (strcmp(input, MSGSTR(45, "no")) == 0)) { (void) fprintf(stderr, MSGSTR(21034, "Not Downloading FCode\n")); return (1); } else { (void) fprintf(stderr, MSGSTR(21035, "Invalid input\n")); goto loop1; } } /* * Name : memstrstr * Input : pointer to buf1, pointer to buf2, size of buf1, size of buf2 * Returns : * Offset of the start of contents-of-buf2 in buf1 if it is found * -1 if buf1 does not contain contents of buf2 * Synopsis: * This function works similar to strstr(). The difference is that null * characters in the buffer are treated like any other character. So, buf1 * and buf2 can have embedded null characters in them. */ static int memstrstr(char *s1, char *s2, int size1, int size2) { int count1, count2; char *s1_ptr, *s2_ptr; count1 = size1; count2 = size2; s1_ptr = s1; s2_ptr = s2; if ((size2 == 0)||(size1 == 0)) return (-1); for (count1 = 0; count1 < (size1 - size2 + 1); count1++) { if (*s1_ptr++ == *s2_ptr++) { if (--count2 == 0) { return (count1 - size2 + 1); } continue; } count2 = size2; s2_ptr = s2; } return (-1); } /* * generic fcode load file routine. given a file descriptor to a fcode file * this routine will issue the FCIO_DOWNLOAD_FCODE ioctl to the given * device. Any ioctl errors will be returned in fcio_errno * * Arguments: * fcode_fd file descriptor to a fcode file * device path to the device we will be downloading the fcode onto * fcio_errno pointer to an int that will be used to return any errors * back to the caller * Retrurn Values: * 0 successful download * >0 otherwise */ static int fcode_load_file(int fcode_fd, char *device, int *fcio_errno) { fcio_t fcio; static int dev_fd, fcode_size; uchar_t *bin; struct stat stat; if (device == NULL || fcio_errno == NULL) { return (FCODE_LOAD_FAILURE); } *fcio_errno = 0; if (lseek(fcode_fd, 0, SEEK_SET) == -1) { perror(MSGSTR(21022, "seek")); return (FCODE_LOAD_FAILURE); } if (fstat(fcode_fd, &stat) == -1) { perror(MSGSTR(21023, "fstat")); return (FCODE_LOAD_FAILURE); } fcode_size = stat.st_size; if ((bin = (uchar_t *)malloc(fcode_size)) == NULL) { (void) fprintf(stderr, MSGSTR(21013, "Error: Memory allocation failed\n")); return (FCODE_LOAD_FAILURE); } if (read(fcode_fd, bin, fcode_size) != fcode_size) { perror(MSGSTR(21001, "read")); free(bin); return (FCODE_LOAD_FAILURE); } if ((dev_fd = open(device, O_RDWR|O_EXCL)) < 0) { (void) fprintf(stderr, MSGSTR(21122, "Error: Could not open %s, failed " "with errno %d\n"), device, errno); free(bin); return (FCODE_LOAD_FAILURE); } fcio.fcio_cmd = FCIO_DOWNLOAD_FCODE; fcio.fcio_xfer = FCIO_XFER_WRITE; fcio.fcio_ibuf = (caddr_t)bin; fcio.fcio_ilen = fcode_size; if (ioctl(dev_fd, FCIO_CMD, &fcio) != 0) { (void) close(dev_fd); *fcio_errno = fcio.fcio_errno; free(bin); return (FCODE_IOCTL_FAILURE); } free(bin); (void) close(dev_fd); return (FCODE_SUCCESS); } /* * Searches for and updates the fcode for Emulex HBA cards * args: FCode file; if NULL only the current FCode * version is printed */ int emulex_update(char *file) { int fd, retval = 0; int devcnt = 0; uint_t state = 0, fflag = 0; static uchar_t bootpath[PATH_MAX]; int fcode_fd = -1; static struct utmpx *utmpp = NULL; di_node_t root; di_node_t node, sib_node, count_node; di_minor_t minor_node; char phys_path[PATH_MAX], *path; int errnum = 0, fcio_errno = 0; static uchar_t prom_ver_data[MAXNAMELEN]; static char ver_file[EMULEX_FCODE_VERSION_LENGTH]; void (*sigint)(); int prop_entries = -1; int *port_data = NULL; if (file) { /* set the fcode download flag */ fflag++; /* check for a valid file */ if ((fcode_fd = open(file, O_RDONLY)) < 0) { (void) fprintf(stderr, MSGSTR(21118, "Error: Could not open %s, failed " "with errno %d\n"), file, errno); return (1); } /* check for single user mode */ while ((utmpp = getutxent()) != NULL) { if (strstr(utmpp->ut_line, "run-level") && (strcmp(utmpp->ut_line, "run-level S") && strcmp(utmpp->ut_line, "run-level 1"))) { if (q_warn(1)) { (void) endutxent(); (void) close(fcode_fd); return (1); } break; } } (void) endutxent(); /* get bootpath */ if (!q_getbootdev((uchar_t *)&bootpath[0]) && getenv("_LUX_D_DEBUG") != NULL) { (void) fprintf(stdout, " Bootpath: %s\n", bootpath); } } /* * Download the Fcode to all the emulex cards found */ /* Create a snapshot of the kernel device tree */ if ((root = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) { (void) fprintf(stderr, MSGSTR(21114, "Error: Could not get /devices path to " "Emulex Devices.\n")); retval++; } /* point to first node which matches emulex driver */ node = di_drv_first_node("emlxs", root); if (node == DI_NODE_NIL) { /* * Could not find any emulex cards */ (void) di_fini(root); (void) fprintf(stderr, MSGSTR(21115, "\n Found Path to %d Emulex Devices.\n"), devcnt); retval++; } else { count_node = node; while (count_node != DI_NODE_NIL) { state = di_state(count_node); if ((state & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) { sib_node = di_child_node(count_node); while (sib_node != DI_NODE_NIL) { state = di_state(sib_node); if ((state & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) { /* Found an attached node */ prop_entries = di_prop_lookup_ints( DDI_DEV_T_ANY, sib_node, "port", &port_data); if (prop_entries != -1) { devcnt++; break; } } sib_node = di_sibling_node(sib_node); } } count_node = di_drv_next_node(count_node); } (void) fprintf(stdout, MSGSTR(21116, "\n Found Path to %d Emulex Devices.\n"), devcnt); } /* * Traverse device tree to find all emulex cards */ while (node != DI_NODE_NIL) { state = di_state(node); if ((state & DI_DRIVER_DETACHED) == DI_DRIVER_DETACHED) { node = di_drv_next_node(node); continue; } sib_node = di_child_node(node); while (sib_node != DI_NODE_NIL) { state = di_state(sib_node); if ((state & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) { /* Found an attached node */ prop_entries = di_prop_lookup_ints( DDI_DEV_T_ANY, sib_node, "port", &port_data); if (prop_entries != -1) { /* Found a node with "port" property */ minor_node = di_minor_next(sib_node, DI_MINOR_NIL); break; } } sib_node = di_sibling_node(sib_node); } if (sib_node == DI_NODE_NIL) { goto try_next; } path = di_devfs_path(sib_node); (void) strcpy(phys_path, "/devices"); (void) strncat(phys_path, path, strlen(path)); di_devfs_path_free(path); if (fflag && (strstr((char *)bootpath, (char *)phys_path) != NULL)) { (void) fprintf(stderr, MSGSTR(21117, "Ignoring %s (bootpath)\n"), phys_path); node = di_drv_next_node(node); continue; } if (minor_node) { (void) strncat(phys_path, ":", 1); (void) strncat(phys_path, di_minor_name(minor_node), strlen(di_minor_name(minor_node))); } (void) fprintf(stdout, MSGSTR(21107, "\n Opening Device: %s\n"), phys_path); /* Check if the device is valid */ if ((fd = open(phys_path, O_RDWR)) < 0) { (void) fprintf(stderr, MSGSTR(21121, "Error: Could not open %s, failed " "with errno %d\n"), phys_path, errno); retval++; node = di_drv_next_node(node); continue; } (void) close(fd); /* * Check FCode version present on the adapter * (at last boot) */ memset(prom_ver_data, 0, sizeof (prom_ver_data)); if (emulex_fcodeversion(node, (uchar_t *)&prom_ver_data[0]) == 0) { errnum = 0; if (strlen((char *)prom_ver_data) == 0) { (void) fprintf(stdout, MSGSTR(21108, " Detected FCode Version:\tNo version available for this FCode\n")); } else { (void) fprintf(stdout, MSGSTR(21109, " Detected FCode Version:\t%s\n"), prom_ver_data); } } else { errnum = 2; /* can't get prom properties */ retval++; } if (fflag) { memset(ver_file, 0, sizeof (ver_file)); if (emulex_fcode_reader(fcode_fd, "fcode-version", ver_file, sizeof (ver_file)) == 0) { (void) fprintf(stdout, MSGSTR(21110, " New FCode Version:\t\t%s\n"), ver_file); } else { di_fini(root); (void) close(fcode_fd); return (1); } /* * Load the New FCode * Give warning if file doesn't appear to be correct */ if (!q_warn(errnum)) { /* Disable user-interrupt Control-C */ sigint = (void (*)(int)) signal(SIGINT, SIG_IGN); /* Load FCode */ (void) fprintf(stdout, MSGSTR(21111, " Loading FCode: %s\n"), file); if (fcode_load_file(fcode_fd, phys_path, &fcio_errno) == FCODE_SUCCESS) { (void) fprintf(stdout, MSGSTR(21112, " Successful FCode download: %s\n"), phys_path); } else { handle_emulex_error(fcio_errno, phys_path); retval++; } /* Restore SIGINT (user interrupt) setting */ (void) signal(SIGINT, sigint); } } try_next: node = di_drv_next_node(node); } di_fini(root); (void) fprintf(stdout, " "); (void) fprintf(stdout, MSGSTR(125, "Complete\n")); if (fcode_fd != -1) (void) close(fcode_fd); return (retval); } /* * Retrieve the version from the card. * uses PROM properties */ static int emulex_fcodeversion(di_node_t node, uchar_t *ver) { di_prom_prop_t promprop; di_prom_handle_t ph; char *promname; uchar_t *ver_data = NULL; int size, found = 0; /* check to make sure ver is not NULL */ if (ver == NULL) { return (1); } if ((ph = di_prom_init()) == DI_PROM_HANDLE_NIL) { return (1); } for (promprop = di_prom_prop_next(ph, node, DI_PROM_PROP_NIL); promprop != DI_PROM_PROP_NIL; promprop = di_prom_prop_next(ph, node, promprop)) { if (((promname = di_prom_prop_name( promprop)) != NULL) && (strcmp(promname, "fcode-version") == 0)) { size = di_prom_prop_data(promprop, &ver_data); (void) memset(ver, 0, size); (void) memcpy(ver, ver_data, size); found = 1; } } if (found) { return (0); } else { return (1); } } /* * Retrieves information from the Emulex fcode * * Given a pattern, this routine will look for this pattern in the fcode * file and if found will return the pattern value * * possible patterns are manufacturer and fcode-version */ int emulex_fcode_reader(int fcode_fd, char *pattern, char *pattern_value, uint32_t pattern_value_size) { int32_t i = 0; uint32_t n = 0; uint32_t b = 0; char byte1; char byte2; char byte3; char byte4; char buffer1[EMULEX_READ_BUFFER_SIZE]; char buffer2[EMULEX_READ_BUFFER_SIZE]; uint32_t plen, image_size; struct stat stat; uchar_t *image; /* Check the arguments */ if (!fcode_fd || !pattern_value || pattern_value_size < 8) { return (1); } if (fstat(fcode_fd, &stat) == -1) { perror(MSGSTR(21023, "fstat")); return (1); } image_size = stat.st_size; if (image_size < 2) { return (1); } if ((image = (uchar_t *)calloc(image_size, 1)) == NULL) { (void) fprintf(stderr, MSGSTR(21013, "Error: Memory allocation failed\n")); return (1); } /* Read the fcode image file */ lseek(fcode_fd, 0, SEEK_SET); read(fcode_fd, image, image_size); /* Initialize */ bzero(buffer1, sizeof (buffer1)); bzero(buffer2, sizeof (buffer2)); /* Default pattern_value string */ strcpy((char *)pattern_value, ""); plen = strlen(pattern); n = 0; b = 0; i = 0; /* Search entire image for pattern string */ while (i <= (image_size - 2)) { /* Read next two bytes */ byte1 = image[i++]; byte2 = image[i++]; /* Check second byte first due to endianness */ /* Save byte in circular buffer */ buffer1[b++] = byte2; if (b == sizeof (buffer1)) { b = 0; } /* Check byte for pattern match */ if (pattern[n++] != byte2) { /* If no match, then reset pattern */ n = 0; } else { /* * If complete pattern has been matched then * exit loop */ if (n == plen) { goto found; } } /* Check first byte second due to endianness */ /* Save byte in circular buffer */ buffer1[b++] = byte1; if (b == sizeof (buffer1)) { b = 0; } /* Check byte for pattern match */ if (pattern[n++] != byte1) { /* If no match, then reset pattern */ n = 0; } else { /* * If complete pattern has been matched * then exit loop */ if (n == plen) { goto found; } } } /* Not found. Try again with different endianess */ /* Initialize */ bzero(buffer1, sizeof (buffer1)); bzero(buffer2, sizeof (buffer2)); n = 0; b = 0; i = 0; /* Search entire 32bit endian image for pattern string */ while (i <= (image_size - 4)) { /* Read next four bytes */ byte1 = image[i++]; byte2 = image[i++]; byte3 = image[i++]; byte4 = image[i++]; /* Save byte in circular buffer */ buffer1[b++] = byte4; if (b == sizeof (buffer1)) { b = 0; } /* Check byte for pattern match */ if (pattern[n++] != byte4) { /* If no match, then reset pattern */ n = 0; } else { /* * If complete pattern has been matched then exit loop */ if (n == plen) { goto found; } } /* Save byte in circular buffer */ buffer1[b++] = byte3; if (b == sizeof (buffer1)) { b = 0; } /* Check byte for pattern match */ if (pattern[n++] != byte3) { /* If no match, then reset pattern */ n = 0; } else { /* * If complete pattern has been matched then exit loop */ if (n == plen) { goto found; } } /* Save byte in circular buffer */ buffer1[b++] = byte2; if (b == sizeof (buffer1)) { b = 0; } /* Check byte for pattern match */ if (pattern[n++] != byte2) { /* If no match, then reset pattern */ n = 0; } else { /* * If complete pattern has been matched then exit loop */ if (n == plen) { goto found; } } /* Save byte in circular buffer */ buffer1[b++] = byte1; if (b == sizeof (buffer1)) { b = 0; } /* Check byte for pattern match */ if (pattern[n++] != byte1) { /* If no match, then reset pattern */ n = 0; } else { /* * If complete pattern has been matched then exit loop */ if (n == plen) { goto found; } } } free(image); return (1); found: free(image); /* Align buffer and eliminate non-printable characters */ for (i = 0; i < (sizeof (buffer1)-plen); i++) { byte1 = buffer1[b++]; if (b == sizeof (buffer1)) { b = 0; } /* Zero any non-printable characters */ if (byte1 >= 33 && byte1 <= 126) { buffer2[i] = byte1; } else { buffer2[i] = 0; } } /* * Scan backwards for first non-zero string. This will be the * version string */ for (i = sizeof (buffer1)-plen-1; i >= 0; i--) { if (buffer2[i] != 0) { for (; i >= 0; i--) { if (buffer2[i] == 0) { i++; strncpy((char *)pattern_value, &buffer2[i], pattern_value_size); break; } } break; } } return (0); } /* * error handling routine to handle emulex error conditions */ static void handle_emulex_error(int fcio_errno, char *phys_path) { if (fcio_errno == EMLX_IMAGE_BAD) { fprintf(stderr, MSGSTR(21119, "Error: Fcode download failed. " "Bad fcode image.\n")); } else if (fcio_errno == EMLX_IMAGE_INCOMPATIBLE) { fprintf(stderr, MSGSTR(21120, "Error: Fcode download failed. Fcode is not " "compatible with card.\n")); } else { (void) fprintf(stderr, MSGSTR(21036, "Error: Driver interface FCIO_DOWNLOAD_FCODE failed\n")); (void) fprintf(stderr, MSGSTR(21113, "Error: FCode download failed: %s\n"), phys_path); } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * I18N message number ranges * This file: 6000 - 6499 * Shared common messages: 1 - 1999 */ #include #include #include #include #include #include #include #include #include #include #include /* * For i18n */ #include /* * 128 is the size of the largest (currently) property name * 8192 - MAXPROPSIZE - sizeof (int) is the size of the largest * (currently) property value, viz. nvramrc. * the sizeof(uint_t) is from struct openpromio */ #define MAXPROPSIZE 128 #define MAXVALSIZE (8192 - MAXPROPSIZE - sizeof (uint_t)) #define BOOTDEV_PROP_NAME "boot-device" static int getbootdevname(char *, char *); static int setprom(unsigned, unsigned, char *); extern int devfs_dev_to_prom_name(char *, char *); /* * Call getbootdevname() to get the absolute pathname of boot device * and call setprom() to set the boot-device variable. */ int setboot(unsigned int yes, unsigned int verbose, char *fname) { char bdev[MAXPATHLEN]; if (!getbootdevname(fname, bdev)) { (void) fprintf(stderr, MSGSTR(6000, "Cannot determine device name for %s\n"), fname); return (errno); } return (setprom(yes, verbose, bdev)); } /* * Read the mnttab and resolve the special device of the fs we are * interested in, into an absolute pathname */ static int getbootdevname(char *bootfs, char *bdev) { FILE *f; char *fname; char *devname; struct mnttab m; struct stat sbuf; int mountpt = 0; int found = 0; devname = bootfs; if (stat(bootfs, &sbuf) < 0) { perror(MSGSTR(6001, "stat")); return (0); } switch (sbuf.st_mode & S_IFMT) { case S_IFBLK: break; default: mountpt = 1; break; } if (mountpt) { fname = MNTTAB; f = fopen(fname, "r"); if (f == NULL) { perror(fname); return (0); } while (getmntent(f, &m) == 0) { if (strcmp(m.mnt_mountp, bootfs)) continue; else { found = 1; break; } } (void) fclose(f); if (!found) { return (0); } devname = m.mnt_special; } if (devfs_dev_to_prom_name(devname, bdev) != 0) { perror(devname); return (0); } return (1); } /* * setprom() - use /dev/openprom to read the "boot_device" variable and set * it to the new value. */ static int setprom(unsigned yes, unsigned verbose, char *bdev) { struct openpromio *pio; int fd; char save_bootdev[MAXVALSIZE]; if ((fd = open("/dev/openprom", O_RDWR)) < 0) { perror(MSGSTR(6002, "Could not open openprom dev")); return (errno); } pio = (struct openpromio *)malloc(sizeof (struct openpromio) + MAXVALSIZE + MAXPROPSIZE); if (pio == (struct openpromio *)NULL) { perror(MSGSTR(6003, " Error: Unable to allocate memory.")); return (errno); } pio->oprom_size = MAXVALSIZE; (void) strcpy(pio->oprom_array, BOOTDEV_PROP_NAME); if (ioctl(fd, OPROMGETOPT, pio) < 0) { perror(MSGSTR(6004, "openprom getopt ioctl")); return (errno); } /* * save the existing boot-device, so we can use it if setting * to new value fails. */ (void) strcpy(save_bootdev, pio->oprom_array); if (verbose) { (void) fprintf(stdout, MSGSTR(6005, "Current boot-device = %s\n"), pio->oprom_array); (void) fprintf(stdout, MSGSTR(6006, "New boot-device = %s\n"), bdev); } if (!yes) { (void) fprintf(stdout, MSGSTR(6007, "Do you want to change boot-device " "to the new setting? (y/n) ")); switch (getchar()) { case 'Y': case 'y': break; default: return (0); } } /* set the new value for boot-device */ pio->oprom_size = (int)strlen(BOOTDEV_PROP_NAME) + 1 + (int)strlen(bdev); (void) strcpy(pio->oprom_array, BOOTDEV_PROP_NAME); (void) strcpy(pio->oprom_array + (int)strlen(BOOTDEV_PROP_NAME) + 1, bdev); if (ioctl(fd, OPROMSETOPT, pio) < 0) { perror(MSGSTR(6008, "openprom setopt ioctl")); return (errno); } /* read back the value that was set */ pio->oprom_size = MAXVALSIZE; (void) strcpy(pio->oprom_array, BOOTDEV_PROP_NAME); if (ioctl(fd, OPROMGETOPT, pio) < 0) { perror(MSGSTR(6009, "openprom getopt ioctl")); return (errno); } if (strcmp(bdev, pio->oprom_array)) { /* could not set the new device name, set the old one back */ perror(MSGSTR(6010, "Could not set boot-device, reverting to old value")); pio->oprom_size = (int)strlen(BOOTDEV_PROP_NAME) + 1 + (int)strlen(save_bootdev); (void) strcpy(pio->oprom_array, BOOTDEV_PROP_NAME); (void) strcpy(pio->oprom_array + (int)strlen(BOOTDEV_PROP_NAME) + 1, save_bootdev); if (ioctl(fd, OPROMSETOPT, pio) < 0) { perror(MSGSTR(6011, "openprom setopt ioctl")); return (errno); } } (void) close(fd); return (0); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include "common.h" #include "errorcodes.h" #include /* The i18n catalog */ nl_catd l_catd; void i18n_catopen() { static int fileopen = 0; if (setlocale(LC_ALL, "") == NULL) { (void) fprintf(stderr, "Cannot operate in the locale requested. " "Continuing in the default C locale\n"); } if (!fileopen) { l_catd = catopen("a5k_g_fc_i18n_cat", NL_CAT_LOCALE); if (l_catd == (nl_catd)-1) { return; } fileopen = 1; } return; } /* * Given an error number, this functions * calls the get_errString() to print a * corresponding error message to the stderr. * get_errString() always returns an error * message, even in case of undefined error number. * So, there is no need to check for a NULL pointer * while printing the error message to the stdout. * * RETURNS: N/A * */ void print_errString(int errnum, char *devpath) { char *errStr; errStr = get_errString(errnum); if (devpath == NULL) { (void) fprintf(stderr, "%s \n\n", errStr); } else { (void) fprintf(stderr, "%s - %s.\n\n", errStr, devpath); } /* free the allocated memory for error string */ if (errStr != NULL) (void) free(errStr); } static void terminate() { fprintf(stdout, MSGSTR(2506, "Unsupported")); fprintf(stdout, "\n"); exit(1); } /*ARGSUSED*/ int adm_display_config(char **a) { terminate(); return (1); } /*ARGSUSED*/ void adm_download(char **a, char *b) { terminate(); } /*ARGSUSED*/ void up_encl_name(char **a, int b) { terminate(); } void adm_failover(char **argv) { int path_index = 0, err = 0, fd; char path_class[MAXNAMELEN]; char client_path[MAXPATHLEN]; char *path_phys = NULL, *trailingMinor; sv_switch_to_cntlr_iocdata_t iocsc; (void) memset(path_class, 0, sizeof (path_class)); (void) strcpy(path_class, argv[path_index++]); if ((strcmp(path_class, "primary") != 0) && (strcmp(path_class, "secondary") != 0)) { (void) fprintf(stderr, MSGSTR(2300, "Incorrect pathclass\n")); exit(-1); } if ((fd = open("/devices/scsi_vhci:devctl", O_RDWR)) < 0) { print_errString(L_OPEN_PATH_FAIL, "/devices/scsi_vhci:devctl"); exit(-1); } iocsc.client = client_path; iocsc.class = path_class; while (argv[path_index] != NULL) { path_phys = get_slash_devices_from_osDevName(argv[path_index++], STANDARD_DEVNAME_HANDLING); if ((path_phys == NULL) || (strstr(path_phys, "/devices/scsi_vhci") == NULL)) { (void) fprintf(stderr, MSGSTR(2301, "Incorrect pathname\n")); close(fd); exit(-1); } strcpy(iocsc.client, path_phys + strlen("/devices")); /* Now chop off the trailing ":xxx" portion if present */ if ((trailingMinor = strrchr(iocsc.client, ':')) != NULL) { trailingMinor[0] = '\0'; } if (ioctl(fd, SCSI_VHCI_SWITCH_TO_CNTLR, &iocsc) != 0) { switch (errno) { case EALREADY: err = L_SCSI_VHCI_ALREADY_ACTIVE; break; case ENXIO: err = L_INVALID_PATH; break; case EIO: err = L_SCSI_VHCI_NO_STANDBY; break; case ENOTSUP: err = L_SCSI_VHCI_FAILOVER_NOTSUP; break; case EBUSY: err = L_SCSI_VHCI_FAILOVER_BUSY; break; case EFAULT: default: err = L_SCSI_VHCI_ERROR; } } if (err != 0) { close(fd); print_errString(err, path_phys); exit(-1); } } close(fd); } /*ARGSUSED*/ int adm_inquiry(char **a) { terminate(); return (1); } /*ARGSUSED*/ void pho_probe() { terminate(); } /*ARGSUSED*/ void non_encl_probe() { terminate(); } /*ARGSUSED*/ void adm_led(char **a, int b) { terminate(); } /*ARGSUSED*/ void up_password(char **a) { terminate(); } /*ARGSUSED*/ int adm_reserve(char *path) { terminate(); return (1); } /*ARGSUSED*/ int adm_release(char *path) { terminate(); return (1); } /*ARGSUSED*/ int adm_start(char **a) { terminate(); return (1); } /*ARGSUSED*/ int adm_stop(char **a) { terminate(); return (1); } /*ARGSUSED*/ int adm_power_off(char **a, int b) { terminate(); return (1); } int adm_forcelip(char **argv) { int path_index = 0, fd; uint64_t wwn; fcio_t fcio; HBA_HANDLE handle; HBA_ADAPTERATTRIBUTES hbaAttrs; HBA_PORTATTRIBUTES portAttrs; HBA_FCPTARGETMAPPINGV2 *map; HBA_STATUS status; int count, adapterIndex, portIndex, mapIndex; char name[256]; int matched, ret = 0, wwnCompare = 0, ntries; char *physical = NULL, *slash_OSDeviceName = NULL; if ((status = loadLibrary())) { /* loadLibrary print out error msg */ return (ret++); } for (path_index = 0; argv[path_index] != NULL; path_index++) { if (is_wwn(argv[path_index])) { (void) sscanf(argv[path_index], "%016llx", &wwn); wwnCompare = 1; } else if (!is_path(argv[path_index])) { print_errString(L_INVALID_PATH, argv[path_index]); ret++; continue; } if (!wwnCompare) { /* Convert the paths to phsyical paths */ physical = get_slash_devices_from_osDevName(argv[path_index], STANDARD_DEVNAME_HANDLING); if (!physical) { print_errString(L_INVALID_PATH, argv[path_index]); ret++; continue; } } count = getNumberOfAdapters(); matched = 0; for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) { status = HBA_GetAdapterName(adapterIndex, (char *)&name); if (status != HBA_STATUS_OK) { /* May have been DR'd */ continue; } handle = HBA_OpenAdapter(name); if (handle == 0) { /* May have been DR'd */ continue; } if (getAdapterAttrs(handle, name, &hbaAttrs)) { /* Should never happen */ HBA_CloseAdapter(handle); continue; } /* Loop over all HBA Ports */ for (portIndex = 0; portIndex < hbaAttrs.NumberOfPorts; portIndex++) { if (getAdapterPortAttrs(handle, name, portIndex, &portAttrs)) { continue; } matched = 0; if (is_wwn(argv[path_index])) { if (wwn == wwnConversion( portAttrs.NodeWWN.wwn) || wwn == wwnConversion( portAttrs.PortWWN.wwn)) { matched = 1; } } else { slash_OSDeviceName = get_slash_devices_from_osDevName( portAttrs.OSDeviceName, STANDARD_DEVNAME_HANDLING); if (!slash_OSDeviceName) { continue; } else { if (strncmp(physical, slash_OSDeviceName, strlen(slash_OSDeviceName) - strlen(strrchr(slash_OSDeviceName, ':'))) == 0) { matched = 1; } free(slash_OSDeviceName); } } if (!matched) { if (!fetch_mappings(handle, portAttrs.PortWWN, &map)) { /* * matchr_mapping checks the arg * so we pass argv here. */ mapIndex = match_mappings(argv[path_index], map); if (mapIndex >= 0) { matched = 1; } } else { continue; } } if (matched) { if ((fd = open(portAttrs.OSDeviceName, O_RDONLY | O_EXCL)) == -1) { print_errString(L_OPEN_PATH_FAIL, portAttrs.OSDeviceName); return (ret++); } fcio.fcio_cmd = FCIO_RESET_LINK; fcio.fcio_xfer = FCIO_XFER_WRITE; /* * Reset the local loop here (fcio_ibuf = 0). * Reset a remote loop on the Fabric by * passing its node wwn (fcio_len = sizeof(nwwn) * and fcio_ibuf = (caddr_t)&nwwn) to the port driver. */ (void) memset(&wwn, 0, sizeof (wwn)); fcio.fcio_ilen = sizeof (wwn); fcio.fcio_ibuf = (caddr_t)&wwn; for (ntries = 0; ntries < RETRY_FCIO_IOCTL; ntries++) { errno = 0; if (ioctl(fd, FCIO_CMD, &fcio) != 0) { /* * When port is offlined, qlc * returns the FC_OFFLINE error and errno * is set to EIO. * We do want to ignore this error, * especially when an enclosure is * removed from the loop. */ if (fcio.fcio_errno == FC_OFFLINE) break; if ((errno == EAGAIN) && (ntries+1 < RETRY_FCIO_IOCTL)) { /* wait WAIT_FCIO_IOCTL */ (void) usleep(WAIT_FCIO_IOCTL); continue; } I_DPRINTF("FCIO ioctl failed.\n" "Error: %s. fc_error = %d (0x%x)\n", strerror(errno), fcio.fcio_errno, fcio.fcio_errno); close(fd); print_errString(L_FCIO_FORCE_LIP_FAIL, portAttrs.OSDeviceName); return (ret++); } else { break; /* ioctl succeeds. */ } } close(fd); if (ntries == RETRY_FCIO_IOCTL) { print_errString(L_FCIO_FORCE_LIP_FAIL, portAttrs.OSDeviceName); return (ret++); } } if (matched) break; /* for HBA port for loop */ } if (matched) /* HBA adapter for loop */ break; } if (!matched) { print_errString(L_INVALID_PATH, argv[path_index]); ret++; } } HBA_FreeLibrary(); return (ret); } /*ARGSUSED*/ void adm_bypass_enable(char **argv, int bypass_flag) { terminate(); } /*ARGSUSED*/ int adm_port_offline_online(char **a, int b) { terminate(); return (1); } /*ARGSUSED*/ void display_link_status(char **a) { terminate(); } /*ARGSUSED*/ void dump_map(char **argv) { terminate(); } /*ARGSUSED*/ int adm_display_port(int a) { terminate(); return (1); } /*ARGSUSED*/ int adm_port_loopback(char *a, int b) { terminate(); return (1); } /*ARGSUSED*/ int hotplug_e(int todo, char **argv, int verbose_flag, int force_flag) { terminate(); return (1); } /*ARGSUSED*/ int setboot(unsigned int yes, unsigned int verbose, char *fname) { terminate(); return (1); } /*ARGSUSED*/ int hotplug(int todo, char **argv, int verbose_flag, int force_flag) { terminate(); return (1); } /*ARGSUSED*/ int adm_check_file(char **argv, int flag) { terminate(); return (1); } /*ARGSUSED*/ int sysdump(int verbose) { terminate(); return (1); } /*ARGSUSED*/ int fcal_update(unsigned int verbose, char *file) { terminate(); return (1); } /*ARGSUSED*/ int q_qlgc_update(unsigned int verbose, char *file) { terminate(); return (1); } /*ARGSUSED*/ int emulex_update(char *file) { terminate(); return (1); } /*ARGSUSED*/ int emulex_fcode_reader(int fcode_fd, char *pattern, char *pattern_value, uint32_t pattern_value_size) { terminate(); return (1); } /*ARGSUSED*/ void dump(char **argv) { terminate(); } /*ARGSUSED*/ int h_insertSena_fcdev() { terminate(); return (1); }