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