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.
30 * This file contains helper routines for the FP plugin
33 #if !defined(TEXT_DOMAIN)
34 #define TEXT_DOMAIN "SYS_TEST"
37 typedef struct strlist
{
50 int (*fcn
)(const devctl_hdl_t
);
56 int (*state_fcn
)(const devctl_hdl_t
, uint_t
*);
59 /* defines for nftw() */
61 #define NFTW_CONTINUE 0
62 #define NFTW_TERMINATE 1
64 #define MAX_RETRIES 10
66 /* Function prototypes */
67 static int do_recurse_dev(const char *path
, const struct stat
*sbuf
,
68 int type
, struct FTW
*ftwp
);
69 static fpcfga_recur_t
lookup_dev(const char *lpath
, void *arg
);
70 static void msg_common(char **err_msgpp
, int append_newline
, int l_errno
,
72 static void lunlist_free(struct luninfo_list
*lunlist
);
78 fpcfga_recur_t (*fcn
)(const char *lpath
, void *arg
);
79 } nftw_arg
= {DEFAULTMUTEX
};
82 * The string table contains most of the strings used by the fp cfgadm plugin.
83 * All strings which are to be internationalized must be in this table.
84 * Some strings which are not internationalized are also included here.
85 * Arguments to messages are NOT internationalized.
87 msgcvt_t str_tbl
[] = {
90 * The first element (ERR_UNKNOWN) MUST always be present in the array.
92 #define UNKNOWN_ERR_IDX 0 /* Keep the index in sync */
95 /* msg_code num_args, I18N msg_string */
98 {ERR_UNKNOWN
, 0, 1, "unknown error"},
99 {ERR_OP_FAILED
, 0, 1, "operation failed"},
100 {ERR_CMD_INVAL
, 0, 1, "invalid command"},
101 {ERR_NOT_BUSAPID
, 0, 1, "not a FP bus apid"},
102 {ERR_APID_INVAL
, 0, 1, "invalid FP ap_id"},
103 {ERR_NOT_BUSOP
, 0, 1, "operation not supported for FC bus"},
104 {ERR_NOT_DEVOP
, 0, 1, "operation not supported for FC device"},
105 {ERR_UNAVAILABLE
, 0, 1, "unavailable"},
106 {ERR_CTRLR_CRIT
, 0, 1, "critical partition controlled by FC HBA"},
107 {ERR_BUS_GETSTATE
, 0, 1, "failed to get state for FC bus"},
108 {ERR_BUS_NOTCONNECTED
, 0, 1, "FC bus not connected"},
109 {ERR_BUS_CONNECTED
, 0, 1, "FC bus not disconnected"},
110 {ERR_BUS_QUIESCE
, 0, 1, "FC bus quiesce failed"},
111 {ERR_BUS_UNQUIESCE
, 0, 1, "FC bus unquiesce failed"},
112 {ERR_BUS_CONFIGURE
, 0, 1, "failed to configure devices on FC bus"},
113 {ERR_BUS_UNCONFIGURE
, 0, 1, "failed to unconfigure FC bus"},
114 {ERR_DEV_CONFIGURE
, 0, 1, "failed to configure FC device"},
115 {ERR_DEV_UNCONFIGURE
, 0, 1, "failed to unconfigure FC device"},
116 {ERR_FCA_CONFIGURE
, 0, 1, "failed to configure ANY device on FCA port"},
117 {ERR_FCA_UNCONFIGURE
, 0, 1, "failed to unconfigure ANY device on FCA port"},
118 {ERR_DEV_REPLACE
, 0, 1, "replace operation failed"},
119 {ERR_DEV_INSERT
, 0, 1, "insert operation failed"},
120 {ERR_DEV_GETSTATE
, 0, 1, "failed to get state for FC device"},
121 {ERR_RESET
, 0, 1, "reset failed"},
122 {ERR_LIST
, 0, 1, "list operation failed"},
123 {ERR_SIG_STATE
, 0, 1, "could not restore signal disposition"},
124 {ERR_MAYBE_BUSY
, 0, 1, "device may be busy"},
125 {ERR_BUS_DEV_MISMATCH
, 0, 1, "mismatched FC bus and device"},
126 {ERR_MEM_ALLOC
, 0, 1, "Failed to allocated memory"},
127 {ERR_DEVCTL_OFFLINE
, 0, 1, "failed to offline device"},
128 {ERR_UPD_REP
, 0, 1, "Repository update failed"},
129 {ERR_CONF_OK_UPD_REP
, 0, 1,
130 "Configuration successful, but Repository update failed"},
131 {ERR_UNCONF_OK_UPD_REP
, 0, 1,
132 "Unconfiguration successful, but Repository update failed"},
133 {ERR_PARTIAL_SUCCESS
, 0, 1,
134 "Operation partially successful. Some failures seen"},
135 {ERR_HBA_LOAD_LIBRARY
, 0, 1,
136 "HBA load library failed"},
137 {ERR_MATCHING_HBA_PORT
, 0, 1,
138 "No match HBA port found"},
139 {ERR_NO_ADAPTER_FOUND
, 0, 1,
140 "No Fibre Channel adapters found"},
142 /* Errors with arguments */
143 {ERRARG_OPT_INVAL
, 1, 1, "invalid option: "},
144 {ERRARG_HWCMD_INVAL
, 1, 1, "invalid command: "},
145 {ERRARG_DEVINFO
, 1, 1, "libdevinfo failed on path: "},
146 {ERRARG_NOT_IN_DEVLIST
, 1, 1, "Device not found in fabric device list: "},
147 {ERRARG_NOT_IN_DEVINFO
, 1, 1, "Could not find entry in devinfo tree: "},
148 {ERRARG_DI_GET_PROP
, 1, 1, "Could not get libdevinfo property: "},
149 {ERRARG_DC_DDEF_ALLOC
, 1, 1, "failed to alloc ddef space: "},
150 {ERRARG_DC_BYTE_ARRAY
, 1, 1, "failed to add property: "},
151 {ERRARG_DC_BUS_ACQUIRE
, 1, 1, "failed to acquire bus handle: "},
152 {ERRARG_BUS_DEV_CREATE
, 1, 1, "failed to create device node: "},
153 {ERRARG_BUS_DEV_CREATE_UNKNOWN
, 1, 1,
154 "failed to create device node... Device may be unconfigurable: "},
155 {ERRARG_DEV_ACQUIRE
, 1, 1, "device acquire operation failed: "},
156 {ERRARG_DEV_REMOVE
, 1, 1, "remove operation failed: "},
158 /* Fibre Channel operation Errors */
159 {ERR_FC
, 0, 1, "FC error"},
160 {ERR_FC_GET_DEVLIST
, 0, 1, "Failed to get fabric device list"},
161 {ERR_FC_GET_NEXT_DEV
, 0, 1, "Failed to get next device on device map"},
162 {ERR_FC_GET_FIRST_DEV
, 0, 1, "Failed to get first device on device map"},
163 {ERRARG_FC_DEV_MAP_INIT
, 1, 1,
164 "Failed to initialize device map for: "},
165 {ERRARG_FC_PROP_LOOKUP_BYTES
, 1, 1, "Failed to get property of "},
166 {ERRARG_FC_INQUIRY
, 1, 1, "inquiry failed: "},
167 {ERRARG_FC_REP_LUNS
, 1, 1, "report LUNs failed: "},
168 {ERRARG_FC_TOPOLOGY
, 1, 1, "failed to get port topology: "},
169 {ERRARG_PATH_TOO_LONG
, 1, 1, "Path length exceeds max possible: "},
170 {ERRARG_INVALID_PATH
, 1, 1, "Invalid path: "},
171 {ERRARG_OPENDIR
, 1, 1, "failure opening directory: "},
174 {ERRARG_VHCI_GET_PATHLIST
, 1, 1, "failed to get path list from vHCI: "},
175 {ERRARG_XPORT_NOT_IN_PHCI_LIST
, 1, 1, "Transport not in pHCI list: "},
178 {ERR_RCM_HANDLE
, 0, 1, "cannot get RCM handle"},
179 {ERRARG_RCM_SUSPEND
, 1, 1, "failed to suspend: "},
180 {ERRARG_RCM_RESUME
, 1, 1, "failed to resume: "},
181 {ERRARG_RCM_OFFLINE
, 1, 1, "failed to offline: "},
182 {ERRARG_RCM_ONLINE
, 1, 1, "failed to online: "},
183 {ERRARG_RCM_REMOVE
, 1, 1, "failed to remove: "},
184 {ERRARG_RCM_INFO
, 1, 1, "failed to query: "},
187 {CMD_INSERT_DEV
, 0, 0, "insert_device"},
188 {CMD_REMOVE_DEV
, 0, 0, "remove_device"},
189 {CMD_REPLACE_DEV
, 0, 0, "replace_device"},
190 {CMD_RESET_DEV
, 0, 0, "reset_device"},
191 {CMD_RESET_BUS
, 0, 0, "reset_bus"},
192 {CMD_RESET_ALL
, 0, 0, "reset_all"},
195 {MSG_HELP_HDR
, 0, 1, "\nfp attachment point specific options:\n"},
196 {MSG_HELP_USAGE
, 0, 0,
197 "\t-c configure -o force_update ap_id [ap_id..]\n"
198 "\t-c configure -o no_update ap_id [ap_id...]\n"
199 "\t-c unconfigure -o force_update ap_id [ap_id... ]\n"
200 "\t-c unconfigure -o no_update ap_id [ap_id... ]\n"},
202 /* hotplug messages */
203 {MSG_INSDEV
, 1, 1, "Adding device to FC HBA: "},
204 {MSG_RMDEV
, 1, 1, "Removing FC device: "},
205 {MSG_REPLDEV
, 1, 1, "Replacing FC device: "},
207 /* Hotplugging confirmation prompts */
208 {CONF_QUIESCE_1
, 1, 1,
209 "This operation will suspend activity on FC bus: "},
211 {CONF_QUIESCE_2
, 0, 1, "\nContinue"},
213 {CONF_UNQUIESCE
, 0, 1,
214 "FC bus quiesced successfully.\n"
215 "It is now safe to proceed with hotplug operation."
216 "\nEnter y if operation is complete or n to abort"},
219 {WARN_DISCONNECT
, 0, 1,
220 "WARNING: Disconnecting critical partitions may cause system hang."
225 #define N_STRS (sizeof (str_tbl) / sizeof (str_tbl[0]))
227 #define GET_MSG_NARGS(i) (str_tbl[msg_idx(i)].nargs)
228 #define GET_MSG_INTL(i) (str_tbl[msg_idx(i)].intl)
230 static errcvt_t err_cvt_tbl
[] = {
231 { FPCFGA_OK
, CFGA_OK
},
232 { FPCFGA_LIB_ERR
, CFGA_LIB_ERROR
},
233 { FPCFGA_APID_NOEXIST
, CFGA_APID_NOEXIST
},
234 { FPCFGA_NACK
, CFGA_NACK
},
235 { FPCFGA_BUSY
, CFGA_BUSY
},
236 { FPCFGA_SYSTEM_BUSY
, CFGA_SYSTEM_BUSY
},
237 { FPCFGA_OPNOTSUPP
, CFGA_OPNOTSUPP
},
238 { FPCFGA_PRIV
, CFGA_PRIV
},
239 { FPCFGA_UNKNOWN_ERR
, CFGA_ERROR
},
240 { FPCFGA_ERR
, CFGA_ERROR
}
243 #define N_ERR_CVT_TBL (sizeof (err_cvt_tbl)/sizeof (err_cvt_tbl[0]))
247 static set_state_cmd_t set_state_cmds
[] = {
249 { FPCFGA_BUS_QUIESCE
, BUS_OP
, devctl_bus_quiesce
},
250 { FPCFGA_BUS_UNQUIESCE
, BUS_OP
, devctl_bus_unquiesce
},
251 { FPCFGA_BUS_CONFIGURE
, BUS_OP
, devctl_bus_configure
},
252 { FPCFGA_BUS_UNCONFIGURE
, BUS_OP
, devctl_bus_unconfigure
},
253 { FPCFGA_RESET_BUS
, BUS_OP
, devctl_bus_reset
},
254 { FPCFGA_RESET_ALL
, BUS_OP
, devctl_bus_resetall
},
255 { FPCFGA_DEV_CONFIGURE
, DEV_OP
, devctl_device_online
},
256 { FPCFGA_DEV_UNCONFIGURE
, DEV_OP
, devctl_device_offline
},
257 { FPCFGA_DEV_REMOVE
, DEV_OP
, devctl_device_remove
},
258 { FPCFGA_RESET_DEV
, DEV_OP
, devctl_device_reset
}
262 #define N_SET_STATE_CMDS (sizeof (set_state_cmds)/sizeof (set_state_cmds[0]))
264 static get_state_cmd_t get_state_cmds
[] = {
265 { FPCFGA_BUS_GETSTATE
, BUS_OP
, devctl_bus_getstate
},
266 { FPCFGA_DEV_GETSTATE
, DEV_OP
, devctl_device_getstate
}
269 #define N_GET_STATE_CMDS (sizeof (get_state_cmds)/sizeof (get_state_cmds[0]))
271 /* Order is important. Earlier directories are searched first */
272 static const char *dev_dir_hints
[] = {
280 #define N_DEV_DIR_HINTS (sizeof (dev_dir_hints) / sizeof (dev_dir_hints[0]))
284 * Routine to search the /dev directory or a subtree of /dev.
285 * If the entire /dev hierarchy is to be searched, the most likely directories
286 * are searched first.
292 fpcfga_recur_t (*fcn
)(const char *lpath
, void *arg
))
294 int i
, rv
= NFTW_ERROR
;
296 (void) mutex_lock(&nftw_arg
.mp
);
301 if (strcmp(basedir
, DEV_DIR
)) {
303 rv
= nftw(basedir
, do_recurse_dev
, NFTW_DEPTH
, FTW_PHYS
);
308 * Search certain selected subdirectories first if basedir == "/dev".
309 * Ignore errors as some of these directories may not exist.
311 for (i
= 0; i
< N_DEV_DIR_HINTS
; i
++) {
313 if ((rv
= nftw(dev_dir_hints
[i
], do_recurse_dev
, NFTW_DEPTH
,
314 FTW_PHYS
)) == NFTW_TERMINATE
) {
321 (void) mutex_unlock(&nftw_arg
.mp
);
322 return (rv
== NFTW_ERROR
? FPCFGA_ERR
: FPCFGA_OK
);
329 const struct stat
*sbuf
,
333 /* We want only VALID symlinks */
334 if (type
!= FTW_SL
) {
335 return (NFTW_CONTINUE
);
338 assert(nftw_arg
.fcn
!= NULL
);
340 if (nftw_arg
.fcn(path
, nftw_arg
.arg
) == FPCFGA_TERMINATE
) {
341 /* terminate prematurely, but may not be error */
343 return (NFTW_TERMINATE
);
345 return (NFTW_CONTINUE
);
350 err_cvt(fpcfga_ret_t fp_err
)
354 for (i
= 0; i
< N_ERR_CVT_TBL
; i
++) {
355 if (err_cvt_tbl
[i
].fp_err
== fp_err
) {
356 return (err_cvt_tbl
[i
].cfga_err
);
364 * Removes duplicate slashes from a pathname and any trailing slashes.
365 * Returns "/" if input is "/"
368 pathdup(const char *path
, int *l_errnop
)
370 int prev_was_slash
= 0;
371 char c
, *dp
= NULL
, *dup
= NULL
;
372 const char *sp
= NULL
;
380 if ((dup
= calloc(1, strlen(path
) + 1)) == NULL
) {
386 for (sp
= path
, dp
= dup
; (c
= *sp
) != '\0'; sp
++) {
387 if (!prev_was_slash
|| c
!= '/') {
397 /* Remove trailing slash except if it is the first char */
398 if (prev_was_slash
&& dp
!= dup
&& dp
- 1 != dup
) {
408 apidt_create(const char *ap_id
, apid_t
*apidp
, char **errstring
)
410 char *xport_phys
= NULL
, *dyn
= NULL
;
411 char *dyncomp
= NULL
;
412 struct luninfo_list
*lunlistp
= NULL
;
417 if ((xport_phys
= pathdup(ap_id
, &l_errno
)) == NULL
) {
418 cfga_err(errstring
, l_errno
, ERR_OP_FAILED
, 0);
419 return (FPCFGA_LIB_ERR
);
422 /* Extract the base(hba) and dynamic(device) component if any */
424 if ((dyn
= GET_DYN(xport_phys
)) != NULL
) {
425 len
= strlen(DYN_TO_DYNCOMP(dyn
)) + 1;
426 dyncomp
= calloc(1, len
);
427 if (dyncomp
== NULL
) {
428 cfga_err(errstring
, errno
, ERR_OP_FAILED
, 0);
429 ret
= FPCFGA_LIB_ERR
;
432 (void) strcpy(dyncomp
, DYN_TO_DYNCOMP(dyn
));
433 if (GET_LUN_DYN(dyncomp
)) {
434 ret
= FPCFGA_APID_NOEXIST
;
438 /* Remove the dynamic component from the base. */
442 /* Get the path of dynamic attachment point if already configured. */
443 if (dyncomp
!= NULL
) {
444 ret
= dyn_apid_to_path(xport_phys
, dyncomp
,
445 &lunlistp
, &l_errno
);
446 if ((ret
!= FPCFGA_OK
) && (ret
!= FPCFGA_APID_NOCONFIGURE
)) {
447 cfga_err(errstring
, l_errno
, ERR_OP_FAILED
, 0);
452 assert(xport_phys
!= NULL
);
454 apidp
->xport_phys
= xport_phys
;
455 apidp
->dyncomp
= dyncomp
;
456 apidp
->lunlist
= lunlistp
;
464 lunlist_free(lunlistp
);
469 lunlist_free(struct luninfo_list
*lunlist
)
471 struct luninfo_list
*lunp
;
473 while (lunlist
!= NULL
) {
474 lunp
= lunlist
->next
;
475 S_FREE(lunlist
->path
);
482 apidt_free(apid_t
*apidp
)
487 S_FREE(apidp
->xport_phys
);
488 S_FREE(apidp
->dyncomp
);
489 lunlist_free(apidp
->lunlist
);
494 const char *physpath
,
502 di_node_t root
, tree_root
, fpnode
;
503 char *root_path
, *cp
= NULL
;
511 if ((root_path
= strdup(physpath
)) == NULL
) {
513 return (FPCFGA_LIB_ERR
);
516 /* Fix up path for di_init() */
517 len
= strlen(DEVICES_DIR
);
518 if (strncmp(root_path
, DEVICES_DIR SLASH
,
519 len
+ strlen(SLASH
)) == 0) {
520 cp
= root_path
+ len
;
521 (void) memmove(root_path
, cp
, strlen(cp
) + 1);
522 } else if (*root_path
!= '/') {
528 /* Remove dynamic component if any */
529 if ((cp
= GET_DYN(root_path
)) != NULL
) {
533 /* Remove minor name if any */
534 if ((cp
= strrchr(root_path
, ':')) != NULL
) {
539 * If force_flag is set
540 * do di_init with DINFOFORCE flag and get to the input fp node
541 * from the device tree.
543 * In order to get the link between path_info node and scsi_vhci node
544 * it is required to take the snapshot of the whole device tree.
545 * this behavior of libdevinfo is inefficient. For a specific
546 * fca port DINFOPROP was sufficient on the fca path prior to
547 * scsi_vhci node support.
550 if ((up
->flags
& FLAG_DEVINFO_FORCE
) == FLAG_DEVINFO_FORCE
) {
551 tree_root
= di_init("/", init_flags
| DINFOFORCE
);
553 tree_root
= di_init("/", init_flags
);
556 if (tree_root
== DI_NODE_NIL
) {
558 ret
= FPCFGA_LIB_ERR
;
562 fpnode
= di_drv_first_node("fp", tree_root
);
565 devfs_fp_path
= di_devfs_path(fpnode
);
566 if ((devfs_fp_path
) && !(strncmp(devfs_fp_path
,
567 root_path
, strlen(root_path
)))) {
569 di_devfs_path_free(devfs_fp_path
);
572 di_devfs_path_free(devfs_fp_path
);
573 fpnode
= di_drv_next_node(fpnode
);
576 ret
= FPCFGA_LIB_ERR
;
584 if (cmd
== FPCFGA_WALK_NODE
) {
585 rv
= di_walk_node(root
, up
->walkmode
.node_args
.flags
, arg
,
586 up
->walkmode
.node_args
.fcn
);
588 assert(cmd
== FPCFGA_WALK_MINOR
);
589 rv
= di_walk_minor(root
, up
->walkmode
.minor_args
.nodetype
, 0,
590 arg
, up
->walkmode
.minor_args
.fcn
);
595 ret
= FPCFGA_LIB_ERR
;
597 if ((up
->flags
& FLAG_PATH_INFO_WALK
) == FLAG_PATH_INFO_WALK
) {
598 ret
= stat_path_info_node(root
, arg
, l_errnop
);
615 msg_idx(msgid_t msgid
)
619 /* The string table index and the error id may or may not be same */
620 if (msgid
>= 0 && msgid
<= N_STRS
- 1 &&
621 str_tbl
[msgid
].msgid
== msgid
) {
624 for (idx
= 0; idx
< N_STRS
; idx
++) {
625 if (str_tbl
[idx
].msgid
== msgid
)
629 idx
= UNKNOWN_ERR_IDX
;
637 * cfga_err() accepts a variable number of message IDs and constructs
638 * a corresponding error string which is returned via the errstring argument.
639 * cfga_err() calls dgettext() to internationalize proper messages.
640 * May be called with a NULL argument.
643 cfga_err(char **errstring
, int l_errno
, ...)
646 int append_newline
= 0;
647 char *tmp_str
, *tmp_err_str
= NULL
;
649 if (errstring
== NULL
) {
654 * Don't append a newline, the application (for example cfgadm)
659 va_start(ap
, l_errno
);
660 msg_common(&tmp_err_str
, append_newline
, l_errno
, ap
);
663 if (*errstring
== NULL
) {
664 *errstring
= tmp_err_str
;
670 * There was something in errstring prior to this call.
671 * So, concatenate the old and new strings
673 if ((tmp_str
= calloc(1,
674 strlen(*errstring
) + strlen(tmp_err_str
) + 2)) == NULL
) {
675 /* In case of error, retain only the earlier message */
680 sprintf(tmp_str
, "%s\n%s", *errstring
, tmp_err_str
);
683 *errstring
= tmp_str
;
687 * This routine accepts a variable number of message IDs and constructs
688 * a corresponding message string which is printed via the message print
692 cfga_msg(struct cfga_msg
*msgp
, ...)
695 int append_newline
= 0, l_errno
= 0;
698 if (msgp
== NULL
|| msgp
->message_routine
== NULL
) {
702 /* Append a newline after message */
707 msg_common(&p
, append_newline
, l_errno
, ap
);
710 (void) (*msgp
->message_routine
)(msgp
->appdata_ptr
, p
);
716 * Get internationalized string corresponding to message id
717 * Caller must free the memory allocated.
720 cfga_str(int append_newline
, ...)
726 va_start(ap
, append_newline
);
727 msg_common(&p
, append_newline
, l_errno
, ap
);
734 msg_common(char **msgpp
, int append_newline
, int l_errno
, va_list ap
)
739 char *s
= NULL
, *t
= NULL
;
741 strlist_t
*savep
= NULL
, *sp
= NULL
, *tailp
= NULL
;
743 if (*msgpp
!= NULL
) {
749 for (len
= 0; (a
= va_arg(ap
, int)) != 0; ) {
750 n
= GET_MSG_NARGS(a
); /* 0 implies no additional args */
751 for (i
= 0; i
<= n
; i
++) {
752 sp
= calloc(1, sizeof (*sp
));
756 if (i
== 0 && GET_MSG_INTL(a
)) {
757 sp
->str
= dgettext(TEXT_DOMAIN
, GET_MSG_STR(a
));
759 sp
->str
= GET_MSG_STR(a
);
761 sp
->str
= va_arg(ap
, char *);
763 len
+= (strlen(sp
->str
));
770 len
+= 1; /* terminating NULL */
774 s
= dgettext(TEXT_DOMAIN
, ": ");
775 t
= S_STR(strerror(l_errno
));
776 if (s
!= NULL
&& t
!= NULL
) {
777 len
+= strlen(s
) + strlen(t
);
781 if (append_newline
) {
785 if ((*msgpp
= calloc(1, len
)) == NULL
) {
790 for (sp
= dummy
.next
; sp
!= NULL
; sp
= sp
->next
) {
791 (void) strcat(*msgpp
, sp
->str
);
794 if (s
!= NULL
&& t
!= NULL
) {
795 (void) strcat(*msgpp
, s
);
796 (void) strcat(*msgpp
, t
);
799 if (append_newline
) {
800 (void) strcat(*msgpp
, dgettext(TEXT_DOMAIN
, "\n"));
815 const char *physpath
,
820 int rv
= -1, i
, type
;
821 devctl_hdl_t hdl
= NULL
;
822 char *cp
= NULL
, *path
= NULL
;
823 int (*func
)(const devctl_hdl_t
);
824 int (*state_func
)(const devctl_hdl_t
, uint_t
*);
828 if (statep
!= NULL
) *statep
= 0;
834 for (i
= 0; i
< N_GET_STATE_CMDS
; i
++) {
835 if (get_state_cmds
[i
].cmd
== cmd
) {
836 state_func
= get_state_cmds
[i
].state_fcn
;
837 type
= get_state_cmds
[i
].type
;
838 assert(statep
!= NULL
);
843 if (state_func
== NULL
) {
844 for (i
= 0; i
< N_SET_STATE_CMDS
; i
++) {
845 if (set_state_cmds
[i
].cmd
== cmd
) {
846 func
= set_state_cmds
[i
].fcn
;
847 type
= set_state_cmds
[i
].type
;
848 assert(statep
== NULL
);
854 assert(type
== BUS_OP
|| type
== DEV_OP
);
856 if (func
== NULL
&& state_func
== NULL
) {
861 * Fix up path for calling devctl.
863 if ((path
= strdup(physpath
)) == NULL
) {
865 return (FPCFGA_LIB_ERR
);
868 /* Remove dynamic component if any */
869 if ((cp
= GET_DYN(path
)) != NULL
) {
873 /* Remove minor name */
874 if ((cp
= strrchr(path
, ':')) != NULL
) {
880 if (type
== BUS_OP
) {
881 hdl
= devctl_bus_acquire(path
, 0);
883 hdl
= devctl_device_acquire(path
, 0);
894 /* Only getstate functions require a second argument */
895 if (func
!= NULL
&& statep
== NULL
) {
898 } else if (state_func
!= NULL
&& statep
!= NULL
) {
899 rv
= state_func(hdl
, statep
);
908 return ((rv
== -1) ? FPCFGA_ERR
: FPCFGA_OK
);
912 * Is device in a known state ? (One of BUSY, ONLINE, OFFLINE)
913 * BUSY --> One or more device special files are open. Implies online
914 * ONLINE --> driver attached
915 * OFFLINE --> CF1 with offline flag set.
916 * UNKNOWN --> None of the above
919 known_state(di_node_t node
)
923 state
= di_state(node
);
926 * CF1 without offline flag set is considered unknown state.
927 * We are in a known state if either CF2 (driver attached) or
930 if ((state
& DI_DEVICE_OFFLINE
) == DI_DEVICE_OFFLINE
||
931 (state
& DI_DRIVER_DETACHED
) != DI_DRIVER_DETACHED
) {
939 list_free(ldata_list_t
**llpp
)
941 ldata_list_t
*lp
, *olp
;
954 * Obtain the devlink from a /devices path
964 pathm_t pmt
= {NULL
};
967 pmt
.phys
= xport_phys
;
968 pmt
.ret
= FPCFGA_NO_REC
;
969 pmt
.match_minor
= match_minor
;
972 * Search the /dev hierarchy starting at basedir.
974 ret
= recurse_dev(basedir
, &pmt
, lookup_dev
);
975 if (ret
== FPCFGA_OK
&& (ret
= pmt
.ret
) == FPCFGA_OK
) {
976 assert(pmt
.log
!= NULL
);
977 *xport_logpp
= pmt
.log
;
979 if (pmt
.log
!= NULL
) {
984 *l_errnop
= pmt
.l_errno
;
990 static fpcfga_recur_t
991 lookup_dev(const char *lpath
, void *arg
)
993 char ppath
[PATH_MAX
];
994 pathm_t
*pmtp
= (pathm_t
*)arg
;
996 if (realpath(lpath
, ppath
) == NULL
) {
997 return (FPCFGA_CONTINUE
);
1000 ppath
[sizeof (ppath
) - 1] = '\0';
1002 /* Is this the physical path we are looking for */
1003 if (dev_cmp(ppath
, pmtp
->phys
, pmtp
->match_minor
)) {
1004 return (FPCFGA_CONTINUE
);
1007 if ((pmtp
->log
= strdup(lpath
)) == NULL
) {
1008 pmtp
->l_errno
= errno
;
1009 pmtp
->ret
= FPCFGA_LIB_ERR
;
1011 pmtp
->ret
= FPCFGA_OK
;
1014 return (FPCFGA_TERMINATE
);
1017 /* Compare HBA physical ap_id and device path */
1019 hba_dev_cmp(const char *hba
, const char *devpath
)
1023 size_t hba_len
, dev_len
;
1024 char l_hba
[MAXPATHLEN
], l_dev
[MAXPATHLEN
];
1026 (void) snprintf(l_hba
, sizeof (l_hba
), "%s", hba
);
1027 (void) snprintf(l_dev
, sizeof (l_dev
), "%s", devpath
);
1029 /* Remove dynamic component if any */
1030 if ((cp
= GET_DYN(l_hba
)) != NULL
) {
1034 if ((cp
= GET_DYN(l_dev
)) != NULL
) {
1039 /* Remove minor names */
1040 if ((cp
= strrchr(l_hba
, ':')) != NULL
) {
1044 if ((cp
= strrchr(l_dev
, ':')) != NULL
) {
1048 hba_len
= strlen(l_hba
);
1049 dev_len
= strlen(l_dev
);
1051 /* Check if HBA path is component of device path */
1052 if (rv
= strncmp(l_hba
, l_dev
, hba_len
)) {
1056 /* devpath must have '/' and 1 char in addition to hba path */
1057 if (dev_len
>= hba_len
+ 2 && l_dev
[hba_len
] == '/') {
1065 dev_cmp(const char *dev1
, const char *dev2
, int match_minor
)
1067 char l_dev1
[MAXPATHLEN
], l_dev2
[MAXPATHLEN
];
1071 (void) snprintf(l_dev1
, sizeof (l_dev1
), "%s", dev1
);
1072 (void) snprintf(l_dev2
, sizeof (l_dev2
), "%s", dev2
);
1074 if ((mn1
= GET_DYN(l_dev1
)) != NULL
) {
1078 if ((mn2
= GET_DYN(l_dev2
)) != NULL
) {
1082 /* Separate out the minor names */
1083 if ((mn1
= strrchr(l_dev1
, ':')) != NULL
) {
1087 if ((mn2
= strrchr(l_dev2
, ':')) != NULL
) {
1091 if ((rv
= strcmp(l_dev1
, l_dev2
)) != 0 || !match_minor
) {
1096 * Compare minor names
1098 if (mn1
== NULL
&& mn2
== NULL
) {
1100 } else if (mn1
== NULL
) {
1102 } else if (mn2
== NULL
) {
1105 return (strcmp(mn1
, mn2
));
1110 * Returns non-zero on failure (aka, HBA_STATUS_ERROR_*
1111 * Will handle retries if applicable.
1114 getAdapterAttrs(HBA_HANDLE handle
, HBA_ADAPTERATTRIBUTES
*attrs
)
1117 HBA_STATUS status
= HBA_STATUS_ERROR_TRY_AGAIN
; /* force first pass */
1119 /* Loop as long as we have a retryable error */
1120 while ((status
== HBA_STATUS_ERROR_TRY_AGAIN
||
1121 status
== HBA_STATUS_ERROR_BUSY
) &&
1122 count
++ < HBA_MAX_RETRIES
) {
1123 status
= HBA_GetAdapterAttributes(handle
, attrs
);
1124 if (status
== HBA_STATUS_OK
) {
1133 * Returns non-zero on failure (aka, HBA_STATUS_ERROR_*
1134 * Will handle retries if applicable.
1137 getPortAttrsByWWN(HBA_HANDLE handle
, HBA_WWN wwn
, HBA_PORTATTRIBUTES
*attrs
)
1140 HBA_STATUS status
= HBA_STATUS_ERROR_TRY_AGAIN
; /* force first pass */
1142 /* Loop as long as we have a retryable error */
1143 while ((status
== HBA_STATUS_ERROR_TRY_AGAIN
||
1144 status
== HBA_STATUS_ERROR_BUSY
) &&
1145 count
++ < HBA_MAX_RETRIES
) {
1146 status
= HBA_GetPortAttributesByWWN(handle
, wwn
, attrs
);
1147 if (status
== HBA_STATUS_OK
) {
1151 /* The odds of this occuring are very slim, but possible. */
1152 if (status
== HBA_STATUS_ERROR_STALE_DATA
) {
1154 * If we hit a stale data scenario,
1155 * we'll just tell the user to try again.
1157 status
= HBA_STATUS_ERROR_TRY_AGAIN
;
1166 * Returns non-zero on failure (aka, HBA_STATUS_ERROR_*
1167 * Will handle retries if applicable.
1170 getAdapterPortAttrs(HBA_HANDLE handle
, int portIndex
,
1171 HBA_PORTATTRIBUTES
*attrs
)
1174 HBA_STATUS status
= HBA_STATUS_ERROR_TRY_AGAIN
; /* force first pass */
1176 /* Loop as long as we have a retryable error */
1177 while ((status
== HBA_STATUS_ERROR_TRY_AGAIN
||
1178 status
== HBA_STATUS_ERROR_BUSY
) &&
1179 count
++ < HBA_MAX_RETRIES
) {
1180 status
= HBA_GetAdapterPortAttributes(handle
, portIndex
, attrs
);
1181 if (status
== HBA_STATUS_OK
) {
1185 /* The odds of this occuring are very slim, but possible. */
1186 if (status
== HBA_STATUS_ERROR_STALE_DATA
) {
1188 * If we hit a stale data scenario,
1189 * we'll just tell the user to try again.
1191 status
= HBA_STATUS_ERROR_TRY_AGAIN
;
1200 * Returns non-zero on failure (aka, HBA_STATUS_ERROR_*
1201 * Will handle retries if applicable.
1204 getDiscPortAttrs(HBA_HANDLE handle
, int portIndex
, int discIndex
,
1205 HBA_PORTATTRIBUTES
*attrs
)
1208 HBA_STATUS status
= HBA_STATUS_ERROR_TRY_AGAIN
; /* force first pass */
1210 /* Loop as long as we have a retryable error */
1211 while ((status
== HBA_STATUS_ERROR_TRY_AGAIN
||
1212 status
== HBA_STATUS_ERROR_BUSY
) &&
1213 count
++ < HBA_MAX_RETRIES
) {
1214 status
= HBA_GetDiscoveredPortAttributes(handle
, portIndex
,
1216 if (status
== HBA_STATUS_OK
) {
1220 /* The odds of this occuring are very slim, but possible. */
1221 if (status
== HBA_STATUS_ERROR_STALE_DATA
) {
1223 * If we hit a stale data scenario, we'll just tell the
1224 * user to try again.
1226 status
= HBA_STATUS_ERROR_TRY_AGAIN
;
1235 * Find the Adapter port that matches the portPath.
1236 * When the matching port is found the caller have to close handle
1240 findMatchingAdapterPort(char *portPath
, HBA_HANDLE
*matchingHandle
,
1241 int *matchingPortIndex
, HBA_PORTATTRIBUTES
*matchingPortAttrs
,
1245 HBA_ADAPTERATTRIBUTES hbaAttrs
;
1246 HBA_PORTATTRIBUTES portAttrs
;
1247 HBA_STATUS status
= HBA_STATUS_OK
;
1248 int count
, retry
= 0, l_errno
= 0;
1249 int adapterIndex
, portIndex
;
1250 char adapterName
[256];
1251 char *cfg_ptr
, *tmpPtr
;
1252 char *logical_apid
= NULL
;
1254 status
= HBA_LoadLibrary();
1255 if (status
!= HBA_STATUS_OK
) {
1256 cfga_err(errstring
, 0, ERR_HBA_LOAD_LIBRARY
, 0);
1257 return (FPCFGA_LIB_ERR
);
1259 count
= HBA_GetNumberOfAdapters();
1261 cfga_err(errstring
, 0, ERR_NO_ADAPTER_FOUND
, 0);
1263 return (FPCFGA_LIB_ERR
);
1266 /* Loop over all HBAs */
1267 for (adapterIndex
= 0; adapterIndex
< count
; adapterIndex
++) {
1268 status
= HBA_GetAdapterName(adapterIndex
, (char *)&adapterName
);
1269 if (status
!= HBA_STATUS_OK
) {
1270 /* May have been DR'd */
1273 handle
= HBA_OpenAdapter(adapterName
);
1275 /* May have been DR'd */
1280 if (getAdapterAttrs(handle
, &hbaAttrs
)) {
1281 /* Should never happen */
1282 HBA_CloseAdapter(handle
);
1286 /* Loop over all HBA Ports */
1288 portIndex
< hbaAttrs
.NumberOfPorts
; portIndex
++) {
1289 if ((status
= getAdapterPortAttrs(handle
,
1291 &portAttrs
)) != HBA_STATUS_OK
) {
1292 /* Need to refresh adapter */
1294 HBA_STATUS_ERROR_STALE_DATA
) {
1295 HBA_RefreshInformation(handle
);
1303 * check to see if OSDeviceName is a /dev/cfg
1304 * link or the physical path
1306 if (strncmp(portAttrs
.OSDeviceName
,
1308 strlen(CFGA_DEV_DIR
)) != 0) {
1309 tmpPtr
= strstr(portAttrs
.OSDeviceName
,
1311 if ((tmpPtr
!= NULL
) &&
1313 portAttrs
.OSDeviceName
,
1314 strlen(portAttrs
.OSDeviceName
) -
1315 strlen(tmpPtr
)) == 0) {
1319 if (matchingPortIndex
)
1320 *matchingPortIndex
=
1322 if (matchingPortAttrs
)
1323 *matchingPortAttrs
=
1329 * strip off the /dev/cfg/ portion of
1330 * the OSDeviceName make sure that the
1331 * OSDeviceName is at least
1332 * strlen("/dev/cfg") + 1 + 1 long.
1333 * first 1 is for the / after /dev/cfg
1334 * second 1 is to make sure there is
1337 if (strlen(portAttrs
.OSDeviceName
) <
1338 (strlen(CFGA_DEV_DIR
) + 1 + 1))
1340 cfg_ptr
= portAttrs
.OSDeviceName
+
1341 strlen(CFGA_DEV_DIR
) + 1;
1342 if (logical_apid
== NULL
) {
1344 * get the /dev/cfg link from
1347 if (make_xport_logid(portPath
,
1349 &l_errno
) != FPCFGA_OK
) {
1358 /* compare logical ap_id */
1359 if (strcmp(logical_apid
,
1364 if (matchingPortIndex
)
1365 *matchingPortIndex
=
1367 if (matchingPortAttrs
)
1368 *matchingPortAttrs
=
1370 S_FREE(logical_apid
);
1375 if (logical_apid
!= NULL
)
1376 S_FREE(logical_apid
);
1377 } while ((status
== HBA_STATUS_ERROR_STALE_DATA
) &&
1378 (retry
++ < HBA_MAX_RETRIES
));
1380 HBA_CloseAdapter(handle
);
1384 /* Got here. No matching adapter port found. */
1385 cfga_err(errstring
, 0, ERR_MATCHING_HBA_PORT
, 0);
1387 return (FPCFGA_LIB_ERR
);