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