summaryrefslogtreecommitdiff
path: root/usr/src/cmd/luxadm/adm.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/cmd/luxadm/adm.c')
-rw-r--r--usr/src/cmd/luxadm/adm.c1104
1 files changed, 1104 insertions, 0 deletions
diff --git a/usr/src/cmd/luxadm/adm.c b/usr/src/cmd/luxadm/adm.c
new file mode 100644
index 0000000000..cb2ad51b43
--- /dev/null
+++ b/usr/src/cmd/luxadm/adm.c
@@ -0,0 +1,1104 @@
+/*
+ * 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*/
+
+
+/*
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <sys/file.h>
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <strings.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <termio.h> /* For password */
+#include <sys/scsi/scsi.h>
+
+#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;
+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);
+}