1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * Administration program for SENA
28 * subsystems and individual FC_AL devices.
29 */
30
31 /*
32 * I18N message number ranges
33 * This file: 2000 - 2999
34 * Shared common messages: 1 - 1999
35 */
36
37 /* #define _POSIX_SOURCE 1 */
38
39 /*
40 * These defines are used to map instance number from sf minor node.
41 * They are copied from SF_INST_SHIFT4MINOR and SF_MINOR2INST in sfvar.h.
42 * sfvar.h is not clean for userland use.
43 * When it is cleaned up, these defines will be removed and sfvar.h
44 * will be included in luxadm.h header file.
45 */
46 #define LUX_SF_INST_SHIFT4MINOR 6
47 #define LUX_SF_MINOR2INST(x) (x >> LUX_SF_INST_SHIFT4MINOR)
48
49 /* Includes */
50 #include <stdlib.h>
51 #include <stdio.h>
52 #include <sys/file.h>
53 #include <sys/errno.h>
54 #include <sys/types.h>
55 #include <sys/stat.h>
56 #include <sys/param.h>
57 #include <fcntl.h>
58 #include <unistd.h>
59 #include <errno.h>
60 #include <string.h>
61 #include <ctype.h>
62 #include <strings.h>
63 #include <sys/stat.h>
64 #include <dirent.h>
65 #include <limits.h>
66 #include <stdarg.h>
67 #include <termio.h> /* For password */
68 #include <sys/scsi/scsi.h>
69
70 #include "common.h"
71 #include "luxadm.h"
72
73
74 /* Global variables */
75 char *dtype[16]; /* setting a global for later use. */
76 char *whoami;
77 int Options;
78 const int OPTION_A = 0x00000001;
79 const int OPTION_B = 0x00000002;
80 const int OPTION_C = 0x00000004;
81 const int OPTION_D = 0x00000008;
82 const int OPTION_E = 0x00000010;
83 const int OPTION_F = 0x00000020;
84 const int OPTION_L = 0x00000040;
85 const int OPTION_P = 0x00000080;
86 const int OPTION_R = 0x00000100;
87 const int OPTION_T = 0x00000200;
88 const int OPTION_V = 0x00000400;
89 const int OPTION_Z = 0x00001000;
90 const int OPTION_Y = 0x00002000;
91 const int OPTION_CAPF = 0x00004000;
92 const int PVERBOSE = 0x00008000;
93 const int SAVE = 0x00010000;
94 const int EXPERT = 0x00020000;
95
96 /*
97 * Given a pointer to a character array, print the character array.
98 * the character array will not necesarily be NULL terminated.
99 *
100 * Inputs:
101 * size - the max number of characters to print
102 * fill_flag - flag when set fills all NULL characters with spaces
103 * Returns:
104 * N/A
105 */
106 void
print_chars(uchar_t * buffer,int size,int fill_flag)107 print_chars(uchar_t *buffer, int size, int fill_flag)
108 {
109
110 int i;
111
112 for (i = 0; i < size; i++) {
113 if (buffer[i])
114 (void) fprintf(stdout, "%c", buffer[i]);
115 else if (fill_flag)
116 (void) fprintf(stdout, " ");
117 else
118 return;
119 }
120 }
121
122 /*
123 * Name : memstrstr
124 * Input : pointer to buf1, pointer to buf2, size of buf1, size of buf2
125 * Returns :
126 * Pointer to start of contents-of-buf2 in buf1 if it is found
127 * NULL if buf1 does not contain contents of buf2
128 * Synopsis:
129 * This function works similar to strstr(). The difference is that null
130 * characters in the buffer are treated like any other character. So, buf1
131 * and buf2 can have embedded null characters in them.
132 */
133 static char *
memstrstr(char * s1,char * s2,int size1,int size2)134 memstrstr(char *s1, char *s2, int size1, int size2)
135 {
136 int count1, count2;
137 char *s1_ptr, *s2_ptr;
138
139 count1 = size1; count2 = size2;
140 s1_ptr = s1; s2_ptr = s2;
141
142 if (size2 == 0)
143 return (s1);
144
145 while (count1--) {
146 if (*s1_ptr++ == *s2_ptr++) {
147 if (--count2 == 0)
148 return (s1_ptr - size2);
149 continue;
150 }
151 count2 = size2;
152 s2_ptr = s2;
153 }
154
155 return (NULL);
156 }
157
158
159 /*
160 * Download host bus adapter FCode to all supported cards.
161 *
162 * Specify a directory that holds the FCode files, or
163 * it will use the default dir. Each file is dealt to
164 * the appropriate function.
165 *
166 * -p prints current versions only, -d specifies a directory to load
167 */
168 static int
adm_fcode(int verbose,char * dir)169 adm_fcode(int verbose, char *dir)
170 {
171 struct stat statbuf;
172 struct dirent *dirp;
173 DIR *dp;
174 int fp;
175 char fbuf[BUFSIZ];
176 char file[MAXPATHLEN];
177 int retval = 0, strfound = 0;
178 char manf[BUFSIZ];
179
180 /* Find all adapters and print the current FCode version */
181 if (Options & OPTION_P) {
182
183 /* SOCAL (SBus) adapters are not supported on x86 */
184 #ifndef __x86
185 if (verbose) {
186 (void) fprintf(stdout,
187 MSGSTR(2215, "\n Searching for FC100/S cards:\n"));
188 }
189 retval += fcal_update(Options & PVERBOSE, NULL);
190 #endif
191
192 if (verbose) {
193 (void) fprintf(stdout,
194 MSGSTR(2216, "\n Searching for FC100/P, FC100/2P cards:\n"));
195 }
196 retval += q_qlgc_update(Options & PVERBOSE, NULL);
197 if (verbose) {
198 (void) fprintf(stdout,
199 MSGSTR(2503, "\n Searching for Emulex cards:\n"));
200 }
201 retval += emulex_update(NULL);
202
203 /* Send files to the correct function for loading to the HBA */
204 } else {
205
206 if (!dir) {
207 (void) fprintf(stdout, MSGSTR(2251,
208 " Location of Fcode not specified.\n"));
209 return (1);
210
211 } else if (verbose) {
212 (void) fprintf(stdout, MSGSTR(2217,
213 " Using directory %s"), dir);
214 }
215 if (lstat(dir, &statbuf) < 0) {
216 (void) fprintf(stderr, MSGSTR(134,
217 "%s: lstat() failed - %s\n"),
218 dir, strerror(errno));
219 return (1);
220 }
221 if (S_ISDIR(statbuf.st_mode) == 0) {
222 (void) fprintf(stderr,
223 MSGSTR(2218, "Error: %s is not a directory.\n"), dir);
224 return (1);
225 }
226 if ((dp = opendir(dir)) == NULL) {
227 (void) fprintf(stderr, MSGSTR(2219,
228 " Error Cannot open directory %s\n"), dir);
229 return (1);
230 }
231
232 while ((dirp = readdir(dp)) != NULL) {
233 if (strcmp(dirp->d_name, ".") == 0 ||
234 strcmp(dirp->d_name, "..") == 0) {
235 continue;
236 }
237 sprintf(file, "%s/%s", dir, dirp->d_name);
238
239 if ((fp = open(file, O_RDONLY)) < 0) {
240 (void) fprintf(stderr,
241 MSGSTR(2220,
242 "Error: open() failed to open file "
243 "%s\n"), file);
244 /*
245 * We should just issue an error message and
246 * make an attempt on the next file,
247 * and the open error is still an error
248 * so the retval should be incremented
249 */
250 retval++;
251 continue;
252 }
253 while ((read(fp, fbuf, BUFSIZ)) > 0) {
254 if (memstrstr(fbuf, "SUNW,socal",
255 BUFSIZ, strlen("SUNW,socal"))
256 != NULL) {
257 (void) fprintf(stdout, MSGSTR(2221,
258 "\n Using file: %s\n"), file);
259 retval += fcal_update(
260 Options & PVERBOSE, file);
261 strfound++;
262 break;
263 } else if ((memstrstr(fbuf, "SUNW,ifp",
264 BUFSIZ, strlen("SUNW,ifp"))
265 != NULL) ||
266 (memstrstr(fbuf, "SUNW,qlc",
267 BUFSIZ, strlen("SUNW,qlc"))
268 != NULL)) {
269 (void) fprintf(stdout, MSGSTR(2221,
270 "\n Using file: %s\n"), file);
271 retval += q_qlgc_update(
272 Options & PVERBOSE, file);
273 strfound++;
274 break;
275 }
276 }
277 if (!strfound) {
278 /* check to see if this is an emulex fcode */
279 memset(manf, 0, sizeof (manf));
280 if ((emulex_fcode_reader(fp, "manufacturer",
281 manf,
282 sizeof (manf)) == 0) &&
283 (strncmp(manf, "Emulex", sizeof (manf))
284 == 0)) {
285 retval += emulex_update(file);
286 strfound = 0;
287 } else {
288 (void) fprintf(stderr, MSGSTR(2222,
289 "\nError: %s is not a valid Fcode "
290 "file.\n"), file);
291 retval++;
292 }
293 } else {
294 strfound = 0;
295 }
296 close(fp);
297 }
298 closedir(dp);
299 }
300 return (retval);
301 }
302
303 /*
304 * Definition of getaction() routine which does keyword parsing
305 *
306 * Operation: A character string containing the ascii cmd to be
307 * parsed is passed in along with an array of structures.
308 * The 1st struct element is a recognizable cmd string, the second
309 * is the minimum number of characters from the start of this string
310 * to succeed on a match. For example, { "offline", 3, ONLINE }
311 * will match "off", "offli", "offline", but not "of" nor "offlinebarf"
312 * The third element is the {usually but not necessarily unique}
313 * integer to return on a successful match. Note: compares are cAsE insensitive.
314 *
315 * To change, extend or use this utility, just add or remove appropriate
316 * lines in the structure initializer below and in the #define s for the
317 * return values.
318 *
319 * N O T E
320 * Do not change the minimum number of characters to produce
321 * a match as someone may be building scripts that use this
322 * feature.
323 */
324 struct keyword {
325 char *match; /* Character String to match against */
326 int num_match; /* Minimum chars to produce a match */
327 int ret_code; /* Value to return on a match */
328 };
329
330 static struct keyword Keywords[] = {
331 {"display", 2, DISPLAY},
332 {"download", 3, DOWNLOAD},
333 {"enclosure_names", 2, ENCLOSURE_NAMES},
334 {"failover", 3, FAILOVER},
335 {"fcal_s_download", 4, FCAL_UPDATE},
336 {"fcode_download", 4, FCODE_UPDATE},
337 {"inquiry", 2, INQUIRY},
338 {"insert_device", 3, INSERT_DEVICE},
339 {"led", 3, LED},
340 {"led_on", 5, LED_ON},
341 {"led_off", 5, LED_OFF},
342 {"led_blink", 5, LED_BLINK},
343 {"password", 2, PASSWORD},
344 {"power_on", 8, POWER_ON},
345 {"power_off", 9, POWER_OFF},
346 {"probe", 2, PROBE},
347 {"qlgc_s_download", 4, QLGC_UPDATE},
348 {"remove_device", 3, REMOVE_DEVICE},
349 {"reserve", 5, RESERVE},
350 {"release", 3, RELEASE},
351 {"set_boot_dev", 5, SET_BOOT_DEV},
352 {"start", 3, START},
353 {"stop", 3, STOP},
354 {"rdls", 2, RDLS},
355 {"bypass", 3, BYPASS},
356 {"enable", 3, ENABLE},
357 {"p_offline", 4, LUX_P_OFFLINE},
358 {"p_online", 4, LUX_P_ONLINE},
359 {"forcelip", 2, FORCELIP},
360 {"dump", 2, DUMP},
361 {"check_file", 2, CHECK_FILE},
362 {"dump_map", 2, DUMP_MAP},
363 {"sysdump", 5, SYSDUMP},
364 {"port", 4, PORT},
365 {"external_loopback", 12, EXT_LOOPBACK},
366 {"internal_loopback", 12, INT_LOOPBACK},
367 {"no_loopback", 11, NO_LOOPBACK},
368 {"version", 2, VERSION},
369 {"create_fabric_device", 2, CREATE_FAB},
370 /* hotplugging device operations */
371 {"online", 2, DEV_ONLINE},
372 {"offline", 2, DEV_OFFLINE},
373 {"dev_getstate", 5, DEV_GETSTATE},
374 {"dev_reset", 5, DEV_RESET},
375 /* hotplugging bus operations */
376 {"bus_quiesce", 5, BUS_QUIESCE},
377 {"bus_unquiesce", 5, BUS_UNQUIESCE},
378 {"bus_getstate", 5, BUS_GETSTATE},
379 {"bus_reset", 9, BUS_RESET},
380 {"bus_resetall", 12, BUS_RESETALL},
381 /* hotplugging "helper" subcommands */
382 { NULL, 0, 0}
383 };
384
385 #ifndef EOK
386 static const int EOK = 0; /* errno.h type success return code */
387 #endif
388
389
390 /*
391 * function getaction() takes a character string, cmd, and
392 * tries to match it against a passed structure of known cmd
393 * character strings. If a match is found, corresponding code
394 * is returned in retval. Status returns as follows:
395 * EOK = Match found, look for cmd's code in retval
396 * EFAULT = One of passed parameters was bad
397 * EINVAL = cmd did not match any in list
398 */
399 static int
getaction(char * cmd,struct keyword * matches,int * retval)400 getaction(char *cmd, struct keyword *matches, int *retval)
401 {
402 int actlen;
403
404 /* Idiot checking of pointers */
405 if (! cmd || ! matches || ! retval ||
406 ! (actlen = strlen(cmd))) /* Is there an cmd ? */
407 return (EFAULT);
408
409 /* Keep looping until NULL match string (end of list) */
410 while (matches->match) {
411 /*
412 * Precedence: Make sure target is no longer than
413 * current match string
414 * and target is at least as long as
415 * minimum # match chars,
416 * then do case insensitive match
417 * based on actual target size
418 */
419 if ((((int)strlen(matches->match)) >= actlen) &&
420 (actlen >= matches->num_match) &&
421 /* can't get strncasecmp to work on SCR4 */
422 /* (strncasecmp(matches->match, cmd, actlen) == 0) */
423 (strncmp(matches->match, cmd, actlen) == 0)) {
424 *retval = matches->ret_code; /* Found our match */
425 return (EOK);
426 } else {
427 matches++; /* Next match string/struct */
428 }
429 } /* End of matches loop */
430 return (EINVAL);
431
432 } /* End of getaction() */
433
434 /* main functions. */
435 int
main(int argc,char ** argv)436 main(int argc, char **argv)
437 {
438 register int c;
439 /* getopt varbs */
440 extern char *optarg;
441 char *optstring = NULL;
442 int path_index, err = 0;
443 int cmd = 0; /* Cmd verb from cmd line */
444 int exit_code = 0; /* exit code for program */
445 int temp_fd; /* For -f option */
446 char *file_name = NULL;
447 int option_t_input = 0;
448 char *path_phys = NULL;
449 int USE_FCHBA = 0;
450
451 whoami = argv[0];
452
453
454 /*
455 * Enable locale announcement
456 */
457 i18n_catopen();
458
459 while ((c = getopt(argc, argv, "ve"))
460 != EOF) {
461 switch (c) {
462 case 'v':
463 Options |= PVERBOSE;
464 break;
465 case 'e':
466 Options |= EXPERT;
467 break;
468 default:
469 /* Note: getopt prints an error if invalid option */
470 USEAGE()
471 exit(-1);
472 } /* End of switch(c) */
473 }
474 setbuf(stdout, NULL); /* set stdout unbuffered. */
475
476 /*
477 * Build any i18n global variables
478 */
479 dtype[0] = MSGSTR(2192, "Disk device");
480 dtype[1] = MSGSTR(2193, "Tape device");
481 dtype[2] = MSGSTR(2194, "Printer device");
482 dtype[3] = MSGSTR(2195, "Processor device");
483 dtype[4] = MSGSTR(2196, "WORM device");
484 dtype[5] = MSGSTR(2197, "CD-ROM device");
485 dtype[6] = MSGSTR(2198, "Scanner device");
486 dtype[7] = MSGSTR(2199, "Optical memory device");
487 dtype[8] = MSGSTR(2200, "Medium changer device");
488 dtype[9] = MSGSTR(2201, "Communications device");
489 dtype[10] = MSGSTR(107, "Graphic arts device");
490 dtype[11] = MSGSTR(107, "Graphic arts device");
491 dtype[12] = MSGSTR(2202, "Array controller device");
492 dtype[13] = MSGSTR(2203, "SES device");
493 dtype[14] = MSGSTR(71, "Reserved");
494 dtype[15] = MSGSTR(71, "Reserved");
495
496
497
498 /*
499 * Get subcommand.
500 */
501 if ((getaction(argv[optind], Keywords, &cmd)) == EOK) {
502 optind++;
503 if ((cmd != PROBE) && (cmd != FCAL_UPDATE) &&
504 (cmd != QLGC_UPDATE) && (cmd != FCODE_UPDATE) &&
505 (cmd != INSERT_DEVICE) && (cmd != SYSDUMP) && (cmd != AU) &&
506 (cmd != PORT) && (cmd != CREATE_FAB) && (optind >= argc)) {
507 (void) fprintf(stderr,
508 MSGSTR(2204,
509 "Error: enclosure or pathname not specified.\n"));
510 USEAGE();
511 exit(-1);
512 }
513 } else {
514 (void) fprintf(stderr,
515 MSGSTR(2205, "%s: subcommand not specified.\n"),
516 whoami);
517 USEAGE();
518 exit(-1);
519 }
520
521 /* Extract & Save subcommand options */
522 if ((cmd == ENABLE) || (cmd == BYPASS)) {
523 optstring = "Ffrab";
524 } else if (cmd == FCODE_UPDATE) {
525 optstring = "pd:";
526 } else if (cmd == REMOVE_DEVICE) {
527 optstring = "F";
528 } else if (cmd == CREATE_FAB) {
529 optstring = "f:";
530 } else {
531 optstring = "Fryszabepcdlvt:f:w:";
532 }
533 while ((c = getopt(argc, argv, optstring)) != EOF) {
534 switch (c) {
535 case 'a':
536 Options |= OPTION_A;
537 break;
538 case 'b':
539 Options |= OPTION_B;
540 break;
541 case 'c':
542 Options |= OPTION_C;
543 break;
544 case 'd':
545 Options |= OPTION_D;
546 if (cmd == FCODE_UPDATE) {
547 file_name = optarg;
548 }
549 break;
550 case 'e':
551 Options |= OPTION_E;
552 break;
553 case 'f':
554 Options |= OPTION_F;
555 if (!((cmd == ENABLE) || (cmd == BYPASS))) {
556 file_name = optarg;
557 }
558 break;
559 case 'F':
560 Options |= OPTION_CAPF;
561 break;
562 case 'l':
563 Options |= OPTION_L;
564 break;
565 case 'p':
566 Options |= OPTION_P;
567 break;
568 case 'r':
569 Options |= OPTION_R;
570 break;
571 case 's':
572 Options |= SAVE;
573 break;
574 case 't':
575 Options |= OPTION_T;
576 option_t_input = atoi(optarg);
577 break;
578 case 'v':
579 Options |= OPTION_V;
580 break;
581 case 'z':
582 Options |= OPTION_Z;
583 break;
584 case 'y':
585 Options |= OPTION_Y;
586 break;
587 default:
588 /* Note: getopt prints an error if invalid option */
589 USEAGE()
590 exit(-1);
591 } /* End of switch(c) */
592 }
593 if ((cmd != PROBE) && (cmd != FCAL_UPDATE) &&
594 (cmd != QLGC_UPDATE) && (cmd != FCODE_UPDATE) &&
595 (cmd != INSERT_DEVICE) && (cmd != SYSDUMP) &&
596 (cmd != AU) && (cmd != PORT) &&
597 (cmd != CREATE_FAB) && (optind >= argc)) {
598 (void) fprintf(stderr,
599 MSGSTR(2206,
600 "Error: enclosure or pathname not specified.\n"));
601 USEAGE();
602 exit(-1);
603 }
604 path_index = optind;
605
606 /*
607 * Check if the file supplied with the -f option is valid
608 * Some sub commands (bypass for example) use the -f option
609 * for other reasons. In such cases, "file_name" should be
610 * NULL.
611 */
612 if ((file_name != NULL) && (Options & OPTION_F)) {
613 if ((temp_fd = open(file_name, O_RDONLY)) == -1) {
614 perror(file_name);
615 exit(-1);
616 } else {
617 close(temp_fd);
618 }
619 }
620
621 /* Determine which mode to operate in (FC-HBA or original) */
622 USE_FCHBA = use_fchba();
623
624 switch (cmd) {
625 case DISPLAY:
626 if (Options &
627 ~(PVERBOSE | OPTION_A | OPTION_Z | OPTION_R |
628 OPTION_P | OPTION_V | OPTION_L | OPTION_E | OPTION_T)) {
629 USEAGE();
630 exit(-1);
631 }
632 /* Display object(s) */
633 if (USE_FCHBA) {
634 exit_code = fchba_display_config(&argv[path_index],
635 option_t_input, argc - path_index);
636 } else {
637 exit_code = adm_display_config(&argv[path_index]);
638 }
639 break;
640
641 case DOWNLOAD:
642 if (Options &
643 ~(PVERBOSE | OPTION_F | SAVE)) {
644 USEAGE();
645 exit(-1);
646 }
647 adm_download(&argv[path_index], file_name);
648 break;
649
650 case ENCLOSURE_NAMES:
651 if (Options & ~PVERBOSE) {
652 USEAGE();
653 exit(-1);
654 }
655 up_encl_name(&argv[path_index], argc);
656 break;
657
658 case FAILOVER:
659 if (Options & ~PVERBOSE) {
660 USEAGE();
661 exit(-1);
662 }
663 adm_failover(&argv[path_index]);
664 break;
665
666 case INQUIRY:
667 if (Options & ~(PVERBOSE)) {
668 USEAGE();
669 exit(-1);
670 }
671 if (USE_FCHBA) {
672 exit_code = fchba_inquiry(&argv[path_index]);
673 } else {
674 exit_code = adm_inquiry(&argv[path_index]);
675 }
676 break;
677
678 case PROBE:
679 if (Options & ~(PVERBOSE | OPTION_P)) {
680 USEAGE();
681 exit(-1);
682 }
683 /*
684 * A special check just in case someone entered
685 * any characters after the -p or the probe.
686 *
687 * (I know, a nit.)
688 */
689 if (((Options & PVERBOSE) && (Options & OPTION_P) &&
690 (argc != 4)) ||
691 (!(Options & PVERBOSE) && (Options & OPTION_P) &&
692 (argc != 3)) ||
693 ((Options & PVERBOSE) && (!(Options & OPTION_P)) &&
694 (argc != 3)) ||
695 (!(Options & PVERBOSE) && (!(Options & OPTION_P)) &&
696 (argc != 2))) {
697 (void) fprintf(stderr,
698 MSGSTR(114, "Error: Incorrect number of arguments.\n"));
699 (void) fprintf(stderr, MSGSTR(2208,
700 "Usage: %s [-v] subcommand [option]\n"), whoami);
701 exit(-1);
702 }
703 if (USE_FCHBA) {
704 exit_code = fchba_non_encl_probe();
705 } else {
706 pho_probe();
707 non_encl_probe();
708 }
709 break;
710
711 case FCODE_UPDATE: /* Update Fcode in all cards */
712 if ((Options & ~(PVERBOSE)) &
713 ~(OPTION_P | OPTION_D) || argv[path_index]) {
714 USEAGE();
715 exit(-1);
716 }
717 if (!((Options & (OPTION_P | OPTION_D)) &&
718 !((Options & OPTION_P) && (Options & OPTION_D)))) {
719 USEAGE();
720 exit(-1);
721 }
722 if (adm_fcode(Options & PVERBOSE, file_name) != 0) {
723 exit(-1);
724 }
725 break;
726
727 case QLGC_UPDATE: /* Update Fcode in PCI HBA card(s) */
728 if ((Options & ~(PVERBOSE)) & ~(OPTION_F) ||
729 argv[path_index]) {
730 USEAGE();
731 exit(-1);
732 }
733 if (q_qlgc_update(Options & PVERBOSE, file_name) != 0) {
734 exit(-1);
735 }
736 break;
737
738 case FCAL_UPDATE: /* Update Fcode in Sbus soc+ card */
739 if ((Options & ~(PVERBOSE)) & ~(OPTION_F) ||
740 argv[path_index]) {
741 USEAGE();
742 exit(-1);
743 }
744 exit_code = fcal_update(Options & PVERBOSE, file_name);
745 break;
746
747 case SET_BOOT_DEV: /* Set boot-device variable in nvram */
748 exit_code = setboot(Options & OPTION_Y,
749 Options & PVERBOSE, argv[path_index]);
750 break;
751
752 case LED:
753 if (Options & ~(PVERBOSE)) {
754 USEAGE();
755 exit(-1);
756 }
757 adm_led(&argv[path_index], L_LED_STATUS);
758 break;
759 case LED_ON:
760 if (Options & ~(PVERBOSE)) {
761 USEAGE();
762 exit(-1);
763 }
764 adm_led(&argv[path_index], L_LED_ON);
765 break;
766 case LED_OFF:
767 if (Options & ~(PVERBOSE)) {
768 USEAGE();
769 exit(-1);
770 }
771 adm_led(&argv[path_index], L_LED_OFF);
772 break;
773 case LED_BLINK:
774 if (Options & ~(PVERBOSE)) {
775 USEAGE();
776 exit(-1);
777 }
778 adm_led(&argv[path_index], L_LED_RQST_IDENTIFY);
779 break;
780 case PASSWORD:
781 if (Options & ~(PVERBOSE)) {
782 USEAGE();
783 exit(-1);
784 }
785 up_password(&argv[path_index]);
786 break;
787
788 case RESERVE:
789
790 if (Options & (~PVERBOSE)) {
791 USEAGE();
792 exit(-1);
793 }
794 VERBPRINT(MSGSTR(2209,
795 " Reserving: \n %s\n"), argv[path_index]);
796 if (USE_FCHBA) {
797 struct stat sbuf;
798 /* Just stat the argument and make sure it exists */
799 if (stat(argv[path_index], &sbuf) < 0) {
800 (void) fprintf(stderr, "%s: ", whoami);
801 (void) fprintf(stderr,
802 MSGSTR(112, "Error: Invalid pathname (%s)"),
803 argv[path_index]);
804 (void) fprintf(stderr, "\n");
805 exit(-1);
806 }
807 path_phys = argv[path_index];
808 if (err = scsi_reserve(path_phys)) {
809 (void) print_errString(err, argv[path_index]);
810 exit(-1);
811 }
812 } else {
813 exit_code = adm_reserve(argv[path_index]);
814 }
815 break;
816
817 case RELEASE:
818 if (Options & (~PVERBOSE)) {
819 USEAGE();
820 exit(-1);
821 }
822 VERBPRINT(MSGSTR(2210, " Canceling Reservation for:\n %s\n"),
823 argv[path_index]);
824 if (USE_FCHBA) {
825 struct stat sbuf;
826 /* Just stat the argument and make sure it exists */
827 if (stat(argv[path_index], &sbuf) < 0) {
828 (void) fprintf(stderr, "%s: ", whoami);
829 (void) fprintf(stderr,
830 MSGSTR(112, "Error: Invalid pathname (%s)"),
831 argv[path_index]);
832 (void) fprintf(stderr, "\n");
833 exit(-1);
834 }
835 path_phys = argv[path_index];
836 if (err = scsi_release(path_phys)) {
837 (void) print_errString(err, argv[path_index]);
838 exit(-1);
839 }
840 } else {
841 exit_code = adm_release(argv[path_index]);
842 }
843 break;
844
845 case START:
846 if (Options & ~(PVERBOSE)) {
847 USEAGE();
848 exit(-1);
849 }
850 exit_code = adm_start(&argv[path_index]);
851 break;
852
853 case STOP:
854 if (Options & ~(PVERBOSE)) {
855 USEAGE();
856 exit(-1);
857 }
858 exit_code = adm_stop(&argv[path_index]);
859 break;
860
861 case POWER_OFF:
862 if (Options & ~(PVERBOSE | OPTION_CAPF)) {
863 USEAGE();
864 exit(-1);
865 }
866 exit_code = adm_power_off(&argv[path_index], 1);
867 break;
868
869 case POWER_ON:
870 if (Options & (~PVERBOSE)) {
871 USEAGE();
872 exit(-1);
873 }
874 exit_code = adm_power_off(&argv[path_index], 0);
875 break;
876
877 /*
878 * EXPERT commands.
879 */
880
881 case FORCELIP:
882 if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) {
883 E_USEAGE();
884 exit(-1);
885 }
886 exit_code = adm_forcelip(&argv[path_index]);
887 break;
888
889 case BYPASS:
890 if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT |
891 OPTION_CAPF | OPTION_A | OPTION_B | OPTION_F |
892 OPTION_R)) || !(Options & (OPTION_A | OPTION_B)) ||
893 ((Options & OPTION_A) && (Options & OPTION_B))) {
894 E_USEAGE();
895 exit(-1);
896 }
897 adm_bypass_enable(&argv[path_index], 1);
898 break;
899
900 case ENABLE:
901 if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT |
902 OPTION_CAPF | OPTION_A | OPTION_B | OPTION_F |
903 OPTION_R)) || !(Options & (OPTION_A | OPTION_B)) ||
904 ((Options & OPTION_A) && (Options & OPTION_B))) {
905 E_USEAGE();
906 exit(-1);
907 }
908 adm_bypass_enable(&argv[path_index], 0);
909 break;
910 case LUX_P_OFFLINE: /* Offline a port */
911 if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) {
912 E_USEAGE();
913 exit(-1);
914 }
915 exit_code = adm_port_offline_online(&argv[path_index],
916 LUX_P_OFFLINE);
917 break;
918
919 case LUX_P_ONLINE: /* Online a port */
920 if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) {
921 E_USEAGE();
922 exit(-1);
923 }
924 exit_code = adm_port_offline_online(&argv[path_index],
925 LUX_P_ONLINE);
926 break;
927
928 case RDLS:
929 if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) {
930 E_USEAGE();
931 exit(-1);
932 }
933 if (USE_FCHBA) {
934 exit_code = fchba_display_link_status(&argv[path_index]);
935 } else {
936 display_link_status(&argv[path_index]);
937 }
938 break;
939
940 case CREATE_FAB:
941 if (!(Options & (EXPERT | OPTION_F)) ||
942 (Options & ~(PVERBOSE | EXPERT | OPTION_F))) {
943 E_USEAGE();
944 exit(-1);
945 }
946 if (read_repos_file(file_name) != 0) {
947 exit(-1);
948 }
949 break;
950
951 /*
952 * Undocumented commands.
953 */
954
955 case CHECK_FILE: /* Undocumented Cmd */
956 if (Options & ~(PVERBOSE)) {
957 USEAGE();
958 exit(-1);
959 }
960 exit_code = adm_check_file(&argv[path_index],
961 (Options & PVERBOSE));
962 break;
963
964 case DUMP: /* Undocumented Cmd */
965 if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) {
966 USEAGE();
967 exit(-1);
968 }
969 dump(&argv[path_index]);
970 break;
971
972 case DUMP_MAP: /* Undocumented Cmd */
973 if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) {
974 USEAGE();
975 exit(-1);
976 }
977 if (USE_FCHBA) {
978 exit_code = fchba_dump_map(&argv[path_index]);
979 } else {
980 dump_map(&argv[path_index]);
981 }
982 break;
983
984 case SYSDUMP:
985 if (Options & ~(PVERBOSE)) {
986 USEAGE();
987 exit(-1);
988 }
989 if (err = sysdump(Options & PVERBOSE)) {
990 (void) print_errString(err, NULL);
991 exit(-1);
992 }
993 break;
994
995 case PORT: /* Undocumented command */
996 if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) {
997 USEAGE();
998 exit(-1);
999 }
1000 if (USE_FCHBA) {
1001 exit_code = fchba_display_port(Options & PVERBOSE);
1002 } else {
1003 exit_code = adm_display_port(Options & PVERBOSE);
1004 }
1005 break;
1006
1007 case EXT_LOOPBACK:
1008 if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) {
1009 USEAGE();
1010 exit(-1);
1011 }
1012 if (adm_port_loopback(argv[path_index], EXT_LOOPBACK) < 0) {
1013 exit(-1);
1014 }
1015 break;
1016
1017 case INT_LOOPBACK:
1018 if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) {
1019 USEAGE();
1020 exit(-1);
1021 }
1022 if (adm_port_loopback(argv[path_index], INT_LOOPBACK) < 0) {
1023 exit(-1);
1024 }
1025 break;
1026
1027 case NO_LOOPBACK:
1028 if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) {
1029 USEAGE();
1030 exit(-1);
1031 }
1032 if (adm_port_loopback(argv[path_index], NO_LOOPBACK) < 0) {
1033 exit(-1);
1034 }
1035 break;
1036
1037 case VERSION:
1038 break;
1039
1040
1041 case INSERT_DEVICE:
1042 if (argv[path_index] == NULL) {
1043 if ((err = h_insertSena_fcdev()) != 0) {
1044 (void) print_errString(err, NULL);
1045 exit(-1);
1046 }
1047 } else if ((err = hotplug(INSERT_DEVICE,
1048 &argv[path_index],
1049 Options & PVERBOSE,
1050 Options & OPTION_CAPF)) != 0) {
1051 (void) print_errString(err, argv[path_index]);
1052 exit(-1);
1053 }
1054 break;
1055 case REMOVE_DEVICE:
1056 if (err = hotplug(REMOVE_DEVICE, &argv[path_index],
1057 Options & PVERBOSE, Options & OPTION_CAPF)) {
1058 (void) print_errString(err, argv[path_index]);
1059 exit(-1);
1060 }
1061 break;
1062
1063 /* for hotplug device operations */
1064 case DEV_ONLINE:
1065 case DEV_OFFLINE:
1066 case DEV_GETSTATE:
1067 case DEV_RESET:
1068 case BUS_QUIESCE:
1069 case BUS_UNQUIESCE:
1070 case BUS_GETSTATE:
1071 case BUS_RESET:
1072 case BUS_RESETALL:
1073 if (!(Options & EXPERT) || (Options & ~(PVERBOSE | EXPERT))) {
1074 E_USEAGE();
1075 exit(-1);
1076 }
1077 if (USE_FCHBA) {
1078 if (fchba_hotplug_e(cmd, &argv[path_index],
1079 Options & PVERBOSE, Options & OPTION_CAPF) != 0) {
1080 exit(-1);
1081 }
1082 } else {
1083 if (hotplug_e(cmd, &argv[path_index],
1084 Options & PVERBOSE, Options & OPTION_CAPF) != 0) {
1085 exit(-1);
1086 }
1087 }
1088 break;
1089
1090 default:
1091 (void) fprintf(stderr,
1092 MSGSTR(2213, "%s: subcommand decode failed.\n"),
1093 whoami);
1094 USEAGE();
1095 exit(-1);
1096 }
1097 return (exit_code);
1098 }
1099