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.
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.
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]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
32 * Hotplug program for SENA, RSM and SSA
33 * subsystems and individual FC_AL devices.
36 /* #define _POSIX_SOURCE 1 */
39 * I18N message number ranges
40 * This file: 5500 - 5999
41 * Shared common messages: 1 - 1999
49 #include <sys/errno.h>
50 #include <sys/types.h>
52 #include <sys/utsname.h>
57 #include <sys/sunddi.h>
58 #include <sys/ddi.h> /* for min */
59 #include <sys/scsi/scsi.h>
74 /* Internal variables. */
75 static char *cmdStrg
[][4] = {
76 { "disks", "-C", 0, 0 },
78 { "drvconfig", "-i", "ssd", 0 },
79 { "drvconfig", 0, 0, 0 },
80 { "devlinks", 0, 0, 0 },
81 { "tapes", "-C", 0, 0 }
84 /* External variables */
85 extern char *dtype
[]; /* From adm.c */
87 extern const int OPTION_CAPF
;
89 /* Internal functions */
90 /* SENA and Individual FC device Hotplug */
91 static int h_pre_insert_encl_dev(timestruc_t
*, timestruc_t
*,
93 static int h_post_insert_dev(timestruc_t
, timestruc_t
);
94 static int h_pre_remove_dev(Hotplug_Devlist
*,
95 WWN_list
*wwn_list
, int, int);
96 static int h_post_remove_dev(Hotplug_Devlist
*, int, int);
97 static int h_pre_hotplug(Hotplug_Devlist
**,
98 WWN_list
*, int, int, int);
99 static int h_post_hotplug(Hotplug_Devlist
*,
100 WWN_list
*, int, int, int, int);
101 static int h_post_insert_encl(timestruc_t
);
102 static int h_pre_hotplug_sena(Hotplug_Devlist
*,
103 WWN_list
*, int, int, int);
104 static int h_post_hotplug_sena(Hotplug_Devlist
*,
105 WWN_list
*, int, int, int, int);
106 static int h_remove_ses_nodes(struct dlist
*);
107 static int h_print_list_warn(Hotplug_Devlist
*, int, int);
108 static int h_display_logical_nodes(struct dlist
*);
109 static void h_print_logical_nodes(struct dlist
*);
110 static int h_remove_nodes(struct dlist
*);
111 static int h_print_list(Hotplug_Devlist
*, int *, int);
112 static int h_get_fcdev_state(char *, char *, int, int *, int *, int);
113 static int h_chk_dev_busy(Hotplug_Devlist
*,
114 WWN_list
*, int *, int, int);
115 static int h_execCmnd(char **, int);
116 int hotplug(int, char **, int, int);
117 int h_insertSena_fcdev();
118 static int h_find_new_device_link(char *, timestruc_t
);
123 * Assists the user in hot inserting FC_AL
124 * individual device(s) and SENA enclosure(s).
133 timestruc_t ses_time
, dsk_time
, rmt_time
;
135 struct stat ses_stat
;
137 if ((err
= h_pre_insert_encl_dev(&ses_time
, &dsk_time
,
141 (void) fprintf(stdout
, MSGSTR(5500,
142 "Please hit <RETURN> when you have finished"
143 " adding Fibre Channel Enclosure(s)/Device(s): "));
146 if ((err
= h_post_insert_dev(dsk_time
, rmt_time
)) != 0) {
150 if (stat(SES_DIR
, &ses_stat
) < 0) {
152 * Non existence of /dev/es dir indicates
153 * no ses devices inserted.
154 * No need to call h_post_insert_encl().
156 if (errno
== ENOENT
) {
157 (void) fprintf(stdout
, MSGSTR(5662,
158 " No new enclosure(s) were added!!\n\n"));
161 return (L_LSTAT_ES_DIR_ERROR
);
166 * if the latest mod time of /dev/es is not newer than
167 * the original mod time no need to call
168 * h_post_insert_encl().
170 if ((&ses_time
!= (timestruc_t
*)NULL
) &&
171 !(NEWER(ses_stat
.st_ctim
, ses_time
))) {
172 (void) fprintf(stdout
, MSGSTR(5662,
173 " No new enclosure(s) were added!!\n\n"));
176 if ((err
= h_post_insert_encl(ses_time
)) != 0) {
185 * gets the devices state - check for disk's reservations.
192 h_get_fcdev_state(char *fc_dev
, char *path_phys
, int force_flag
,
193 int *busy_flag
, int *reserve_flag
, int verbose_flag
)
197 L_disk_state l_disk_state
;
200 if ((err
= g_get_inquiry(path_phys
, &inq
)) != 0) {
201 (void) fprintf(stderr
,
203 "Inquiry failed for %s\n"),
208 if ((err
= l_get_disk_port_status(path_phys
, &l_disk_state
,
209 FC_PORT_B
, verbose_flag
)) != 0) {
213 if ((err
= l_get_disk_port_status(path_phys
, &l_disk_state
,
214 FC_PORT_A
, verbose_flag
)) != 0) {
220 * Don't print error msg. if disk is reserved
221 * and tried to be removed from the same port.
222 * If force flag is set, remove the disk without
223 * checking the disk reservations.
226 if (((inq
.inq_port
) &&
227 (l_disk_state
.g_disk_state
.d_state_flags
[FC_PORT_B
] &
230 (l_disk_state
.g_disk_state
.d_state_flags
[FC_PORT_A
] &
240 * Forks a child process and let the child to
241 * execute a given command string by calling the
242 * the execvp() function. Then, the parent process
243 * waits for the child to exit. Once the parent process
244 * is notified by the kernel with the termination of
245 * the child, then the parent checks for the exit
246 * status of the child and return to the caller with -1 in case
247 * of error and zero otherwise.
254 h_execCmnd(char *argStr
[], int nArg
)
259 if ((pid
= fork()) < 0) {
260 (void) fprintf(stderr
,
262 "Error: Failed to fork a process.\n"));
264 } else if (pid
== 0) {
266 if (execvp(argStr
[0], argStr
) < 0) {
267 (void) fprintf(stderr
,
269 " Error: execvp() failed to run "
271 for (ix
= 0; ix
< nArg
; ix
++) {
272 (void) fprintf(stderr
,
275 (void) fprintf(stderr
, "\n");
276 /* let parent know about the error. */
281 /* parent executes the following. */
282 if (waitpid(pid
, &status
, 0) != pid
) {
283 (void) fprintf(stderr
,
285 "Error: waitpid() failed.\n"));
288 if (WIFEXITED(status
) &&
289 WEXITSTATUS(status
) == ENOEXEC
) {
290 /* child failed to run the command string. */
301 * frees the hotplug disk list structure.
307 h_free_hotplug_dlist(Hotplug_Devlist
**hotplug_dlist
)
309 Hotplug_Devlist
*list
= NULL
;
311 while (*hotplug_dlist
!= NULL
) {
312 list
= *hotplug_dlist
;
313 *hotplug_dlist
= (*hotplug_dlist
)->next
;
314 (void) g_free_multipath(list
->seslist
);
315 (void) g_free_multipath(list
->dlhead
);
316 (void) free((void *)list
);
322 * finds whether device (SENA or an FCAL device) is busy or not.
325 * busy_flag = 1 (if device busy)
332 h_chk_dev_busy(Hotplug_Devlist
*hotplug_dev
, WWN_list
*wwn_list
,
333 int *busy_flag
, int force_flag
, int verbose_flag
)
338 if (hotplug_dev
->dev_type
== DTYPE_ESI
) {
339 if ((err
= l_offline_photon(hotplug_dev
, wwn_list
,
340 force_flag
, verbose_flag
)) != 0) {
341 if (err
== L_DEV_BUSY
) {
347 for (dlist
= hotplug_dev
->dlhead
;
348 dlist
!= NULL
; dlist
= dlist
->next
) {
349 (void) g_online_drive(dlist
->multipath
,
353 if ((err
= g_offline_drive(hotplug_dev
->dlhead
,
355 if (err
== L_DEV_BUSY
) {
361 (void) g_online_drive(hotplug_dev
->dlhead
, force_flag
);
369 * prints the given list to stdout,
370 * gets the input from user whether
371 * to skip the busy devices or quit
372 * and passes that input to the calling
385 h_print_list(Hotplug_Devlist
*bsyRsrv_disk_list
, int *action
, int enc_type
)
387 Hotplug_Devlist
*list
;
391 (void) fprintf(stdout
,
392 MSGSTR(5504, "The list of devices being used"
393 " (either busy or reserved) by the host:\n"));
394 for (list
= bsyRsrv_disk_list
; list
!= NULL
; list
= list
->next
, i
++) {
395 if ((list
->dev_type
== DTYPE_DIRECT
) &&
396 (list
->dev_location
== SENA
)) {
397 if (list
->f_flag
!= NULL
) {
398 if (enc_type
== DAK_ENC_TYPE
) {
399 (void) fprintf(stdout
, MSGSTR(5663,
400 " %d: Box Name: \"%s\" slot %d\n"),
401 i
, list
->box_name
, list
->slot
);
403 (void) fprintf(stdout
, MSGSTR(137,
404 " %d: Box Name: \"%s\" front slot %d\n"),
405 i
, list
->box_name
, list
->slot
);
408 if (enc_type
== DAK_ENC_TYPE
) {
409 (void) fprintf(stdout
, MSGSTR(5663,
410 " %d: Box Name: \"%s\" slot %d\n"),
411 i
, list
->box_name
, list
->slot
+ (MAX_DRIVES_DAK
/2));
413 (void) fprintf(stdout
, MSGSTR(136,
414 " %d: Box Name: \"%s\" rear slot %d\n"),
415 i
, list
->box_name
, list
->slot
);
418 } else if (((list
->dev_type
== DTYPE_DIRECT
) ||
419 (list
->dev_type
== DTYPE_SEQUENTIAL
)) &&
420 (list
->dev_location
== NON_SENA
)) {
421 (void) fprintf(stdout
, MSGSTR(5505,
424 } else if (list
->dev_type
== DTYPE_ESI
) {
425 (void) fprintf(stdout
, MSGSTR(5506,
431 /* Get the user input and continue accordingly. */
432 (void) fprintf(stdout
,
434 "\n\nPlease enter 's' or <CR> to Skip the \"busy/reserved\""
435 " device(s) or\n'q' to Quit and run the"
436 " subcommand with\n-F (force) option. [Default: s]: "));
439 if (choice
[0] == 'q' || choice
[0] == 'Q' ||
440 choice
[0] == 's' || choice
[0] == 'S' ||
444 (void) fprintf(stdout
, MSGSTR(5508,
445 " Enter an appropriate option [s,<CR>,q]: "));
447 if (choice
[0] == 'q' || choice
[0] == 'Q') {
452 (void) fprintf(stdout
, "\n\n");
459 * prints the warning message.
467 (void) fprintf(stderr
,
469 "\n WARNING!!! Please ensure that no"
470 " filesystems are mounted on these device(s).\n"
471 " All data on these devices should have been"
472 " backed up.\n\n\n"));
478 * handle helper-mode hotplug commands
485 hotplug(int todo
, char **argv
, int verbose_flag
, int force_flag
)
487 char ses_path
[MAXPATHLEN
], dev_path
[MAXPATHLEN
];
488 char *path_phys
= NULL
, code
, node_wwn_s
[WWN_S_LEN
];
489 char inq_path
[MAXNAMELEN
], *ptr
= NULL
;
490 uchar_t node_wwn
[WWN_SIZE
], port_wwn
[WWN_SIZE
];
491 int tid
, slot
, path_index
, dtype
, f_r
, err
= 0;
492 int al_pa
, i
, dev_location
, found_nullwwn
= 0;
493 int busy_flag
= 0, reserve_flag
= 0, action
= 0;
497 Path_struct
*path_struct
;
498 WWN_list
*wwn_list
= NULL
;
500 Hotplug_Devlist
*disk_list
, *disk_list_head
, *disk_list_tail
;
501 Hotplug_Devlist
*bsyRsrv_dskLst_head
, *bsyRsrv_dskLst_tail
;
505 Path_struct
*p_pathstruct
;
506 char temp2path
[MAXPATHLEN
];
507 mp_pathlist_t pathlist
;
508 int p_pw
= 0, p_on
= 0, p_st
= 0;
510 /* Initialize structures and pointers here */
511 disk_list_head
= disk_list_tail
= (Hotplug_Devlist
*)NULL
;
512 bsyRsrv_dskLst_head
= (Hotplug_Devlist
*)NULL
;
513 bsyRsrv_dskLst_tail
= (Hotplug_Devlist
*)NULL
;
517 (void) fprintf(stderr
,
518 "DEBUG: luxadm: hotplug() entering for \"%s\" ...\n",
519 argv
[0] ? argv
[0] : "<null ptr>");
521 if ((err
= l_get_box_list(&box_list
, 0)) != 0) {
525 if (todo
== REMOVE_DEVICE
) {
526 (void) h_prt_warning();
530 * At this point user want to insert or remove
531 * one or more pathnames they've specified.
533 if ((err
= g_get_wwn_list(&wwn_list
, verbose_flag
)) != 0) {
534 (void) l_free_box_list(&box_list
);
537 for (path_index
= 0; argv
[path_index
] != NULL
; path_index
++) {
538 if ((err
= l_convert_name(argv
[path_index
], &path_phys
,
539 &path_struct
, verbose_flag
)) != 0) {
540 /* Make sure we have a device path. */
541 (void) strcpy(inq_path
, argv
[path_index
]);
542 if (((ptr
= strstr(inq_path
, ",")) != NULL
) &&
543 ((*(ptr
+ 1) == 'f') || (*(ptr
+ 1) == 'r') ||
544 (*(ptr
+1) == 's')) &&
545 todo
== REMOVE_DEVICE
) {
547 (void) print_errString(err
,
553 slot
= path_struct
->slot
;
554 f_r
= path_struct
->f_flag
;
555 if ((err
= l_convert_name(inq_path
, &path_phys
,
556 &path_struct
, verbose_flag
)) != 0) {
557 (void) fprintf(stderr
, "\n");
558 (void) fprintf(stderr
,
561 " %s to physical path.\n"
562 " Invalid pathname.\n"),
565 (void) print_errString(err
,
571 if ((err
= print_devState(argv
[path_index
],
572 path_struct
->p_physical_path
,
573 f_r
, slot
, verbose_flag
)) != 0) {
578 if (path_struct
->ib_path_flag
) {
579 path_phys
= path_struct
->p_physical_path
;
582 (void) print_errString(err
,
585 (void) fprintf(stderr
, "\n");
586 (void) fprintf(stderr
,
589 " %s to physical path.\n"
590 " Invalid pathname.\n"),
597 if (path_struct
->slot_valid
||
598 strstr(path_phys
, DRV_NAME_SSD
)) {
599 dtype
= DTYPE_DIRECT
;
600 } else if (strstr(path_phys
, SLSH_DRV_NAME_ST
)) {
601 dtype
= DTYPE_SEQUENTIAL
;
606 if (strstr(path_phys
, SCSI_VHCI
) != NULL
) {
608 (void) strcpy(temp2path
, path_phys
);
609 if (err
= g_get_pathlist(temp2path
, &pathlist
)) {
610 (void) print_errString(err
, NULL
);
613 pathcnt
= pathlist
.path_count
;
614 p_pw
= p_on
= p_st
= 0;
615 for (i
= 0; i
< pathcnt
; i
++) {
616 if (pathlist
.path_info
[i
].path_state
<
618 if (strstr(pathlist
.path_info
[i
].
620 path_struct
->argv
) != NULL
) {
624 if (pathlist
.path_info
[i
].path_state
==
625 MDI_PATHINFO_STATE_ONLINE
) {
628 if (pathlist
.path_info
[i
].path_state
==
629 MDI_PATHINFO_STATE_STANDBY
) {
634 if (strstr(pathlist
.path_info
[p_pw
].path_addr
,
635 path_struct
->argv
) != NULL
) {
636 /* matching input pwwn */
637 (void) strcpy(temp2path
,
638 pathlist
.path_info
[p_pw
].path_hba
);
639 } else if (pathlist
.path_info
[p_on
].path_state
==
640 MDI_PATHINFO_STATE_ONLINE
) {
642 (void) strcpy(temp2path
,
643 pathlist
.path_info
[p_on
].path_hba
);
645 /* standby or path0 */
646 (void) strcpy(temp2path
,
647 pathlist
.path_info
[p_st
].path_hba
);
649 free(pathlist
.path_info
);
650 (void) strcat(temp2path
, FC_CTLR
);
652 (void) strcpy(temp2path
, path_phys
);
655 if ((err
= g_get_dev_map(temp2path
, &map
, verbose_flag
))
660 if ((map
.hba_addr
.port_topology
== FC_TOP_PUBLIC_LOOP
) ||
661 (map
.hba_addr
.port_topology
== FC_TOP_FABRIC
)) {
662 /* public or fabric loop device */
663 free((void *)map
.dev_addr
);
664 (void) fprintf(stderr
, MSGSTR(5540,
665 "This operation is not "
666 "supported in this topology.\n"));
670 if (todo
== REPLACE_DEVICE
) {
671 (void) fprintf(stderr
,
674 " replace_device is not supported"
675 " on this subsystem.\n"));
679 if ((todo
== REMOVE_DEVICE
) &&
680 (dtype
== DTYPE_DIRECT
||
681 dtype
== DTYPE_SEQUENTIAL
||
682 dtype
== DTYPE_UNKNOWN
)) {
683 if (l_chk_null_wwn(path_struct
, ses_path
,
684 &l_state
, verbose_flag
) == 1) {
687 * set dev_path to NULL,
688 * if disk has null wwn.
696 (void) strcpy(ses_path
, path_phys
);
698 if (strstr(ses_path
, "ses") == NULL
&&
699 l_get_ses_path(path_phys
, ses_path
, &map
,
700 verbose_flag
) != 0) {
702 /* Could be a non-photon disk device */
703 if ((todo
== REMOVE_DEVICE
) &&
704 (dtype
== DTYPE_DIRECT
||
705 dtype
== DTYPE_SEQUENTIAL
)) {
706 dev_location
= NON_SENA
;
708 if ((err
= h_get_fcdev_state(argv
[path_index
],
709 path_phys
, force_flag
,
710 &busy_flag
, &reserve_flag
,
711 verbose_flag
)) != 0) {
714 (void) strcpy(dev_path
, path_phys
);
715 if ((err
= g_get_wwn(dev_path
, port_wwn
,
717 verbose_flag
)) != 0) {
720 (void) sprintf(node_wwn_s
,
721 "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
722 node_wwn
[0], node_wwn
[1], node_wwn
[2],
723 node_wwn
[3], node_wwn
[4], node_wwn
[5],
724 node_wwn
[6], node_wwn
[7]);
725 tid
= g_sf_alpa_to_switch
[al_pa
];
731 if (strstr(ses_path
, "ses") != NULL
) {
733 if ((err
= l_convert_name(ses_path
, &physpath
,
734 &p_pathstruct
, 0)) != 0) {
740 if ((err
= g_get_inquiry(physpath
, &inq
)) != 0) {
745 enc_type
= l_get_enc_type(inq
);
748 if ((err
= l_get_status(ses_path
,
749 &l_state
, verbose_flag
)) != 0) {
752 if (dtype
== DTYPE_ESI
) {
753 /* could be removing a photon */
754 if (todo
== REMOVE_DEVICE
) {
756 * Need the select ID (tid) for the IB.
758 if ((err
= g_get_wwn(ses_path
, port_wwn
,
760 verbose_flag
)) != 0) {
763 (void) sprintf(node_wwn_s
,
764 "%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x%1.2x",
765 node_wwn
[0], node_wwn
[1], node_wwn
[2],
766 node_wwn
[3], node_wwn
[4], node_wwn
[5],
767 node_wwn
[6], node_wwn
[7]);
768 tid
= g_sf_alpa_to_switch
[al_pa
];
771 * Check if any disk in this photon
772 * is reserved by another host
777 i
< l_state
.total_num_drv
/2;
779 if ((l_state
.drv_front
[i
].g_disk_state
.d_state_flags
[PORT_A
] &
781 (l_state
.drv_front
[i
].g_disk_state
.d_state_flags
[PORT_B
] &
783 (l_state
.drv_rear
[i
].g_disk_state
.d_state_flags
[PORT_A
] &
785 (l_state
.drv_rear
[i
].g_disk_state
.d_state_flags
[PORT_B
] &
793 (void) fprintf(stderr
,
795 "Error: %s already exists!!\n"),
800 if (!path_struct
->slot_valid
) {
801 /* We are passing the disks path */
802 if ((err
= l_get_slot(path_struct
, &l_state
,
803 verbose_flag
)) != 0) {
808 slot
= path_struct
->slot
;
809 if (path_struct
->f_flag
) {
810 tid
= l_state
.drv_front
[slot
].ib_status
.sel_id
;
811 code
= l_state
.drv_front
[slot
].ib_status
.code
;
812 (void) strcpy(node_wwn_s
,
813 l_state
.drv_front
[slot
].g_disk_state
.node_wwn_s
);
815 tid
= l_state
.drv_rear
[slot
].ib_status
.sel_id
;
816 code
= l_state
.drv_rear
[slot
].ib_status
.code
;
817 (void) strcpy(node_wwn_s
,
818 l_state
.drv_rear
[slot
].g_disk_state
.node_wwn_s
);
825 l_make_node(ses_path
, tid
, dev_path
, &map
, 0);
827 if ((todo
== INSERT_DEVICE
) &&
828 (g_device_in_map(&map
, tid
) ||
829 (code
!= S_NOT_INSTALLED
))) {
830 (void) fprintf(stderr
,
831 MSGSTR(5513, "\nNotice: %s may "
832 "already be present.\n"),
834 if (path_struct
->f_flag
) {
835 if ((l_state
.drv_front
[slot
].l_state_flag
836 != L_NO_PATH_FOUND
) &&
837 (!l_state
.drv_front
[slot
].ib_status
.dev_off
))
840 if ((l_state
.drv_rear
[slot
].l_state_flag
841 != L_NO_PATH_FOUND
) &&
842 (!l_state
.drv_rear
[slot
].ib_status
.dev_off
))
847 /* Check if disk is reserved */
848 if ((todo
== REMOVE_DEVICE
) && (!force_flag
)) {
849 if (path_struct
->f_flag
) {
850 if ((l_state
.drv_front
[slot
].g_disk_state
.d_state_flags
[PORT_A
] &
852 (l_state
.drv_front
[slot
].g_disk_state
.d_state_flags
[PORT_B
] &
857 if ((l_state
.drv_rear
[slot
].g_disk_state
.d_state_flags
[PORT_A
] &
859 (l_state
.drv_rear
[slot
].g_disk_state
.d_state_flags
[PORT_B
] &
867 if ((disk_list
= (Hotplug_Devlist
*)
868 calloc(1, sizeof (Hotplug_Devlist
))) == NULL
) {
869 (void) print_errString(L_MALLOC_FAILED
, NULL
);
874 * dev_path is NULL when removing a whole encloser. We
875 * don't want to call g_get_multipath while removing whole
876 * enclosure. Its being taken care later in the code path
879 if ((todo
!= INSERT_DEVICE
) && (dtype
!= DTYPE_ESI
)) {
880 if ((err
= g_get_multipath(dev_path
,
881 &(disk_list
->dlhead
),
882 wwn_list
, verbose_flag
)) != 0) {
883 if (disk_list
->dlhead
!= NULL
) {
884 (void) g_free_multipath(
890 disk_list
->dev_type
= dtype
;
891 disk_list
->dev_location
= dev_location
;
892 (void) strcpy(disk_list
->dev_name
,
894 disk_list
->tid
= tid
;
895 (void) strcpy(disk_list
->node_wwn_s
, node_wwn_s
);
896 if (dev_location
== SENA
) {
897 if ((err
= l_get_allses(ses_path
, box_list
,
898 &(disk_list
->seslist
), 0)) != 0) {
899 if (disk_list
->seslist
!= NULL
) {
900 (void) g_free_multipath(disk_list
->seslist
);
904 (void) strcpy(disk_list
->box_name
,
905 (char *)l_state
.ib_tbl
.enclosure_name
);
906 disk_list
->slot
= slot
;
907 disk_list
->f_flag
= path_struct
->f_flag
;
909 if (todo
== REMOVE_DEVICE
&& !force_flag
&& !reserve_flag
) {
910 if ((err
= h_chk_dev_busy(disk_list
, wwn_list
,
911 &busy_flag
, force_flag
, verbose_flag
)) != 0) {
916 if (reserve_flag
|| busy_flag
) {
918 disk_list
->reserve_flag
= 1;
920 disk_list
->busy_flag
= 1;
922 if (bsyRsrv_dskLst_head
== NULL
) {
923 bsyRsrv_dskLst_head
=
924 bsyRsrv_dskLst_tail
= disk_list
;
926 disk_list
->prev
= bsyRsrv_dskLst_tail
;
927 bsyRsrv_dskLst_tail
->next
= disk_list
;
928 bsyRsrv_dskLst_tail
= disk_list
;
933 } else if (disk_list_head
== NULL
) {
934 disk_list_head
= disk_list_tail
= disk_list
;
936 disk_list
->prev
= disk_list_tail
;
937 disk_list_tail
->next
= disk_list
;
938 disk_list_tail
= disk_list
;
942 if (bsyRsrv_dskLst_head
!= NULL
) {
943 if ((err
= h_print_list(bsyRsrv_dskLst_head
,
944 &action
, enc_type
)) != 0) {
947 if (action
== SKIP
) {
948 (void) h_free_hotplug_dlist(&bsyRsrv_dskLst_head
);
949 } else if (action
== QUIT
) {
953 if (disk_list_head
!= NULL
) {
954 if ((h_print_list_warn(disk_list_head
, todo
, enc_type
)) != 0) {
957 if ((err
= h_pre_hotplug(&disk_list_head
, wwn_list
, todo
, verbose_flag
,
961 if (disk_list_head
!= NULL
) {
962 if (todo
== REMOVE_DEVICE
) {
963 (void) fprintf(stdout
, MSGSTR(5514,
964 "\nHit <Return> after "
965 "removing the device(s)."));
967 (void) fprintf(stdout
, MSGSTR(5515,
968 "\nHit <Return> after "
969 "inserting the device(s)."));
972 (void) fprintf(stdout
, "\n");
973 if ((err
= h_post_hotplug(disk_list_head
, wwn_list
,
974 todo
, verbose_flag
, force_flag
,
981 (void) l_free_box_list(&box_list
);
982 (void) g_free_wwn_list(&wwn_list
);
983 if (err
&& err
!= -1) {
986 free((void *)map
.dev_addr
);
994 * Internal routine to clean up ../'s in paths.
995 * returns 0 if no "../" are left.
997 * Wouldn't it be nice if there was a standard system library
998 * routine to do this...?
1001 cleanup_dotdot_path(char *path
)
1003 char holder
[MAXPATHLEN
];
1005 char *previous_slash
;
1007 /* Find the first "/../" in the string */
1008 dotdot
= strstr(path
, "/../");
1009 if (dotdot
== NULL
) {
1015 * If the [0] character is '/' and "../" immediatly
1016 * follows it, then we can strip the ../
1018 * /../../foo/bar == /foo/bar
1021 if (dotdot
== path
) {
1022 strcpy(holder
, &path
[3]); /* strip "/.." */
1023 strcpy(path
, holder
);
1028 * Now look for the LAST "/" before the "/../"
1029 * as this is the parent dir we can get rid of.
1030 * We do this by temporarily truncating the string
1031 * at the '/' just before "../" using the dotdot pointer.
1034 previous_slash
= strrchr(path
, '/');
1035 if (previous_slash
== NULL
) {
1037 * hmm, somethings wrong. path looks something
1038 * like "foo/../bar/" so we can't really deal with it.
1043 * Now truncate the path just after the previous '/'
1044 * and slam everything after the "../" back on
1046 *(previous_slash
+1) = '\0';
1047 (void) strcat(path
, dotdot
+4);
1048 return (1); /* We may have more "../"s */
1053 * Follow symbolic links from the logical device name to
1054 * the /devfs physical device name. To be complete, we
1055 * handle the case of multiple links. This function
1056 * either returns NULL (no links, or some other error),
1057 * or the physical device name, alloc'ed on the heap.
1059 * For S10 the physical path may be non-existent.
1061 * NOTE: If the path is relative, it will be forced into
1062 * an absolute path by pre-pending the pwd to it.
1065 h_get_physical_name_from_link(char *path
)
1068 char source
[MAXPATHLEN
];
1069 char scratch
[MAXPATHLEN
];
1070 char pwd
[MAXPATHLEN
];
1074 /* return NULL if path is NULL */
1079 strcpy(source
, path
);
1083 * First make sure the path is absolute. If not, make it.
1084 * If it's already an absolute path, we have no need
1085 * to determine the cwd, so the program should still
1086 * function within security-by-obscurity directories.
1088 if (source
[0] != '/') {
1089 tmp
= getcwd(pwd
, MAXPATHLEN
);
1091 O_DPRINTF("getcwd() failed - %s\n",
1096 * Handle special case of "./foo/bar"
1098 if (source
[0] == '.' && source
[1] == '/') {
1099 strcpy(scratch
, source
+2);
1100 } else { /* no "./" so just take everything */
1101 strcpy(scratch
, source
);
1103 strcpy(source
, pwd
);
1104 (void) strcat(source
, "/");
1105 (void) strcat(source
, scratch
);
1109 * Clean up any "../"s that are in the path
1111 while (cleanup_dotdot_path(source
));
1114 * source is now an absolute path to the link we're
1117 * S10: Do NOT ignore dangling links, pointing to devfs nodes.
1119 if (strstr(source
, "/devices")) {
1120 return (g_alloc_string(source
));
1123 if (lstat(source
, &stbuf
) == -1) {
1124 O_DPRINTF("lstat() failed for - %s\n",
1125 source
, strerror(errno
));
1129 * If the file is not a link, we're done one
1130 * way or the other. If there were links,
1131 * return the full pathname of the resulting
1134 * Note: All of our temp's are on the stack,
1135 * so we have to copy the final result to the heap.
1137 if (!S_ISLNK(stbuf
.st_mode
)) {
1138 return (g_alloc_string(source
));
1140 cnt
= readlink(source
, scratch
, sizeof (scratch
));
1142 O_DPRINTF("readlink() failed - %s\n",
1147 * scratch is on the heap, and for some reason readlink
1148 * doesn't always terminate things properly so we have
1149 * to make certain we're properly terminated
1151 scratch
[cnt
] = '\0';
1154 * Now check to see if the link is relative. If so,
1155 * then we have to append it to the directory
1156 * which the source was in. (This is non trivial)
1158 if (scratch
[0] != '/') {
1159 tmp
= strrchr(source
, '/');
1160 if (tmp
== NULL
) { /* Whoa! Something's hosed! */
1161 O_DPRINTF("Internal error... corrupt path.\n");
1164 /* Now strip off just the directory path */
1165 *(tmp
+1) = '\0'; /* Keeping the last '/' */
1166 /* and append the new link */
1167 (void) strcat(source
, scratch
);
1169 * Note: At this point, source should have "../"s
1170 * but we'll clean it up in the next pass through
1174 /* It's an absolute link so no worries */
1175 strcpy(source
, scratch
);
1178 /* Never reach here */
1182 * Function for getting physical pathnames
1184 * For S10 the physical path may not exist at the time devctl calls
1185 * are made. So we should not return error if stat fails on /devices path.
1187 * This function can handle 2 different inputs.
1189 * 1) Inputs of the form /dev/rdsk/cNtNdNsN
1190 * These are identified by being a link
1191 * The physical path they are linked to is returned.
1193 * 2) Inputs of the form /devices/...
1194 * These are actual physical names.
1195 * They are not converted.
1198 h_get_physical_name(char *path
)
1202 char savedir
[MAXPATHLEN
];
1203 char *result
= NULL
;
1206 /* return invalid path if path NULL */
1211 (void) strcpy(s
, path
);
1213 status
= lstat(s
, &stbuf
);
1216 * S10: If string is devfs node we allow failed lstat.
1218 if ((status
== -1) || !S_ISLNK(stbuf
.st_mode
)) {
1219 /* Make sure a full path as that is required. */
1220 if (strstr(s
, "/devices")) {
1221 result
= g_alloc_string(s
);
1224 sizeof (savedir
)) == NULL
) {
1228 * Check for this format:
1232 (void) strcat(savedir
, &s
[1]);
1234 (void) strcat(savedir
, "/");
1235 (void) strcat(savedir
, s
);
1237 if ((status
!= -1) || strstr(s
, "/devices")) {
1238 result
= g_alloc_string(savedir
);
1243 * Entry is linked file
1244 * so follow link to physical name
1246 result
= h_get_physical_name_from_link(path
);
1255 * handle expert-mode hotplug commands
1257 * return 0 iff all is okay
1260 hotplug_e(int todo
, char **argv
, int verbose_flag
, int force_flag
)
1262 char *path_phys
= NULL
;
1263 char bus_path
[MAXPATHLEN
];
1268 int i
= 0, pathcnt
= 1;
1269 mp_pathlist_t pathlist
;
1270 int p_pw
= 0, p_on
= 0, p_st
= 0;
1278 /* get physical name */
1279 if ((path_phys
= h_get_physical_name(argv
[0])) == NULL
) {
1281 (void) fprintf(stderr
,
1282 MSGSTR(112, "Error: Invalid pathname (%s)"),
1284 (void) fprintf(stderr
, "\n");
1289 (void) fprintf(stdout
,
1291 "phys path = \"%s\"\n"),
1295 /* acquire rights to hack on device */
1296 if ((dcp
= devctl_device_acquire(path_phys
,
1297 force_flag
? 0 : DC_EXCL
)) == NULL
) {
1299 (void) fprintf(stderr
, MSGSTR(5517,
1300 "Error: can't acquire \"%s\": %s\n"),
1301 path_phys
, strerror(errno
));
1307 exit_code
= devctl_device_online(dcp
);
1310 exit_code
= devctl_device_offline(dcp
);
1313 if ((exit_code
= devctl_device_getstate(dcp
,
1315 print_dev_state(argv
[0], devstate
);
1319 exit_code
= devctl_device_reset(dcp
);
1323 if (exit_code
!= 0) {
1324 perror(MSGSTR(5518, "devctl"));
1327 /* all done now -- release device */
1328 devctl_release(dcp
);
1331 /* for hotplugging bus operations */
1337 /* get physical name */
1338 if ((path_phys
= h_get_physical_name(argv
[0])) ==
1340 (void) fprintf(stderr
,
1341 MSGSTR(112, "Error: Invalid pathname (%s)"),
1343 (void) fprintf(stderr
, "\n");
1347 printf(MSGSTR(5519, "phys path = \"%s\"\n"), path_phys
);
1350 /* acquire rights to hack on device */
1351 /* delete leaf part from path_phys. */
1352 if (strstr(path_phys
, SCSI_VHCI
) != NULL
) {
1354 (void) strcpy(bus_path
, path_phys
);
1355 if (g_get_pathlist(bus_path
, &pathlist
)) {
1356 (void) fprintf(stderr
,
1357 MSGSTR(112, "Error: Invalid pathname (%s)"),
1359 (void) fprintf(stderr
, "\n");
1362 pathcnt
= pathlist
.path_count
;
1363 p_pw
= p_on
= p_st
= 0;
1364 for (i
= 0; i
< pathcnt
; i
++) {
1365 if (pathlist
.path_info
[i
].path_state
<
1367 if (strstr(pathlist
.path_info
[i
].
1373 if (pathlist
.path_info
[i
].path_state
==
1374 MDI_PATHINFO_STATE_ONLINE
) {
1377 if (pathlist
.path_info
[i
].path_state
==
1378 MDI_PATHINFO_STATE_STANDBY
) {
1383 if (strstr(pathlist
.path_info
[p_pw
].path_addr
,
1385 /* matching input pwwn */
1386 (void) strcpy(bus_path
,
1387 pathlist
.path_info
[p_pw
].path_hba
);
1388 } else if (pathlist
.path_info
[p_on
].path_state
==
1389 MDI_PATHINFO_STATE_ONLINE
) {
1391 (void) strcpy(bus_path
,
1392 pathlist
.path_info
[p_on
].path_hba
);
1394 /* standby or path0 */
1395 (void) strcpy(bus_path
,
1396 pathlist
.path_info
[p_st
].path_hba
);
1398 free(pathlist
.path_info
);
1401 (void) strcpy(bus_path
, path_phys
);
1402 ptr
= strrchr(bus_path
, '/');
1406 (void) fprintf(stderr
,
1407 MSGSTR(112, "Error: Invalid pathname (%s)"),
1409 (void) fprintf(stderr
, "\n");
1414 if ((dcp
= devctl_bus_acquire(bus_path
,
1415 force_flag
? 0 : DC_EXCL
)) == NULL
) {
1416 (void) fprintf(stderr
,
1418 " Error: can't acquire bus node from"
1419 " the path \"%s\": %s\n"),
1420 bus_path
, strerror(errno
));
1426 exit_code
= devctl_bus_quiesce(dcp
);
1429 exit_code
= devctl_bus_unquiesce(dcp
);
1432 if ((exit_code
= devctl_bus_getstate(dcp
,
1434 print_bus_state(argv
[0], devstate
);
1438 exit_code
= devctl_bus_reset(dcp
);
1441 exit_code
= devctl_bus_resetall(dcp
);
1445 if (exit_code
!= 0) {
1446 perror(MSGSTR(5522, "devctl"));
1449 /* all done now -- release device */
1450 devctl_release(dcp
);
1460 * Prepares an individual FC_AL device
1461 * to be removed from the specified
1466 * non-zero otherwise.
1469 h_pre_remove_dev(Hotplug_Devlist
*hotplug_disk
, WWN_list
*wwn_list
,
1470 int verbose_flag
, int force_flag
)
1472 char *dev_path
, device_name
[MAXNAMELEN
];
1475 /* Initialize pointers */
1478 if (hotplug_disk
->dlhead
!= NULL
) {
1479 dev_path
= hotplug_disk
->dlhead
->dev_path
;
1480 (void) strcpy(device_name
, (hotplug_disk
->dlhead
)->logical_path
);
1482 (void) fprintf(stdout
,
1484 "stopping: %s...."), device_name
);
1485 if (!(strstr(dev_path
, SLSH_DRV_NAME_ST
))) {
1486 if ((err
= g_dev_stop(dev_path
, wwn_list
, verbose_flag
)) != 0)
1489 (void) fprintf(stdout
, MSGSTR(156, "Done\n"));
1491 (void) fprintf(stdout
,
1492 MSGSTR(158, "offlining: %s...."), device_name
);
1493 if ((err
= g_offline_drive(hotplug_disk
->dlhead
,
1494 force_flag
)) != 0) {
1495 (void) fprintf(stdout
,
1497 "\nonlining: %s\n"), device_name
);
1499 (void) g_online_drive(hotplug_disk
->dlhead
, force_flag
);
1500 (void) fprintf(stdout
,
1501 MSGSTR(159, "starting: %s...."),
1503 if ((err
= g_dev_start(dev_path
, 0)) != 0) {
1506 (void) fprintf(stdout
, MSGSTR(156, "Done\n"));
1509 (void) fprintf(stdout
, MSGSTR(156, "Done\n"));
1516 * Prepares a SENA enclosure or SENA FC_AL device
1517 * to be inserted/removed from a specified slot.
1521 * non-zero otherwise.
1524 h_pre_hotplug_sena(Hotplug_Devlist
*hotplug_dev
,
1525 WWN_list
*wwn_list
, int todo
,
1526 int verbose_flag
, int force_flag
)
1528 int slot
, f_r
, i
, found_null_wwn
= 0, err
;
1529 char *ses_path
, *dev_path
, code
;
1530 char node_wwn_s
[WWN_SIZE
], device_name
[MAXNAMELEN
];
1531 struct l_state_struct l_state
;
1535 if (hotplug_dev
->dev_type
== DTYPE_ESI
) {
1536 /* entire photon is being removed */
1537 if ((err
= l_offline_photon(hotplug_dev
, wwn_list
,
1538 force_flag
, verbose_flag
)) != 0) {
1544 /* if device is an individual sena disk */
1545 dl
= hotplug_dev
->seslist
;
1547 ses_path
= dl
->dev_path
;
1548 if ((err
= l_get_status(ses_path
, &l_state
,
1549 verbose_flag
)) == 0)
1554 return (L_GET_STATUS_FAILED
);
1557 f_r
= hotplug_dev
->f_flag
;
1558 slot
= hotplug_dev
->slot
;
1559 (void) l_get_drive_name(device_name
, slot
, f_r
, hotplug_dev
->box_name
);
1561 /* check if disk has null wwn */
1563 (void) strncpy(node_wwn_s
,
1564 l_state
.drv_front
[slot
].g_disk_state
.node_wwn_s
, WWN_SIZE
);
1566 (void) strncpy(node_wwn_s
,
1567 l_state
.drv_rear
[slot
].g_disk_state
.node_wwn_s
, WWN_SIZE
);
1569 for (i
= 0; i
< WWN_SIZE
; i
++) {
1570 if (node_wwn_s
[i
] != '0')
1577 if (hotplug_dev
->f_flag
) {
1579 l_state
.drv_front
[slot
].ib_status
.code
;
1582 l_state
.drv_rear
[slot
].ib_status
.code
;
1584 if (code
& S_NOT_INSTALLED
) {
1586 * At this point we know that the drive is not
1587 * there. Turn on the RQST INSERT bit to make
1590 if ((err
= l_encl_status_page_funcs
1591 (SET_RQST_INSRT
, 0, todo
,
1592 ses_path
, &l_state
, f_r
, slot
,
1593 verbose_flag
)) != 0) {
1594 (void) print_errString(err
,
1596 (void) fprintf(stderr
,
1598 " %s: could not turn "
1604 * Drive is there so start it.
1606 if ((err
= l_encl_status_page_funcs
1607 (SET_DRV_ON
, 0, todo
,
1608 ses_path
, &l_state
, f_r
, slot
,
1609 verbose_flag
)) != 0) {
1610 (void) print_errString(err
,
1612 (void) fprintf(stderr
,
1623 * if disk has null wwn, then
1624 * there is no need to check the
1627 if (found_null_wwn
== 1) {
1628 if (getenv("_LUX_W_DEBUG") != NULL
) {
1629 (void) fprintf(stdout
,
1636 if (hotplug_dev
->f_flag
) {
1638 l_state
.drv_front
[slot
].ib_status
.code
1639 == S_NOT_INSTALLED
) {
1640 (void) fprintf(stderr
,
1642 " Notice: %s may already"
1648 l_state
.drv_rear
[slot
].ib_status
.code
1649 == S_NOT_INSTALLED
) {
1650 (void) fprintf(stderr
,
1652 " Notice: %s may already"
1659 if (hotplug_dev
->dlhead
== NULL
) {
1662 dev_path
= hotplug_dev
->dlhead
->dev_path
;
1665 (void) fprintf(stdout
,
1667 "stopping: %s...."), device_name
);
1668 if ((err
= g_dev_stop(dev_path
, wwn_list
, 0)) != 0) {
1671 (void) fprintf(stdout
, MSGSTR(156, "Done\n"));
1673 (void) fprintf(stdout
,
1674 MSGSTR(158, "offlining: %s...."),
1676 if ((err
= g_offline_drive(hotplug_dev
->dlhead
,
1677 force_flag
)) != 0) {
1678 (void) fprintf(stdout
,
1680 "\nonlining: %s\n"), device_name
);
1681 (void) g_online_drive(hotplug_dev
->dlhead
, force_flag
);
1683 (void) fprintf(stdout
,
1684 MSGSTR(159, "starting: %s...."),
1686 (void) g_dev_start(dev_path
, 0);
1687 (void) fprintf(stdout
, MSGSTR(156, "Done\n"));
1690 (void) fprintf(stdout
, MSGSTR(156, "Done\n"));
1693 * Take the drive off the loop
1694 * and blink the LED.
1696 if (hotplug_dev
->dev_location
== SENA
) {
1697 if ((err
= l_encl_status_page_funcs(SET_RQST_RMV
, 0,
1698 todo
, ses_path
, &l_state
, f_r
,
1699 slot
, verbose_flag
)) != 0) {
1700 (void) print_errString(err
, device_name
);
1701 (void) fprintf(stderr
,
1703 " %s: could not blink"
1704 " the yellow LED\n"),
1716 * Performs the post removal operations for
1717 * a SENA enclosure or a SENA FC_AL disk.
1721 * non-zero otherwise
1724 h_post_hotplug_sena(Hotplug_Devlist
*hotplug_dev
,
1725 WWN_list
*wwn_list
, int todo
,
1726 int verbose_flag
, int force_flag
, int enc_type
)
1728 char *ses_path
, *dev_path
= NULL
, device_name
[MAXNAMELEN
];
1729 int tid
, slot
, f_r
, al_pa
, timeout
= 0;
1730 uchar_t port_wwn
[WWN_SIZE
], node_wwn
[WWN_SIZE
];
1732 int wait_spinup_flag
= 0, wait_map_flag
= 0;
1733 int wait_node_flag
= 0, err
= 0, nArg
;
1735 WWN_list
*newWwn_list
= NULL
;
1736 struct dlist
*dl
, *dl1
;
1737 struct l_state_struct l_state
;
1740 dl
= hotplug_dev
->seslist
;
1741 slot
= hotplug_dev
->slot
;
1742 f_r
= hotplug_dev
->f_flag
;
1743 tid
= hotplug_dev
->tid
;
1745 if (hotplug_dev
->dev_type
== DTYPE_ESI
) {
1747 * See if photon has really been removed. If not,
1748 * try onlining the devices if applicable
1750 H_DPRINTF(" post_hotplug_sena: Seeing if enclosure "
1751 "has really been removed:\n"
1752 " tid=0x%x, ses_path %s\n",
1756 ses_path
= dl
->dev_path
;
1757 if ((err
= g_get_dev_map(ses_path
, &map
, 0)) == 0) {
1758 if ((map
.hba_addr
.port_topology
==
1759 FC_TOP_PUBLIC_LOOP
) ||
1760 (map
.hba_addr
.port_topology
==
1762 /* public or fabric loop device */
1763 free((void *)map
.dev_addr
);
1764 (void) fprintf(stdout
, MSGSTR(5540,
1765 "This operation is not "
1766 "supported in this topology.\n"));
1769 if ((err
= g_get_wwn(ses_path
, port_wwn
,
1770 node_wwn
, &al_pa
, verbose_flag
)) == 0) {
1771 tid
= g_sf_alpa_to_switch
[al_pa
];
1772 if (g_device_in_map(&map
, tid
)) {
1773 free((void *)map
.dev_addr
);
1777 FREE_DEV_ADDR(map
.dev_addr
);
1782 FREE_DEV_ADDR(map
.dev_addr
);
1784 (void) fprintf(stdout
, MSGSTR(5640,
1785 "Photon \"%s\" not removed."
1786 " Onlining Drives in enclosure.\n"),
1787 hotplug_dev
->box_name
);
1788 for (dl
= hotplug_dev
->dlhead
; dl
; ) {
1789 (void) g_online_drive(dl
->multipath
,
1791 (void) g_free_multipath(dl
->multipath
);
1796 hotplug_dev
->dlhead
= NULL
;
1800 * Remove logical nodes for this
1801 * photon, this includes ses and
1803 * In Solaris7, disks with -C option
1804 * removes the /dev/dsk entries.
1805 * The -C option is available
1806 * only for Solaris7. From Solaris8
1807 * or higher releases, the "disks"
1808 * program will be replaced by the
1811 /* pass "disks -C" as cmdStrg. */
1813 if (h_execCmnd(cmdStrg
[0], nArg
) != 0) {
1814 for (dl
= hotplug_dev
->dlhead
;
1815 dl
!= NULL
; dl
= dl
->next
) {
1816 if ((err
= h_remove_nodes(dl
->multipath
))
1822 (void) fprintf(stdout
,
1824 " Logical Nodes being removed"
1825 " under /dev/dsk/ and /dev/rdsk:\n"));
1826 for (dl
= hotplug_dev
->dlhead
;
1827 dl
!= NULL
; dl
= dl
->next
) {
1828 (void) h_print_logical_nodes(dl
->multipath
);
1832 for (dl
= hotplug_dev
->dlhead
; dl
!= NULL
; ) {
1833 (void) g_free_multipath(dl
->multipath
);
1838 hotplug_dev
->dlhead
= NULL
;
1839 if ((err
= h_remove_ses_nodes(hotplug_dev
->seslist
)) != 0) {
1845 /* post hotplug operations for a SENA disk. */
1846 if (enc_type
== DAK_ENC_TYPE
) {
1847 (void) sprintf(device_name
, MSGSTR(5664,
1848 " Drive in Box Name \"%s\" slot %d"),
1849 hotplug_dev
->box_name
,
1850 f_r
? slot
: slot
+ (MAX_DRIVES_DAK
/2));
1853 (void) sprintf(device_name
, MSGSTR(5542,
1854 " Drive in Box Name \"%s\" rear slot %d"),
1855 hotplug_dev
->box_name
, slot
);
1857 (void) sprintf(device_name
, MSGSTR(5543,
1858 " Drive in Box Name \"%s\" front slot %d"),
1859 hotplug_dev
->box_name
, slot
);
1862 (void) fprintf(stdout
, "%s\n", device_name
);
1864 dl
= hotplug_dev
->seslist
;
1866 ses_path
= dl
->dev_path
;
1867 if ((err
= l_get_status(ses_path
, &l_state
,
1868 verbose_flag
)) == 0)
1873 print_errString(err
, ses_path
);
1874 return (L_GET_STATUS_FAILED
);
1878 while (((err
= l_encl_status_page_funcs(OVERALL_STATUS
,
1879 &code
, todo
, ses_path
, &l_state
, f_r
, slot
,
1880 verbose_flag
)) != 0) || (code
!= 0)) {
1882 (void) print_errString(err
, ses_path
);
1883 } else if (todo
== REMOVE_DEVICE
) {
1885 (void) fprintf(stderr
,
1887 "\n Warning: Device has not been"
1888 " removed from the enclosure\n"
1889 " and is still on the loop."));
1892 (void) fprintf(stderr
,
1894 " Notice: Device has not been"
1895 " removed from the enclosure.\n"
1896 " It has been removed from the"
1897 " loop and is ready to be\n"
1899 " from the enclosure, and"
1900 " the LED is blinking.\n\n"));
1903 } else if ((todo
== INSERT_DEVICE
) &&
1904 ((code
!= S_NOT_AVAILABLE
) ||
1906 PHOTON_SPINUP_TIMEOUT
) ||
1908 (void) fprintf(stderr
,
1910 "\n Warning: Disk status is"
1914 (void) sleep(PHOTON_SPINUP_DELAY
);
1915 if (wait_spinup_flag
++ == 0) {
1916 (void) fprintf(stdout
, MSGSTR(5547,
1917 " Waiting for the disk to spin up:"));
1919 (void) fprintf(stdout
, ".");
1923 if (wait_spinup_flag
) {
1924 (void) fprintf(stdout
, "\n");
1929 /* check loop map that drive is present */
1931 dl
= hotplug_dev
->seslist
;
1932 map
.dev_addr
= (gfc_port_dev_info_t
*)NULL
;
1934 ses_path
= dl
->dev_path
;
1935 if ((err
= g_get_dev_map(ses_path
,
1936 &map
, verbose_flag
)) != 0) {
1937 (void) fprintf(stderr
,
1939 " Error: Could not get"
1944 if (g_device_in_map(&map
, tid
)) {
1947 FREE_DEV_ADDR(map
.dev_addr
);
1950 if (timeout
> PHOTON_SPINUP_TIMEOUT
) {
1951 (void) fprintf(stderr
,
1953 " Warning: Device not in"
1955 FREE_DEV_ADDR(map
.dev_addr
);
1958 if (wait_map_flag
++ == 0) {
1959 (void) fprintf(stdout
,
1961 " Waiting for the device "
1962 "to appear in the loop map:"));
1964 (void) fprintf(stdout
, ".");
1967 (void) sleep(PHOTON_SPINUP_DELAY
);
1970 if (wait_map_flag
) {
1971 (void) fprintf(stdout
, "\n");
1975 * Run drvconfig and disks to create
1979 /* pass "disks" as cmdStrg */
1981 if (h_execCmnd(cmdStrg
[2], nArg
) != 0) {
1982 (void) fprintf(stderr
,
1985 "run drvconfig.\n"));
1986 FREE_DEV_ADDR(map
.dev_addr
);
1987 return (L_DRVCONFIG_ERROR
);
1990 if (l_device_present(ses_path
, tid
, &map
,
1991 verbose_flag
, &dev_path
) == 1)
1993 if (timeout
> PHOTON_SPINUP_TIMEOUT
) {
1994 (void) fprintf(stderr
,
1996 " Warning: Could not find "
1997 "any node for inserted "
1999 FREE_DEV_ADDR(map
.dev_addr
);
2002 if (wait_node_flag
++ == 0) {
2003 (void) fprintf(stdout
,
2005 " Waiting for the logical "
2006 "node to be created:"));
2008 (void) fprintf(stdout
, ".");
2011 (void) sleep(PHOTON_SPINUP_DELAY
);
2013 FREE_DEV_ADDR(map
.dev_addr
);
2014 if (wait_node_flag
) {
2015 (void) fprintf(stdout
, "\n");
2018 * In Solaris7, disks with -C
2019 * option creates the new links
2020 * and removes any stale links.
2021 * In pre-Solaris7 releases, just
2022 * disks should do it all.
2024 /* pass "disks -C" as cmdStrg */
2026 if (h_execCmnd(cmdStrg
[0], nArg
) != 0) {
2027 return (L_DISKS_ERROR
);
2030 * Get a new wwn list here in order to
2031 * get the multiple paths to a newly added
2034 if ((err
= g_get_wwn_list(&newWwn_list
,
2035 verbose_flag
)) != 0) {
2038 if ((err
= g_get_multipath(dev_path
, &dl
,
2039 newWwn_list
, 0)) != 0) {
2042 if ((err
= h_display_logical_nodes(dl
)) != 0) {
2050 * Need to check all loops.
2052 /* check whether device is still in loop map */
2053 if ((err
= g_get_dev_map(ses_path
, &map
,
2054 verbose_flag
)) != 0) {
2058 if ((map
.hba_addr
.port_topology
==
2059 FC_TOP_PUBLIC_LOOP
) ||
2060 (map
.hba_addr
.port_topology
==
2062 /* public or fabric loop device */
2063 free((void *)map
.dev_addr
);
2064 (void) fprintf(stderr
, MSGSTR(5540,
2065 "This operation is not "
2066 "supported in this topology.\n"));
2068 * calling routine expects a 0 return code
2069 * or a pre-defined luxadm error code.
2070 * Here we do not have a pre-defined error
2071 * code, a 0 is returned.
2076 if (g_device_in_map(&map
, tid
)) {
2077 (void) fprintf(stderr
, MSGSTR(5554,
2078 " Warning: Device still in the loop map.\n"));
2079 FREE_DEV_ADDR(map
.dev_addr
);
2082 FREE_DEV_ADDR(map
.dev_addr
);
2084 * In Solaris7, "disks -C" program
2085 * removes the /dev/{r}dsk entries.
2086 * The -C option is available only
2087 * for Solaris7. From Solaris8 or
2088 * higher releases, the "disks" program
2089 * will be replaced by devfsadm.
2091 /* pass "disks -C" as cmdStrg */
2093 if (h_execCmnd(cmdStrg
[0], nArg
) != 0) {
2094 return (L_DISKS_ERROR
);
2096 (void) fprintf(stdout
,
2098 " Logical Nodes being removed"
2099 " under /dev/dsk/ and /dev/rdsk:\n"));
2100 (void) h_print_logical_nodes(
2101 hotplug_dev
->dlhead
);
2111 * Creates new ses entries under /dev/es
2112 * directory for the newly added
2117 * non-zero otherwise
2120 h_post_insert_encl(timestruc_t ses_lastmtim
)
2122 struct stat ses_stat
;
2123 char lname
[MAXPATHLEN
];
2124 int err
, found_newlink
= 0;
2126 struct dirent
*dirent
;
2127 Box_list
*bl1
, *box_list
= NULL
;
2130 if ((dir
= opendir(SES_DIR
)) == NULL
) {
2131 return (L_OPEN_ES_DIR_FAILED
);
2133 if ((err
= l_get_box_list(&box_list
, 0)) != 0) {
2139 * The mod time of /dev/es was newer than the mod time prior to
2140 * insert so dir entry is checked at this time.
2142 while ((dirent
= readdir(dir
)) != NULL
) {
2143 if (strcmp(dirent
->d_name
, ".") == 0 ||
2144 strcmp(dirent
->d_name
, "..") == 0)
2147 (void) sprintf(lname
, SES_DIR
"/%s", dirent
->d_name
);
2148 if (lstat(lname
, &ses_stat
) < 0) {
2149 (void) print_errString(L_LSTAT_ES_DIR_ERROR
,
2154 for (bl1
= box_list
; bl1
; bl1
= bl1
->box_next
) {
2155 if (strstr(lname
, bl1
->b_physical_path
))
2159 if (box_list
&& bl1
)
2162 if (NEWER(ses_stat
.st_ctim
, ses_lastmtim
)) {
2163 /* New enclosure was detected. */
2165 if (found_newlink
== 1) {
2166 (void) fprintf(stdout
, MSGSTR(5556,
2167 " New Logical Nodes under /dev/es:\n"));
2169 (void) fprintf(stdout
, "\t%s\n",
2173 if (!found_newlink
) {
2174 (void) fprintf(stdout
, MSGSTR(5662,
2175 " No new enclosure(s) were added!!\n\n"));
2180 (void) l_free_box_list(&box_list
);
2187 * performs the post removal of individual
2192 * non-zero otherwise
2195 h_post_remove_dev(Hotplug_Devlist
*hotplug_disk
,
2196 int todo
, int verbose_flag
)
2198 char device_name
[MAXNAMELEN
], *dev_path
= NULL
;
2204 tid
= hotplug_disk
->tid
;
2205 (void) sprintf(device_name
,
2208 (hotplug_disk
->dlhead
)->logical_path
);
2210 (void) fprintf(stdout
, "%s\n", device_name
);
2212 dev_path
= (hotplug_disk
->dlhead
)->dev_path
;
2215 * On qlc, after a forcelip on a FC combo box, it sometimes takes 17
2216 * seconds for the loop to come back online. During this 17 seconds,
2217 * g_get_dev_map * will return L_NO_DEVICES_FOUND. This delay
2218 * has been added to assure that the L_NO_DEVICES_FOUND returned from
2219 * g_get_dev_map is not the result of the 17 second delay on FC combo.
2220 * This only affects qlc.
2222 if ((err
= g_get_dev_map(dev_path
, &map
, verbose_flag
)) != 0) {
2223 if ((err
== L_NO_DEVICES_FOUND
) &&
2224 (strstr(dev_path
, "SUNW,qlc@") != NULL
)) {
2225 sleep(QLC_LIP_DELAY
);
2226 if ((err
= g_get_dev_map(dev_path
, &map
, verbose_flag
))
2228 if (err
!= L_NO_DEVICES_FOUND
)
2231 } else if (err
!= L_NO_DEVICES_FOUND
)
2236 * if g_get_dev_map returns L_NO_DEVICES_FOUND, then there are not
2237 * devices attached to the HBA and there is no sense in calling
2238 * g_device_in_map().
2240 if (err
!= L_NO_DEVICES_FOUND
) {
2241 if ((map
.hba_addr
.port_topology
== FC_TOP_PUBLIC_LOOP
) ||
2242 (map
.hba_addr
.port_topology
== FC_TOP_FABRIC
)) {
2243 /* public or fabric loop device */
2244 free((void *)map
.dev_addr
);
2245 (void) fprintf(stderr
, MSGSTR(5540,
2246 "This operation is not "
2247 "supported in this topology.\n"));
2251 if (g_device_in_map(&map
, tid
) != 0) {
2252 (void) fprintf(stderr
,
2254 " Warning: Device has"
2255 " not been removed from\n"
2256 " the slot and is still"
2257 " in the loop map.\n\n"));
2258 free((void *)map
.dev_addr
);
2261 free((void *)map
.dev_addr
);
2264 * In Solaris7, "disks -C" program
2265 * removes the /dev/{r}dsk entries.
2266 * The -C option is available only
2267 * for Solaris7. From Solaris8 or
2268 * higher releases, the "disks" program
2269 * will be replaced by devfsadm.
2271 /* pass "disks -C" as cmdStrg. */
2273 if (h_execCmnd(cmdStrg
[0], nArg
) != 0) {
2274 return (L_DISKS_ERROR
);
2276 /* pass "tapes -C as cmdStrg. */
2277 if (h_execCmnd(cmdStrg
[5], nArg
) != 0) {
2278 return (L_TAPES_ERROR
);
2280 (void) h_print_logical_nodes(hotplug_disk
->dlhead
);
2288 * Gets the last modification time for
2289 * /dev/es/ and /dev/rdsk directories
2290 * and passes these values to the caller.
2294 * non-zero in case of error
2297 h_pre_insert_encl_dev(timestruc_t
*ses_time
, timestruc_t
*dsk_time
,
2298 timestruc_t
*rmt_time
)
2300 struct stat ses_stat
, dsk_stat
, rmt_stat
;
2302 if (stat(SES_DIR
, &ses_stat
) < 0) {
2304 * Even if there exists no /dev/es don't fail it.
2305 * The host doesn't have to have any enclosure device
2308 if (errno
== ENOENT
) {
2309 ses_time
= (timestruc_t
*)NULL
;
2311 return (L_LSTAT_ES_DIR_ERROR
);
2314 *ses_time
= ses_stat
.st_mtim
;
2317 if (stat(DEV_DSK_DIR
, &dsk_stat
) < 0) {
2318 return (L_STAT_DEV_DIR_ERROR
);
2320 *dsk_time
= dsk_stat
.st_mtim
;
2322 if (stat(DEV_TAPE_DIR
, &rmt_stat
) < 0) {
2324 * Even if there exists no /dev/rmt don't fail it.
2325 * The host doesn't have to have any tape device
2328 if (errno
== ENOENT
) {
2329 rmt_time
= (timestruc_t
*)NULL
;
2331 return (L_STAT_RMT_DIR_ERROR
);
2334 *rmt_time
= rmt_stat
.st_mtim
;
2343 * Waits for loop intialization to complete
2344 * and runs drvconfig, disks and devlinks to create device nodes
2345 * for devices that are being added and prints the newly created
2346 * /dev/rdsk entries.
2350 * non-zero in case of error
2354 h_post_insert_dev(timestruc_t dsk_lastmtim
, timestruc_t rmt_lastmtim
)
2356 int found_newlink
= 0, nArg
;
2358 (void) fprintf(stdout
,
2360 "\nWaiting for Loop Initialization to complete...\n"));
2363 * We sleep here to let the system create nodes. Not sleeping
2364 * could cause the drvconfig below to run too soon.
2367 (void) sleep(NODE_CREATION_TIME
);
2370 * Run drvconfig and disks to create
2373 /* pass "drvconfig" as cmdStrg */
2375 if (h_execCmnd(cmdStrg
[3], nArg
) != 0) {
2376 return (L_DRVCONFIG_ERROR
);
2380 * In 2.7, disks with the -C
2381 * option should be used to
2382 * create new links and remove
2384 * In pre-2.7 releases, just
2385 * disks should do it all.
2388 /* pass "disks -C" as cmdStrg */
2390 if (h_execCmnd(cmdStrg
[0], nArg
) != 0) {
2391 return (L_DISKS_ERROR
);
2393 /* pass "tapes -C as cmdStrg */
2394 if (h_execCmnd(cmdStrg
[5], nArg
) != 0) {
2395 return (L_TAPES_ERROR
);
2398 /* pass "devlinks" as cmdStrg */
2400 if (h_execCmnd(cmdStrg
[4], nArg
) != 0) {
2401 return (L_DEVLINKS_ERROR
);
2404 /* check /dev/dsk and /dev/rmt for new links */
2405 found_newlink
= h_find_new_device_link(DEV_DSK_DIR
, dsk_lastmtim
) +
2406 h_find_new_device_link(DEV_TAPE_DIR
, rmt_lastmtim
);
2408 if (!found_newlink
) {
2409 (void) fprintf(stdout
, MSGSTR(5562,
2410 " No new device(s) were added!!\n\n"));
2419 * Performs the pre hotplug operations on SENA enclosure(s),
2420 * SENA disk(s) and individual fcal disk(s).
2421 * If the device is failed to remove, then it removes the device from the
2422 * hotplug list and continues with the next device in the list.
2426 * prints an error message to stderr and returns 0
2429 h_pre_hotplug(Hotplug_Devlist
**disk_list_head_ptr
,
2430 WWN_list
*wwn_list
, int todo
,
2431 int verbose_flag
, int force_flag
)
2433 Hotplug_Devlist
*list
, *disk_list
;
2436 disk_list
= *disk_list_head_ptr
;
2437 while (disk_list
!= NULL
) {
2438 if ((disk_list
->dev_type
== DTYPE_ESI
) ||
2439 (disk_list
->dev_location
== SENA
)) {
2440 if ((err
= h_pre_hotplug_sena(disk_list
, wwn_list
,
2441 todo
, verbose_flag
, force_flag
)) != 0) {
2442 (void) print_errString(err
,
2443 disk_list
->dev_name
);
2446 } else if (disk_list
->dev_location
== NON_SENA
) {
2447 if ((err
= h_pre_remove_dev(disk_list
, wwn_list
,
2448 verbose_flag
, force_flag
)) != 0) {
2449 (void) print_errString(err
,
2450 disk_list
->dev_name
);
2454 disk_list
= disk_list
->next
;
2457 list
= disk_list
->prev
;
2459 list
->next
= disk_list
->next
;
2460 if (list
->next
!= NULL
)
2461 list
->next
->prev
= list
;
2464 disk_list
= disk_list
->next
;
2465 if (list
== *disk_list_head_ptr
)
2466 *disk_list_head_ptr
= disk_list
;
2467 (void) g_free_multipath(list
->seslist
);
2468 (void) g_free_multipath(list
->dlhead
);
2477 * Performs the post removal of a list of SENA enclosure(s),
2478 * SENA disk(s) and individual fcal disk(s).
2482 * non-zero otherwise
2485 h_post_hotplug(Hotplug_Devlist
*hotplug_dlist
,
2486 WWN_list
*wwn_list
, int todo
,
2487 int verbose_flag
, int force_flag
, int enc_type
)
2489 Hotplug_Devlist
*list
;
2492 /* Do a lip on every loop so that we get the latest loop maps */
2493 if (todo
!= INSERT_DEVICE
) {
2494 if ((err
= g_forcelip_all(hotplug_dlist
)) != 0) {
2499 while (hotplug_dlist
!= NULL
) {
2500 if ((hotplug_dlist
->dev_location
== SENA
) ||
2501 (hotplug_dlist
->dev_type
== DTYPE_ESI
)) {
2502 if ((err
= h_post_hotplug_sena(hotplug_dlist
, wwn_list
, todo
,
2503 verbose_flag
, force_flag
, enc_type
)) != 0)
2504 (void) print_errString(err
, hotplug_dlist
->dev_name
);
2505 } else if (hotplug_dlist
->dev_location
== NON_SENA
) {
2506 if ((err
= h_post_remove_dev(hotplug_dlist
,
2507 todo
, verbose_flag
)) != 0)
2508 (void) print_errString(err
,
2509 hotplug_dlist
->dev_name
);
2511 list
= hotplug_dlist
;
2512 hotplug_dlist
= hotplug_dlist
->next
;
2513 (void) g_free_multipath(list
->seslist
);
2514 (void) g_free_multipath(list
->dlhead
);
2522 * removes the device's logical paths.
2526 * non-zero otherwise
2529 h_remove_nodes(struct dlist
*dl
)
2531 char link
[MAXPATHLEN
], path
[MAXPATHLEN
];
2532 char lname
[MAXPATHLEN
], *ptr
;
2534 struct dirent
*dirent
;
2535 struct dlist
*dlist
;
2537 if ((dir
= opendir(DEV_DSK_DIR
)) == NULL
) {
2538 return (L_READ_DEV_DIR_ERROR
);
2541 /* pass "disks" as cmdStrg */
2542 if (h_execCmnd(cmdStrg
[1], 1) != 0) {
2543 return (L_DISKS_ERROR
);
2547 (void) fprintf(stdout
,
2549 " Removing Logical Nodes: \n"));
2551 while ((dirent
= readdir(dir
)) != NULL
) {
2552 if (strcmp(dirent
->d_name
, ".") == 0 ||
2553 strcmp(dirent
->d_name
, "..") == 0) {
2556 (void) sprintf(lname
, DEV_DSK_DIR
"/%s", dirent
->d_name
);
2557 if (readlink((const char *)lname
, (char *)link
,
2558 (size_t)MAXPATHLEN
) <= 0) {
2559 (void) fprintf(stderr
,
2561 " Error: Could not read %s\n"),
2565 for (dlist
= dl
; dlist
!= NULL
; dlist
= dlist
->next
) {
2566 (void) strcpy(path
, dlist
->dev_path
);
2567 ptr
= strrchr(path
, ':');
2570 if (strstr(link
, path
)) {
2571 (void) unlink(lname
);
2572 (void) sprintf(lname
, "/dev/rdsk/%s",
2574 (void) fprintf(stdout
,
2578 (void) unlink(lname
);
2589 * removes the SENA's ses paths.
2593 * non-zero otherwise
2596 h_remove_ses_nodes(struct dlist
*dlist
)
2598 char link
[MAXPATHLEN
], lname
[MAXPATHLEN
];
2600 struct dirent
*dirent
;
2604 if ((dir
= opendir(SES_DIR
)) == NULL
) {
2605 return (L_READ_DEV_DIR_ERROR
);
2608 (void) fprintf(stdout
, MSGSTR(5566, " Removing Ses Nodes:\n"));
2611 * Remove the ses entries
2612 * of the form ses<#>
2613 * from the /dev/es directory.
2616 while ((dirent
= readdir(dir
)) != NULL
) {
2617 if (strcmp(dirent
->d_name
, ".") == 0 ||
2618 strcmp(dirent
->d_name
, "..") == 0)
2621 (void) sprintf(lname
, SES_DIR
"/%s", dirent
->d_name
);
2622 if (readlink((const char *)lname
, (char *)link
,
2623 (size_t)MAXPATHLEN
) <= 0) {
2624 (void) fprintf(stderr
,
2626 " Error: Could not read %s\n"),
2630 for (dl
= dlist
; dl
!= NULL
; dl
= dl
->next
) {
2631 if (strstr(link
, dl
->dev_path
)) {
2632 (void) fprintf(stdout
,
2636 (void) unlink(lname
);
2641 (void) g_free_multipath(dlist
);
2647 * prints the device's logical
2648 * paths for disks to stdout.
2652 * non-zero otherwise
2655 h_print_logical_nodes(struct dlist
*disk_list
)
2657 char *lpath
, *ptr
, *buf_ptr
, buf
[MAXNAMELEN
], dev
[MAXNAMELEN
];
2658 struct dlist
*dlist
;
2659 int i
, found_dev
= 0;
2660 char *tape_entries
[] = { "", "b", "bn", "c", "cb", "cbn", "cn",
2661 "h", "hb", "hbn", "hn", "l", "lb",
2662 "lbn", "ln", "m", "mb", "mbn", "mn",
2663 "n", "u", "ub", "ubn", "un", NULL
};
2665 for (dlist
= disk_list
; dlist
!= NULL
; dlist
= dlist
->next
) {
2666 lpath
= dlist
->logical_path
;
2667 if ((ptr
= strrchr(lpath
, 'c')) == NULL
)
2669 (void) strcpy(buf
, ptr
);
2670 if ((ptr
= strrchr(buf
, 's')) == NULL
)
2675 (void) fprintf(stdout
,
2676 MSGSTR(5559, " Logical Nodes being "
2677 "removed under /dev/dsk/ and "
2679 for (i
= 0; i
<= 7; i
++) {
2680 (void) sprintf(dev
, "%s%d", buf
, i
);
2681 (void) fprintf(stdout
, "\t%s\n", dev
);
2685 for (dlist
= disk_list
; dlist
!= NULL
; dlist
= dlist
->next
) {
2686 lpath
= dlist
->logical_path
;
2687 if (strstr(lpath
, DEV_TAPE_DIR
)) {
2688 if ((ptr
= strrchr(lpath
, '/')) == NULL
)
2692 (void) fprintf(stdout
, "Logical Nodes being "
2693 "removed under /dev/rmt:\n");
2696 while (*ptr
>= '0' && *ptr
<= '9')
2699 for (i
= 0, ptr
= tape_entries
[0];
2701 i
++, ptr
= tape_entries
[i
]) {
2702 (void) sprintf(dev
, "%s%s", buf_ptr
, ptr
);
2703 (void) fprintf(stdout
, "\t%s\n", dev
);
2710 * displays logical paths to a
2715 * non-zero otherwise
2718 h_display_logical_nodes(struct dlist
*dlist
)
2720 char link
[MAXPATHLEN
], path
[MAXPATHLEN
];
2721 char lname
[MAXPATHLEN
], *d1
;
2723 struct dirent
*dirent
;
2727 if ((dir
= opendir(DEV_DSK_DIR
)) == NULL
) {
2728 return (L_READ_DEV_DIR_ERROR
);
2730 (void) fprintf(stdout
,
2732 " Logical Nodes under /dev/dsk and /dev/rdsk :\n"));
2734 while ((dirent
= readdir(dir
)) != NULL
) {
2735 if (strcmp(dirent
->d_name
, ".") == 0 ||
2736 strcmp(dirent
->d_name
, "..") == 0) {
2739 (void) sprintf(lname
, DEV_DSK_DIR
"/%s", dirent
->d_name
);
2740 if (readlink((const char *)lname
, (char *)link
,
2741 (size_t)MAXPATHLEN
) <= 0) {
2742 (void) print_errString(L_SYMLINK_ERROR
, lname
);
2745 for (dl
= dlist
; dl
; dl
= dl
->next
) {
2746 (void) strcpy(path
, dl
->dev_path
);
2747 d1
= strrchr(path
, ':');
2750 if (strstr(link
, path
)) {
2751 (void) fprintf(stdout
,
2765 * prints a list of devices which
2766 * will be inserted or removed
2767 * to the stdout and asks for
2768 * the user's confirmation.
2772 * non-zero otherwise
2775 h_print_list_warn(Hotplug_Devlist
*disk_list_head
, int todo
, int enc_type
)
2779 struct dlist
*dl_ses
, *dl_multi
;
2780 Hotplug_Devlist
*disk_list
= disk_list_head
;
2782 (void) fprintf(stdout
,
2783 MSGSTR(5570, "The list of devices which will be "));
2786 (void) fprintf(stdout
,
2787 MSGSTR(5571, "inserted is:\n"));
2790 (void) fprintf(stdout
,
2791 MSGSTR(5572, "removed is:\n"));
2795 for (i
= 1; disk_list
; i
++, disk_list
= disk_list
->next
) {
2796 if ((disk_list
->dev_type
== DTYPE_DIRECT
) &&
2797 (disk_list
->dev_location
== SENA
)) {
2798 if (disk_list
->f_flag
!= NULL
) {
2799 if (enc_type
== DAK_ENC_TYPE
) {
2800 (void) fprintf(stdout
, MSGSTR(5665,
2801 " %d: Box Name: \"%s\" slot %d\n"),
2802 i
, disk_list
->box_name
, disk_list
->slot
);
2804 (void) fprintf(stdout
, MSGSTR(137,
2805 " %d: Box Name: \"%s\" front slot %d\n"),
2806 i
, disk_list
->box_name
, disk_list
->slot
);
2809 if (enc_type
== DAK_ENC_TYPE
) {
2810 (void) fprintf(stdout
, MSGSTR(5665,
2811 " %d: Box Name: \"%s\" slot %d\n"),
2812 i
, disk_list
->box_name
,
2813 disk_list
->slot
+ (MAX_DRIVES_DAK
/2));
2815 (void) fprintf(stdout
, MSGSTR(136,
2816 " %d: Box Name: \"%s\" rear slot %d\n"),
2817 i
, disk_list
->box_name
, disk_list
->slot
);
2820 } else if (((disk_list
->dev_type
== DTYPE_DIRECT
) ||
2821 (disk_list
->dev_type
== DTYPE_SEQUENTIAL
)) &&
2822 (disk_list
->dev_location
== NON_SENA
)) {
2823 (void) fprintf(stdout
, MSGSTR(5573,
2824 " %d: Device name: %s\n"),
2825 i
, disk_list
->dev_name
);
2826 } else if (disk_list
->dev_type
== DTYPE_ESI
) {
2827 (void) fprintf(stdout
, MSGSTR(5574,
2828 " %d: Box name: %s\n"),
2829 i
, disk_list
->box_name
);
2831 if (getenv("_LUX_H_DEBUG") != NULL
) {
2832 if (disk_list
->dev_location
== SENA
) {
2833 (void) fprintf(stdout
,
2834 " Select ID:\t0x%x\n",
2836 if (disk_list
->dev_type
!= DTYPE_ESI
) {
2837 if (enc_type
== DAK_ENC_TYPE
) {
2838 (void) fprintf(stdout
,
2839 " Location: \tSlot %d \n",
2845 (void) fprintf(stdout
,
2846 " Location: \tSlot %d %s \n",
2847 disk_list
->slot
, disk_list
->f_flag
2848 ? "front" : "rear");
2853 if (todo
== REMOVE_DEVICE
) {
2854 (void) fprintf(stdout
, " ");
2855 (void) fprintf(stdout
, MSGSTR(90, "Node WWN:"));
2856 (void) fprintf(stdout
, " %s\n",
2857 disk_list
->node_wwn_s
);
2859 (void) fprintf(stdout
, " ");
2860 (void) fprintf(stdout
, MSGSTR(35, "Device Type:"));
2861 if (disk_list
->dev_type
== DTYPE_ESI
) {
2862 (void) fprintf(stdout
, MSGSTR(5581,
2864 dtype
[disk_list
->dev_type
]);
2866 (void) fprintf(stdout
, "%s\n",
2867 dtype
[disk_list
->dev_type
]);
2870 if (disk_list
->dev_type
== DTYPE_ESI
) {
2871 dl_ses
= disk_list
->seslist
;
2872 (void) fprintf(stdout
, MSGSTR(5575,
2875 (void) fprintf(stdout
, MSGSTR(5576,
2876 " %s\n"), dl_ses
->dev_path
);
2877 dl_ses
= dl_ses
->next
;
2880 dl_multi
= disk_list
->dlhead
;
2881 (void) fprintf(stdout
, MSGSTR(5577,
2882 " Device Paths:\n"));
2884 (void) fprintf(stdout
, MSGSTR(5578,
2886 dl_multi
->logical_path
);
2887 dl_multi
= dl_multi
->next
;
2891 (void) fprintf(stdout
, "\n");
2893 (void) fprintf(stdout
, MSGSTR(5579,
2894 "\nPlease verify the above list of devices"
2895 " and\nthen enter 'c' or <CR> to Continue"
2896 " or 'q' to Quit. [Default: c]: "));
2898 /* Get the user input and continue accordingly. */
2900 (void) gets(choice
);
2901 if (choice
[0] == 'c' || choice
[0] == 'C' ||
2902 choice
[0] == 'q' || choice
[0] == 'Q' ||
2903 choice
[0] == '\0') {
2906 (void) fprintf(stdout
, MSGSTR(5580,
2907 " Enter an appropriate option [c,<CR>,q]: "));
2910 if (choice
[0] == 'q' || choice
[0] == 'Q') {
2918 h_find_new_device_link(char *device_dir
, timestruc_t lastmtim
)
2920 struct stat dsk_stat
;
2921 char lname
[MAXPATHLEN
], link
[MAXPATHLEN
];
2924 struct dirent
*dirent
;
2925 int found_newlink
= 0;
2928 if ((dir
= opendir(device_dir
)) == NULL
) {
2929 if (errno
== ENOENT
) {
2932 return (L_READ_DEV_DIR_ERROR
);
2936 while ((dirent
= readdir(dir
)) != NULL
) {
2937 if (strcmp(dirent
->d_name
, ".") == 0 ||
2938 strcmp(dirent
->d_name
, "..") == 0) {
2941 (void) sprintf(lname
, "%s/%s", device_dir
, dirent
->d_name
);
2942 if (lstat(lname
, &dsk_stat
) < 0) {
2943 (void) print_errString(L_LSTAT_ES_DIR_ERROR
,
2947 if (readlink((const char *)lname
, (char *)link
,
2948 (size_t)MAXPATHLEN
) <= 0) {
2949 (void) print_errString(L_SYMLINK_ERROR
, lname
);
2954 * "link" can be a relative pathname. But, since
2955 * g_get_path_type() only accepts absolute paths, we
2956 * will skip to the part where "/devices/" begins and pass a
2957 * pointer from there. Since "link" is got from readlink(),
2958 * it is unlikely that it will not have /devices string, but
2959 * we will check for it anyways.
2961 if (!(link_ptr
= strstr(link
, "/devices/")))
2963 if (!g_get_path_type(link_ptr
)) {
2966 if (NEWER(dsk_stat
.st_ctim
, lastmtim
)) {
2968 if (found_newlink
== 1) {
2969 if (! (strcmp(device_dir
, DEV_DSK_DIR
))) {
2970 (void) fprintf(stdout
, MSGSTR(5561,
2971 " New Logical Nodes under "
2972 "/dev/dsk and /dev/rdsk :\n"));
2973 } else { /* device_dir is /dev/rmt */
2974 (void) fprintf(stdout
, "New Logical "
2975 "Node under /dev/rmt:\n");
2978 (void) fprintf(stdout
, "\t%s\n", dirent
->d_name
);
2982 return (found_newlink
);
2987 * prints the device state.
2993 print_dev_state(char *devname
, int state
)
2995 (void) printf("\t%s: ", devname
);
2996 if (state
& DEVICE_ONLINE
) {
2997 (void) printf(MSGSTR(3000, "Online"));
2998 if (state
& DEVICE_BUSY
) {
3000 (void) printf(MSGSTR(37, "Busy"));
3002 if (state
& DEVICE_DOWN
) {
3004 (void) printf(MSGSTR(118, "Down"));
3007 if (state
& DEVICE_OFFLINE
) {
3008 (void) printf(MSGSTR(3001, "Offline"));
3009 if (state
& DEVICE_DOWN
) {
3011 (void) printf(MSGSTR(118, "Down"));
3015 (void) printf("\n");
3020 * prints the bus state.
3026 print_bus_state(char *devname
, int state
)
3028 (void) printf("\t%s: ", devname
);
3029 if (state
== BUS_QUIESCED
) {
3030 (void) printf(MSGSTR(3002, "Quiesced"));
3031 } else if (state
== BUS_ACTIVE
) {
3032 (void) printf(MSGSTR(39, "Active"));
3033 } else if (state
== BUS_SHUTDOWN
) {
3034 (void) printf(MSGSTR(3003, "Shutdown"));
3036 (void) printf("\n");