xref: /onnv-gate/usr/src/lib/cfgadm_plugins/fp/common/cfga_utils.c (revision 7836:4e95154b5b7a)
1*7836SJohn.Forte@Sun.COM /*
2*7836SJohn.Forte@Sun.COM  * CDDL HEADER START
3*7836SJohn.Forte@Sun.COM  *
4*7836SJohn.Forte@Sun.COM  * The contents of this file are subject to the terms of the
5*7836SJohn.Forte@Sun.COM  * Common Development and Distribution License (the "License").
6*7836SJohn.Forte@Sun.COM  * You may not use this file except in compliance with the License.
7*7836SJohn.Forte@Sun.COM  *
8*7836SJohn.Forte@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*7836SJohn.Forte@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*7836SJohn.Forte@Sun.COM  * See the License for the specific language governing permissions
11*7836SJohn.Forte@Sun.COM  * and limitations under the License.
12*7836SJohn.Forte@Sun.COM  *
13*7836SJohn.Forte@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*7836SJohn.Forte@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*7836SJohn.Forte@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*7836SJohn.Forte@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*7836SJohn.Forte@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*7836SJohn.Forte@Sun.COM  *
19*7836SJohn.Forte@Sun.COM  * CDDL HEADER END
20*7836SJohn.Forte@Sun.COM  */
21*7836SJohn.Forte@Sun.COM /*
22*7836SJohn.Forte@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*7836SJohn.Forte@Sun.COM  * Use is subject to license terms.
24*7836SJohn.Forte@Sun.COM  */
25*7836SJohn.Forte@Sun.COM 
26*7836SJohn.Forte@Sun.COM 
27*7836SJohn.Forte@Sun.COM #include "cfga_fp.h"
28*7836SJohn.Forte@Sun.COM 
29*7836SJohn.Forte@Sun.COM /*
30*7836SJohn.Forte@Sun.COM  * This file contains helper routines for the FP plugin
31*7836SJohn.Forte@Sun.COM  */
32*7836SJohn.Forte@Sun.COM 
33*7836SJohn.Forte@Sun.COM #if !defined(TEXT_DOMAIN)
34*7836SJohn.Forte@Sun.COM #define	TEXT_DOMAIN	"SYS_TEST"
35*7836SJohn.Forte@Sun.COM #endif
36*7836SJohn.Forte@Sun.COM 
37*7836SJohn.Forte@Sun.COM typedef struct strlist {
38*7836SJohn.Forte@Sun.COM 	const char *str;
39*7836SJohn.Forte@Sun.COM 	struct strlist *next;
40*7836SJohn.Forte@Sun.COM } strlist_t;
41*7836SJohn.Forte@Sun.COM 
42*7836SJohn.Forte@Sun.COM typedef	struct {
43*7836SJohn.Forte@Sun.COM 	fpcfga_ret_t	fp_err;
44*7836SJohn.Forte@Sun.COM 	cfga_err_t	cfga_err;
45*7836SJohn.Forte@Sun.COM } errcvt_t;
46*7836SJohn.Forte@Sun.COM 
47*7836SJohn.Forte@Sun.COM typedef struct {
48*7836SJohn.Forte@Sun.COM 	fpcfga_cmd_t cmd;
49*7836SJohn.Forte@Sun.COM 	int type;
50*7836SJohn.Forte@Sun.COM 	int (*fcn)(const devctl_hdl_t);
51*7836SJohn.Forte@Sun.COM } set_state_cmd_t;
52*7836SJohn.Forte@Sun.COM 
53*7836SJohn.Forte@Sun.COM typedef struct {
54*7836SJohn.Forte@Sun.COM 	fpcfga_cmd_t cmd;
55*7836SJohn.Forte@Sun.COM 	int type;
56*7836SJohn.Forte@Sun.COM 	int (*state_fcn)(const devctl_hdl_t, uint_t *);
57*7836SJohn.Forte@Sun.COM } get_state_cmd_t;
58*7836SJohn.Forte@Sun.COM 
59*7836SJohn.Forte@Sun.COM /* defines for nftw() */
60*7836SJohn.Forte@Sun.COM #define	NFTW_DEPTH	1
61*7836SJohn.Forte@Sun.COM #define	NFTW_CONTINUE	0
62*7836SJohn.Forte@Sun.COM #define	NFTW_TERMINATE	1
63*7836SJohn.Forte@Sun.COM #define	NFTW_ERROR	-1
64*7836SJohn.Forte@Sun.COM #define	MAX_RETRIES	10
65*7836SJohn.Forte@Sun.COM 
66*7836SJohn.Forte@Sun.COM /* Function prototypes */
67*7836SJohn.Forte@Sun.COM static int do_recurse_dev(const char *path, const struct stat *sbuf,
68*7836SJohn.Forte@Sun.COM     int type, struct FTW *ftwp);
69*7836SJohn.Forte@Sun.COM static fpcfga_recur_t lookup_dev(const char *lpath, void *arg);
70*7836SJohn.Forte@Sun.COM static void msg_common(char **err_msgpp, int append_newline, int l_errno,
71*7836SJohn.Forte@Sun.COM     va_list ap);
72*7836SJohn.Forte@Sun.COM static void lunlist_free(struct luninfo_list *lunlist);
73*7836SJohn.Forte@Sun.COM 
74*7836SJohn.Forte@Sun.COM /* Globals */
75*7836SJohn.Forte@Sun.COM struct {
76*7836SJohn.Forte@Sun.COM 	mutex_t mp;
77*7836SJohn.Forte@Sun.COM 	void *arg;
78*7836SJohn.Forte@Sun.COM 	fpcfga_recur_t (*fcn)(const char *lpath, void *arg);
79*7836SJohn.Forte@Sun.COM } nftw_arg = {DEFAULTMUTEX};
80*7836SJohn.Forte@Sun.COM 
81*7836SJohn.Forte@Sun.COM /*
82*7836SJohn.Forte@Sun.COM  * The string table contains most of the strings used by the fp cfgadm plugin.
83*7836SJohn.Forte@Sun.COM  * All strings which are to be internationalized must be in this table.
84*7836SJohn.Forte@Sun.COM  * Some strings which are not internationalized are also included here.
85*7836SJohn.Forte@Sun.COM  * Arguments to messages are NOT internationalized.
86*7836SJohn.Forte@Sun.COM  */
87*7836SJohn.Forte@Sun.COM msgcvt_t str_tbl[] = {
88*7836SJohn.Forte@Sun.COM 
89*7836SJohn.Forte@Sun.COM /*
90*7836SJohn.Forte@Sun.COM  * The first element (ERR_UNKNOWN) MUST always be present in the array.
91*7836SJohn.Forte@Sun.COM  */
92*7836SJohn.Forte@Sun.COM #define	UNKNOWN_ERR_IDX		0	/* Keep the index in sync */
93*7836SJohn.Forte@Sun.COM 
94*7836SJohn.Forte@Sun.COM 
95*7836SJohn.Forte@Sun.COM /* msg_code	num_args, I18N	msg_string				*/
96*7836SJohn.Forte@Sun.COM 
97*7836SJohn.Forte@Sun.COM /* ERRORS */
98*7836SJohn.Forte@Sun.COM {ERR_UNKNOWN,		0, 1,	"unknown error"},
99*7836SJohn.Forte@Sun.COM {ERR_OP_FAILED,		0, 1,	"operation failed"},
100*7836SJohn.Forte@Sun.COM {ERR_CMD_INVAL,		0, 1,	"invalid command"},
101*7836SJohn.Forte@Sun.COM {ERR_NOT_BUSAPID,	0, 1,	"not a FP bus apid"},
102*7836SJohn.Forte@Sun.COM {ERR_APID_INVAL,	0, 1,	"invalid FP ap_id"},
103*7836SJohn.Forte@Sun.COM {ERR_NOT_BUSOP,		0, 1,	"operation not supported for FC bus"},
104*7836SJohn.Forte@Sun.COM {ERR_NOT_DEVOP,		0, 1,	"operation not supported for FC device"},
105*7836SJohn.Forte@Sun.COM {ERR_UNAVAILABLE,	0, 1,	"unavailable"},
106*7836SJohn.Forte@Sun.COM {ERR_CTRLR_CRIT,	0, 1,	"critical partition controlled by FC HBA"},
107*7836SJohn.Forte@Sun.COM {ERR_BUS_GETSTATE,	0, 1,	"failed to get state for FC bus"},
108*7836SJohn.Forte@Sun.COM {ERR_BUS_NOTCONNECTED,	0, 1,	"FC bus not connected"},
109*7836SJohn.Forte@Sun.COM {ERR_BUS_CONNECTED,	0, 1,	"FC bus not disconnected"},
110*7836SJohn.Forte@Sun.COM {ERR_BUS_QUIESCE,	0, 1,	"FC bus quiesce failed"},
111*7836SJohn.Forte@Sun.COM {ERR_BUS_UNQUIESCE,	0, 1,	"FC bus unquiesce failed"},
112*7836SJohn.Forte@Sun.COM {ERR_BUS_CONFIGURE,	0, 1,	"failed to configure devices on FC bus"},
113*7836SJohn.Forte@Sun.COM {ERR_BUS_UNCONFIGURE,	0, 1,	"failed to unconfigure FC bus"},
114*7836SJohn.Forte@Sun.COM {ERR_DEV_CONFIGURE,	0, 1,	"failed to configure FC device"},
115*7836SJohn.Forte@Sun.COM {ERR_DEV_UNCONFIGURE,	0, 1,	"failed to unconfigure FC device"},
116*7836SJohn.Forte@Sun.COM {ERR_FCA_CONFIGURE,	0, 1,	"failed to configure ANY device on FCA port"},
117*7836SJohn.Forte@Sun.COM {ERR_FCA_UNCONFIGURE,	0, 1,	"failed to unconfigure ANY device on FCA port"},
118*7836SJohn.Forte@Sun.COM {ERR_DEV_REPLACE,	0, 1,	"replace operation failed"},
119*7836SJohn.Forte@Sun.COM {ERR_DEV_INSERT,	0, 1,	"insert operation failed"},
120*7836SJohn.Forte@Sun.COM {ERR_DEV_GETSTATE,	0, 1,	"failed to get state for FC device"},
121*7836SJohn.Forte@Sun.COM {ERR_RESET,		0, 1,	"reset failed"},
122*7836SJohn.Forte@Sun.COM {ERR_LIST,		0, 1,	"list operation failed"},
123*7836SJohn.Forte@Sun.COM {ERR_SIG_STATE,		0, 1,	"could not restore signal disposition"},
124*7836SJohn.Forte@Sun.COM {ERR_MAYBE_BUSY,	0, 1,	"device may be busy"},
125*7836SJohn.Forte@Sun.COM {ERR_BUS_DEV_MISMATCH,	0, 1,	"mismatched FC bus and device"},
126*7836SJohn.Forte@Sun.COM {ERR_MEM_ALLOC,		0, 1,	"Failed to allocated memory"},
127*7836SJohn.Forte@Sun.COM {ERR_DEVCTL_OFFLINE,	0, 1,	"failed to offline device"},
128*7836SJohn.Forte@Sun.COM {ERR_UPD_REP,		0, 1,	"Repository update failed"},
129*7836SJohn.Forte@Sun.COM {ERR_CONF_OK_UPD_REP,	0, 1,
130*7836SJohn.Forte@Sun.COM 		"Configuration successful, but Repository update failed"},
131*7836SJohn.Forte@Sun.COM {ERR_UNCONF_OK_UPD_REP,	0, 1,
132*7836SJohn.Forte@Sun.COM 		"Unconfiguration successful, but Repository update failed"},
133*7836SJohn.Forte@Sun.COM {ERR_PARTIAL_SUCCESS,	0, 1,
134*7836SJohn.Forte@Sun.COM 			"Operation partially successful. Some failures seen"},
135*7836SJohn.Forte@Sun.COM {ERR_HBA_LOAD_LIBRARY,	0, 1,
136*7836SJohn.Forte@Sun.COM 			"HBA load library failed"},
137*7836SJohn.Forte@Sun.COM {ERR_MATCHING_HBA_PORT,	0, 1,
138*7836SJohn.Forte@Sun.COM 			"No match HBA port found"},
139*7836SJohn.Forte@Sun.COM {ERR_NO_ADAPTER_FOUND,	0, 1,
140*7836SJohn.Forte@Sun.COM 			"No Fibre Channel adpaters found"},
141*7836SJohn.Forte@Sun.COM 
142*7836SJohn.Forte@Sun.COM /* Errors with arguments */
143*7836SJohn.Forte@Sun.COM {ERRARG_OPT_INVAL,	1, 1,	"invalid option: "},
144*7836SJohn.Forte@Sun.COM {ERRARG_HWCMD_INVAL,	1, 1,	"invalid command: "},
145*7836SJohn.Forte@Sun.COM {ERRARG_DEVINFO,	1, 1,	"libdevinfo failed on path: "},
146*7836SJohn.Forte@Sun.COM {ERRARG_NOT_IN_DEVLIST,	1, 1,	"Device not found in fabric device list: "},
147*7836SJohn.Forte@Sun.COM {ERRARG_NOT_IN_DEVINFO,	1, 1,	"Could not find entry in devinfo tree: "},
148*7836SJohn.Forte@Sun.COM {ERRARG_DI_GET_PROP,	1, 1,	"Could not get libdevinfo property: "},
149*7836SJohn.Forte@Sun.COM {ERRARG_DC_DDEF_ALLOC,	1, 1,	"failed to alloc ddef space: "},
150*7836SJohn.Forte@Sun.COM {ERRARG_DC_BYTE_ARRAY,	1, 1,	"failed to add property: "},
151*7836SJohn.Forte@Sun.COM {ERRARG_DC_BUS_ACQUIRE,	1, 1,	"failed to acquire bus handle: "},
152*7836SJohn.Forte@Sun.COM {ERRARG_BUS_DEV_CREATE,	1, 1,	"failed to create device node: "},
153*7836SJohn.Forte@Sun.COM {ERRARG_BUS_DEV_CREATE_UNKNOWN,	1, 1,
154*7836SJohn.Forte@Sun.COM 	"failed to create device node... Device may be unconfigurable: "},
155*7836SJohn.Forte@Sun.COM {ERRARG_DEV_ACQUIRE,	1, 1,	"device acquire operation failed: "},
156*7836SJohn.Forte@Sun.COM {ERRARG_DEV_REMOVE,	1, 1,	"remove operation failed: "},
157*7836SJohn.Forte@Sun.COM 
158*7836SJohn.Forte@Sun.COM /* Fibre Channel operation Errors */
159*7836SJohn.Forte@Sun.COM {ERR_FC,		0, 1,	"FC error"},
160*7836SJohn.Forte@Sun.COM {ERR_FC_GET_DEVLIST,	0, 1,	"Failed to get fabric device list"},
161*7836SJohn.Forte@Sun.COM {ERR_FC_GET_NEXT_DEV,	0, 1,	"Failed to get next device on device map"},
162*7836SJohn.Forte@Sun.COM {ERR_FC_GET_FIRST_DEV,	0, 1,	"Failed to get first device on device map"},
163*7836SJohn.Forte@Sun.COM {ERRARG_FC_DEV_MAP_INIT,	1, 1,
164*7836SJohn.Forte@Sun.COM 	"Failed to initialize device map for: "},
165*7836SJohn.Forte@Sun.COM {ERRARG_FC_PROP_LOOKUP_BYTES,	1, 1,	"Failed to get property of "},
166*7836SJohn.Forte@Sun.COM {ERRARG_FC_INQUIRY,	1, 1,	"inquiry failed: "},
167*7836SJohn.Forte@Sun.COM {ERRARG_FC_REP_LUNS,	1, 1,	"report LUNs failed: "},
168*7836SJohn.Forte@Sun.COM {ERRARG_FC_TOPOLOGY,	1, 1,	"failed to get port topology: "},
169*7836SJohn.Forte@Sun.COM {ERRARG_PATH_TOO_LONG,	1, 1,	"Path length exceeds max possible: "},
170*7836SJohn.Forte@Sun.COM {ERRARG_INVALID_PATH,	1, 1,	"Invalid path: "},
171*7836SJohn.Forte@Sun.COM {ERRARG_OPENDIR,	1, 1,	"failure opening directory: "},
172*7836SJohn.Forte@Sun.COM 
173*7836SJohn.Forte@Sun.COM /* MPXIO Errors */
174*7836SJohn.Forte@Sun.COM {ERRARG_VHCI_GET_PATHLIST,	1, 1,	"failed to get path list from vHCI: "},
175*7836SJohn.Forte@Sun.COM {ERRARG_XPORT_NOT_IN_PHCI_LIST,	1, 1,	"Transport not in pHCI list: "},
176*7836SJohn.Forte@Sun.COM 
177*7836SJohn.Forte@Sun.COM /* RCM Errors */
178*7836SJohn.Forte@Sun.COM {ERR_RCM_HANDLE,	0, 1,	"cannot get RCM handle"},
179*7836SJohn.Forte@Sun.COM {ERRARG_RCM_SUSPEND,	1, 1,	"failed to suspend: "},
180*7836SJohn.Forte@Sun.COM {ERRARG_RCM_RESUME,	1, 1,	"failed to resume: "},
181*7836SJohn.Forte@Sun.COM {ERRARG_RCM_OFFLINE,	1, 1,	"failed to offline: "},
182*7836SJohn.Forte@Sun.COM {ERRARG_RCM_ONLINE,	1, 1,	"failed to online: "},
183*7836SJohn.Forte@Sun.COM {ERRARG_RCM_REMOVE,	1, 1,	"failed to remove: "},
184*7836SJohn.Forte@Sun.COM {ERRARG_RCM_INFO,	1, 1,	"failed to query: "},
185*7836SJohn.Forte@Sun.COM 
186*7836SJohn.Forte@Sun.COM /* Commands */
187*7836SJohn.Forte@Sun.COM {CMD_INSERT_DEV,	0, 0,	"insert_device"},
188*7836SJohn.Forte@Sun.COM {CMD_REMOVE_DEV,	0, 0,	"remove_device"},
189*7836SJohn.Forte@Sun.COM {CMD_REPLACE_DEV,	0, 0,	"replace_device"},
190*7836SJohn.Forte@Sun.COM {CMD_RESET_DEV,		0, 0,	"reset_device"},
191*7836SJohn.Forte@Sun.COM {CMD_RESET_BUS,		0, 0,	"reset_bus"},
192*7836SJohn.Forte@Sun.COM {CMD_RESET_ALL,		0, 0,	"reset_all"},
193*7836SJohn.Forte@Sun.COM 
194*7836SJohn.Forte@Sun.COM /* help messages */
195*7836SJohn.Forte@Sun.COM {MSG_HELP_HDR,		0, 1,	"\nfp attachment point specific options:\n"},
196*7836SJohn.Forte@Sun.COM {MSG_HELP_USAGE,	0, 0,
197*7836SJohn.Forte@Sun.COM 		"\t-c configure -o force_update ap_id [ap_id..]\n"
198*7836SJohn.Forte@Sun.COM 		"\t-c configure -o no_update ap_id [ap_id...]\n"
199*7836SJohn.Forte@Sun.COM 		"\t-c unconfigure -o force_update ap_id [ap_id... ]\n"
200*7836SJohn.Forte@Sun.COM 		"\t-c unconfigure -o no_update ap_id [ap_id... ]\n"},
201*7836SJohn.Forte@Sun.COM 
202*7836SJohn.Forte@Sun.COM /* hotplug messages */
203*7836SJohn.Forte@Sun.COM {MSG_INSDEV,		1, 1,	"Adding device to FC HBA: "},
204*7836SJohn.Forte@Sun.COM {MSG_RMDEV,		1, 1,	"Removing FC device: "},
205*7836SJohn.Forte@Sun.COM {MSG_REPLDEV,		1, 1,	"Replacing FC device: "},
206*7836SJohn.Forte@Sun.COM 
207*7836SJohn.Forte@Sun.COM /* Hotplugging confirmation prompts */
208*7836SJohn.Forte@Sun.COM {CONF_QUIESCE_1,	1, 1,
209*7836SJohn.Forte@Sun.COM 	"This operation will suspend activity on FC bus: "},
210*7836SJohn.Forte@Sun.COM 
211*7836SJohn.Forte@Sun.COM {CONF_QUIESCE_2,	0, 1,	"\nContinue"},
212*7836SJohn.Forte@Sun.COM 
213*7836SJohn.Forte@Sun.COM {CONF_UNQUIESCE,	0, 1,
214*7836SJohn.Forte@Sun.COM 	"FC bus quiesced successfully.\n"
215*7836SJohn.Forte@Sun.COM 	"It is now safe to proceed with hotplug operation."
216*7836SJohn.Forte@Sun.COM 	"\nEnter y if operation is complete or n to abort"},
217*7836SJohn.Forte@Sun.COM 
218*7836SJohn.Forte@Sun.COM /* Misc. */
219*7836SJohn.Forte@Sun.COM {WARN_DISCONNECT,	0, 1,
220*7836SJohn.Forte@Sun.COM 	"WARNING: Disconnecting critical partitions may cause system hang."
221*7836SJohn.Forte@Sun.COM 	"\nContinue"}
222*7836SJohn.Forte@Sun.COM };
223*7836SJohn.Forte@Sun.COM 
224*7836SJohn.Forte@Sun.COM 
225*7836SJohn.Forte@Sun.COM #define	N_STRS	(sizeof (str_tbl) / sizeof (str_tbl[0]))
226*7836SJohn.Forte@Sun.COM 
227*7836SJohn.Forte@Sun.COM #define	GET_MSG_NARGS(i)	(str_tbl[msg_idx(i)].nargs)
228*7836SJohn.Forte@Sun.COM #define	GET_MSG_INTL(i)		(str_tbl[msg_idx(i)].intl)
229*7836SJohn.Forte@Sun.COM 
230*7836SJohn.Forte@Sun.COM static errcvt_t err_cvt_tbl[] = {
231*7836SJohn.Forte@Sun.COM 	{ FPCFGA_OK,		CFGA_OK			},
232*7836SJohn.Forte@Sun.COM 	{ FPCFGA_LIB_ERR,	CFGA_LIB_ERROR		},
233*7836SJohn.Forte@Sun.COM 	{ FPCFGA_APID_NOEXIST,	CFGA_APID_NOEXIST	},
234*7836SJohn.Forte@Sun.COM 	{ FPCFGA_NACK,		CFGA_NACK		},
235*7836SJohn.Forte@Sun.COM 	{ FPCFGA_BUSY,		CFGA_BUSY		},
236*7836SJohn.Forte@Sun.COM 	{ FPCFGA_SYSTEM_BUSY,	CFGA_SYSTEM_BUSY	},
237*7836SJohn.Forte@Sun.COM 	{ FPCFGA_OPNOTSUPP,	CFGA_OPNOTSUPP		},
238*7836SJohn.Forte@Sun.COM 	{ FPCFGA_PRIV,		CFGA_PRIV		},
239*7836SJohn.Forte@Sun.COM 	{ FPCFGA_UNKNOWN_ERR,	CFGA_ERROR		},
240*7836SJohn.Forte@Sun.COM 	{ FPCFGA_ERR,		CFGA_ERROR		}
241*7836SJohn.Forte@Sun.COM };
242*7836SJohn.Forte@Sun.COM 
243*7836SJohn.Forte@Sun.COM #define	N_ERR_CVT_TBL	(sizeof (err_cvt_tbl)/sizeof (err_cvt_tbl[0]))
244*7836SJohn.Forte@Sun.COM 
245*7836SJohn.Forte@Sun.COM #define	DEV_OP	0
246*7836SJohn.Forte@Sun.COM #define	BUS_OP	1
247*7836SJohn.Forte@Sun.COM static set_state_cmd_t set_state_cmds[] = {
248*7836SJohn.Forte@Sun.COM 
249*7836SJohn.Forte@Sun.COM { FPCFGA_BUS_QUIESCE,		BUS_OP,		devctl_bus_quiesce	},
250*7836SJohn.Forte@Sun.COM { FPCFGA_BUS_UNQUIESCE,		BUS_OP,		devctl_bus_unquiesce	},
251*7836SJohn.Forte@Sun.COM { FPCFGA_BUS_CONFIGURE,		BUS_OP,		devctl_bus_configure	},
252*7836SJohn.Forte@Sun.COM { FPCFGA_BUS_UNCONFIGURE, 	BUS_OP,		devctl_bus_unconfigure	},
253*7836SJohn.Forte@Sun.COM { FPCFGA_RESET_BUS,		BUS_OP,		devctl_bus_reset	},
254*7836SJohn.Forte@Sun.COM { FPCFGA_RESET_ALL, 		BUS_OP,		devctl_bus_resetall	},
255*7836SJohn.Forte@Sun.COM { FPCFGA_DEV_CONFIGURE,		DEV_OP,		devctl_device_online	},
256*7836SJohn.Forte@Sun.COM { FPCFGA_DEV_UNCONFIGURE,	DEV_OP,		devctl_device_offline	},
257*7836SJohn.Forte@Sun.COM { FPCFGA_DEV_REMOVE,		DEV_OP,		devctl_device_remove	},
258*7836SJohn.Forte@Sun.COM { FPCFGA_RESET_DEV,		DEV_OP,		devctl_device_reset	}
259*7836SJohn.Forte@Sun.COM 
260*7836SJohn.Forte@Sun.COM };
261*7836SJohn.Forte@Sun.COM 
262*7836SJohn.Forte@Sun.COM #define	N_SET_STATE_CMDS (sizeof (set_state_cmds)/sizeof (set_state_cmds[0]))
263*7836SJohn.Forte@Sun.COM 
264*7836SJohn.Forte@Sun.COM static get_state_cmd_t get_state_cmds[] = {
265*7836SJohn.Forte@Sun.COM { FPCFGA_BUS_GETSTATE,		BUS_OP,		devctl_bus_getstate	},
266*7836SJohn.Forte@Sun.COM { FPCFGA_DEV_GETSTATE,		DEV_OP,		devctl_device_getstate	}
267*7836SJohn.Forte@Sun.COM };
268*7836SJohn.Forte@Sun.COM 
269*7836SJohn.Forte@Sun.COM #define	N_GET_STATE_CMDS (sizeof (get_state_cmds)/sizeof (get_state_cmds[0]))
270*7836SJohn.Forte@Sun.COM 
271*7836SJohn.Forte@Sun.COM /* Order is important. Earlier directories are searched first */
272*7836SJohn.Forte@Sun.COM static const char *dev_dir_hints[] = {
273*7836SJohn.Forte@Sun.COM 	CFGA_DEV_DIR,
274*7836SJohn.Forte@Sun.COM 	DEV_RMT,
275*7836SJohn.Forte@Sun.COM 	DEV_DSK,
276*7836SJohn.Forte@Sun.COM 	DEV_RDSK,
277*7836SJohn.Forte@Sun.COM 	DEV_DIR
278*7836SJohn.Forte@Sun.COM };
279*7836SJohn.Forte@Sun.COM 
280*7836SJohn.Forte@Sun.COM #define	N_DEV_DIR_HINTS	(sizeof (dev_dir_hints) / sizeof (dev_dir_hints[0]))
281*7836SJohn.Forte@Sun.COM 
282*7836SJohn.Forte@Sun.COM 
283*7836SJohn.Forte@Sun.COM /*
284*7836SJohn.Forte@Sun.COM  * Routine to search the /dev directory or a subtree of /dev.
285*7836SJohn.Forte@Sun.COM  * If the entire /dev hierarchy is to be searched, the most likely directories
286*7836SJohn.Forte@Sun.COM  * are searched first.
287*7836SJohn.Forte@Sun.COM  */
288*7836SJohn.Forte@Sun.COM fpcfga_ret_t
recurse_dev(const char * basedir,void * arg,fpcfga_recur_t (* fcn)(const char * lpath,void * arg))289*7836SJohn.Forte@Sun.COM recurse_dev(
290*7836SJohn.Forte@Sun.COM 	const char	*basedir,
291*7836SJohn.Forte@Sun.COM 	void		*arg,
292*7836SJohn.Forte@Sun.COM 	fpcfga_recur_t (*fcn)(const char *lpath, void *arg))
293*7836SJohn.Forte@Sun.COM {
294*7836SJohn.Forte@Sun.COM 	int i, rv = NFTW_ERROR;
295*7836SJohn.Forte@Sun.COM 
296*7836SJohn.Forte@Sun.COM 	(void) mutex_lock(&nftw_arg.mp);
297*7836SJohn.Forte@Sun.COM 
298*7836SJohn.Forte@Sun.COM 	nftw_arg.arg = arg;
299*7836SJohn.Forte@Sun.COM 	nftw_arg.fcn = fcn;
300*7836SJohn.Forte@Sun.COM 
301*7836SJohn.Forte@Sun.COM 	if (strcmp(basedir, DEV_DIR)) {
302*7836SJohn.Forte@Sun.COM 		errno = 0;
303*7836SJohn.Forte@Sun.COM 		rv = nftw(basedir, do_recurse_dev, NFTW_DEPTH, FTW_PHYS);
304*7836SJohn.Forte@Sun.COM 		goto out;
305*7836SJohn.Forte@Sun.COM 	}
306*7836SJohn.Forte@Sun.COM 
307*7836SJohn.Forte@Sun.COM 	/*
308*7836SJohn.Forte@Sun.COM 	 * Search certain selected subdirectories first if basedir == "/dev".
309*7836SJohn.Forte@Sun.COM 	 * Ignore errors as some of these directories may not exist.
310*7836SJohn.Forte@Sun.COM 	 */
311*7836SJohn.Forte@Sun.COM 	for (i = 0; i < N_DEV_DIR_HINTS; i++) {
312*7836SJohn.Forte@Sun.COM 		errno = 0;
313*7836SJohn.Forte@Sun.COM 		if ((rv = nftw(dev_dir_hints[i], do_recurse_dev, NFTW_DEPTH,
314*7836SJohn.Forte@Sun.COM 		    FTW_PHYS)) == NFTW_TERMINATE) {
315*7836SJohn.Forte@Sun.COM 			break;
316*7836SJohn.Forte@Sun.COM 		}
317*7836SJohn.Forte@Sun.COM 	}
318*7836SJohn.Forte@Sun.COM 
319*7836SJohn.Forte@Sun.COM 	/*FALLTHRU*/
320*7836SJohn.Forte@Sun.COM out:
321*7836SJohn.Forte@Sun.COM 	(void) mutex_unlock(&nftw_arg.mp);
322*7836SJohn.Forte@Sun.COM 	return (rv == NFTW_ERROR ? FPCFGA_ERR : FPCFGA_OK);
323*7836SJohn.Forte@Sun.COM }
324*7836SJohn.Forte@Sun.COM 
325*7836SJohn.Forte@Sun.COM /*ARGSUSED*/
326*7836SJohn.Forte@Sun.COM static int
do_recurse_dev(const char * path,const struct stat * sbuf,int type,struct FTW * ftwp)327*7836SJohn.Forte@Sun.COM do_recurse_dev(
328*7836SJohn.Forte@Sun.COM 	const char *path,
329*7836SJohn.Forte@Sun.COM 	const struct stat *sbuf,
330*7836SJohn.Forte@Sun.COM 	int type,
331*7836SJohn.Forte@Sun.COM 	struct FTW *ftwp)
332*7836SJohn.Forte@Sun.COM {
333*7836SJohn.Forte@Sun.COM 	/* We want only VALID symlinks */
334*7836SJohn.Forte@Sun.COM 	if (type != FTW_SL) {
335*7836SJohn.Forte@Sun.COM 		return (NFTW_CONTINUE);
336*7836SJohn.Forte@Sun.COM 	}
337*7836SJohn.Forte@Sun.COM 
338*7836SJohn.Forte@Sun.COM 	assert(nftw_arg.fcn != NULL);
339*7836SJohn.Forte@Sun.COM 
340*7836SJohn.Forte@Sun.COM 	if (nftw_arg.fcn(path, nftw_arg.arg) == FPCFGA_TERMINATE) {
341*7836SJohn.Forte@Sun.COM 		/* terminate prematurely, but may not be error */
342*7836SJohn.Forte@Sun.COM 		errno = 0;
343*7836SJohn.Forte@Sun.COM 		return (NFTW_TERMINATE);
344*7836SJohn.Forte@Sun.COM 	} else {
345*7836SJohn.Forte@Sun.COM 		return (NFTW_CONTINUE);
346*7836SJohn.Forte@Sun.COM 	}
347*7836SJohn.Forte@Sun.COM }
348*7836SJohn.Forte@Sun.COM 
349*7836SJohn.Forte@Sun.COM cfga_err_t
err_cvt(fpcfga_ret_t fp_err)350*7836SJohn.Forte@Sun.COM err_cvt(fpcfga_ret_t fp_err)
351*7836SJohn.Forte@Sun.COM {
352*7836SJohn.Forte@Sun.COM 	int i;
353*7836SJohn.Forte@Sun.COM 
354*7836SJohn.Forte@Sun.COM 	for (i = 0; i < N_ERR_CVT_TBL; i++) {
355*7836SJohn.Forte@Sun.COM 		if (err_cvt_tbl[i].fp_err == fp_err) {
356*7836SJohn.Forte@Sun.COM 			return (err_cvt_tbl[i].cfga_err);
357*7836SJohn.Forte@Sun.COM 		}
358*7836SJohn.Forte@Sun.COM 	}
359*7836SJohn.Forte@Sun.COM 
360*7836SJohn.Forte@Sun.COM 	return (CFGA_ERROR);
361*7836SJohn.Forte@Sun.COM }
362*7836SJohn.Forte@Sun.COM 
363*7836SJohn.Forte@Sun.COM /*
364*7836SJohn.Forte@Sun.COM  * Removes duplicate slashes from a pathname and any trailing slashes.
365*7836SJohn.Forte@Sun.COM  * Returns "/" if input is "/"
366*7836SJohn.Forte@Sun.COM  */
367*7836SJohn.Forte@Sun.COM char *
pathdup(const char * path,int * l_errnop)368*7836SJohn.Forte@Sun.COM pathdup(const char *path, int *l_errnop)
369*7836SJohn.Forte@Sun.COM {
370*7836SJohn.Forte@Sun.COM 	int prev_was_slash = 0;
371*7836SJohn.Forte@Sun.COM 	char c, *dp = NULL, *dup = NULL;
372*7836SJohn.Forte@Sun.COM 	const char *sp = NULL;
373*7836SJohn.Forte@Sun.COM 
374*7836SJohn.Forte@Sun.COM 	*l_errnop = 0;
375*7836SJohn.Forte@Sun.COM 
376*7836SJohn.Forte@Sun.COM 	if (path == NULL) {
377*7836SJohn.Forte@Sun.COM 		return (NULL);
378*7836SJohn.Forte@Sun.COM 	}
379*7836SJohn.Forte@Sun.COM 
380*7836SJohn.Forte@Sun.COM 	if ((dup = calloc(1, strlen(path) + 1)) == NULL) {
381*7836SJohn.Forte@Sun.COM 		*l_errnop = errno;
382*7836SJohn.Forte@Sun.COM 		return (NULL);
383*7836SJohn.Forte@Sun.COM 	}
384*7836SJohn.Forte@Sun.COM 
385*7836SJohn.Forte@Sun.COM 	prev_was_slash = 0;
386*7836SJohn.Forte@Sun.COM 	for (sp = path, dp = dup; (c = *sp) != '\0'; sp++) {
387*7836SJohn.Forte@Sun.COM 		if (!prev_was_slash || c != '/') {
388*7836SJohn.Forte@Sun.COM 			*dp++ = c;
389*7836SJohn.Forte@Sun.COM 		}
390*7836SJohn.Forte@Sun.COM 		if (c == '/') {
391*7836SJohn.Forte@Sun.COM 			prev_was_slash = 1;
392*7836SJohn.Forte@Sun.COM 		} else {
393*7836SJohn.Forte@Sun.COM 			prev_was_slash = 0;
394*7836SJohn.Forte@Sun.COM 		}
395*7836SJohn.Forte@Sun.COM 	}
396*7836SJohn.Forte@Sun.COM 
397*7836SJohn.Forte@Sun.COM 	/* Remove trailing slash except if it is the first char */
398*7836SJohn.Forte@Sun.COM 	if (prev_was_slash && dp != dup && dp - 1 != dup) {
399*7836SJohn.Forte@Sun.COM 		*(--dp) = '\0';
400*7836SJohn.Forte@Sun.COM 	} else {
401*7836SJohn.Forte@Sun.COM 		*dp = '\0';
402*7836SJohn.Forte@Sun.COM 	}
403*7836SJohn.Forte@Sun.COM 
404*7836SJohn.Forte@Sun.COM 	return (dup);
405*7836SJohn.Forte@Sun.COM }
406*7836SJohn.Forte@Sun.COM 
407*7836SJohn.Forte@Sun.COM fpcfga_ret_t
apidt_create(const char * ap_id,apid_t * apidp,char ** errstring)408*7836SJohn.Forte@Sun.COM apidt_create(const char *ap_id, apid_t *apidp, char **errstring)
409*7836SJohn.Forte@Sun.COM {
410*7836SJohn.Forte@Sun.COM 	char *xport_phys = NULL, *dyn = NULL;
411*7836SJohn.Forte@Sun.COM 	char *dyncomp = NULL;
412*7836SJohn.Forte@Sun.COM 	struct luninfo_list *lunlistp = NULL;
413*7836SJohn.Forte@Sun.COM 	int l_errno = 0;
414*7836SJohn.Forte@Sun.COM 	size_t len = 0;
415*7836SJohn.Forte@Sun.COM 	fpcfga_ret_t ret;
416*7836SJohn.Forte@Sun.COM 
417*7836SJohn.Forte@Sun.COM 	if ((xport_phys = pathdup(ap_id, &l_errno)) == NULL) {
418*7836SJohn.Forte@Sun.COM 		cfga_err(errstring, l_errno, ERR_OP_FAILED, 0);
419*7836SJohn.Forte@Sun.COM 		return (FPCFGA_LIB_ERR);
420*7836SJohn.Forte@Sun.COM 	}
421*7836SJohn.Forte@Sun.COM 
422*7836SJohn.Forte@Sun.COM 	/* Extract the base(hba) and dynamic(device) component if any */
423*7836SJohn.Forte@Sun.COM 	dyncomp = NULL;
424*7836SJohn.Forte@Sun.COM 	if ((dyn = GET_DYN(xport_phys)) != NULL) {
425*7836SJohn.Forte@Sun.COM 		len = strlen(DYN_TO_DYNCOMP(dyn)) + 1;
426*7836SJohn.Forte@Sun.COM 		dyncomp = calloc(1, len);
427*7836SJohn.Forte@Sun.COM 		if (dyncomp == NULL) {
428*7836SJohn.Forte@Sun.COM 			cfga_err(errstring, errno, ERR_OP_FAILED, 0);
429*7836SJohn.Forte@Sun.COM 			ret = FPCFGA_LIB_ERR;
430*7836SJohn.Forte@Sun.COM 			goto err;
431*7836SJohn.Forte@Sun.COM 		}
432*7836SJohn.Forte@Sun.COM 		(void) strcpy(dyncomp, DYN_TO_DYNCOMP(dyn));
433*7836SJohn.Forte@Sun.COM 		if (GET_LUN_DYN(dyncomp)) {
434*7836SJohn.Forte@Sun.COM 			ret = FPCFGA_APID_NOEXIST;
435*7836SJohn.Forte@Sun.COM 			goto err;
436*7836SJohn.Forte@Sun.COM 		}
437*7836SJohn.Forte@Sun.COM 
438*7836SJohn.Forte@Sun.COM 		/* Remove the dynamic component from the base. */
439*7836SJohn.Forte@Sun.COM 		*dyn = '\0';
440*7836SJohn.Forte@Sun.COM 	}
441*7836SJohn.Forte@Sun.COM 
442*7836SJohn.Forte@Sun.COM 	/* Get the path of dynamic attachment point if already configured. */
443*7836SJohn.Forte@Sun.COM 	if (dyncomp != NULL) {
444*7836SJohn.Forte@Sun.COM 		ret = dyn_apid_to_path(xport_phys, dyncomp,
445*7836SJohn.Forte@Sun.COM 				&lunlistp, &l_errno);
446*7836SJohn.Forte@Sun.COM 		if ((ret != FPCFGA_OK) && (ret != FPCFGA_APID_NOCONFIGURE)) {
447*7836SJohn.Forte@Sun.COM 			cfga_err(errstring, l_errno, ERR_OP_FAILED, 0);
448*7836SJohn.Forte@Sun.COM 			goto err;
449*7836SJohn.Forte@Sun.COM 		}
450*7836SJohn.Forte@Sun.COM 	}
451*7836SJohn.Forte@Sun.COM 
452*7836SJohn.Forte@Sun.COM 	assert(xport_phys != NULL);
453*7836SJohn.Forte@Sun.COM 
454*7836SJohn.Forte@Sun.COM 	apidp->xport_phys = xport_phys;
455*7836SJohn.Forte@Sun.COM 	apidp->dyncomp = dyncomp;
456*7836SJohn.Forte@Sun.COM 	apidp->lunlist = lunlistp;
457*7836SJohn.Forte@Sun.COM 	apidp->flags = 0;
458*7836SJohn.Forte@Sun.COM 
459*7836SJohn.Forte@Sun.COM 	return (FPCFGA_OK);
460*7836SJohn.Forte@Sun.COM 
461*7836SJohn.Forte@Sun.COM err:
462*7836SJohn.Forte@Sun.COM 	S_FREE(xport_phys);
463*7836SJohn.Forte@Sun.COM 	S_FREE(dyncomp);
464*7836SJohn.Forte@Sun.COM 	lunlist_free(lunlistp);
465*7836SJohn.Forte@Sun.COM 	return (ret);
466*7836SJohn.Forte@Sun.COM }
467*7836SJohn.Forte@Sun.COM 
468*7836SJohn.Forte@Sun.COM static void
lunlist_free(struct luninfo_list * lunlist)469*7836SJohn.Forte@Sun.COM lunlist_free(struct luninfo_list *lunlist)
470*7836SJohn.Forte@Sun.COM {
471*7836SJohn.Forte@Sun.COM struct luninfo_list *lunp;
472*7836SJohn.Forte@Sun.COM 
473*7836SJohn.Forte@Sun.COM 	while (lunlist != NULL) {
474*7836SJohn.Forte@Sun.COM 		lunp = lunlist->next;
475*7836SJohn.Forte@Sun.COM 		S_FREE(lunlist->path);
476*7836SJohn.Forte@Sun.COM 		S_FREE(lunlist);
477*7836SJohn.Forte@Sun.COM 		lunlist = lunp;
478*7836SJohn.Forte@Sun.COM 	}
479*7836SJohn.Forte@Sun.COM }
480*7836SJohn.Forte@Sun.COM 
481*7836SJohn.Forte@Sun.COM void
apidt_free(apid_t * apidp)482*7836SJohn.Forte@Sun.COM apidt_free(apid_t *apidp)
483*7836SJohn.Forte@Sun.COM {
484*7836SJohn.Forte@Sun.COM 	if (apidp == NULL)
485*7836SJohn.Forte@Sun.COM 		return;
486*7836SJohn.Forte@Sun.COM 
487*7836SJohn.Forte@Sun.COM 	S_FREE(apidp->xport_phys);
488*7836SJohn.Forte@Sun.COM 	S_FREE(apidp->dyncomp);
489*7836SJohn.Forte@Sun.COM 	lunlist_free(apidp->lunlist);
490*7836SJohn.Forte@Sun.COM }
491*7836SJohn.Forte@Sun.COM 
492*7836SJohn.Forte@Sun.COM fpcfga_ret_t
walk_tree(const char * physpath,void * arg,uint_t init_flags,walkarg_t * up,fpcfga_cmd_t cmd,int * l_errnop)493*7836SJohn.Forte@Sun.COM walk_tree(
494*7836SJohn.Forte@Sun.COM 	const char	*physpath,
495*7836SJohn.Forte@Sun.COM 	void		*arg,
496*7836SJohn.Forte@Sun.COM 	uint_t		init_flags,
497*7836SJohn.Forte@Sun.COM 	walkarg_t	*up,
498*7836SJohn.Forte@Sun.COM 	fpcfga_cmd_t	cmd,
499*7836SJohn.Forte@Sun.COM 	int		*l_errnop)
500*7836SJohn.Forte@Sun.COM {
501*7836SJohn.Forte@Sun.COM 	int rv;
502*7836SJohn.Forte@Sun.COM 	di_node_t root, tree_root, fpnode;
503*7836SJohn.Forte@Sun.COM 	char *root_path, *cp = NULL;
504*7836SJohn.Forte@Sun.COM 	char *devfs_fp_path;
505*7836SJohn.Forte@Sun.COM 	size_t len;
506*7836SJohn.Forte@Sun.COM 	fpcfga_ret_t ret;
507*7836SJohn.Forte@Sun.COM 	int	found = 0;
508*7836SJohn.Forte@Sun.COM 
509*7836SJohn.Forte@Sun.COM 	*l_errnop = 0;
510*7836SJohn.Forte@Sun.COM 
511*7836SJohn.Forte@Sun.COM 	if ((root_path = strdup(physpath)) == NULL) {
512*7836SJohn.Forte@Sun.COM 		*l_errnop = errno;
513*7836SJohn.Forte@Sun.COM 		return (FPCFGA_LIB_ERR);
514*7836SJohn.Forte@Sun.COM 	}
515*7836SJohn.Forte@Sun.COM 
516*7836SJohn.Forte@Sun.COM 	/* Fix up path for di_init() */
517*7836SJohn.Forte@Sun.COM 	len = strlen(DEVICES_DIR);
518*7836SJohn.Forte@Sun.COM 	if (strncmp(root_path, DEVICES_DIR SLASH,
519*7836SJohn.Forte@Sun.COM 	    len + strlen(SLASH)) == 0) {
520*7836SJohn.Forte@Sun.COM 		cp = root_path + len;
521*7836SJohn.Forte@Sun.COM 		(void) memmove(root_path, cp, strlen(cp) + 1);
522*7836SJohn.Forte@Sun.COM 	} else if (*root_path != '/') {
523*7836SJohn.Forte@Sun.COM 		*l_errnop = 0;
524*7836SJohn.Forte@Sun.COM 		ret = FPCFGA_ERR;
525*7836SJohn.Forte@Sun.COM 		goto out;
526*7836SJohn.Forte@Sun.COM 	}
527*7836SJohn.Forte@Sun.COM 
528*7836SJohn.Forte@Sun.COM 	/* Remove dynamic component if any */
529*7836SJohn.Forte@Sun.COM 	if ((cp = GET_DYN(root_path)) != NULL) {
530*7836SJohn.Forte@Sun.COM 		*cp = '\0';
531*7836SJohn.Forte@Sun.COM 	}
532*7836SJohn.Forte@Sun.COM 
533*7836SJohn.Forte@Sun.COM 	/* Remove minor name if any */
534*7836SJohn.Forte@Sun.COM 	if ((cp = strrchr(root_path, ':')) != NULL) {
535*7836SJohn.Forte@Sun.COM 		*cp = '\0';
536*7836SJohn.Forte@Sun.COM 	}
537*7836SJohn.Forte@Sun.COM 
538*7836SJohn.Forte@Sun.COM 	/*
539*7836SJohn.Forte@Sun.COM 	 * If force_flag is set
540*7836SJohn.Forte@Sun.COM 	 * do di_init with DINFOFORCE flag and get to the input fp node
541*7836SJohn.Forte@Sun.COM 	 * from the device tree.
542*7836SJohn.Forte@Sun.COM 	 *
543*7836SJohn.Forte@Sun.COM 	 * In order to get the link between path_info node and scsi_vhci node
544*7836SJohn.Forte@Sun.COM 	 * it is required to take the snapshot of the whole device tree.
545*7836SJohn.Forte@Sun.COM 	 * this behavior of libdevinfo is inefficient.  For a specific
546*7836SJohn.Forte@Sun.COM 	 * fca port DINFOPROP was sufficient on the fca path prior to
547*7836SJohn.Forte@Sun.COM 	 * scsi_vhci node support.
548*7836SJohn.Forte@Sun.COM 	 *
549*7836SJohn.Forte@Sun.COM 	 */
550*7836SJohn.Forte@Sun.COM 	if ((up->flags & FLAG_DEVINFO_FORCE) == FLAG_DEVINFO_FORCE) {
551*7836SJohn.Forte@Sun.COM 		tree_root = di_init("/", init_flags | DINFOFORCE);
552*7836SJohn.Forte@Sun.COM 	} else {
553*7836SJohn.Forte@Sun.COM 		tree_root = di_init("/", init_flags);
554*7836SJohn.Forte@Sun.COM 	}
555*7836SJohn.Forte@Sun.COM 
556*7836SJohn.Forte@Sun.COM 	if (tree_root == DI_NODE_NIL) {
557*7836SJohn.Forte@Sun.COM 		*l_errnop = errno;
558*7836SJohn.Forte@Sun.COM 		ret = FPCFGA_LIB_ERR;
559*7836SJohn.Forte@Sun.COM 		goto out;
560*7836SJohn.Forte@Sun.COM 	}
561*7836SJohn.Forte@Sun.COM 
562*7836SJohn.Forte@Sun.COM 	fpnode = di_drv_first_node("fp", tree_root);
563*7836SJohn.Forte@Sun.COM 
564*7836SJohn.Forte@Sun.COM 	while (fpnode) {
565*7836SJohn.Forte@Sun.COM 		devfs_fp_path = di_devfs_path(fpnode);
566*7836SJohn.Forte@Sun.COM 		if ((devfs_fp_path) && !(strncmp(devfs_fp_path,
567*7836SJohn.Forte@Sun.COM 				root_path, strlen(root_path)))) {
568*7836SJohn.Forte@Sun.COM 			found = 1;
569*7836SJohn.Forte@Sun.COM 			di_devfs_path_free(devfs_fp_path);
570*7836SJohn.Forte@Sun.COM 			break;
571*7836SJohn.Forte@Sun.COM 		}
572*7836SJohn.Forte@Sun.COM 		di_devfs_path_free(devfs_fp_path);
573*7836SJohn.Forte@Sun.COM 		fpnode = di_drv_next_node(fpnode);
574*7836SJohn.Forte@Sun.COM 	}
575*7836SJohn.Forte@Sun.COM 	if (!(found)) {
576*7836SJohn.Forte@Sun.COM 		ret = FPCFGA_LIB_ERR;
577*7836SJohn.Forte@Sun.COM 		goto out;
578*7836SJohn.Forte@Sun.COM 	} else {
579*7836SJohn.Forte@Sun.COM 		root = fpnode;
580*7836SJohn.Forte@Sun.COM 	}
581*7836SJohn.Forte@Sun.COM 
582*7836SJohn.Forte@Sun.COM 	/* Walk the tree */
583*7836SJohn.Forte@Sun.COM 	errno = 0;
584*7836SJohn.Forte@Sun.COM 	if (cmd == FPCFGA_WALK_NODE) {
585*7836SJohn.Forte@Sun.COM 		rv = di_walk_node(root, up->walkmode.node_args.flags, arg,
586*7836SJohn.Forte@Sun.COM 		    up->walkmode.node_args.fcn);
587*7836SJohn.Forte@Sun.COM 	} else {
588*7836SJohn.Forte@Sun.COM 		assert(cmd == FPCFGA_WALK_MINOR);
589*7836SJohn.Forte@Sun.COM 		rv = di_walk_minor(root, up->walkmode.minor_args.nodetype, 0,
590*7836SJohn.Forte@Sun.COM 			arg, up->walkmode.minor_args.fcn);
591*7836SJohn.Forte@Sun.COM 	}
592*7836SJohn.Forte@Sun.COM 
593*7836SJohn.Forte@Sun.COM 	if (rv != 0) {
594*7836SJohn.Forte@Sun.COM 		*l_errnop = errno;
595*7836SJohn.Forte@Sun.COM 		ret = FPCFGA_LIB_ERR;
596*7836SJohn.Forte@Sun.COM 	} else {
597*7836SJohn.Forte@Sun.COM 		if ((up->flags & FLAG_PATH_INFO_WALK) == FLAG_PATH_INFO_WALK) {
598*7836SJohn.Forte@Sun.COM 			ret = stat_path_info_node(root, arg, l_errnop);
599*7836SJohn.Forte@Sun.COM 		} else {
600*7836SJohn.Forte@Sun.COM 			*l_errnop = 0;
601*7836SJohn.Forte@Sun.COM 			ret = FPCFGA_OK;
602*7836SJohn.Forte@Sun.COM 		}
603*7836SJohn.Forte@Sun.COM 	}
604*7836SJohn.Forte@Sun.COM 
605*7836SJohn.Forte@Sun.COM 	di_fini(tree_root);
606*7836SJohn.Forte@Sun.COM 
607*7836SJohn.Forte@Sun.COM 	/*FALLTHRU*/
608*7836SJohn.Forte@Sun.COM out:
609*7836SJohn.Forte@Sun.COM 	S_FREE(root_path);
610*7836SJohn.Forte@Sun.COM 	return (ret);
611*7836SJohn.Forte@Sun.COM }
612*7836SJohn.Forte@Sun.COM 
613*7836SJohn.Forte@Sun.COM 
614*7836SJohn.Forte@Sun.COM int
msg_idx(msgid_t msgid)615*7836SJohn.Forte@Sun.COM msg_idx(msgid_t msgid)
616*7836SJohn.Forte@Sun.COM {
617*7836SJohn.Forte@Sun.COM 	int idx = 0;
618*7836SJohn.Forte@Sun.COM 
619*7836SJohn.Forte@Sun.COM 	/* The string table index and the error id may or may not be same */
620*7836SJohn.Forte@Sun.COM 	if (msgid >= 0 && msgid <= N_STRS - 1 &&
621*7836SJohn.Forte@Sun.COM 	    str_tbl[msgid].msgid == msgid) {
622*7836SJohn.Forte@Sun.COM 		idx = msgid;
623*7836SJohn.Forte@Sun.COM 	} else {
624*7836SJohn.Forte@Sun.COM 		for (idx = 0; idx < N_STRS; idx++) {
625*7836SJohn.Forte@Sun.COM 			if (str_tbl[idx].msgid == msgid)
626*7836SJohn.Forte@Sun.COM 				break;
627*7836SJohn.Forte@Sun.COM 		}
628*7836SJohn.Forte@Sun.COM 		if (idx >= N_STRS) {
629*7836SJohn.Forte@Sun.COM 			idx =  UNKNOWN_ERR_IDX;
630*7836SJohn.Forte@Sun.COM 		}
631*7836SJohn.Forte@Sun.COM 	}
632*7836SJohn.Forte@Sun.COM 
633*7836SJohn.Forte@Sun.COM 	return (idx);
634*7836SJohn.Forte@Sun.COM }
635*7836SJohn.Forte@Sun.COM 
636*7836SJohn.Forte@Sun.COM /*
637*7836SJohn.Forte@Sun.COM  * cfga_err() accepts a variable number of message IDs and constructs
638*7836SJohn.Forte@Sun.COM  * a corresponding error string which is returned via the errstring argument.
639*7836SJohn.Forte@Sun.COM  * cfga_err() calls dgettext() to internationalize proper messages.
640*7836SJohn.Forte@Sun.COM  * May be called with a NULL argument.
641*7836SJohn.Forte@Sun.COM  */
642*7836SJohn.Forte@Sun.COM void
cfga_err(char ** errstring,int l_errno,...)643*7836SJohn.Forte@Sun.COM cfga_err(char **errstring, int l_errno, ...)
644*7836SJohn.Forte@Sun.COM {
645*7836SJohn.Forte@Sun.COM 	va_list ap;
646*7836SJohn.Forte@Sun.COM 	int append_newline = 0;
647*7836SJohn.Forte@Sun.COM 	char *tmp_str, *tmp_err_str = NULL;
648*7836SJohn.Forte@Sun.COM 
649*7836SJohn.Forte@Sun.COM 	if (errstring == NULL) {
650*7836SJohn.Forte@Sun.COM 		return;
651*7836SJohn.Forte@Sun.COM 	}
652*7836SJohn.Forte@Sun.COM 
653*7836SJohn.Forte@Sun.COM 	/*
654*7836SJohn.Forte@Sun.COM 	 * Don't append a newline, the application (for example cfgadm)
655*7836SJohn.Forte@Sun.COM 	 * should do that.
656*7836SJohn.Forte@Sun.COM 	 */
657*7836SJohn.Forte@Sun.COM 	append_newline = 0;
658*7836SJohn.Forte@Sun.COM 
659*7836SJohn.Forte@Sun.COM 	va_start(ap, l_errno);
660*7836SJohn.Forte@Sun.COM 	msg_common(&tmp_err_str, append_newline, l_errno, ap);
661*7836SJohn.Forte@Sun.COM 	va_end(ap);
662*7836SJohn.Forte@Sun.COM 
663*7836SJohn.Forte@Sun.COM 	if (*errstring == NULL) {
664*7836SJohn.Forte@Sun.COM 		*errstring = tmp_err_str;
665*7836SJohn.Forte@Sun.COM 		return;
666*7836SJohn.Forte@Sun.COM 	}
667*7836SJohn.Forte@Sun.COM 
668*7836SJohn.Forte@Sun.COM 	/*
669*7836SJohn.Forte@Sun.COM 	 * *errstring != NULL
670*7836SJohn.Forte@Sun.COM 	 * There was something in errstring prior to this call.
671*7836SJohn.Forte@Sun.COM 	 * So, concatenate the old and new strings
672*7836SJohn.Forte@Sun.COM 	 */
673*7836SJohn.Forte@Sun.COM 	if ((tmp_str = calloc(1,
674*7836SJohn.Forte@Sun.COM 		strlen(*errstring) + strlen(tmp_err_str) + 2)) == NULL) {
675*7836SJohn.Forte@Sun.COM 		/* In case of error, retain only the earlier message */
676*7836SJohn.Forte@Sun.COM 		free(tmp_err_str);
677*7836SJohn.Forte@Sun.COM 		return;
678*7836SJohn.Forte@Sun.COM 	}
679*7836SJohn.Forte@Sun.COM 
680*7836SJohn.Forte@Sun.COM 	sprintf(tmp_str, "%s\n%s", *errstring, tmp_err_str);
681*7836SJohn.Forte@Sun.COM 	free(tmp_err_str);
682*7836SJohn.Forte@Sun.COM 	free(*errstring);
683*7836SJohn.Forte@Sun.COM 	*errstring = tmp_str;
684*7836SJohn.Forte@Sun.COM }
685*7836SJohn.Forte@Sun.COM 
686*7836SJohn.Forte@Sun.COM /*
687*7836SJohn.Forte@Sun.COM  * This routine accepts a variable number of message IDs and constructs
688*7836SJohn.Forte@Sun.COM  * a corresponding message string which is printed via the message print
689*7836SJohn.Forte@Sun.COM  * routine argument.
690*7836SJohn.Forte@Sun.COM  */
691*7836SJohn.Forte@Sun.COM void
cfga_msg(struct cfga_msg * msgp,...)692*7836SJohn.Forte@Sun.COM cfga_msg(struct cfga_msg *msgp, ...)
693*7836SJohn.Forte@Sun.COM {
694*7836SJohn.Forte@Sun.COM 	char *p = NULL;
695*7836SJohn.Forte@Sun.COM 	int append_newline = 0, l_errno = 0;
696*7836SJohn.Forte@Sun.COM 	va_list ap;
697*7836SJohn.Forte@Sun.COM 
698*7836SJohn.Forte@Sun.COM 	if (msgp == NULL || msgp->message_routine == NULL) {
699*7836SJohn.Forte@Sun.COM 		return;
700*7836SJohn.Forte@Sun.COM 	}
701*7836SJohn.Forte@Sun.COM 
702*7836SJohn.Forte@Sun.COM 	/* Append a newline after message */
703*7836SJohn.Forte@Sun.COM 	append_newline = 1;
704*7836SJohn.Forte@Sun.COM 	l_errno = 0;
705*7836SJohn.Forte@Sun.COM 
706*7836SJohn.Forte@Sun.COM 	va_start(ap, msgp);
707*7836SJohn.Forte@Sun.COM 	msg_common(&p, append_newline, l_errno, ap);
708*7836SJohn.Forte@Sun.COM 	va_end(ap);
709*7836SJohn.Forte@Sun.COM 
710*7836SJohn.Forte@Sun.COM 	(void) (*msgp->message_routine)(msgp->appdata_ptr, p);
711*7836SJohn.Forte@Sun.COM 
712*7836SJohn.Forte@Sun.COM 	S_FREE(p);
713*7836SJohn.Forte@Sun.COM }
714*7836SJohn.Forte@Sun.COM 
715*7836SJohn.Forte@Sun.COM /*
716*7836SJohn.Forte@Sun.COM  * Get internationalized string corresponding to message id
717*7836SJohn.Forte@Sun.COM  * Caller must free the memory allocated.
718*7836SJohn.Forte@Sun.COM  */
719*7836SJohn.Forte@Sun.COM char *
cfga_str(int append_newline,...)720*7836SJohn.Forte@Sun.COM cfga_str(int append_newline, ...)
721*7836SJohn.Forte@Sun.COM {
722*7836SJohn.Forte@Sun.COM 	char *p = NULL;
723*7836SJohn.Forte@Sun.COM 	int l_errno = 0;
724*7836SJohn.Forte@Sun.COM 	va_list ap;
725*7836SJohn.Forte@Sun.COM 
726*7836SJohn.Forte@Sun.COM 	va_start(ap, append_newline);
727*7836SJohn.Forte@Sun.COM 	msg_common(&p, append_newline, l_errno, ap);
728*7836SJohn.Forte@Sun.COM 	va_end(ap);
729*7836SJohn.Forte@Sun.COM 
730*7836SJohn.Forte@Sun.COM 	return (p);
731*7836SJohn.Forte@Sun.COM }
732*7836SJohn.Forte@Sun.COM 
733*7836SJohn.Forte@Sun.COM static void
msg_common(char ** msgpp,int append_newline,int l_errno,va_list ap)734*7836SJohn.Forte@Sun.COM msg_common(char **msgpp, int append_newline, int l_errno, va_list ap)
735*7836SJohn.Forte@Sun.COM {
736*7836SJohn.Forte@Sun.COM 	int a = 0;
737*7836SJohn.Forte@Sun.COM 	size_t len = 0;
738*7836SJohn.Forte@Sun.COM 	int i = 0, n = 0;
739*7836SJohn.Forte@Sun.COM 	char *s = NULL, *t = NULL;
740*7836SJohn.Forte@Sun.COM 	strlist_t dummy;
741*7836SJohn.Forte@Sun.COM 	strlist_t *savep = NULL, *sp = NULL, *tailp = NULL;
742*7836SJohn.Forte@Sun.COM 
743*7836SJohn.Forte@Sun.COM 	if (*msgpp != NULL) {
744*7836SJohn.Forte@Sun.COM 		return;
745*7836SJohn.Forte@Sun.COM 	}
746*7836SJohn.Forte@Sun.COM 
747*7836SJohn.Forte@Sun.COM 	dummy.next = NULL;
748*7836SJohn.Forte@Sun.COM 	tailp = &dummy;
749*7836SJohn.Forte@Sun.COM 	for (len = 0; (a = va_arg(ap, int)) != 0; ) {
750*7836SJohn.Forte@Sun.COM 		n = GET_MSG_NARGS(a); /* 0 implies no additional args */
751*7836SJohn.Forte@Sun.COM 		for (i = 0; i <= n; i++) {
752*7836SJohn.Forte@Sun.COM 			sp = calloc(1, sizeof (*sp));
753*7836SJohn.Forte@Sun.COM 			if (sp == NULL) {
754*7836SJohn.Forte@Sun.COM 				goto out;
755*7836SJohn.Forte@Sun.COM 			}
756*7836SJohn.Forte@Sun.COM 			if (i == 0 && GET_MSG_INTL(a)) {
757*7836SJohn.Forte@Sun.COM 				sp->str = dgettext(TEXT_DOMAIN, GET_MSG_STR(a));
758*7836SJohn.Forte@Sun.COM 			} else if (i == 0) {
759*7836SJohn.Forte@Sun.COM 				sp->str = GET_MSG_STR(a);
760*7836SJohn.Forte@Sun.COM 			} else {
761*7836SJohn.Forte@Sun.COM 				sp->str = va_arg(ap, char *);
762*7836SJohn.Forte@Sun.COM 			}
763*7836SJohn.Forte@Sun.COM 			len += (strlen(sp->str));
764*7836SJohn.Forte@Sun.COM 			sp->next = NULL;
765*7836SJohn.Forte@Sun.COM 			tailp->next = sp;
766*7836SJohn.Forte@Sun.COM 			tailp = sp;
767*7836SJohn.Forte@Sun.COM 		}
768*7836SJohn.Forte@Sun.COM 	}
769*7836SJohn.Forte@Sun.COM 
770*7836SJohn.Forte@Sun.COM 	len += 1;	/* terminating NULL */
771*7836SJohn.Forte@Sun.COM 
772*7836SJohn.Forte@Sun.COM 	s = t = NULL;
773*7836SJohn.Forte@Sun.COM 	if (l_errno) {
774*7836SJohn.Forte@Sun.COM 		s = dgettext(TEXT_DOMAIN, ": ");
775*7836SJohn.Forte@Sun.COM 		t = S_STR(strerror(l_errno));
776*7836SJohn.Forte@Sun.COM 		if (s != NULL && t != NULL) {
777*7836SJohn.Forte@Sun.COM 			len += strlen(s) + strlen(t);
778*7836SJohn.Forte@Sun.COM 		}
779*7836SJohn.Forte@Sun.COM 	}
780*7836SJohn.Forte@Sun.COM 
781*7836SJohn.Forte@Sun.COM 	if (append_newline) {
782*7836SJohn.Forte@Sun.COM 		len++;
783*7836SJohn.Forte@Sun.COM 	}
784*7836SJohn.Forte@Sun.COM 
785*7836SJohn.Forte@Sun.COM 	if ((*msgpp = calloc(1, len)) == NULL) {
786*7836SJohn.Forte@Sun.COM 		goto out;
787*7836SJohn.Forte@Sun.COM 	}
788*7836SJohn.Forte@Sun.COM 
789*7836SJohn.Forte@Sun.COM 	**msgpp = '\0';
790*7836SJohn.Forte@Sun.COM 	for (sp = dummy.next; sp != NULL; sp = sp->next) {
791*7836SJohn.Forte@Sun.COM 		(void) strcat(*msgpp, sp->str);
792*7836SJohn.Forte@Sun.COM 	}
793*7836SJohn.Forte@Sun.COM 
794*7836SJohn.Forte@Sun.COM 	if (s != NULL && t != NULL) {
795*7836SJohn.Forte@Sun.COM 		(void) strcat(*msgpp, s);
796*7836SJohn.Forte@Sun.COM 		(void) strcat(*msgpp, t);
797*7836SJohn.Forte@Sun.COM 	}
798*7836SJohn.Forte@Sun.COM 
799*7836SJohn.Forte@Sun.COM 	if (append_newline) {
800*7836SJohn.Forte@Sun.COM 		(void) strcat(*msgpp, dgettext(TEXT_DOMAIN, "\n"));
801*7836SJohn.Forte@Sun.COM 	}
802*7836SJohn.Forte@Sun.COM 
803*7836SJohn.Forte@Sun.COM 	/* FALLTHROUGH */
804*7836SJohn.Forte@Sun.COM out:
805*7836SJohn.Forte@Sun.COM 	sp = dummy.next;
806*7836SJohn.Forte@Sun.COM 	while (sp != NULL) {
807*7836SJohn.Forte@Sun.COM 		savep = sp->next;
808*7836SJohn.Forte@Sun.COM 		S_FREE(sp);
809*7836SJohn.Forte@Sun.COM 		sp = savep;
810*7836SJohn.Forte@Sun.COM 	}
811*7836SJohn.Forte@Sun.COM }
812*7836SJohn.Forte@Sun.COM 
813*7836SJohn.Forte@Sun.COM fpcfga_ret_t
devctl_cmd(const char * physpath,fpcfga_cmd_t cmd,uint_t * statep,int * l_errnop)814*7836SJohn.Forte@Sun.COM devctl_cmd(
815*7836SJohn.Forte@Sun.COM 	const char	*physpath,
816*7836SJohn.Forte@Sun.COM 	fpcfga_cmd_t	cmd,
817*7836SJohn.Forte@Sun.COM 	uint_t		*statep,
818*7836SJohn.Forte@Sun.COM 	int		*l_errnop)
819*7836SJohn.Forte@Sun.COM {
820*7836SJohn.Forte@Sun.COM 	int rv = -1, i, type;
821*7836SJohn.Forte@Sun.COM 	devctl_hdl_t hdl = NULL;
822*7836SJohn.Forte@Sun.COM 	char *cp = NULL, *path = NULL;
823*7836SJohn.Forte@Sun.COM 	int (*func)(const devctl_hdl_t);
824*7836SJohn.Forte@Sun.COM 	int (*state_func)(const devctl_hdl_t, uint_t *);
825*7836SJohn.Forte@Sun.COM 
826*7836SJohn.Forte@Sun.COM 	*l_errnop = 0;
827*7836SJohn.Forte@Sun.COM 
828*7836SJohn.Forte@Sun.COM 	if (statep != NULL) *statep = 0;
829*7836SJohn.Forte@Sun.COM 
830*7836SJohn.Forte@Sun.COM 	func = NULL;
831*7836SJohn.Forte@Sun.COM 	state_func = NULL;
832*7836SJohn.Forte@Sun.COM 	type = 0;
833*7836SJohn.Forte@Sun.COM 
834*7836SJohn.Forte@Sun.COM 	for (i = 0; i < N_GET_STATE_CMDS; i++) {
835*7836SJohn.Forte@Sun.COM 		if (get_state_cmds[i].cmd == cmd) {
836*7836SJohn.Forte@Sun.COM 			state_func = get_state_cmds[i].state_fcn;
837*7836SJohn.Forte@Sun.COM 			type = get_state_cmds[i].type;
838*7836SJohn.Forte@Sun.COM 			assert(statep != NULL);
839*7836SJohn.Forte@Sun.COM 			break;
840*7836SJohn.Forte@Sun.COM 		}
841*7836SJohn.Forte@Sun.COM 	}
842*7836SJohn.Forte@Sun.COM 
843*7836SJohn.Forte@Sun.COM 	if (state_func == NULL) {
844*7836SJohn.Forte@Sun.COM 		for (i = 0; i < N_SET_STATE_CMDS; i++) {
845*7836SJohn.Forte@Sun.COM 			if (set_state_cmds[i].cmd == cmd) {
846*7836SJohn.Forte@Sun.COM 				func = set_state_cmds[i].fcn;
847*7836SJohn.Forte@Sun.COM 				type = set_state_cmds[i].type;
848*7836SJohn.Forte@Sun.COM 				assert(statep == NULL);
849*7836SJohn.Forte@Sun.COM 				break;
850*7836SJohn.Forte@Sun.COM 			}
851*7836SJohn.Forte@Sun.COM 		}
852*7836SJohn.Forte@Sun.COM 	}
853*7836SJohn.Forte@Sun.COM 
854*7836SJohn.Forte@Sun.COM 	assert(type == BUS_OP || type == DEV_OP);
855*7836SJohn.Forte@Sun.COM 
856*7836SJohn.Forte@Sun.COM 	if (func == NULL && state_func == NULL) {
857*7836SJohn.Forte@Sun.COM 		return (FPCFGA_ERR);
858*7836SJohn.Forte@Sun.COM 	}
859*7836SJohn.Forte@Sun.COM 
860*7836SJohn.Forte@Sun.COM 	/*
861*7836SJohn.Forte@Sun.COM 	 * Fix up path for calling devctl.
862*7836SJohn.Forte@Sun.COM 	 */
863*7836SJohn.Forte@Sun.COM 	if ((path = strdup(physpath)) == NULL) {
864*7836SJohn.Forte@Sun.COM 		*l_errnop = errno;
865*7836SJohn.Forte@Sun.COM 		return (FPCFGA_LIB_ERR);
866*7836SJohn.Forte@Sun.COM 	}
867*7836SJohn.Forte@Sun.COM 
868*7836SJohn.Forte@Sun.COM 	/* Remove dynamic component if any */
869*7836SJohn.Forte@Sun.COM 	if ((cp = GET_DYN(path)) != NULL) {
870*7836SJohn.Forte@Sun.COM 		*cp = '\0';
871*7836SJohn.Forte@Sun.COM 	}
872*7836SJohn.Forte@Sun.COM 
873*7836SJohn.Forte@Sun.COM 	/* Remove minor name */
874*7836SJohn.Forte@Sun.COM 	if ((cp = strrchr(path, ':')) != NULL) {
875*7836SJohn.Forte@Sun.COM 		*cp = '\0';
876*7836SJohn.Forte@Sun.COM 	}
877*7836SJohn.Forte@Sun.COM 
878*7836SJohn.Forte@Sun.COM 	errno = 0;
879*7836SJohn.Forte@Sun.COM 
880*7836SJohn.Forte@Sun.COM 	if (type == BUS_OP) {
881*7836SJohn.Forte@Sun.COM 		hdl = devctl_bus_acquire(path, 0);
882*7836SJohn.Forte@Sun.COM 	} else {
883*7836SJohn.Forte@Sun.COM 		hdl = devctl_device_acquire(path, 0);
884*7836SJohn.Forte@Sun.COM 	}
885*7836SJohn.Forte@Sun.COM 	*l_errnop = errno;
886*7836SJohn.Forte@Sun.COM 
887*7836SJohn.Forte@Sun.COM 	S_FREE(path);
888*7836SJohn.Forte@Sun.COM 
889*7836SJohn.Forte@Sun.COM 	if (hdl == NULL) {
890*7836SJohn.Forte@Sun.COM 		return (FPCFGA_ERR);
891*7836SJohn.Forte@Sun.COM 	}
892*7836SJohn.Forte@Sun.COM 
893*7836SJohn.Forte@Sun.COM 	errno = 0;
894*7836SJohn.Forte@Sun.COM 	/* Only getstate functions require a second argument */
895*7836SJohn.Forte@Sun.COM 	if (func != NULL && statep == NULL) {
896*7836SJohn.Forte@Sun.COM 		rv = func(hdl);
897*7836SJohn.Forte@Sun.COM 		*l_errnop = errno;
898*7836SJohn.Forte@Sun.COM 	} else if (state_func != NULL && statep != NULL) {
899*7836SJohn.Forte@Sun.COM 		rv = state_func(hdl, statep);
900*7836SJohn.Forte@Sun.COM 		*l_errnop = errno;
901*7836SJohn.Forte@Sun.COM 	} else {
902*7836SJohn.Forte@Sun.COM 		rv = -1;
903*7836SJohn.Forte@Sun.COM 		*l_errnop = 0;
904*7836SJohn.Forte@Sun.COM 	}
905*7836SJohn.Forte@Sun.COM 
906*7836SJohn.Forte@Sun.COM 	devctl_release(hdl);
907*7836SJohn.Forte@Sun.COM 
908*7836SJohn.Forte@Sun.COM 	return ((rv == -1) ? FPCFGA_ERR : FPCFGA_OK);
909*7836SJohn.Forte@Sun.COM }
910*7836SJohn.Forte@Sun.COM 
911*7836SJohn.Forte@Sun.COM /*
912*7836SJohn.Forte@Sun.COM  * Is device in a known state ? (One of BUSY, ONLINE, OFFLINE)
913*7836SJohn.Forte@Sun.COM  *	BUSY --> One or more device special files are open. Implies online
914*7836SJohn.Forte@Sun.COM  *	ONLINE --> driver attached
915*7836SJohn.Forte@Sun.COM  *	OFFLINE --> CF1 with offline flag set.
916*7836SJohn.Forte@Sun.COM  *	UNKNOWN --> None of the above
917*7836SJohn.Forte@Sun.COM  */
918*7836SJohn.Forte@Sun.COM int
known_state(di_node_t node)919*7836SJohn.Forte@Sun.COM known_state(di_node_t node)
920*7836SJohn.Forte@Sun.COM {
921*7836SJohn.Forte@Sun.COM 	uint_t state;
922*7836SJohn.Forte@Sun.COM 
923*7836SJohn.Forte@Sun.COM 	state = di_state(node);
924*7836SJohn.Forte@Sun.COM 
925*7836SJohn.Forte@Sun.COM 	/*
926*7836SJohn.Forte@Sun.COM 	 * CF1 without offline flag set is considered unknown state.
927*7836SJohn.Forte@Sun.COM 	 * We are in a known state if either CF2 (driver attached) or
928*7836SJohn.Forte@Sun.COM 	 * offline.
929*7836SJohn.Forte@Sun.COM 	 */
930*7836SJohn.Forte@Sun.COM 	if ((state & DI_DEVICE_OFFLINE) == DI_DEVICE_OFFLINE ||
931*7836SJohn.Forte@Sun.COM 		(state & DI_DRIVER_DETACHED) != DI_DRIVER_DETACHED) {
932*7836SJohn.Forte@Sun.COM 		return (1);
933*7836SJohn.Forte@Sun.COM 	}
934*7836SJohn.Forte@Sun.COM 
935*7836SJohn.Forte@Sun.COM 	return (0);
936*7836SJohn.Forte@Sun.COM }
937*7836SJohn.Forte@Sun.COM 
938*7836SJohn.Forte@Sun.COM void
list_free(ldata_list_t ** llpp)939*7836SJohn.Forte@Sun.COM list_free(ldata_list_t **llpp)
940*7836SJohn.Forte@Sun.COM {
941*7836SJohn.Forte@Sun.COM 	ldata_list_t *lp, *olp;
942*7836SJohn.Forte@Sun.COM 
943*7836SJohn.Forte@Sun.COM 	lp = *llpp;
944*7836SJohn.Forte@Sun.COM 	while (lp != NULL) {
945*7836SJohn.Forte@Sun.COM 		olp = lp;
946*7836SJohn.Forte@Sun.COM 		lp = olp->next;
947*7836SJohn.Forte@Sun.COM 		S_FREE(olp);
948*7836SJohn.Forte@Sun.COM 	}
949*7836SJohn.Forte@Sun.COM 
950*7836SJohn.Forte@Sun.COM 	*llpp = NULL;
951*7836SJohn.Forte@Sun.COM }
952*7836SJohn.Forte@Sun.COM 
953*7836SJohn.Forte@Sun.COM /*
954*7836SJohn.Forte@Sun.COM  * Obtain the devlink from a /devices path
955*7836SJohn.Forte@Sun.COM  */
956*7836SJohn.Forte@Sun.COM fpcfga_ret_t
physpath_to_devlink(const char * basedir,char * xport_phys,char ** xport_logpp,int * l_errnop,int match_minor)957*7836SJohn.Forte@Sun.COM physpath_to_devlink(
958*7836SJohn.Forte@Sun.COM 	const char *basedir,
959*7836SJohn.Forte@Sun.COM 	char *xport_phys,
960*7836SJohn.Forte@Sun.COM 	char **xport_logpp,
961*7836SJohn.Forte@Sun.COM 	int *l_errnop,
962*7836SJohn.Forte@Sun.COM 	int match_minor)
963*7836SJohn.Forte@Sun.COM {
964*7836SJohn.Forte@Sun.COM 	pathm_t pmt = {NULL};
965*7836SJohn.Forte@Sun.COM 	fpcfga_ret_t ret;
966*7836SJohn.Forte@Sun.COM 
967*7836SJohn.Forte@Sun.COM 	pmt.phys = xport_phys;
968*7836SJohn.Forte@Sun.COM 	pmt.ret = FPCFGA_NO_REC;
969*7836SJohn.Forte@Sun.COM 	pmt.match_minor = match_minor;
970*7836SJohn.Forte@Sun.COM 
971*7836SJohn.Forte@Sun.COM 	/*
972*7836SJohn.Forte@Sun.COM 	 * Search the /dev hierarchy starting at basedir.
973*7836SJohn.Forte@Sun.COM 	 */
974*7836SJohn.Forte@Sun.COM 	ret = recurse_dev(basedir, &pmt, lookup_dev);
975*7836SJohn.Forte@Sun.COM 	if (ret == FPCFGA_OK && (ret = pmt.ret) == FPCFGA_OK) {
976*7836SJohn.Forte@Sun.COM 		assert(pmt.log != NULL);
977*7836SJohn.Forte@Sun.COM 		*xport_logpp  = pmt.log;
978*7836SJohn.Forte@Sun.COM 	} else {
979*7836SJohn.Forte@Sun.COM 		if (pmt.log != NULL) {
980*7836SJohn.Forte@Sun.COM 			S_FREE(pmt.log);
981*7836SJohn.Forte@Sun.COM 		}
982*7836SJohn.Forte@Sun.COM 
983*7836SJohn.Forte@Sun.COM 		*xport_logpp = NULL;
984*7836SJohn.Forte@Sun.COM 		*l_errnop = pmt.l_errno;
985*7836SJohn.Forte@Sun.COM 	}
986*7836SJohn.Forte@Sun.COM 
987*7836SJohn.Forte@Sun.COM 	return (ret);
988*7836SJohn.Forte@Sun.COM }
989*7836SJohn.Forte@Sun.COM 
990*7836SJohn.Forte@Sun.COM static fpcfga_recur_t
lookup_dev(const char * lpath,void * arg)991*7836SJohn.Forte@Sun.COM lookup_dev(const char *lpath, void *arg)
992*7836SJohn.Forte@Sun.COM {
993*7836SJohn.Forte@Sun.COM 	char ppath[PATH_MAX];
994*7836SJohn.Forte@Sun.COM 	pathm_t *pmtp = (pathm_t *)arg;
995*7836SJohn.Forte@Sun.COM 
996*7836SJohn.Forte@Sun.COM 	if (realpath(lpath, ppath) == NULL) {
997*7836SJohn.Forte@Sun.COM 		return (FPCFGA_CONTINUE);
998*7836SJohn.Forte@Sun.COM 	}
999*7836SJohn.Forte@Sun.COM 
1000*7836SJohn.Forte@Sun.COM 	ppath[sizeof (ppath) - 1] = '\0';
1001*7836SJohn.Forte@Sun.COM 
1002*7836SJohn.Forte@Sun.COM 	/* Is this the physical path we are looking for */
1003*7836SJohn.Forte@Sun.COM 	if (dev_cmp(ppath, pmtp->phys, pmtp->match_minor))  {
1004*7836SJohn.Forte@Sun.COM 		return (FPCFGA_CONTINUE);
1005*7836SJohn.Forte@Sun.COM 	}
1006*7836SJohn.Forte@Sun.COM 
1007*7836SJohn.Forte@Sun.COM 	if ((pmtp->log = strdup(lpath)) == NULL) {
1008*7836SJohn.Forte@Sun.COM 		pmtp->l_errno = errno;
1009*7836SJohn.Forte@Sun.COM 		pmtp->ret = FPCFGA_LIB_ERR;
1010*7836SJohn.Forte@Sun.COM 	} else {
1011*7836SJohn.Forte@Sun.COM 		pmtp->ret = FPCFGA_OK;
1012*7836SJohn.Forte@Sun.COM 	}
1013*7836SJohn.Forte@Sun.COM 
1014*7836SJohn.Forte@Sun.COM 	return (FPCFGA_TERMINATE);
1015*7836SJohn.Forte@Sun.COM }
1016*7836SJohn.Forte@Sun.COM 
1017*7836SJohn.Forte@Sun.COM /* Compare HBA physical ap_id and device path */
1018*7836SJohn.Forte@Sun.COM int
hba_dev_cmp(const char * hba,const char * devpath)1019*7836SJohn.Forte@Sun.COM hba_dev_cmp(const char *hba, const char *devpath)
1020*7836SJohn.Forte@Sun.COM {
1021*7836SJohn.Forte@Sun.COM 	char *cp = NULL;
1022*7836SJohn.Forte@Sun.COM 	int rv;
1023*7836SJohn.Forte@Sun.COM 	size_t hba_len, dev_len;
1024*7836SJohn.Forte@Sun.COM 	char l_hba[MAXPATHLEN], l_dev[MAXPATHLEN];
1025*7836SJohn.Forte@Sun.COM 
1026*7836SJohn.Forte@Sun.COM 	(void) snprintf(l_hba, sizeof (l_hba), "%s", hba);
1027*7836SJohn.Forte@Sun.COM 	(void) snprintf(l_dev, sizeof (l_dev), "%s", devpath);
1028*7836SJohn.Forte@Sun.COM 
1029*7836SJohn.Forte@Sun.COM 	/* Remove dynamic component if any */
1030*7836SJohn.Forte@Sun.COM 	if ((cp = GET_DYN(l_hba)) != NULL) {
1031*7836SJohn.Forte@Sun.COM 		*cp = '\0';
1032*7836SJohn.Forte@Sun.COM 	}
1033*7836SJohn.Forte@Sun.COM 
1034*7836SJohn.Forte@Sun.COM 	if ((cp = GET_DYN(l_dev)) != NULL) {
1035*7836SJohn.Forte@Sun.COM 		*cp = '\0';
1036*7836SJohn.Forte@Sun.COM 	}
1037*7836SJohn.Forte@Sun.COM 
1038*7836SJohn.Forte@Sun.COM 
1039*7836SJohn.Forte@Sun.COM 	/* Remove minor names */
1040*7836SJohn.Forte@Sun.COM 	if ((cp = strrchr(l_hba, ':')) != NULL) {
1041*7836SJohn.Forte@Sun.COM 		*cp = '\0';
1042*7836SJohn.Forte@Sun.COM 	}
1043*7836SJohn.Forte@Sun.COM 
1044*7836SJohn.Forte@Sun.COM 	if ((cp = strrchr(l_dev, ':')) != NULL) {
1045*7836SJohn.Forte@Sun.COM 		*cp = '\0';
1046*7836SJohn.Forte@Sun.COM 	}
1047*7836SJohn.Forte@Sun.COM 
1048*7836SJohn.Forte@Sun.COM 	hba_len = strlen(l_hba);
1049*7836SJohn.Forte@Sun.COM 	dev_len = strlen(l_dev);
1050*7836SJohn.Forte@Sun.COM 
1051*7836SJohn.Forte@Sun.COM 	/* Check if HBA path is component of device path */
1052*7836SJohn.Forte@Sun.COM 	if (rv = strncmp(l_hba, l_dev, hba_len)) {
1053*7836SJohn.Forte@Sun.COM 		return (rv);
1054*7836SJohn.Forte@Sun.COM 	}
1055*7836SJohn.Forte@Sun.COM 
1056*7836SJohn.Forte@Sun.COM 	/* devpath must have '/' and 1 char in addition to hba path */
1057*7836SJohn.Forte@Sun.COM 	if (dev_len >= hba_len + 2 && l_dev[hba_len] == '/') {
1058*7836SJohn.Forte@Sun.COM 		return (0);
1059*7836SJohn.Forte@Sun.COM 	} else {
1060*7836SJohn.Forte@Sun.COM 		return (-1);
1061*7836SJohn.Forte@Sun.COM 	}
1062*7836SJohn.Forte@Sun.COM }
1063*7836SJohn.Forte@Sun.COM 
1064*7836SJohn.Forte@Sun.COM int
dev_cmp(const char * dev1,const char * dev2,int match_minor)1065*7836SJohn.Forte@Sun.COM dev_cmp(const char *dev1, const char *dev2, int match_minor)
1066*7836SJohn.Forte@Sun.COM {
1067*7836SJohn.Forte@Sun.COM 	char l_dev1[MAXPATHLEN], l_dev2[MAXPATHLEN];
1068*7836SJohn.Forte@Sun.COM 	char *mn1, *mn2;
1069*7836SJohn.Forte@Sun.COM 	int rv;
1070*7836SJohn.Forte@Sun.COM 
1071*7836SJohn.Forte@Sun.COM 	(void) snprintf(l_dev1, sizeof (l_dev1), "%s", dev1);
1072*7836SJohn.Forte@Sun.COM 	(void) snprintf(l_dev2, sizeof (l_dev2), "%s", dev2);
1073*7836SJohn.Forte@Sun.COM 
1074*7836SJohn.Forte@Sun.COM 	if ((mn1 = GET_DYN(l_dev1)) != NULL) {
1075*7836SJohn.Forte@Sun.COM 		*mn1 = '\0';
1076*7836SJohn.Forte@Sun.COM 	}
1077*7836SJohn.Forte@Sun.COM 
1078*7836SJohn.Forte@Sun.COM 	if ((mn2 = GET_DYN(l_dev2)) != NULL) {
1079*7836SJohn.Forte@Sun.COM 		*mn2 = '\0';
1080*7836SJohn.Forte@Sun.COM 	}
1081*7836SJohn.Forte@Sun.COM 
1082*7836SJohn.Forte@Sun.COM 	/* Separate out the minor names */
1083*7836SJohn.Forte@Sun.COM 	if ((mn1 = strrchr(l_dev1, ':')) != NULL) {
1084*7836SJohn.Forte@Sun.COM 		*mn1++ = '\0';
1085*7836SJohn.Forte@Sun.COM 	}
1086*7836SJohn.Forte@Sun.COM 
1087*7836SJohn.Forte@Sun.COM 	if ((mn2 = strrchr(l_dev2, ':')) != NULL) {
1088*7836SJohn.Forte@Sun.COM 		*mn2++ = '\0';
1089*7836SJohn.Forte@Sun.COM 	}
1090*7836SJohn.Forte@Sun.COM 
1091*7836SJohn.Forte@Sun.COM 	if ((rv = strcmp(l_dev1, l_dev2)) != 0 || !match_minor) {
1092*7836SJohn.Forte@Sun.COM 		return (rv);
1093*7836SJohn.Forte@Sun.COM 	}
1094*7836SJohn.Forte@Sun.COM 
1095*7836SJohn.Forte@Sun.COM 	/*
1096*7836SJohn.Forte@Sun.COM 	 * Compare minor names
1097*7836SJohn.Forte@Sun.COM 	 */
1098*7836SJohn.Forte@Sun.COM 	if (mn1 == NULL && mn2 == NULL) {
1099*7836SJohn.Forte@Sun.COM 		return (0);
1100*7836SJohn.Forte@Sun.COM 	} else if (mn1 == NULL) {
1101*7836SJohn.Forte@Sun.COM 		return (-1);
1102*7836SJohn.Forte@Sun.COM 	} else if (mn2 == NULL) {
1103*7836SJohn.Forte@Sun.COM 		return (1);
1104*7836SJohn.Forte@Sun.COM 	} else {
1105*7836SJohn.Forte@Sun.COM 		return (strcmp(mn1, mn2));
1106*7836SJohn.Forte@Sun.COM 	}
1107*7836SJohn.Forte@Sun.COM }
1108*7836SJohn.Forte@Sun.COM 
1109*7836SJohn.Forte@Sun.COM /*
1110*7836SJohn.Forte@Sun.COM  * Returns non-zero on failure (aka, HBA_STATUS_ERROR_*
1111*7836SJohn.Forte@Sun.COM  * Will handle retries if applicable.
1112*7836SJohn.Forte@Sun.COM  */
1113*7836SJohn.Forte@Sun.COM int
getAdapterAttrs(HBA_HANDLE handle,HBA_ADAPTERATTRIBUTES * attrs)1114*7836SJohn.Forte@Sun.COM getAdapterAttrs(HBA_HANDLE handle, HBA_ADAPTERATTRIBUTES *attrs)
1115*7836SJohn.Forte@Sun.COM {
1116*7836SJohn.Forte@Sun.COM 	int count = 0;
1117*7836SJohn.Forte@Sun.COM 	HBA_STATUS status = HBA_STATUS_ERROR_TRY_AGAIN; /* force first pass */
1118*7836SJohn.Forte@Sun.COM 
1119*7836SJohn.Forte@Sun.COM 	/* Loop as long as we have a retryable error */
1120*7836SJohn.Forte@Sun.COM 	while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
1121*7836SJohn.Forte@Sun.COM 		status == HBA_STATUS_ERROR_BUSY) &&
1122*7836SJohn.Forte@Sun.COM 		count++ < HBA_MAX_RETRIES) {
1123*7836SJohn.Forte@Sun.COM 		status = HBA_GetAdapterAttributes(handle, attrs);
1124*7836SJohn.Forte@Sun.COM 		if (status == HBA_STATUS_OK) {
1125*7836SJohn.Forte@Sun.COM 			break;
1126*7836SJohn.Forte@Sun.COM 		}
1127*7836SJohn.Forte@Sun.COM 		sleep(1);
1128*7836SJohn.Forte@Sun.COM 	}
1129*7836SJohn.Forte@Sun.COM 	return (status);
1130*7836SJohn.Forte@Sun.COM }
1131*7836SJohn.Forte@Sun.COM 
1132*7836SJohn.Forte@Sun.COM /*
1133*7836SJohn.Forte@Sun.COM  * Returns non-zero on failure (aka, HBA_STATUS_ERROR_*
1134*7836SJohn.Forte@Sun.COM  * Will handle retries if applicable.
1135*7836SJohn.Forte@Sun.COM  */
1136*7836SJohn.Forte@Sun.COM int
getPortAttrsByWWN(HBA_HANDLE handle,HBA_WWN wwn,HBA_PORTATTRIBUTES * attrs)1137*7836SJohn.Forte@Sun.COM getPortAttrsByWWN(HBA_HANDLE handle, HBA_WWN wwn, HBA_PORTATTRIBUTES *attrs)
1138*7836SJohn.Forte@Sun.COM {
1139*7836SJohn.Forte@Sun.COM 	int count = 0;
1140*7836SJohn.Forte@Sun.COM 	HBA_STATUS status = HBA_STATUS_ERROR_TRY_AGAIN; /* force first pass */
1141*7836SJohn.Forte@Sun.COM 
1142*7836SJohn.Forte@Sun.COM 	/* Loop as long as we have a retryable error */
1143*7836SJohn.Forte@Sun.COM 	while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
1144*7836SJohn.Forte@Sun.COM 		status == HBA_STATUS_ERROR_BUSY) &&
1145*7836SJohn.Forte@Sun.COM 		count++ < HBA_MAX_RETRIES) {
1146*7836SJohn.Forte@Sun.COM 		status = HBA_GetPortAttributesByWWN(handle, wwn, attrs);
1147*7836SJohn.Forte@Sun.COM 		if (status == HBA_STATUS_OK) {
1148*7836SJohn.Forte@Sun.COM 		    break;
1149*7836SJohn.Forte@Sun.COM 		}
1150*7836SJohn.Forte@Sun.COM 
1151*7836SJohn.Forte@Sun.COM 		/* The odds of this occuring are very slim, but possible. */
1152*7836SJohn.Forte@Sun.COM 		if (status == HBA_STATUS_ERROR_STALE_DATA) {
1153*7836SJohn.Forte@Sun.COM 			/*
1154*7836SJohn.Forte@Sun.COM 			 * If we hit a stale data scenario,
1155*7836SJohn.Forte@Sun.COM 			 * we'll just tell the user to try again.
1156*7836SJohn.Forte@Sun.COM 			 */
1157*7836SJohn.Forte@Sun.COM 			status = HBA_STATUS_ERROR_TRY_AGAIN;
1158*7836SJohn.Forte@Sun.COM 			break;
1159*7836SJohn.Forte@Sun.COM 		}
1160*7836SJohn.Forte@Sun.COM 		sleep(1);
1161*7836SJohn.Forte@Sun.COM 	}
1162*7836SJohn.Forte@Sun.COM 	return (status);
1163*7836SJohn.Forte@Sun.COM }
1164*7836SJohn.Forte@Sun.COM 
1165*7836SJohn.Forte@Sun.COM /*
1166*7836SJohn.Forte@Sun.COM  * Returns non-zero on failure (aka, HBA_STATUS_ERROR_*
1167*7836SJohn.Forte@Sun.COM  * Will handle retries if applicable.
1168*7836SJohn.Forte@Sun.COM  */
1169*7836SJohn.Forte@Sun.COM int
getAdapterPortAttrs(HBA_HANDLE handle,int portIndex,HBA_PORTATTRIBUTES * attrs)1170*7836SJohn.Forte@Sun.COM getAdapterPortAttrs(HBA_HANDLE handle, int portIndex,
1171*7836SJohn.Forte@Sun.COM 	    HBA_PORTATTRIBUTES *attrs)
1172*7836SJohn.Forte@Sun.COM {
1173*7836SJohn.Forte@Sun.COM 	int count = 0;
1174*7836SJohn.Forte@Sun.COM 	HBA_STATUS status = HBA_STATUS_ERROR_TRY_AGAIN; /* force first pass */
1175*7836SJohn.Forte@Sun.COM 
1176*7836SJohn.Forte@Sun.COM 	/* Loop as long as we have a retryable error */
1177*7836SJohn.Forte@Sun.COM 	while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
1178*7836SJohn.Forte@Sun.COM 		status == HBA_STATUS_ERROR_BUSY) &&
1179*7836SJohn.Forte@Sun.COM 		count++ < HBA_MAX_RETRIES) {
1180*7836SJohn.Forte@Sun.COM 		status = HBA_GetAdapterPortAttributes(handle, portIndex, attrs);
1181*7836SJohn.Forte@Sun.COM 		if (status == HBA_STATUS_OK) {
1182*7836SJohn.Forte@Sun.COM 			break;
1183*7836SJohn.Forte@Sun.COM 		}
1184*7836SJohn.Forte@Sun.COM 
1185*7836SJohn.Forte@Sun.COM 		/* The odds of this occuring are very slim, but possible. */
1186*7836SJohn.Forte@Sun.COM 		if (status == HBA_STATUS_ERROR_STALE_DATA) {
1187*7836SJohn.Forte@Sun.COM 			/*
1188*7836SJohn.Forte@Sun.COM 			 * If we hit a stale data scenario,
1189*7836SJohn.Forte@Sun.COM 			 * we'll just tell the user to try again.
1190*7836SJohn.Forte@Sun.COM 			 */
1191*7836SJohn.Forte@Sun.COM 			status = HBA_STATUS_ERROR_TRY_AGAIN;
1192*7836SJohn.Forte@Sun.COM 			break;
1193*7836SJohn.Forte@Sun.COM 		}
1194*7836SJohn.Forte@Sun.COM 		sleep(1);
1195*7836SJohn.Forte@Sun.COM 	}
1196*7836SJohn.Forte@Sun.COM 	return (status);
1197*7836SJohn.Forte@Sun.COM }
1198*7836SJohn.Forte@Sun.COM 
1199*7836SJohn.Forte@Sun.COM /*
1200*7836SJohn.Forte@Sun.COM  * Returns non-zero on failure (aka, HBA_STATUS_ERROR_*
1201*7836SJohn.Forte@Sun.COM  * Will handle retries if applicable.
1202*7836SJohn.Forte@Sun.COM  */
1203*7836SJohn.Forte@Sun.COM int
getDiscPortAttrs(HBA_HANDLE handle,int portIndex,int discIndex,HBA_PORTATTRIBUTES * attrs)1204*7836SJohn.Forte@Sun.COM getDiscPortAttrs(HBA_HANDLE handle, int portIndex, int discIndex,
1205*7836SJohn.Forte@Sun.COM 	    HBA_PORTATTRIBUTES *attrs)
1206*7836SJohn.Forte@Sun.COM {
1207*7836SJohn.Forte@Sun.COM 	int count = 0;
1208*7836SJohn.Forte@Sun.COM 	HBA_STATUS status = HBA_STATUS_ERROR_TRY_AGAIN; /* force first pass */
1209*7836SJohn.Forte@Sun.COM 
1210*7836SJohn.Forte@Sun.COM 	/* Loop as long as we have a retryable error */
1211*7836SJohn.Forte@Sun.COM 	while ((status == HBA_STATUS_ERROR_TRY_AGAIN ||
1212*7836SJohn.Forte@Sun.COM 		status == HBA_STATUS_ERROR_BUSY) &&
1213*7836SJohn.Forte@Sun.COM 		count++ < HBA_MAX_RETRIES) {
1214*7836SJohn.Forte@Sun.COM 		status = HBA_GetDiscoveredPortAttributes(handle, portIndex,
1215*7836SJohn.Forte@Sun.COM 				discIndex, attrs);
1216*7836SJohn.Forte@Sun.COM 		if (status == HBA_STATUS_OK) {
1217*7836SJohn.Forte@Sun.COM 			break;
1218*7836SJohn.Forte@Sun.COM 		}
1219*7836SJohn.Forte@Sun.COM 
1220*7836SJohn.Forte@Sun.COM 		/* The odds of this occuring are very slim, but possible. */
1221*7836SJohn.Forte@Sun.COM 		if (status == HBA_STATUS_ERROR_STALE_DATA) {
1222*7836SJohn.Forte@Sun.COM 			/*
1223*7836SJohn.Forte@Sun.COM 			 * If we hit a stale data scenario, we'll just tell the
1224*7836SJohn.Forte@Sun.COM 			 * user to try again.
1225*7836SJohn.Forte@Sun.COM 			 */
1226*7836SJohn.Forte@Sun.COM 			status = HBA_STATUS_ERROR_TRY_AGAIN;
1227*7836SJohn.Forte@Sun.COM 			break;
1228*7836SJohn.Forte@Sun.COM 		}
1229*7836SJohn.Forte@Sun.COM 		sleep(1);
1230*7836SJohn.Forte@Sun.COM 	}
1231*7836SJohn.Forte@Sun.COM 	return (status);
1232*7836SJohn.Forte@Sun.COM }
1233*7836SJohn.Forte@Sun.COM 
1234*7836SJohn.Forte@Sun.COM /*
1235*7836SJohn.Forte@Sun.COM  * Find the Adapter port that matches the portPath.
1236*7836SJohn.Forte@Sun.COM  * When the matching port is found the caller have to close handle
1237*7836SJohn.Forte@Sun.COM  * and free library.
1238*7836SJohn.Forte@Sun.COM  */
1239*7836SJohn.Forte@Sun.COM fpcfga_ret_t
findMatchingAdapterPort(char * portPath,HBA_HANDLE * matchingHandle,int * matchingPortIndex,HBA_PORTATTRIBUTES * matchingPortAttrs,char ** errstring)1240*7836SJohn.Forte@Sun.COM findMatchingAdapterPort(char *portPath, HBA_HANDLE *matchingHandle,
1241*7836SJohn.Forte@Sun.COM 	int *matchingPortIndex, HBA_PORTATTRIBUTES *matchingPortAttrs,
1242*7836SJohn.Forte@Sun.COM 	char **errstring)
1243*7836SJohn.Forte@Sun.COM {
1244*7836SJohn.Forte@Sun.COM 	HBA_HANDLE	handle;
1245*7836SJohn.Forte@Sun.COM 	HBA_ADAPTERATTRIBUTES	hbaAttrs;
1246*7836SJohn.Forte@Sun.COM 	HBA_PORTATTRIBUTES	portAttrs;
1247*7836SJohn.Forte@Sun.COM 	HBA_STATUS status = HBA_STATUS_OK;
1248*7836SJohn.Forte@Sun.COM 	int count, retry = 0, l_errno = 0;
1249*7836SJohn.Forte@Sun.COM 	int adapterIndex, portIndex;
1250*7836SJohn.Forte@Sun.COM 	char			adapterName[256];
1251*7836SJohn.Forte@Sun.COM 	char			*cfg_ptr, *tmpPtr;
1252*7836SJohn.Forte@Sun.COM 	char			*logical_apid = NULL;
1253*7836SJohn.Forte@Sun.COM 
1254*7836SJohn.Forte@Sun.COM 	status = HBA_LoadLibrary();
1255*7836SJohn.Forte@Sun.COM 	if (status != HBA_STATUS_OK) {
1256*7836SJohn.Forte@Sun.COM 	    cfga_err(errstring, 0, ERR_HBA_LOAD_LIBRARY, 0);
1257*7836SJohn.Forte@Sun.COM 	    return (FPCFGA_LIB_ERR);
1258*7836SJohn.Forte@Sun.COM 	}
1259*7836SJohn.Forte@Sun.COM 	count = HBA_GetNumberOfAdapters();
1260*7836SJohn.Forte@Sun.COM 	if (count == 0) {
1261*7836SJohn.Forte@Sun.COM 	    cfga_err(errstring, 0, ERR_NO_ADAPTER_FOUND, 0);
1262*7836SJohn.Forte@Sun.COM 	    HBA_FreeLibrary();
1263*7836SJohn.Forte@Sun.COM 	    return (FPCFGA_LIB_ERR);
1264*7836SJohn.Forte@Sun.COM 	}
1265*7836SJohn.Forte@Sun.COM 
1266*7836SJohn.Forte@Sun.COM 	/* Loop over all HBAs */
1267*7836SJohn.Forte@Sun.COM 	for (adapterIndex = 0; adapterIndex < count; adapterIndex ++) {
1268*7836SJohn.Forte@Sun.COM 	    status = HBA_GetAdapterName(adapterIndex, (char *)&adapterName);
1269*7836SJohn.Forte@Sun.COM 	    if (status != HBA_STATUS_OK) {
1270*7836SJohn.Forte@Sun.COM 		/* May have been DR'd */
1271*7836SJohn.Forte@Sun.COM 		continue;
1272*7836SJohn.Forte@Sun.COM 	    }
1273*7836SJohn.Forte@Sun.COM 	    handle = HBA_OpenAdapter(adapterName);
1274*7836SJohn.Forte@Sun.COM 	    if (handle == 0) {
1275*7836SJohn.Forte@Sun.COM 		/* May have been DR'd */
1276*7836SJohn.Forte@Sun.COM 		continue;
1277*7836SJohn.Forte@Sun.COM 	    }
1278*7836SJohn.Forte@Sun.COM 
1279*7836SJohn.Forte@Sun.COM 	    do {
1280*7836SJohn.Forte@Sun.COM 		if (getAdapterAttrs(handle, &hbaAttrs)) {
1281*7836SJohn.Forte@Sun.COM 		/* Should never happen */
1282*7836SJohn.Forte@Sun.COM 		    HBA_CloseAdapter(handle);
1283*7836SJohn.Forte@Sun.COM 		    continue;
1284*7836SJohn.Forte@Sun.COM 		}
1285*7836SJohn.Forte@Sun.COM 
1286*7836SJohn.Forte@Sun.COM 		/* Loop over all HBA Ports */
1287*7836SJohn.Forte@Sun.COM 		for (portIndex = 0;
1288*7836SJohn.Forte@Sun.COM 		    portIndex < hbaAttrs.NumberOfPorts; portIndex++) {
1289*7836SJohn.Forte@Sun.COM 		    if ((status = getAdapterPortAttrs(handle, portIndex,
1290*7836SJohn.Forte@Sun.COM 			&portAttrs)) != HBA_STATUS_OK) {
1291*7836SJohn.Forte@Sun.COM 			/* Need to refresh adapter */
1292*7836SJohn.Forte@Sun.COM 			if (status == HBA_STATUS_ERROR_STALE_DATA) {
1293*7836SJohn.Forte@Sun.COM 			    HBA_RefreshInformation(handle);
1294*7836SJohn.Forte@Sun.COM 			    break;
1295*7836SJohn.Forte@Sun.COM 			} else {
1296*7836SJohn.Forte@Sun.COM 			    continue;
1297*7836SJohn.Forte@Sun.COM 			}
1298*7836SJohn.Forte@Sun.COM 		    }
1299*7836SJohn.Forte@Sun.COM 
1300*7836SJohn.Forte@Sun.COM 			/*
1301*7836SJohn.Forte@Sun.COM 			 * check to see if OSDeviceName is a /dev/cfg link
1302*7836SJohn.Forte@Sun.COM 			 * or the physical path
1303*7836SJohn.Forte@Sun.COM 			 */
1304*7836SJohn.Forte@Sun.COM 		    if (strncmp(portAttrs.OSDeviceName, CFGA_DEV_DIR,
1305*7836SJohn.Forte@Sun.COM 			strlen(CFGA_DEV_DIR)) != 0) {
1306*7836SJohn.Forte@Sun.COM 			tmpPtr = strstr(portAttrs.OSDeviceName, MINOR_SEP);
1307*7836SJohn.Forte@Sun.COM 			if (tmpPtr != NULL) {
1308*7836SJohn.Forte@Sun.COM 				if (strncmp(portPath,
1309*7836SJohn.Forte@Sun.COM 					    portAttrs.OSDeviceName,
1310*7836SJohn.Forte@Sun.COM 					    strlen(portAttrs.OSDeviceName) -
1311*7836SJohn.Forte@Sun.COM 					    strlen(tmpPtr)) == 0) {
1312*7836SJohn.Forte@Sun.COM 					if (matchingHandle)
1313*7836SJohn.Forte@Sun.COM 						*matchingHandle = handle;
1314*7836SJohn.Forte@Sun.COM 					if (matchingPortIndex)
1315*7836SJohn.Forte@Sun.COM 						*matchingPortIndex = portIndex;
1316*7836SJohn.Forte@Sun.COM 					if (matchingPortAttrs)
1317*7836SJohn.Forte@Sun.COM 						*matchingPortAttrs = portAttrs;
1318*7836SJohn.Forte@Sun.COM 					return (FPCFGA_OK);
1319*7836SJohn.Forte@Sun.COM 				}
1320*7836SJohn.Forte@Sun.COM 			}
1321*7836SJohn.Forte@Sun.COM 		    } else {
1322*7836SJohn.Forte@Sun.COM 			/*
1323*7836SJohn.Forte@Sun.COM 			 * strip off the /dev/cfg/ portion of the
1324*7836SJohn.Forte@Sun.COM 			 * OSDeviceName
1325*7836SJohn.Forte@Sun.COM 			 * make sure that the OSDeviceName is at least
1326*7836SJohn.Forte@Sun.COM 			 * strlen("/dev/cfg") + 1 + 1 long.
1327*7836SJohn.Forte@Sun.COM 			 *	first 1 is for the / after /dev/cfg
1328*7836SJohn.Forte@Sun.COM 			 *	second 1 is to make sure there is somthing
1329*7836SJohn.Forte@Sun.COM 			 *	after
1330*7836SJohn.Forte@Sun.COM 			 */
1331*7836SJohn.Forte@Sun.COM 			if (strlen(portAttrs.OSDeviceName) <
1332*7836SJohn.Forte@Sun.COM 			    (strlen(CFGA_DEV_DIR) + 1 + 1))
1333*7836SJohn.Forte@Sun.COM 				continue;
1334*7836SJohn.Forte@Sun.COM 			cfg_ptr = portAttrs.OSDeviceName +
1335*7836SJohn.Forte@Sun.COM 			    strlen(CFGA_DEV_DIR) + 1;
1336*7836SJohn.Forte@Sun.COM 			if (logical_apid == NULL) {
1337*7836SJohn.Forte@Sun.COM 				/* get the /dev/cfg link from the portPath */
1338*7836SJohn.Forte@Sun.COM 				if (make_xport_logid(portPath, &logical_apid,
1339*7836SJohn.Forte@Sun.COM 					    &l_errno) != FPCFGA_OK) {
1340*7836SJohn.Forte@Sun.COM 					cfga_err(errstring, l_errno,
1341*7836SJohn.Forte@Sun.COM 					    ERR_LIST, 0);
1342*7836SJohn.Forte@Sun.COM 					HBA_FreeLibrary();
1343*7836SJohn.Forte@Sun.COM 					return (FPCFGA_LIB_ERR);
1344*7836SJohn.Forte@Sun.COM 				}
1345*7836SJohn.Forte@Sun.COM 			}
1346*7836SJohn.Forte@Sun.COM 			/* compare logical ap_id */
1347*7836SJohn.Forte@Sun.COM 			if (strcmp(logical_apid, cfg_ptr) == 0) {
1348*7836SJohn.Forte@Sun.COM 				if (matchingHandle)
1349*7836SJohn.Forte@Sun.COM 					*matchingHandle = handle;
1350*7836SJohn.Forte@Sun.COM 				if (matchingPortIndex)
1351*7836SJohn.Forte@Sun.COM 					*matchingPortIndex = portIndex;
1352*7836SJohn.Forte@Sun.COM 				if (matchingPortAttrs)
1353*7836SJohn.Forte@Sun.COM 					*matchingPortAttrs = portAttrs;
1354*7836SJohn.Forte@Sun.COM 				S_FREE(logical_apid);
1355*7836SJohn.Forte@Sun.COM 				return (FPCFGA_OK);
1356*7836SJohn.Forte@Sun.COM 			}
1357*7836SJohn.Forte@Sun.COM 		    }
1358*7836SJohn.Forte@Sun.COM 		}
1359*7836SJohn.Forte@Sun.COM 		if (logical_apid != NULL)
1360*7836SJohn.Forte@Sun.COM 			S_FREE(logical_apid);
1361*7836SJohn.Forte@Sun.COM 	    } while ((status == HBA_STATUS_ERROR_STALE_DATA) &&
1362*7836SJohn.Forte@Sun.COM 		(retry++ < HBA_MAX_RETRIES));
1363*7836SJohn.Forte@Sun.COM 
1364*7836SJohn.Forte@Sun.COM 	    HBA_CloseAdapter(handle);
1365*7836SJohn.Forte@Sun.COM 	}
1366*7836SJohn.Forte@Sun.COM 	free(logical_apid);
1367*7836SJohn.Forte@Sun.COM 
1368*7836SJohn.Forte@Sun.COM 	/* Got here. No mathcing adatper port found. */
1369*7836SJohn.Forte@Sun.COM 	cfga_err(errstring, 0, ERR_MATCHING_HBA_PORT, 0);
1370*7836SJohn.Forte@Sun.COM 	HBA_FreeLibrary();
1371*7836SJohn.Forte@Sun.COM 	return (FPCFGA_LIB_ERR);
1372*7836SJohn.Forte@Sun.COM }
1373