xref: /illumos-gate/usr/src/lib/cfgadm_plugins/ib/common/cfga_ib.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include "cfga_ib.h"
30 
31 /*
32  * cfga_ib.c:
33  *	All cfgadm entry points that are defined in the config_admin(3X)
34  *	needed for InfiniBand support are described here. These cfgadm
35  *	interfaces issue ioctl(s) to the IB nexus driver. Attachment points
36  *	supported are - IOC, VPPA, Port, HCA_SVC and Pseudo dynamic ap_ids,
37  *	the HCA static ap_id, and the IB static ap_id.
38  *
39  *	Given InfiniBand bus is fabric based, #of dynamic ap_ids present are
40  *	unknown at any given point of time. Hence this plugin uses a
41  *	packed nvlist data structure to hold ap_id related information.
42  *	The IB nexus driver allocates the nvlist data in the kernel
43  *	and this plugin processes the data (it is freed by IB nexus driver).
44  */
45 
46 
47 /* function prototypes */
48 static int		ib_get_link(di_devlink_t, void *);
49 static icfga_ret_t	ib_physpath_to_devlink(char *, char **, int *);
50 static const char	*ib_get_msg(uint_t, msgcvt_t *, uint_t);
51 static void		ib_set_msg(char **, ...);
52 static cfga_err_t	ib_err_msg(char **, cfga_ib_ret_t, const char *, int);
53 static int		ib_verify_valid_apid(const char *);
54 static cfga_ib_ret_t	ib_verify_params(const char *, const char *, char **);
55 static void		ib_cleanup_after_devctl_cmd(devctl_hdl_t, nvlist_t *);
56 static cfga_ib_ret_t	ib_setup_for_devctl_cmd(char *, boolean_t,
57 			    devctl_hdl_t *, nvlist_t **);
58 static cfga_ib_ret_t	ib_device_configured(devctl_hdl_t, nvlist_t *,
59 			    ap_rstate_t *);
60 static cfga_ib_ret_t	ib_device_connected(devctl_hdl_t, nvlist_t *,
61 			    ap_ostate_t *);
62 static cfga_ib_ret_t	ib_do_control_ioctl(char *, uint_t, uint_t, uint_t,
63 			    void **, size_t *);
64 cfga_err_t		cfga_change_state(cfga_cmd_t, const char *,
65 			    const char *, struct cfga_confirm *,
66 			    struct cfga_msg *, char **, cfga_flags_t);
67 cfga_err_t		cfga_private_func(const char *, const char *,
68 			    const char *, struct cfga_confirm *,
69 			    struct cfga_msg *, char **, cfga_flags_t);
70 cfga_err_t		cfga_test(const char *, const char *, struct cfga_msg *,
71 			    char **, cfga_flags_t);
72 static cfga_ib_ret_t	ib_fill_static_apids(char *, cfga_list_data_t *);
73 cfga_err_t		cfga_list_ext(const char *, cfga_list_data_t **, int *,
74 			    const char *, const char *, char **, cfga_flags_t);
75 void			cfga_msg(struct cfga_msg *, const char *);
76 cfga_err_t		cfga_help(struct cfga_msg *, const char *,
77 			    cfga_flags_t);
78 static int		ib_confirm(struct cfga_confirm *, char *);
79 static char 		*ib_get_devicepath(const char *);
80 
81 
82 /* External function prototypes */
83 extern cfga_ib_ret_t	ib_rcm_offline(const char *, char **, char *,
84 			    cfga_flags_t);
85 extern cfga_ib_ret_t	ib_rcm_online(const char *, char **, char *,
86 			    cfga_flags_t);
87 extern cfga_ib_ret_t	ib_rcm_remove(const char *, char **, char *,
88 			    cfga_flags_t);
89 extern int		ib_add_service(char **);
90 extern int		ib_delete_service(char **);
91 extern int		ib_list_services(struct cfga_msg *, char **);
92 
93 
94 /* Globals */
95 int		cfga_version = CFGA_HSL_V2;	/* Set the version number for */
96 						/* the cfgadm library's use. */
97 
98 static char	*ib_help[] = {	/* Help messages */
99 	NULL,
100 	/* CFGA_IB_HELP_HEADER */	"IB specific commands:\n",
101 	/* CFGA_IB_HELP_CONFIG */	"cfgadm -c [configure|unconfigure] "
102 	    "ap_id [ap_id...]\n",
103 	/* CFGA_IB_HELP_LIST */		"cfgadm -x list_clients hca_ap_id "
104 	    "[hca_ap_id...]\n",
105 	/* CFGA_IB_HELP_UPD_PKEY */	"cfgadm -x update_pkey_tbls ib\n",
106 	/* CFGA_IB_HELP_CONF_FILE1 */	"cfgadm -o comm=[port|vppa|hca-svc],"
107 	    "service=<name> -x [add_service|delete_service] ib\n",
108 	/* CFGA_IB_HELP_CONF_FILE2 */	"cfgadm -x list_services ib\n",
109 	/* CFGA_IB_HELP_UPD_IOC_CONF */ "cfgadm -x update_ioc_config "
110 	    "[ib | ioc_apid]\n",
111 	/* CFGA_IB_HELP_UNCFG_CLNTS */	"cfgadm -x unconfig_clients hca_ap_id "
112 	    "[hca_ap_id...]\n",
113 	/* CFGA_IB_HELP_UNKNOWN */	"\tunknown command or option: ",
114 	NULL
115 };
116 
117 static msgcvt_t	ib_error_msgs[] = {	/* Error messages */
118 	/* CFGA_IB_OK */		{ CVT, CFGA_OK, "ok" },
119 	/* CFGA_IB_UNKNOWN */		{ CVT, CFGA_LIB_ERROR,
120 	    "Unknown message; internal error " },
121 	/* CFGA_IB_INTERNAL_ERR */	{ CVT, CFGA_LIB_ERROR,
122 	    "Internal error " },
123 	/* CFGA_IB_INVAL_ARG_ERR */	{ CVT, CFGA_LIB_ERROR,
124 	    "Invalid input args " },
125 	/* CFGA_IB_OPTIONS_ERR */	{ CVT, CFGA_ERROR,
126 	    "Hardware specific options not supported " },
127 	/* CFGA_IB_AP_ERR */		{ CVT, CFGA_APID_NOEXIST, "" },
128 	/* CFGA_IB_DEVCTL_ERR */	{ CVT, CFGA_LIB_ERROR,
129 	    "Cannot issue devctl to " },
130 	/* CFGA_IB_NOT_CONNECTED */	{ CVT, CFGA_INSUFFICENT_CONDITION,
131 	    "No device connected to " },
132 	/* CFGA_IB_NOT_CONFIGURED */	{ CVT, CFGA_INSUFFICENT_CONDITION,
133 	    "No device configured to " },
134 	/* CFGA_IB_ALREADY_CONNECTED */	{ CVT, CFGA_INSUFFICENT_CONDITION,
135 	    "already connected; cannot connect again " },
136 	/* CFGA_IB_ALREADY_CONFIGURED */ { CVT, CFGA_INSUFFICENT_CONDITION,
137 	    "already configured " },
138 	/* CFGA_IB_CONFIG_OP_ERR */	{ CVT, CFGA_ERROR,
139 	    "configure operation failed " },
140 	/* CFGA_IB_UNCONFIG_OP_ERR */	{ CVT, CFGA_ERROR,
141 	    "unconfigure operation failed " },
142 	/* CFGA_IB_OPEN_ERR */		{ CVT, CFGA_LIB_ERROR, "Cannot open " },
143 	/* CFGA_IB_IOCTL_ERR */		{ CVT, CFGA_LIB_ERROR,
144 	    "Driver ioctl failed " },
145 	/* CFGA_IB_BUSY_ERR */		{ CVT, CFGA_SYSTEM_BUSY, " " },
146 	/* CFGA_IB_ALLOC_FAIL */	{ CVT, CFGA_LIB_ERROR,
147 	    "Memory allocation failure " },
148 	/* CFGA_IB_OPNOTSUPP */		{ CVT, CFGA_OPNOTSUPP,
149 	    "Operation not supported " },
150 	/* CFGA_IB_INVAL_APID_ERR */	{ CVT, CFGA_LIB_ERROR,
151 	    "Invalid ap_id supplied " },
152 	/* CFGA_IB_DEVLINK_ERR */	{ CVT, CFGA_LIB_ERROR,
153 	    "Could not find /dev/cfg link for " },
154 	/* CFGA_IB_PRIV_ERR */		{ CVT, CFGA_PRIV, " " },
155 	/* CFGA_IB_NVLIST_ERR */	{ CVT, CFGA_ERROR,
156 	    "Internal error (nvlist) " },
157 	/* CFGA_IB_HCA_LIST_ERR */	{ CVT, CFGA_ERROR,
158 	    "Listing HCA's clients failed " },
159 	/* CFGA_IB_HCA_UNCONFIG_ERR */	{ CVT, CFGA_ERROR,
160 	    "Unconfiguring HCA's clients failed " },
161 	/* CFGA_IB_UPD_PKEY_TBLS_ERR */	{ CVT, CFGA_ERROR,
162 	    "Updating P_Key tables failed " },
163 	/* CFGA_IB_RCM_HANDLE_ERR */	{ CVT, CFGA_ERROR,
164 	    "Opening ib.conf file failed " },
165 	/* CFGA_IB_LOCK_FILE_ERR */	{ CVT, CFGA_LIB_ERROR,
166 	    "Locking ib.conf file failed " },
167 	/* CFGA_IB_UNLOCK_FILE_ERR */	{ CVT, CFGA_LIB_ERROR,
168 	    "Unlocking ib.conf file failed " },
169 	/* CFGA_IB_COMM_INVAL_ERR */	{ CVT, CFGA_INVAL,
170 	    "Communication type incorrectly specified " },
171 	/* CFGA_IB_SVC_INVAL_ERR */	{ CVT, CFGA_INVAL,
172 	    "Service name incorrectly specified " },
173 	/* CFGA_IB_SVC_LEN_ERR_ERR */	{ CVT, CFGA_INVAL,
174 	    "Service name len should be <= to 4, " },
175 	/* CFGA_IB_SVC_EXISTS_ERR */	{ CVT, CFGA_INVAL, " "},
176 	/* CFGA_IB_SVC_NO_EXIST_ERR */	{ CVT, CFGA_INVAL, " " },
177 	/* CFGA_IB_UCFG_CLNTS_ERR */	{ CVT, CFGA_INVAL,
178 	    "unconfig_clients failed for HCA " },
179 	/* CFGA_IB_INVALID_OP_ERR */	{ CVT, CFGA_OPNOTSUPP, "on " },
180 	/* CFGA_IB_RCM_HANDLE */	{ CVT, CFGA_ERROR,
181 	    "cannot get RCM handle "},
182 	/* CFGA_IB_RCM_ONLINE_ERR */	{ CVT, CFGA_SYSTEM_BUSY,
183 	    "failed to online: "},
184 	/* CFGA_IB_RCM_OFFLINE_ERR */	{ CVT, CFGA_SYSTEM_BUSY,
185 	    "failed to offline: "}
186 };
187 
188 /*
189  * these are the only valid sub-options for services.
190  */
191 static char		*ib_service_subopts[] = {
192 				"comm",
193 				"service",
194 				NULL
195 			};
196 
197 /* Communication Service name : "port" or "vppa" or "hca-svc" */
198 static char		*comm_name = NULL;
199 
200 char 			*service_name = NULL;	/* service name */
201 ib_service_type_t	service_type = IB_NONE;	/* service type */
202 
203 
204 /* ========================================================================= */
205 /*
206  * The next two funcs are imported from cfgadm_scsi.
207  * ib_physpath_to_devlink is the only func directly used by cfgadm_ib.
208  * ib_get_link supports it.
209  */
210 
211 /*
212  * Function:
213  *	ib_get_link
214  * Input:
215  *	devlink		- devlink for the device path
216  *	arg		- argument passed to this "walker" function
217  * Output:
218  *	NONE
219  * Returns:
220  *	Continue "walking" or not
221  * Description:
222  *	Routine to search the /dev directory or a subtree of /dev.
223  */
224 static int
225 ib_get_link(di_devlink_t devlink, void *arg)
226 {
227 	walk_link_t	*larg = (walk_link_t *)arg;
228 
229 	/*
230 	 * When path is specified, it's the node path without minor
231 	 * name. Therefore, the ../.. prefixes needs to be stripped.
232 	 */
233 	if (larg->path) {
234 		char *content = (char *)di_devlink_content(devlink);
235 		char *start = strstr(content, "/devices/");
236 
237 		/* line content must have minor node */
238 		if (start == NULL ||
239 		    strncmp(start, larg->path, larg->len) != 0 ||
240 		    start[larg->len] != ':') {
241 			return (DI_WALK_CONTINUE);
242 		}
243 	}
244 
245 	*(larg->linkpp) = strdup(di_devlink_path(devlink));
246 	return (DI_WALK_TERMINATE);
247 }
248 
249 
250 /*
251  * Function:
252  *	ib_physpath_to_devlink
253  * Input:
254  *	node_path	- Physical path of the ap_id node
255  * Output:
256  *	logpp		- Logical path to the ap_id node
257  *	l_errnop	- "errno"
258  * Returns:
259  *	ICFGA_OK if everything was fine; otherwise an error with
260  *	l_errnop set.
261  * Description:
262  *	Given a physical path to an ap_id ensure that it exists
263  */
264 /* ARGSUSED */
265 static icfga_ret_t
266 ib_physpath_to_devlink(char *node_path, char **logpp, int *l_errnop)
267 {
268 	char			*minor_path;
269 	walk_link_t		larg;
270 	di_devlink_handle_t	hdl;
271 
272 	if ((hdl = di_devlink_init(NULL, 0)) == NULL) {
273 		*l_errnop = errno;
274 		return (ICFGA_LIB_ERR);
275 	}
276 
277 	*logpp = NULL;
278 	larg.linkpp = logpp;
279 	minor_path = (char *)node_path + strlen("/devices");
280 	larg.path = NULL;
281 	larg.len = 0;
282 
283 	(void) di_devlink_walk(hdl, "^cfg/", minor_path, DI_PRIMARY_LINK,
284 	    (void *)&larg, ib_get_link);
285 
286 	di_devlink_fini(&hdl);
287 
288 	if (*logpp == NULL) {
289 		*l_errnop = errno;
290 		return (ICFGA_LIB_ERR);
291 	}
292 
293 	return (ICFGA_OK);
294 }
295 
296 
297 /* ========================================================================= */
298 /* Utilities */
299 
300 /*
301  * Function:
302  *	ib_get_msg
303  * Input:
304  *	msg_index	- Index into the message table
305  *	msg_tbl		- the message table
306  *	tbl_size	- size of the message table
307  * Output:
308  *	NONE
309  * Returns:
310  *	Message string if valid, otherwise an error
311  * Description:
312  *	Given the index into a table (msgcvt_t) of messages,
313  *	get the message string, converting it to the proper
314  *	locale if necessary.
315  *
316  *	NOTE: See cfga_ib.h
317  */
318 static const char *
319 ib_get_msg(uint_t msg_index, msgcvt_t *msg_tbl, uint_t tbl_size)
320 {
321 	if (msg_index >= tbl_size) {
322 		DPRINTF("get_error_msg: bad error msg index: %d\n", msg_index);
323 		msg_index = CFGA_IB_UNKNOWN;
324 	}
325 
326 	return ((msg_tbl[msg_index].intl) ?
327 	    dgettext(TEXT_DOMAIN, msg_tbl[msg_index].msgstr) :
328 	    msg_tbl[msg_index].msgstr);
329 }
330 
331 
332 /*
333  * Function:
334  *	ib_set_msg
335  * Input:
336  *	NONE
337  * Output:
338  *	ret_str	- Returned "message" string.
339  * Returns:
340  *	NONE
341  * Description:
342  *	Allocates and creates a message string (in *ret_str),
343  *	by concatenating all the (char *) args together, in order.
344  *	Last arg MUST be NULL.
345  */
346 static void
347 ib_set_msg(char **ret_str, ...)
348 {
349 	char	*str;
350 	size_t	total_len, ret_str_len;
351 	va_list	valist;
352 
353 	va_start(valist, ret_str);
354 
355 	total_len = (*ret_str == NULL) ? 0 : strlen(*ret_str);
356 
357 	while ((str = va_arg(valist, char *)) != NULL) {
358 		size_t	len = strlen(str);
359 		char	*old_str = *ret_str;
360 
361 		ret_str_len = total_len + len + 1;
362 		*ret_str = (char *)realloc(*ret_str, ret_str_len);
363 		if (*ret_str == NULL) {
364 			free(old_str);
365 			DPRINTF("ib_set_msg: realloc failed.\n");
366 			va_end(valist);
367 			return;
368 		}
369 
370 		(void) strlcpy(*ret_str + total_len, str, ret_str_len);
371 		total_len += len;
372 	}
373 
374 	va_end(valist);
375 }
376 
377 
378 /*
379  * Function:
380  *	ib_err_msg
381  * Input:
382  *	ap_id		- The attachment point of an IB fabric
383  * Output:
384  *	errstring	- Fill in the error msg string
385  *	l_errno		- The "errno" to be filled in.
386  * Returns:
387  *	CFGA_IB_OK if we are able to fill in error msg;
388  *	otherwise emit an error.
389  * Description:
390  *	Error message handling.
391  *
392  *	For the rv passed in, looks up the corresponding error message
393  *	string(s), internationalized it if necessary, and concatenates
394  *	it into a new memory buffer, and points *errstring to it.
395  *	Note not all "rv"s will result in an error message return, as
396  *	not all error conditions warrant a IB-specific error message.
397  *
398  *	Some messages may display ap_id or errno, which is why they are
399  *	passed in.
400  */
401 static cfga_err_t
402 ib_err_msg(char **errstring, cfga_ib_ret_t rv, const char *ap_id, int l_errno)
403 {
404 	char *errno_str;
405 
406 	if (errstring == NULL) {
407 		return (ib_error_msgs[rv].cfga_err);
408 	}
409 
410 	/* Generate the appropriate IB-specific error message(s) (if any). */
411 	switch (rv) {
412 	case CFGA_IB_OK:	/* Special case - do nothing.  */
413 		break;
414 	case CFGA_IB_AP_ERR:
415 	case CFGA_IB_UNKNOWN:
416 	case CFGA_IB_INTERNAL_ERR:
417 	case CFGA_IB_OPTIONS_ERR:
418 	case CFGA_IB_ALLOC_FAIL:
419 		/* These messages require no additional strings passed. */
420 		ib_set_msg(errstring, ERR_STR(rv), NULL);
421 		break;
422 	case CFGA_IB_NOT_CONNECTED:
423 	case CFGA_IB_NOT_CONFIGURED:
424 	case CFGA_IB_ALREADY_CONNECTED:
425 	case CFGA_IB_ALREADY_CONFIGURED:
426 	case CFGA_IB_CONFIG_OP_ERR:
427 	case CFGA_IB_UNCONFIG_OP_ERR:
428 	case CFGA_IB_BUSY_ERR:
429 	case CFGA_IB_DEVLINK_ERR:
430 	case CFGA_IB_RCM_HANDLE_ERR:
431 	case CFGA_IB_RCM_ONLINE_ERR:
432 	case CFGA_IB_RCM_OFFLINE_ERR:
433 	case CFGA_IB_DEVCTL_ERR:
434 	case CFGA_IB_COMM_INVAL_ERR:
435 	case CFGA_IB_SVC_INVAL_ERR:
436 	case CFGA_IB_SVC_LEN_ERR:
437 	case CFGA_IB_SVC_EXISTS_ERR:
438 	case CFGA_IB_SVC_NO_EXIST_ERR:
439 	case CFGA_IB_LOCK_FILE_ERR:
440 	case CFGA_IB_CONFIG_FILE_ERR:
441 	case CFGA_IB_UNLOCK_FILE_ERR:
442 	case CFGA_IB_UCFG_CLNTS_ERR:
443 	case CFGA_IB_INVALID_OP_ERR:
444 		/* These messages also print ap_id.  */
445 		ib_set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "", NULL);
446 		break;
447 	case CFGA_IB_IOCTL_ERR:	/* These messages also print errno.  */
448 	case CFGA_IB_NVLIST_ERR:
449 		errno_str = l_errno ? strerror(l_errno) : "";
450 		ib_set_msg(errstring, ERR_STR(rv), errno_str,
451 		    l_errno ? "\n" : "", NULL);
452 		break;
453 	case CFGA_IB_OPEN_ERR: /* This messages also prints apid and errno.  */
454 	case CFGA_IB_PRIV_ERR:
455 	case CFGA_IB_HCA_LIST_ERR:
456 	case CFGA_IB_OPNOTSUPP:
457 	case CFGA_IB_INVAL_ARG_ERR:
458 	case CFGA_IB_INVAL_APID_ERR:
459 	case CFGA_IB_HCA_UNCONFIG_ERR:
460 	case CFGA_IB_UPD_PKEY_TBLS_ERR:
461 		errno_str = l_errno ? strerror(l_errno) : "";
462 		ib_set_msg(errstring, ERR_STR(rv), "ap_id: ", ap_id, "\n",
463 		    errno_str, l_errno ? "\n" : "", NULL);
464 		break;
465 	default:
466 		DPRINTF("ib_err_msg: Unrecognized message index: %d\n", rv);
467 		ib_set_msg(errstring, ERR_STR(CFGA_IB_INTERNAL_ERR), NULL);
468 	}
469 
470 	/*
471 	 * Determine the proper error code to send back to the cfgadm library.
472 	 */
473 	return (ib_error_msgs[rv].cfga_err);
474 }
475 
476 
477 /*
478  * Function:
479  *	ib_verify_valid_apid
480  * Input:
481  *	ap_id		- The attachment point of an IB fabric
482  * Output:
483  *	NONE
484  * Returns:
485  *	0 if ap_id is valid; otherwise -1
486  * Description:
487  *	Check if ap_id is valid or not.
488  *	Ensure the ap_id passed is in the correct (physical ap_id) form:
489  *	path/device:xx[.xx]+
490  *	where xx is a one or two-digit number.
491  *
492  *	Note the library always calls the plugin with a physical ap_id.
493  *	Called by ib_verify_params().
494  */
495 static int
496 ib_verify_valid_apid(const char *ap_id)
497 {
498 	char	*l_ap_id;
499 
500 	if (ap_id == NULL) {
501 		return (-1);
502 	}
503 
504 	l_ap_id = strchr(ap_id, *MINOR_SEP);
505 	l_ap_id++;
506 
507 	/* fabric apids */
508 	if (strstr((char *)ap_id, IBNEX_FABRIC) != NULL) {
509 		DPRINTF("ib_valid_apid: l_apid = %s\n", l_ap_id);
510 		/* if the ap_id is "ib::" then report an error */
511 		if ((strlen(l_ap_id) == strlen(IBNEX_FABRIC) + 1) ||
512 		    (strlen(l_ap_id) == strlen(IBNEX_FABRIC) + 2)) {
513 			return (-1);
514 		}
515 
516 		if (strstr(l_ap_id, "...") != NULL) {
517 			return (-1);
518 		}
519 
520 	} else {	/* HCA ap_ids */
521 		/* ap_id has 1..2 or more than 2 dots */
522 		if (strstr(l_ap_id, "..") != NULL) {
523 			return (-1);
524 		}
525 	}
526 
527 	return (0);
528 }
529 
530 
531 /*
532  * Function:
533  *	ib_verify_params
534  * Input:
535  *	ap_id		- The attachment point of an IB fabric
536  *	options		- command options passed by the cfgadm(1M)
537  *	errstring	- This contains error msg if command fails
538  * Output:
539  *	NONE
540  * Returns:
541  *	CFGA_IB_OK if parameters are valid; otherwise emit an error.
542  * Description:
543  *	Check if "options" and "errstring" are valid and if ap_id is
544  *	valid or not.
545  */
546 static cfga_ib_ret_t
547 ib_verify_params(const char *ap_id, const char *options, char **errstring)
548 {
549 	if (errstring != NULL) {
550 		*errstring = NULL;
551 	}
552 
553 	if (options != NULL) {
554 		DPRINTF("ib_verify_params: h/w-specific options not "
555 		    "supported.\n");
556 		return (CFGA_IB_OPTIONS_ERR);
557 	}
558 
559 	if (ib_verify_valid_apid(ap_id) != 0) {
560 		DPRINTF("ib_verify_params: not an IB ap_id.\n");
561 		return (CFGA_IB_AP_ERR);
562 	}
563 	return (CFGA_IB_OK);
564 }
565 
566 
567 /*
568  * Function:
569  *	ib_cleanup_after_devctl_cmd
570  * Input:
571  *	devctl_hdl	- Handler to devctl
572  *	user_nvlistp	- Name-value-pair list pointer
573  * Output:
574  *	NONE
575  * Returns:
576  *	NONE
577  * Description:
578  *	Cleanup an initialization/setup done in the next function i.e.
579  *	ib_setup_for_devctl_cmd().
580  */
581 static void
582 ib_cleanup_after_devctl_cmd(devctl_hdl_t devctl_hdl, nvlist_t *user_nvlist)
583 {
584 	if (user_nvlist != NULL) {
585 		nvlist_free(user_nvlist);
586 	}
587 
588 	if (devctl_hdl != NULL) {
589 		devctl_release(devctl_hdl);
590 	}
591 }
592 
593 
594 /*
595  * Function:
596  *	ib_setup_for_devctl_cmd
597  * Input:
598  *	ap_id		- Attachment point for the IB device in question
599  *	use_static_ap_id - Whether to use static ap_id or not flag
600  * Output:
601  *	devctl_hdl	- Handler to devctl
602  *	user_nvlistp	- Name-value-pair list pointer
603  * Returns:
604  *	CFGA_IB_OK if it succeeds or an appropriate error.
605  * Description:
606  *	For any IB device  that is doing a cfgadm operation this function
607  *	sets up a devctl_hdl and allocates a nvlist_t. The devctl_hdl
608  *	is acquired using libdevice APIs. The nvlist_t is filled up with
609  *	the ap_id (as a string). This nvlist_t is looked up in the kernel
610  *	to figure out which ap_id we are currently dealing with.
611  *
612  *	"use_static_ap_id" flag tells if one should do a devctl_ap_acquire
613  *	with IB_STATIC_APID or not. NOTE: We need an actual file-system
614  *	vnode to do a devctl_ap_acquire.
615  *
616  *	NOTE: always call ib_cleanup_after_devctl_cmd() after this function.
617  */
618 static cfga_ib_ret_t
619 ib_setup_for_devctl_cmd(char *ap_id, boolean_t use_static_ap_id,
620     devctl_hdl_t *devctl_hdl, nvlist_t **user_nvlistp)
621 {
622 	char	*apid = (use_static_ap_id == B_TRUE) ? IB_STATIC_APID : ap_id;
623 
624 	/* Get a handle to the ap */
625 	if ((*devctl_hdl = devctl_ap_acquire(apid, NULL)) == NULL) {
626 		DPRINTF("ib_setup_for_devctl_cmd: devctl_ap_acquire "
627 		    "errno: %d\n", errno);
628 		ib_cleanup_after_devctl_cmd(*devctl_hdl, *user_nvlistp);
629 		return (CFGA_IB_DEVCTL_ERR);
630 	}
631 
632 	/* Set up to pass dynamic ap_id down to driver */
633 	if (nvlist_alloc(user_nvlistp, NV_UNIQUE_NAME_TYPE, NULL) != 0) {
634 		DPRINTF("ib_setup_for_devctl: nvlist_alloc errno: %d\n", errno);
635 		*user_nvlistp = NULL;	/* Prevent possible incorrect free in */
636 					/* ib_cleanup_after_devctl_cmd */
637 		ib_cleanup_after_devctl_cmd(*devctl_hdl, *user_nvlistp);
638 		return (CFGA_IB_NVLIST_ERR);
639 	}
640 
641 	/* create a "string" entry */
642 	if (nvlist_add_string(*user_nvlistp, IB_APID, ap_id) == -1) {
643 		DPRINTF("ib_setup_for_devctl_cmd: nvlist_add_string failed. "
644 		    "errno: %d\n", errno);
645 		ib_cleanup_after_devctl_cmd(*devctl_hdl, *user_nvlistp);
646 		return (CFGA_IB_NVLIST_ERR);
647 	}
648 
649 	return (CFGA_IB_OK);
650 }
651 
652 
653 /*
654  * Function:
655  *	ib_device_configured
656  * Input:
657  *	hdl		- Handler to devctl
658  *	nvl		- Name-value-pair list pointer
659  * Output:
660  *	rstate		- Receptacle state for the apid
661  * Returns:
662  *	CFGA_IB_OK if it succeeds or an appropriate error.
663  * Description:
664  *	Checks if there is a device actually configured to the ap? If so,
665  *	issues a "devctl" to get the Receptacle state for that ap_id.
666  *	If the ap_id is already configured it returns CFGA_IB_OK.
667  *	Otherwise it returns a failure.
668  */
669 static cfga_ib_ret_t
670 ib_device_configured(devctl_hdl_t hdl, nvlist_t *nvl, ap_rstate_t *rstate)
671 {
672 	cfga_ib_ret_t		rv;
673 	devctl_ap_state_t	devctl_ap_state;
674 
675 	/* get ap_id's "devctl_ap_state" first */
676 	if (devctl_ap_getstate(hdl, nvl, &devctl_ap_state) == -1) {
677 		DPRINTF("ib_device_configured failed, errno: %d\n", errno);
678 		return (CFGA_IB_DEVCTL_ERR);
679 	}
680 
681 	rv = CFGA_IB_ALREADY_CONFIGURED;
682 	*rstate = devctl_ap_state.ap_rstate;
683 	if (devctl_ap_state.ap_ostate != AP_OSTATE_CONFIGURED) {
684 		return (CFGA_IB_NOT_CONFIGURED);
685 	}
686 
687 	return (rv);
688 }
689 
690 
691 /*
692  * Function:
693  *	ib_device_connected
694  * Input:
695  *	hdl		- Handler to devctl
696  *	nvl		- Name-value-pair list pointer
697  * Output:
698  *	ostate		- Occupant state for the apid
699  * Returns:
700  *	CFGA_IB_OK if it succeeds or an appropriate error.
701  * Description:
702  *	Checks if there is a device actually connected to the ap? If so,
703  *	issues a "devctl" to get the Occupant state for that ap_id.
704  *	If the ap_id is already connected it returns CFGA_IB_OK.
705  *	Otherwise it returns a failure.
706  */
707 static cfga_ib_ret_t
708 ib_device_connected(devctl_hdl_t hdl, nvlist_t *list, ap_ostate_t *ostate)
709 {
710 	cfga_ib_ret_t		rv = CFGA_IB_ALREADY_CONNECTED;
711 	devctl_ap_state_t	devctl_ap_state;
712 
713 	if (devctl_ap_getstate(hdl, list, &devctl_ap_state) == -1) {
714 		DPRINTF("ib_device_connected failed, errno: %d\n", errno);
715 		return (CFGA_IB_DEVCTL_ERR);
716 	}
717 
718 	*ostate =  devctl_ap_state.ap_ostate;
719 	if (devctl_ap_state.ap_rstate != AP_RSTATE_CONNECTED) {
720 		return (CFGA_IB_NOT_CONNECTED);
721 	}
722 
723 	return (rv);
724 }
725 
726 
727 /*
728  * Function:
729  *	ib_do_control_ioctl
730  * Input:
731  *	ap_id		- The dynamic attachment point of an IB device
732  *	sub_cmd1	- Sub Command 1 to DEVCTL_AP_CONTROL devctl
733  *	sub_cmd2	- Sub Command 2 to DEVCTL_AP_CONTROL devctl
734  *				(Mandatory except for IBNEX_NUM_HCA_NODES,
735  *				IBNEX_NUM_DEVICE_NODES,
736  *				IBNEX_UPDATE_PKEY_TBLS &
737  *				IBNEX_UPDATE_IOC_CONF)
738  *	misc_arg	- optional arguments to DEVCTL_AP_CONTROL devctl
739  * Output:
740  *	descrp		- Buffer containing data back from kernel
741  *	sizep		- Length of the buffer back from kernel
742  * Returns:
743  *	CFGA_IB_OK if it succeeds or an appropriate error.
744  * Description:
745  *	Issues DEVCTL_AP_CONTROL devctl with sub_cmd1 first which actually
746  *	queries the IBNEX module in the kernel on the size of the data to
747  *	be returned.
748  *
749  *	Next issues DEVCTL_AP_CONTROL devctl with a buffer of that much
750  *	size and gets the actual data back.
751  *	Passes the data and the size back to caller.
752  */
753 static cfga_ib_ret_t
754 ib_do_control_ioctl(char *ap_id, uint_t sub_cmd1, uint_t sub_cmd2,
755     uint_t misc_arg, void **descrp, size_t *sizep)
756 {
757 	int			fd = -1;
758 	uint32_t		local_size = 0;
759 	cfga_ib_ret_t		rv = CFGA_IB_OK;
760 	struct ibnex_ioctl_data	ioctl_data;
761 
762 	/* try to open the ONLY static ap_id */
763 	if ((fd = open(IB_STATIC_APID, O_RDONLY)) == -1) {
764 		DPRINTF("ib_do_control_ioctl: open failed: "
765 		    "errno = %d\n", errno);
766 		/* Provides a more useful error msg */
767 		rv = (errno == EBUSY) ? CFGA_IB_BUSY_ERR : CFGA_IB_OPEN_ERR;
768 		return (rv);
769 	}
770 
771 	/*
772 	 * Find out first how large a buffer is needed?
773 	 * NOTE: Ioctls only accept/return a 32-bit int for a get_size
774 	 * to avoid 32/64 and BE/LE issues.
775 	 */
776 	ioctl_data.cmd = sub_cmd1;
777 	ioctl_data.misc_arg = (uint_t)misc_arg;
778 	ioctl_data.buf = (caddr_t)&local_size;
779 	ioctl_data.bufsiz = sizeof (local_size);
780 
781 	/* Pass "ap_id" up for all other commands */
782 	if (sub_cmd1 != IBNEX_NUM_DEVICE_NODES &&
783 	    sub_cmd1 != IBNEX_NUM_HCA_NODES &&
784 	    sub_cmd1 != IBNEX_UPDATE_PKEY_TBLS) {
785 		ioctl_data.ap_id = (caddr_t)ap_id;
786 		ioctl_data.ap_id_len = strlen(ap_id);
787 
788 	} else {
789 		ioctl_data.ap_id = NULL;
790 		ioctl_data.ap_id_len = 0;
791 	}
792 
793 	if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
794 		DPRINTF("ib_do_control_ioctl: size ioctl ERR, errno: %d\n",
795 		    errno);
796 		(void) close(fd);
797 		rv = (errno == EBUSY) ? CFGA_IB_BUSY_ERR : CFGA_IB_IOCTL_ERR;
798 		return (rv);
799 	}
800 	*sizep = local_size;
801 
802 	/*
803 	 * Don't do the second ioctl only in these cases
804 	 * (NOTE: the data is returned in the first ioctl itself; if any)
805 	 */
806 	if (sub_cmd1 == IBNEX_NUM_DEVICE_NODES ||
807 	    sub_cmd1 == IBNEX_NUM_HCA_NODES ||
808 	    sub_cmd1 == IBNEX_UPDATE_PKEY_TBLS ||
809 	    sub_cmd1 == IBNEX_UPDATE_IOC_CONF) {
810 		(void) close(fd);
811 		return (rv);
812 	}
813 
814 	if (local_size == 0 || (*descrp = malloc(*sizep)) == NULL) {
815 		DPRINTF("ib_do_control_ioctl: malloc failed\n");
816 		(void) close(fd);
817 		return (CFGA_IB_ALLOC_FAIL);
818 	}
819 
820 	/* Get the data */
821 	ioctl_data.cmd = sub_cmd2;
822 	ioctl_data.buf = (caddr_t)*descrp;
823 	ioctl_data.bufsiz = *sizep;
824 
825 	if (ioctl(fd, DEVCTL_AP_CONTROL, &ioctl_data) != 0) {
826 		DPRINTF("ib_do_control_ioctl: ioctl failed: errno:%d\n", errno);
827 		if (*descrp != NULL) {
828 			free(*descrp);
829 			*descrp = NULL;
830 		}
831 		rv = (errno == EBUSY) ? CFGA_IB_BUSY_ERR : CFGA_IB_IOCTL_ERR;
832 	}
833 
834 	(void) close(fd);
835 	return (rv);
836 }
837 
838 
839 /* ========================================================================== */
840 /* Entry points */
841 
842 /*
843  * Function:
844  *	cfga_change_state
845  * Input:
846  *	state_change_cmd - Argument to the cfgadm -c command
847  *	ap_id		- The attachment point of an IB fabric
848  *	options		- State Change command options passed by the cfgadm(1M)
849  *	confp		- Whether this command requires confirmation?
850  *	msgp		- cfgadm error message for this plugin
851  *	errstring	- This contains error msg if command fails
852  *	flags		- Cfgadm(1m) flags
853  * Output:
854  *	NONE
855  * Returns:
856  *	If the command succeeded perform the cfgadm -c <cmd>;
857  *	otherwise emit an error
858  * Description:
859  *	Do cfgadm -c <cmd>
860  */
861 /*ARGSUSED*/
862 cfga_err_t
863 cfga_change_state(cfga_cmd_t state_change_cmd, const char *ap_id,
864     const char *options, struct cfga_confirm *confp, struct cfga_msg *msgp,
865     char **errstring, cfga_flags_t flags)
866 {
867 	int		ret;
868 	int		len;
869 	char		*msg;
870 	char		*devpath;
871 	nvlist_t	*nvl = NULL;
872 	boolean_t	static_ap_id = B_TRUE;
873 	ap_rstate_t	rstate;
874 	ap_ostate_t	ostate;
875 	devctl_hdl_t	hdl = NULL;
876 	cfga_ib_ret_t	rv = CFGA_IB_OK;
877 
878 	if ((rv = ib_verify_params(ap_id, options, errstring)) != CFGA_IB_OK) {
879 		(void) cfga_help(msgp, options, flags);
880 		return (ib_err_msg(errstring, CFGA_IB_INVAL_APID_ERR,
881 		    ap_id, errno));
882 	}
883 
884 	/*
885 	 * All subcommands which can change state of device require
886 	 * root privileges.
887 	 */
888 	if (geteuid() != 0) {
889 		return (ib_err_msg(errstring, CFGA_IB_PRIV_ERR, ap_id, errno));
890 	}
891 
892 	if (strstr((char *)ap_id, IB_FABRIC_APID_STR) == NULL)
893 		static_ap_id = B_FALSE;
894 
895 	if ((rv = ib_setup_for_devctl_cmd((char *)ap_id, static_ap_id,
896 	    &hdl, &nvl)) != CFGA_IB_OK) {
897 		ib_cleanup_after_devctl_cmd(hdl, nvl);
898 		return (ib_err_msg(errstring, rv, ap_id, errno));
899 	}
900 
901 	switch (state_change_cmd) {
902 	case CFGA_CMD_CONFIGURE:
903 		rv = ib_device_connected(hdl, nvl, &ostate);
904 		if (rv != CFGA_IB_ALREADY_CONNECTED) {
905 			ret = (rv != CFGA_IB_NOT_CONNECTED) ?
906 			    CFGA_IB_CONFIG_OP_ERR : rv;
907 			ib_cleanup_after_devctl_cmd(hdl, nvl);
908 			return (ib_err_msg(errstring, ret, ap_id, errno));
909 		}
910 
911 		if (rv == CFGA_IB_ALREADY_CONNECTED) {
912 			/*
913 			 * special case handling for
914 			 * SLM based cfgadm disconnects
915 			 */
916 			if (ostate == AP_OSTATE_CONFIGURED) {
917 				ib_cleanup_after_devctl_cmd(hdl, nvl);
918 				return (ib_err_msg(errstring,
919 				    CFGA_IB_ALREADY_CONFIGURED, ap_id,
920 				    errno));
921 			}
922 		}
923 
924 
925 		rv = CFGA_IB_OK;	/* Other status don't matter */
926 
927 		len = strlen(IB_CONFIRM0) + strlen(IB_CONFIRM1) +
928 				strlen("Configure") + strlen(ap_id);
929 		if ((msg = (char *)calloc(len + 3, 1)) != NULL) {
930 			(void) snprintf(msg, len + 3, "Configure %s%s\n%s",
931 			    IB_CONFIRM0, ap_id, IB_CONFIRM1);
932 		}
933 
934 		if (!ib_confirm(confp, msg)) {
935 			free(msg);
936 			ib_cleanup_after_devctl_cmd(hdl, nvl);
937 			return (CFGA_NACK);
938 		}
939 		free(msg);
940 
941 		if (devctl_ap_configure(hdl, nvl) != 0) {
942 			DPRINTF("cfga_change_state: devctl_ap_configure "
943 			    "failed. errno: %d\n", errno);
944 			rv = CFGA_IB_CONFIG_OP_ERR;
945 			break;
946 		}
947 
948 		devpath = ib_get_devicepath(ap_id);
949 		if (devpath == NULL) {
950 			int i;
951 
952 			/*
953 			 * try for some time as IB hotplug thread
954 			 * takes a while to create the path
955 			 * and then eventually give up
956 			 */
957 			for (i = 0;
958 			    i < IB_RETRY_DEVPATH && (devpath == NULL); i++) {
959 				sleep(IB_MAX_DEVPATH_DELAY);
960 				devpath = ib_get_devicepath(ap_id);
961 			}
962 
963 			if (devpath == NULL) {
964 				DPRINTF("cfga_change_state: get device "
965 				    "path failed i = %d\n", i);
966 				rv = CFGA_IB_CONFIG_OP_ERR;
967 				break;
968 			}
969 		}
970 		S_FREE(devpath);
971 		break;
972 
973 	case CFGA_CMD_UNCONFIGURE:
974 		if ((rv = ib_device_connected(hdl, nvl, &ostate)) !=
975 		    CFGA_IB_ALREADY_CONNECTED) {
976 			ib_cleanup_after_devctl_cmd(hdl, nvl);
977 			if (rv == CFGA_IB_DEVCTL_ERR)
978 				rv = CFGA_IB_INVALID_OP_ERR;
979 			return (ib_err_msg(errstring, rv, ap_id, errno));
980 		}
981 
982 		/* check if it is already unconfigured */
983 		if ((rv = ib_device_configured(hdl, nvl, &rstate)) ==
984 		    CFGA_IB_NOT_CONFIGURED) {
985 			ib_cleanup_after_devctl_cmd(hdl, nvl);
986 			return (ib_err_msg(errstring, rv, ap_id, errno));
987 		}
988 
989 		rv = CFGA_IB_OK;	/* Other statuses don't matter */
990 		len = strlen(IB_CONFIRM0) + strlen(IB_CONFIRM1) +
991 				strlen("Unconfigure") + strlen(ap_id);
992 		if ((msg = (char *)calloc(len + 3, 1)) != NULL) {
993 			(void) snprintf(msg, len + 3, "Unconfigure %s%s\n%s",
994 			    IB_CONFIRM0, ap_id, IB_CONFIRM1);
995 		}
996 
997 		if (!ib_confirm(confp, msg)) {
998 			free(msg);
999 			ib_cleanup_after_devctl_cmd(hdl, nvl);
1000 			return (CFGA_NACK);
1001 		}
1002 		free(msg);
1003 
1004 		devpath = ib_get_devicepath(ap_id);
1005 		if (devpath == NULL) {
1006 			DPRINTF("cfga_change_state: get device path failed\n");
1007 			rv = CFGA_IB_UNCONFIG_OP_ERR;
1008 			break;
1009 		}
1010 
1011 		if ((rv = ib_rcm_offline(ap_id, errstring, devpath, flags)) !=
1012 		    CFGA_IB_OK) {
1013 			S_FREE(devpath);
1014 			break;
1015 		}
1016 
1017 		ret = devctl_ap_unconfigure(hdl, nvl);
1018 		if (ret != 0) {
1019 			DPRINTF("cfga_change_state: devctl_ap_unconfigure "
1020 			    "failed with errno: %d\n", errno);
1021 			rv = CFGA_IB_UNCONFIG_OP_ERR;
1022 			if (errno == EBUSY) {
1023 				rv = CFGA_IB_BUSY_ERR;
1024 			}
1025 			(void) ib_rcm_online(ap_id, errstring, devpath, flags);
1026 
1027 		} else {
1028 			(void) ib_rcm_remove(ap_id, errstring, devpath, flags);
1029 		}
1030 
1031 		S_FREE(devpath);
1032 		break;
1033 
1034 	case CFGA_CMD_LOAD:
1035 	case CFGA_CMD_UNLOAD:
1036 	case CFGA_CMD_CONNECT:
1037 	case CFGA_CMD_DISCONNECT:
1038 		(void) cfga_help(msgp, options, flags);
1039 		rv = CFGA_IB_OPNOTSUPP;
1040 		break;
1041 
1042 	case CFGA_CMD_NONE:
1043 	default:
1044 		(void) cfga_help(msgp, options, flags);
1045 		rv = CFGA_IB_INTERNAL_ERR;
1046 	}
1047 
1048 	ib_cleanup_after_devctl_cmd(hdl, nvl);
1049 	return (ib_err_msg(errstring, rv, ap_id, errno));
1050 }
1051 
1052 
1053 /*
1054  * Function:
1055  *	cfga_private_func
1056  * Input:
1057  *	func		- The private function (passed w/ -x option)
1058  *	ap_id		- The attachment point of an IB fabric
1059  *	options		- Private function command options passed
1060  *				by the cfgadm(1M)
1061  *	confp		- Whether this command requires confirmation?
1062  *	msgp		- cfgadm error message for this plugin
1063  *	errstring	- This contains error msg if command fails
1064  *	flags		- Cfgadm(1m) flags
1065  * Output:
1066  *	NONE
1067  * Returns:
1068  *	If the command succeeded perform the 'cfgadm -x <func>'; otherwise
1069  *	return failure.
1070  * Description:
1071  *	Do cfgadm -x <func>
1072  */
1073 /*ARGSUSED*/
1074 cfga_err_t
1075 cfga_private_func(const char *func, const char *ap_id, const char *options,
1076     struct cfga_confirm *confp, struct cfga_msg *msgp, char **errstring,
1077     cfga_flags_t flags)
1078 {
1079 	int		len, ret, count = 0;
1080 	char		*clnt_name = NULL, *alt_hca = NULL;
1081 	char		*clnt_apid = NULL, *clnt_devpath = NULL;
1082 	char		*name, *msg = NULL;
1083 	char		*fab_apid = strstr((char *)ap_id, IBNEX_FABRIC);
1084 	size_t		info_len = 0;
1085 	uchar_t		*info = NULL;
1086 	nvlist_t	*nvl;
1087 	nvpair_t	*nvp = NULL;
1088 	ap_rstate_t	rstate;
1089 	devctl_hdl_t	hdl = NULL;
1090 	cfga_ib_ret_t	rv;
1091 
1092 	if ((rv = ib_verify_params(ap_id, NULL, errstring)) != CFGA_IB_OK) {
1093 		DPRINTF("cfga_private_func: ib_verify_params "
1094 		    "failed with rv: %d\n", rv);
1095 		return (ib_err_msg(errstring, rv, ap_id, errno));
1096 	}
1097 
1098 	if (func == NULL) {
1099 		DPRINTF("cfga_private_func: func is NULL\n");
1100 		return (ib_err_msg(errstring, CFGA_IB_INVAL_ARG_ERR, ap_id,
1101 		    errno));
1102 	}
1103 
1104 	/*
1105 	 * check first if IB static ap_id is "configured" for use
1106 	 */
1107 	if (fab_apid != NULL) {
1108 		if ((rv = ib_setup_for_devctl_cmd(fab_apid, B_TRUE, &hdl,
1109 		    &nvl)) != CFGA_IB_OK) {
1110 			ib_cleanup_after_devctl_cmd(hdl, nvl);
1111 			return (ib_err_msg(errstring, rv, ap_id, errno));
1112 		}
1113 		if ((rv = ib_device_configured(hdl, nvl, &rstate)) ==
1114 		    CFGA_IB_NOT_CONFIGURED) {
1115 			return (ib_err_msg(errstring, rv, ap_id, errno));
1116 		}
1117 		ib_cleanup_after_devctl_cmd(hdl, nvl);
1118 	}
1119 
1120 	rv = CFGA_IB_OK;
1121 	DPRINTF("cfga_private_func: func is %s\n", func);
1122 	if (strcmp(func, IB_LIST_HCA_CLIENTS) == 0) {	/* -x list_clients */
1123 
1124 		/* only supported on HCA ap_ids */
1125 		if (fab_apid != NULL) {
1126 			DPRINTF("cfga_private_func: fabric apid supplied\n");
1127 			return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
1128 			    ap_id, errno));
1129 		}
1130 
1131 		if ((msg = (char *)calloc(80, 1)) == NULL) {
1132 			DPRINTF("cfga_private_func: malloc for msg failed. "
1133 			    "errno: %d\n", errno);
1134 			return (ib_err_msg(errstring, CFGA_IB_ALLOC_FAIL,
1135 			    ap_id, errno));
1136 		}
1137 
1138 		if ((rv = ib_do_control_ioctl((char *)ap_id, IBNEX_HCA_LIST_SZ,
1139 		    IBNEX_HCA_LIST_INFO, 0, (void **)&info, &info_len)) != 0) {
1140 			DPRINTF("cfga_private_func: "
1141 			    "ib_do_control_ioctl list failed :%d\n", rv);
1142 			S_FREE(msg);
1143 			return (ib_err_msg(errstring, CFGA_IB_HCA_LIST_ERR,
1144 			    ap_id, errno));
1145 		}
1146 
1147 		if (nvlist_unpack((char *)info, info_len, &nvl, 0)) {
1148 			DPRINTF("cfga_private_func: "
1149 			    "nvlist_unpack 2 failed %p\n", info);
1150 			S_FREE(info);
1151 			S_FREE(msg);
1152 			return (ib_err_msg(errstring, CFGA_IB_NVLIST_ERR, ap_id,
1153 			    errno));
1154 		}
1155 
1156 		(void) snprintf(msg, 80, "Ap_Id\t\t\t       IB Client\t\t "
1157 		    "Alternate HCA\n");
1158 		cfga_msg(msgp, msg);
1159 
1160 		/* Walk the NVPAIR data */
1161 		while (nvp = nvlist_next_nvpair(nvl, nvp)) {
1162 			name = nvpair_name(nvp);
1163 			if (strcmp(name, "Client") == 0) {
1164 				(void) nvpair_value_string(nvp, &clnt_name);
1165 				++count;
1166 			} else if (strcmp(name, "Alt_HCA") == 0) {
1167 				(void) nvpair_value_string(nvp, &alt_hca);
1168 				++count;
1169 			} else if (strcmp(name, "ApID") == 0) {
1170 				(void) nvpair_value_string(nvp, &clnt_apid);
1171 				++count;
1172 			}
1173 
1174 			/* check at the end; print message per client found */
1175 			if (count == 3) {
1176 				count = 0;
1177 				(void) snprintf(msg, 80, "%-31s%-26s%s\n",
1178 				    clnt_apid, clnt_name, alt_hca);
1179 				cfga_msg(msgp, msg);
1180 			}
1181 		} /* end of while */
1182 
1183 		S_FREE(info);
1184 		S_FREE(msg);
1185 		nvlist_free(nvl);
1186 
1187 	/* -x unconfig_clients */
1188 	} else if (strcmp(func, IB_UNCONFIG_HCA_CLIENTS) == 0) {
1189 		/*
1190 		 * -x unconfig_clients changes state by calling into RCM.
1191 		 * It needs root privileges.
1192 		 */
1193 		if (geteuid() != 0) {
1194 			return (ib_err_msg(errstring, CFGA_IB_PRIV_ERR, ap_id,
1195 			    errno));
1196 		}
1197 
1198 		/* only supported on HCA ap_ids */
1199 		if (fab_apid != NULL) {
1200 			DPRINTF("cfga_private_func: fabric apid supplied\n");
1201 			return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
1202 			    ap_id, errno));
1203 		}
1204 
1205 		/* Check w/ user if it is ok to do this operation */
1206 		len = strlen(IB_CONFIRM2) + strlen(IB_CONFIRM3) + strlen(ap_id);
1207 		if ((msg = (char *)calloc(len + 3, 1)) != NULL) {
1208 			(void) snprintf(msg, len + 3, "%s %s\n%s",
1209 			    IB_CONFIRM2, ap_id, IB_CONFIRM3);
1210 		}
1211 
1212 		/* If the user fails to confirm, bailout */
1213 		if (!ib_confirm(confp, msg)) {
1214 			free(msg);
1215 			return (CFGA_NACK);
1216 		}
1217 		free(msg);
1218 
1219 		/* Get device-paths of all the IOC/Port/Pseudo devices */
1220 		rv = ib_do_control_ioctl((char *)ap_id, IBNEX_UNCFG_CLNTS_SZ,
1221 		    IBNEX_UNCFG_CLNTS_INFO, 0, (void **)&info, &info_len);
1222 		if (rv != 0) {
1223 			DPRINTF("cfga_private_func: ib_do_control_ioctl "
1224 			    "failed :%d\n", rv);
1225 			return (ib_err_msg(errstring, CFGA_IB_HCA_UNCONFIG_ERR,
1226 			    ap_id, errno));
1227 		}
1228 
1229 		if (nvlist_unpack((char *)info, info_len, &nvl, 0)) {
1230 			DPRINTF("cfga_private_func: nvlist_unpack failed %p\n",
1231 			    info);
1232 			S_FREE(info);
1233 			return (ib_err_msg(errstring, CFGA_IB_NVLIST_ERR, ap_id,
1234 			    errno));
1235 		}
1236 
1237 		ret = 0;
1238 
1239 		/* Call RCM Offline on all device paths */
1240 		while (nvp = nvlist_next_nvpair(nvl, nvp)) {
1241 			name = nvpair_name(nvp);
1242 			if (strcmp(name, "devpath") == 0) {
1243 				(void) nvpair_value_string(nvp, &clnt_devpath);
1244 				++count;
1245 			} else if (strcmp(name, "ApID") == 0) {
1246 				(void) nvpair_value_string(nvp, &clnt_apid);
1247 				++count;
1248 			}
1249 
1250 			/* handle the client unconfigure now */
1251 			if (count == 2) {
1252 				count = 0;	/* reset count */
1253 
1254 				DPRINTF("cfga_private_func: client apid = %s, "
1255 				    "DevPath = %s\n", clnt_apid, clnt_devpath);
1256 				if ((rv = ib_setup_for_devctl_cmd(clnt_apid,
1257 				    B_TRUE, &hdl, &nvl)) != CFGA_IB_OK) {
1258 					ib_cleanup_after_devctl_cmd(hdl, nvl);
1259 					return (ib_err_msg(errstring, rv,
1260 					    clnt_apid, errno));
1261 				}
1262 
1263 				if ((rv = ib_device_configured(hdl, nvl,
1264 				    &rstate)) == CFGA_IB_NOT_CONFIGURED)
1265 					continue;
1266 
1267 				if ((rv = ib_rcm_offline(clnt_apid, errstring,
1268 				    clnt_devpath, flags)) != CFGA_IB_OK) {
1269 					DPRINTF("cfga_private_func: client rcm "
1270 					    "offline failed for %s, with %d\n",
1271 					    clnt_devpath, rv);
1272 					ret = rv;
1273 					continue;
1274 				}
1275 
1276 				if (devctl_ap_unconfigure(hdl, nvl) != 0) {
1277 					DPRINTF("cfga_private_func: client "
1278 					    "unconfigure failed: errno %d\n",
1279 					    errno);
1280 					ret = CFGA_IB_UNCONFIG_OP_ERR;
1281 					if (errno == EBUSY)
1282 						ret = CFGA_IB_BUSY_ERR;
1283 					(void) ib_rcm_online(clnt_apid,
1284 					    errstring, clnt_devpath, flags);
1285 					continue;
1286 				} else {
1287 					(void) ib_rcm_remove(clnt_apid,
1288 					    errstring, clnt_devpath, flags);
1289 				}
1290 				ib_cleanup_after_devctl_cmd(hdl, nvl);
1291 
1292 			} /* end of if count == 2 */
1293 
1294 		} /* end of while */
1295 
1296 		S_FREE(info);
1297 		nvlist_free(nvl);
1298 		if (ret) {
1299 			DPRINTF("cfga_private_func: unconfig_clients of %s "
1300 			    "failed with %d\n", ap_id, ret);
1301 			return (ib_err_msg(errstring, CFGA_IB_UCFG_CLNTS_ERR,
1302 			    ap_id, errno));
1303 		}
1304 
1305 	/* -x update_pkey_tbls */
1306 	} else if (strcmp(func, IB_UPDATE_PKEY_TBLS) == 0) {
1307 		/*
1308 		 * Check for root privileges.
1309 		 */
1310 		if (geteuid() != 0) {
1311 			return (ib_err_msg(errstring, CFGA_IB_PRIV_ERR, ap_id,
1312 			    errno));
1313 		}
1314 
1315 		/* CHECK: Only supported on fabric ap_ids */
1316 		if (fab_apid == NULL) {
1317 			DPRINTF("cfga_private_func: fabric apid needed\n");
1318 			return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
1319 			    ap_id, errno));
1320 		}
1321 
1322 		/* Check w/ user if it is ok to do this operation */
1323 		len = strlen(IB_CONFIRM4) + 10;
1324 		if ((msg = (char *)calloc(len, 1)) != NULL) {
1325 			(void) snprintf(msg, len, "%s\nContinue", IB_CONFIRM4);
1326 		}
1327 
1328 		/* If the user fails to confirm, return */
1329 		if (!ib_confirm(confp, msg)) {
1330 			free(msg);
1331 			return (CFGA_NACK);
1332 		}
1333 		free(msg);
1334 
1335 		/* Update P_Key tables for all ports of all HCAs */
1336 		rv = ib_do_control_ioctl((char *)ap_id, IBNEX_UPDATE_PKEY_TBLS,
1337 		    0, 0, 0, &info_len);
1338 
1339 		if (rv != 0) {
1340 			DPRINTF("cfga_private_func: ib_do_control_ioctl "
1341 			    "failed :%d\n", rv);
1342 			return (ib_err_msg(errstring, CFGA_IB_UPD_PKEY_TBLS_ERR,
1343 			    ap_id, errno));
1344 		}
1345 
1346 	/* -x [add_service|delete_service] */
1347 	} else if ((strncmp(func, IB_ADD_SERVICE, 12) == 0) ||
1348 	    (strncmp(func, IB_DELETE_SERVICE, 15) == 0)) {
1349 		char			*subopts, *val;
1350 		uint8_t			cmd;
1351 
1352 		/* check: Only supported on fabric ap_ids */
1353 		if (fab_apid == NULL || strcmp(fab_apid, IBNEX_FABRIC) != 0) {
1354 			DPRINTF("cfga_private_func: fabric apid needed\n");
1355 			return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
1356 			    ap_id, errno));
1357 		}
1358 
1359 		/* Check for root privileges. */
1360 		if (geteuid() != 0) {
1361 			return (ib_err_msg(errstring, CFGA_IB_PRIV_ERR, ap_id,
1362 			    errno));
1363 		}
1364 
1365 		/* return error if no options are specified */
1366 		subopts = (char *)options;
1367 		if (subopts == (char *)NULL) {
1368 			DPRINTF("cfga_private_func: no sub-options\n");
1369 			(void) cfga_help(msgp, options, flags);
1370 			return (ib_err_msg(errstring, CFGA_IB_INVAL_ARG_ERR,
1371 			    ap_id, errno));
1372 		}
1373 
1374 		/* parse options specified */
1375 		while (*subopts != '\0') {
1376 			switch (getsubopt(&subopts, ib_service_subopts, &val)) {
1377 			case 0: /* comm */
1378 				if (val == NULL) {
1379 					(void) cfga_help(msgp, options, flags);
1380 					S_FREE(service_name);
1381 					return (ib_err_msg(errstring,
1382 					    CFGA_IB_INVAL_ARG_ERR,
1383 					    ap_id, errno));
1384 				} else {
1385 					comm_name = strdup(val);
1386 					if (comm_name == NULL) {
1387 						DPRINTF("comm sub-opt invalid "
1388 						    "arg\n");
1389 						S_FREE(service_name);
1390 						return (ib_err_msg(errstring,
1391 						    CFGA_IB_COMM_INVAL_ERR,
1392 						    ap_id, errno));
1393 					}
1394 				}
1395 				break;
1396 
1397 			case 1: /* service */
1398 				if (val == NULL) {
1399 					(void) cfga_help(msgp, options, flags);
1400 					S_FREE(comm_name);
1401 					return (ib_err_msg(errstring,
1402 					    CFGA_IB_INVAL_ARG_ERR,
1403 					    ap_id, errno));
1404 				} else {
1405 					/* service can be upto 4 long */
1406 					if (strlen(val) == 0 ||
1407 					    strlen(val) > 4) {
1408 						DPRINTF("comm sub-opt invalid "
1409 						    "service passed\n");
1410 						S_FREE(comm_name);
1411 						return (ib_err_msg(errstring,
1412 						    CFGA_IB_SVC_LEN_ERR,
1413 						    ap_id, errno));
1414 					}
1415 					service_name = strdup(val);
1416 					if (service_name == NULL) {
1417 						DPRINTF("comm sub-opt "
1418 						    "internal error\n");
1419 						S_FREE(comm_name);
1420 						return (ib_err_msg(errstring,
1421 						    CFGA_IB_SVC_INVAL_ERR,
1422 						    ap_id, errno));
1423 					}
1424 				}
1425 				break;
1426 
1427 			default:
1428 				(void) cfga_help(msgp, options, flags);
1429 				S_FREE(comm_name);
1430 				S_FREE(service_name);
1431 				return (ib_err_msg(errstring,
1432 				    CFGA_IB_INVAL_ARG_ERR, ap_id, errno));
1433 			}
1434 		}
1435 
1436 		/* figure out the "operation" */
1437 		if (strncasecmp(func, IB_ADD_SERVICE, 11) == 0)
1438 			cmd = IBCONF_ADD_ENTRY;
1439 		else if (strncasecmp(func, IB_DELETE_SERVICE, 14) == 0)
1440 			cmd = IBCONF_DELETE_ENTRY;
1441 		DPRINTF("Service = %s, Comm = %s, Operation = %s\n",
1442 		    service_name, comm_name, func);
1443 
1444 		if (strncasecmp(comm_name, IBNEX_PORT_STR, 4) == 0)
1445 			service_type = IB_PORT_SERVICE;
1446 		else if (strncasecmp(comm_name, IBNEX_VPPA_STR, 4) == 0)
1447 			service_type = IB_VPPA_SERVICE;
1448 		else if (strncasecmp(comm_name, IBNEX_HCASVC_STR, 4) == 0)
1449 			service_type = IB_HCASVC_SERVICE;
1450 		else {
1451 			(void) cfga_help(msgp, options, flags);
1452 			S_FREE(comm_name);
1453 			S_FREE(service_name);
1454 			return (ib_err_msg(errstring, CFGA_IB_INVAL_ARG_ERR,
1455 			    ap_id, errno));
1456 		}
1457 
1458 		/* do the add/delete entry to the service */
1459 		if (cmd == IBCONF_ADD_ENTRY) {
1460 			if ((rv = ib_add_service(errstring)) != CFGA_IB_OK)
1461 				DPRINTF("cfga_private_func: add failed\n");
1462 		} else if (cmd == IBCONF_DELETE_ENTRY) {
1463 			if ((rv = ib_delete_service(errstring)) != CFGA_IB_OK)
1464 				DPRINTF("cfga_private_func: delete failed\n");
1465 		}
1466 
1467 		S_FREE(comm_name);
1468 		S_FREE(service_name);
1469 		return (ib_err_msg(errstring, rv, ap_id, errno));
1470 
1471 	} else if (strncmp(func, IB_LIST_SERVICES, 13) == 0) {
1472 
1473 		/* check: Only supported on fabric ap_ids */
1474 		if (fab_apid == NULL || strcmp(fab_apid, IBNEX_FABRIC) != 0) {
1475 			DPRINTF("cfga_private_func: fabric apid needed\n");
1476 			return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
1477 			    ap_id, errno));
1478 		}
1479 
1480 		/* do the list services */
1481 		rv = ib_list_services(msgp, errstring);
1482 		if (rv != CFGA_IB_OK) {
1483 			DPRINTF("cfga_private_func: ib_list_services failed\n");
1484 			return (ib_err_msg(errstring, rv, ap_id, errno));
1485 		}
1486 
1487 	/* -x update_ioc_conf */
1488 	} else if (strncmp(func, IB_UPDATE_IOC_CONF, 17) == 0) {
1489 		uint_t misc_arg;
1490 
1491 		/* Supported only with root privilege */
1492 		if (geteuid() != 0) {
1493 			return (ib_err_msg(errstring, CFGA_IB_PRIV_ERR, ap_id,
1494 			    errno));
1495 		}
1496 
1497 		/*
1498 		 * check: Only supported on fabric ap_id or IOC APID
1499 		 * IOC APID does not have any commas in it.
1500 		 */
1501 		if (fab_apid == NULL ||
1502 		    (fab_apid != NULL && strstr(fab_apid, ",") != NULL)) {
1503 			DPRINTF("cfga_private_func: fabric/IOC apid needed\n");
1504 			return (ib_err_msg(errstring, CFGA_IB_INVALID_OP_ERR,
1505 			    ap_id, errno));
1506 		}
1507 
1508 		/* Check w/ user if it is ok to do this operation */
1509 		len = strlen(IB_CONFIRM5) + 10;
1510 		if ((msg = (char *)calloc(len, 1)) != NULL) {
1511 			(void) snprintf(msg, len, "%s\nContinue", IB_CONFIRM5);
1512 		}
1513 
1514 		/* If the user fails to confirm, return */
1515 		if (!ib_confirm(confp, msg)) {
1516 			free(msg);
1517 			return (CFGA_NACK);
1518 		}
1519 		free(msg);
1520 
1521 		misc_arg = (strcmp(fab_apid, IBNEX_FABRIC) == 0) ?
1522 			IBNEX_BASE_APID : IBNEX_DYN_APID;
1523 
1524 		/* Reprobe and update IOC(s) configuration */
1525 		rv = ib_do_control_ioctl((char *)ap_id, IBNEX_UPDATE_IOC_CONF,
1526 		    0, misc_arg, 0, &info_len);
1527 
1528 		if (rv != 0) {
1529 			DPRINTF("cfga_private_func: ib_do_control_ioctl "
1530 			    "failed :%d\n", rv);
1531 			return (ib_err_msg(errstring, CFGA_IB_DEVCTL_ERR,
1532 			    ap_id, errno));
1533 		}
1534 	} else {
1535 		DPRINTF("cfga_private_func: unrecognized command.\n");
1536 		(void) cfga_help(msgp, options, flags);
1537 		errno = EINVAL;
1538 		return (CFGA_INVAL);
1539 	}
1540 
1541 	return (ib_err_msg(errstring, rv, ap_id, errno));
1542 }
1543 
1544 
1545 /*
1546  * Function:
1547  *	cfga_test
1548  * Input:
1549  *	ap_id		- The attachment point of an IB fabric
1550  *	options		- Test command options passed by the cfgadm(1M)
1551  *	msgp		- cfgadm error message for this plugin
1552  *	errstring	- This contains error msg if command fails
1553  *	flags		- Cfgadm(1m) flags
1554  * Output:
1555  *	NONE
1556  * Returns:
1557  *	CFGA_OPNOTSUPP
1558  * Description:
1559  *	Do "cfgadm -t"
1560  */
1561 /*ARGSUSED*/
1562 cfga_err_t
1563 cfga_test(const char *ap_id, const char *options, struct cfga_msg *msgp,
1564     char **errstring, cfga_flags_t flags)
1565 {
1566 	(void) cfga_help(msgp, options, flags);
1567 	return (CFGA_OPNOTSUPP);
1568 }
1569 
1570 
1571 /*
1572  * Function:
1573  *	ib_fill_static_apids
1574  * Input:
1575  *	ap_id		- The static attachment point of an IB device
1576  *	clp		- The returned "list" information array
1577  * Output:
1578  *	NONE
1579  * Returns:
1580  *	Fills up the "list" information array for the static attachment point
1581  * Description:
1582  *	IB fabric supports two types of static attachment points.
1583  *	One is fabric and other is for the HCAs. This fills up
1584  *	"cfga_list_data_t" for static attachment points.
1585  */
1586 static cfga_ib_ret_t
1587 ib_fill_static_apids(char *ap_id, cfga_list_data_t *clp)
1588 {
1589 	int	rv, l_err;
1590 	char	*ap_id_log = NULL;
1591 
1592 	/* Get /dev/cfg path to corresponding to the physical ap_id */
1593 	/* Remember ap_id_log must be freed */
1594 	if ((cfga_ib_ret_t)ib_physpath_to_devlink(ap_id, &ap_id_log,
1595 	    &l_err) != ICFGA_OK) {
1596 		DPRINTF("ib_fill_static_apids: "
1597 		    "ib_physpath_to_devlink failed\n");
1598 		return (CFGA_IB_DEVLINK_ERR);
1599 	}
1600 	assert(ap_id_log != NULL);
1601 
1602 	/* Get logical ap-id corresponding to the physical */
1603 	if (strstr(ap_id_log, CFGA_DEV_DIR) == NULL) {
1604 		DPRINTF("ib_fill_static_apids: devlink doesn't contain "
1605 		    "/dev/cfg\n");
1606 		free(ap_id_log);
1607 		return (CFGA_IB_DEVLINK_ERR);
1608 	}
1609 
1610 	clp->ap_cond = CFGA_COND_OK;
1611 	clp->ap_r_state = CFGA_STAT_CONNECTED;
1612 	clp->ap_o_state = CFGA_STAT_CONFIGURED;
1613 	clp->ap_class[0] = '\0';	/* Filled by libcfgadm */
1614 	clp->ap_busy = 0;
1615 	clp->ap_status_time = (time_t)-1;
1616 	(void) snprintf(clp->ap_log_id, sizeof (clp->ap_log_id), "%s",
1617 	    /* Strip off /dev/cfg/ */ ap_id_log + strlen(CFGA_DEV_DIR) + 1);
1618 	(void) strlcpy(clp->ap_phys_id, ap_id, sizeof (clp->ap_phys_id));
1619 
1620 	/* Static IB apid */
1621 	if (strstr((char *)ap_id, IB_FABRIC_APID_STR) != NULL)  {
1622 		(void) strlcpy(clp->ap_type, IB_FABRIC_TYPE,
1623 		    sizeof (clp->ap_type));	/* Fill in type */
1624 		(void) strlcpy(clp->ap_info, IB_FABRIC_INFO,
1625 		    sizeof (clp->ap_info));
1626 
1627 	} else {	/* Static HCA apid */
1628 		size_t	size = 0;
1629 		uchar_t	*data = NULL;
1630 
1631 		(void) strlcpy(clp->ap_type, IB_HCA_TYPE,
1632 		    sizeof (clp->ap_type));	/* Fill in type */
1633 
1634 		rv = ib_do_control_ioctl(ap_id, IBNEX_HCA_VERBOSE_SZ,
1635 		    IBNEX_HCA_VERBOSE_INFO, 0, (void **)&data, &size);
1636 		if (rv != 0) {
1637 			DPRINTF("ib_fill_static_apids: ib_do_control_ioctl "
1638 			    "failed :%d\n", rv);
1639 			free(ap_id_log);
1640 			S_FREE(data);
1641 			return (CFGA_IB_IOCTL_ERR);
1642 		}
1643 
1644 		(void) strlcpy(clp->ap_info, (char *)data,
1645 		    sizeof (clp->ap_info));
1646 		S_FREE(data);
1647 	}
1648 	free(ap_id_log);
1649 	return (CFGA_IB_OK);
1650 }
1651 
1652 
1653 /*
1654  * Function:
1655  *	cfga_list_ext
1656  * Input:
1657  *	ap_id		- The attachment point of an IB fabric
1658  *	ap_id_list	- The returned "list" information array
1659  *	nlistp		- Number of elements in the "list" information array
1660  *	options		- List command options passed by the cfgadm(1M)
1661  *	listopts	- "-s" specific options
1662  *	errstring	- This contains error msg if command fails
1663  *	flags		- Cfgadm(1m) flags
1664  * Output:
1665  *	NONE
1666  * Returns:
1667  *	If the command succeeded, cfgadm -l output otherwise an error
1668  * Description:
1669  *	Do cfgadm -l
1670  */
1671 /*ARGSUSED*/
1672 cfga_err_t
1673 cfga_list_ext(const char *ap_id, cfga_list_data_t **ap_id_list, int *nlistp,
1674     const char *options, const char *listopts, char **errstring,
1675     cfga_flags_t flags)
1676 {
1677 	int			expand = 0;
1678 	int			i, index, count;
1679 	int			show_dynamic = 0;
1680 	size_t			num_devices = 0;
1681 	size_t			num_hcas = 0;
1682 	size_t			snap_size = 0;
1683 	uchar_t			*snap_data = NULL;
1684 	nvpair_t		*nvp = NULL;	/* for lint purposes */
1685 	nvlist_t		*nvl = NULL;
1686 	boolean_t		apid_matched = B_FALSE;	/* for valid ap_id */
1687 	cfga_ib_ret_t		rv = CFGA_IB_OK;
1688 	cfga_list_data_t	*clp = NULL;
1689 
1690 	if ((rv = ib_verify_params(ap_id, options, errstring)) != CFGA_IB_OK) {
1691 		(void) cfga_help(NULL, options, flags);
1692 		return (ib_err_msg(errstring, rv, ap_id, errno));
1693 	}
1694 
1695 	/* make sure we have a valid ap_id_list */
1696 	if (ap_id_list == NULL || nlistp == NULL) {
1697 		DPRINTF("cfga_list_ext: list = NULL or nlistp = NULL\n");
1698 		(void) cfga_help(NULL, options, flags);
1699 		return (ib_err_msg(errstring, CFGA_IB_INVAL_ARG_ERR,
1700 		    ap_id, errno));
1701 	}
1702 
1703 	DPRINTF("cfga_list_ext: ap_id = %s\n", ap_id);
1704 
1705 	if ((flags & CFGA_FLAG_LIST_ALL) == CFGA_FLAG_LIST_ALL) {
1706 		expand = 1;		/* -a flag passed */
1707 	}
1708 
1709 	if (GET_DYN(ap_id) != NULL) {
1710 		show_dynamic = 1;
1711 	}
1712 
1713 	if ((expand == 1) &&	/* -a option passed */
1714 	    (strstr((char *)ap_id, IB_FABRIC_APID_STR) != NULL)) {
1715 		/*
1716 		 * Figure out how many IOC/Port/Pseudo
1717 		 * devices exist in the system?
1718 		 */
1719 		if ((rv = ib_do_control_ioctl((char *)ap_id,
1720 		    IBNEX_NUM_DEVICE_NODES, 0, 0, 0, &num_devices)) !=
1721 		    CFGA_IB_OK) {
1722 			DPRINTF("cfga_list_ext: ib_do_control_ioctl "
1723 			    "IBNEX_NUM_DEVICE_NODES failed :%d\n", rv);
1724 			if (errno == ENOENT)
1725 				return (CFGA_APID_NOEXIST);
1726 			return (ib_err_msg(errstring, rv, ap_id, errno));
1727 		}
1728 
1729 		DPRINTF("cfga_list_ext: num_devices = %d\n", num_devices);
1730 	}
1731 
1732 	/* Figure out how many HCA nodes exist in the system. */
1733 	if ((rv = ib_do_control_ioctl((char *)ap_id, IBNEX_NUM_HCA_NODES, 0, 0,
1734 	    0, &num_hcas)) != CFGA_IB_OK) {
1735 		DPRINTF("cfga_list_ext: ib_do_control_ioctl "
1736 		    "IBNEX_NUM_HCA_NODES failed :%d\n", rv);
1737 		if (errno == ENOENT)
1738 			return (CFGA_APID_NOEXIST);
1739 		return (ib_err_msg(errstring, rv, ap_id, errno));
1740 	}
1741 	DPRINTF("cfga_list_ext: num_hcas = %d\n", num_hcas);
1742 
1743 	/*
1744 	 * No HCAs or IOC/VPPA/Port/HCA_SVC/Pseudo devices seen (non-IB system)
1745 	 */
1746 	if (!(num_hcas || num_devices)) {
1747 		DPRINTF("cfga_list_ext: no IB devices found\n");
1748 		return (CFGA_APID_NOEXIST);
1749 	}
1750 
1751 	/*
1752 	 * *nlistp contains to how many APIDs to show w/ cfgadm -l.
1753 	 * If ap_id is "fabric" then
1754 	 * 	*nlistp is all Dynamic Apids + One more for "fabric"
1755 	 * If ap_id is "HCA" ap_id then
1756 	 *	*nlistp is 1
1757 	 * Note that each HCA is a static APID, so nlistp will be 1 always
1758 	 * and this function will be called N times for each of the N HCAs
1759 	 * in the host.
1760 	 */
1761 	if (strstr((char *)ap_id, IB_FABRIC_APID_STR) != NULL) {
1762 		*nlistp = num_devices + 1;
1763 
1764 	} else {
1765 		/* Assume it as a HCA ap_id */
1766 		*nlistp = 1;
1767 	}
1768 
1769 	/* Allocate storage for passing "list" info back */
1770 	if ((*ap_id_list = (cfga_list_data_t *)calloc(*nlistp,
1771 	    sizeof (cfga_list_data_t))) == NULL) {
1772 		DPRINTF("cfga_list_ext: malloc for cfga_list_data_t failed. "
1773 		    "errno: %d\n", errno);
1774 		return (ib_err_msg(errstring, CFGA_IB_ALLOC_FAIL,
1775 		    ap_id, errno));
1776 	}
1777 
1778 	/*
1779 	 * Only static ap_id is ib_fabric:
1780 	 * If -a options isn't specified then only show the static ap_id.
1781 	 */
1782 	if (!show_dynamic) {
1783 		clp = &(*ap_id_list[0]);
1784 
1785 		if ((rv = ib_fill_static_apids((char *)ap_id, clp)) !=
1786 		    CFGA_IB_OK) {
1787 			S_FREE(*ap_id_list);
1788 			return (ib_err_msg(errstring, rv, ap_id, errno));
1789 		}
1790 		apid_matched = B_TRUE;
1791 	}
1792 
1793 	/*
1794 	 * No -a specified
1795 	 * No HCAs or IOC/VPPA/HCA_SVC/Port/Pseudo devices seen (non-IB system)
1796 	 */
1797 	if (!expand || (!num_hcas && !num_devices)) {
1798 		if (!show_dynamic)
1799 			return (CFGA_OK);
1800 	}
1801 
1802 	if (strstr((char *)ap_id, IB_FABRIC_APID_STR) != NULL) {
1803 		rv = ib_do_control_ioctl((char *)ap_id, IBNEX_SNAPSHOT_SIZE,
1804 		    IBNEX_GET_SNAPSHOT, IBNEX_DONOT_PROBE_FLAG,
1805 		    (void **)&snap_data, &snap_size);
1806 		if (rv != 0) {
1807 			DPRINTF("cfga_list_ext: ib_do_control_ioctl "
1808 			    "failed :%d\n", rv);
1809 			S_FREE(*ap_id_list);
1810 			S_FREE(snap_data);
1811 			return (ib_err_msg(errstring, rv, ap_id, errno));
1812 		}
1813 
1814 		if (nvlist_unpack((char *)snap_data, snap_size, &nvl, 0)) {
1815 			DPRINTF("cfga_list_ext: nvlist_unpack 1 failed %p\n",
1816 			    snap_data);
1817 			S_FREE(*ap_id_list);
1818 			S_FREE(snap_data);
1819 			return (ib_err_msg(errstring, CFGA_IB_NVLIST_ERR,
1820 			    ap_id, errno));
1821 		}
1822 
1823 		/*
1824 		 * In kernel a nvlist is build per ap_id which contains
1825 		 * information that is displayed using cfgadm -l.
1826 		 * For IB devices only these 6 items are shown:
1827 		 *	ap_id, type, occupant, receptacle, condition and info
1828 		 *
1829 		 * In addition, one could specify a dynamic ap_id from
1830 		 * command-line. Then cfgadm -l should show only that
1831 		 * ap_id and skip rest.
1832 		 */
1833 		index = 1; count = 0;
1834 		while (nvp = nvlist_next_nvpair(nvl, nvp)) {
1835 			int32_t intval = 0;
1836 			int32_t node_type;
1837 			char	*info;
1838 			char	*nv_apid;
1839 			char	*name = nvpair_name(nvp);
1840 
1841 			/* start of with next device */
1842 			if (count == IB_NUM_NVPAIRS) {
1843 				count = 0;
1844 				++index;
1845 			}
1846 
1847 			/* fill up data into "clp" */
1848 			clp =  (show_dynamic != 0) ? &(*ap_id_list[0]) :
1849 			    &(ap_id_list[0][index]);
1850 
1851 			/* First nvlist entry is "ap_id" always */
1852 			if (strcmp(name, IBNEX_NODE_APID_NVL) == 0) {
1853 				(void) nvpair_value_string(nvp, &nv_apid);
1854 				DPRINTF("cfga_list_ext: Name = %s, apid = %s\n",
1855 				    name, nv_apid);
1856 
1857 				/*
1858 				 * If a dynamic ap_id is specified in the
1859 				 * command-line, skip all entries until
1860 				 * the one needed matches.
1861 				 */
1862 				if (show_dynamic &&
1863 				    strstr(ap_id, nv_apid) == NULL) {
1864 					DPRINTF("cfga_list_ext: NO MATCH\n");
1865 
1866 					/*
1867 					 * skip rest of the entries of this
1868 					 * device.
1869 					 */
1870 					for (i = 0; i < IB_NUM_NVPAIRS - 1; i++)
1871 						nvp = nvlist_next_nvpair(nvl,
1872 						    nvp);
1873 					count = 0;	/* reset it */
1874 					continue;
1875 				}
1876 
1877 				apid_matched = B_TRUE;
1878 
1879 				/* build the physical ap_id */
1880 				if (strstr(ap_id, DYN_SEP) == NULL) {
1881 					(void) snprintf(clp->ap_phys_id,
1882 					    sizeof (clp->ap_phys_id), "%s%s%s",
1883 					    ap_id, DYN_SEP, nv_apid);
1884 				} else {
1885 					(void) snprintf(clp->ap_phys_id,
1886 					    sizeof (clp->ap_phys_id), "%s",
1887 					    ap_id);
1888 				}
1889 
1890 				/* ensure that this is a valid apid */
1891 				if (ib_verify_valid_apid(clp->ap_phys_id) !=
1892 				    0) {
1893 					DPRINTF("cfga_list_ext: "
1894 					    "not a valid IB ap_id\n");
1895 					S_FREE(*ap_id_list);
1896 					S_FREE(snap_data);
1897 					nvlist_free(nvl);
1898 					return (ib_err_msg(errstring,
1899 					    CFGA_IB_AP_ERR, ap_id, errno));
1900 				}
1901 
1902 				/* build the logical ap_id */
1903 				(void) snprintf(clp->ap_log_id,
1904 				    sizeof (clp->ap_log_id), "ib%s%s",
1905 				    DYN_SEP, nv_apid);
1906 				DPRINTF("cfga_list_ext: ap_pi = %s, ap_li = %s,"
1907 				    "\nap_info = %s\n", clp->ap_phys_id,
1908 				    clp->ap_log_id, clp->ap_info);
1909 				++count;
1910 
1911 			} else if (strcmp(name, IBNEX_NODE_INFO_NVL) == 0) {
1912 				(void) nvpair_value_string(nvp, &info);
1913 				DPRINTF("cfga_list_ext: Name = %s, info = %s\n",
1914 				    name, info);
1915 				(void) snprintf(clp->ap_info,
1916 				    sizeof (clp->ap_info), "%s", info);
1917 				++count;
1918 
1919 			} else if (strcmp(name, IBNEX_NODE_TYPE_NVL) == 0) {
1920 				(void) nvpair_value_int32(nvp, &node_type);
1921 				if (node_type == IBNEX_PORT_NODE_TYPE) {
1922 					(void) snprintf(clp->ap_type,
1923 					    sizeof (clp->ap_type), "%s",
1924 					    IB_PORT_TYPE);
1925 				} else if (node_type == IBNEX_VPPA_NODE_TYPE) {
1926 					(void) snprintf(clp->ap_type,
1927 					    sizeof (clp->ap_type), "%s",
1928 					    IB_VPPA_TYPE);
1929 				} else if (node_type ==
1930 				    IBNEX_HCASVC_NODE_TYPE) {
1931 					(void) snprintf(clp->ap_type,
1932 					    sizeof (clp->ap_type), "%s",
1933 					    IB_HCASVC_TYPE);
1934 				} else if (node_type == IBNEX_IOC_NODE_TYPE) {
1935 					(void) snprintf(clp->ap_type,
1936 					    sizeof (clp->ap_type), "%s",
1937 					    IB_IOC_TYPE);
1938 				} else if (node_type ==
1939 				    IBNEX_PSEUDO_NODE_TYPE) {
1940 					(void) snprintf(clp->ap_type,
1941 					    sizeof (clp->ap_type), "%s",
1942 					    IB_PSEUDO_TYPE);
1943 				}
1944 				DPRINTF("cfga_list_ext: Name = %s, type = %x\n",
1945 				    name, intval);
1946 				++count;
1947 
1948 			} else if (strcmp(name, IBNEX_NODE_RSTATE_NVL) == 0) {
1949 				(void) nvpair_value_int32(nvp, &intval);
1950 
1951 				if (intval == AP_RSTATE_EMPTY)
1952 					clp->ap_r_state = CFGA_STAT_EMPTY;
1953 				else if (intval == AP_RSTATE_DISCONNECTED)
1954 					clp->ap_r_state =
1955 						CFGA_STAT_DISCONNECTED;
1956 				else if (intval == AP_RSTATE_CONNECTED)
1957 					clp->ap_r_state = CFGA_STAT_CONNECTED;
1958 				DPRINTF("cfga_list_ext: Name = %s, "
1959 				    "rstate = %x\n", name, intval);
1960 				++count;
1961 
1962 			} else if (strcmp(name, IBNEX_NODE_OSTATE_NVL) == 0) {
1963 				(void) nvpair_value_int32(nvp, &intval);
1964 
1965 				if (intval == AP_OSTATE_CONFIGURED)
1966 					clp->ap_o_state = CFGA_STAT_CONFIGURED;
1967 				else if (intval == AP_OSTATE_UNCONFIGURED)
1968 					clp->ap_o_state =
1969 						CFGA_STAT_UNCONFIGURED;
1970 				DPRINTF("cfga_list_ext: Name = %s, "
1971 				    "ostate = %x\n", name, intval);
1972 				++count;
1973 
1974 			} else if (strcmp(name, IBNEX_NODE_COND_NVL) == 0) {
1975 				(void) nvpair_value_int32(nvp, &intval);
1976 
1977 				if (intval == AP_COND_OK)
1978 					clp->ap_cond = CFGA_COND_OK;
1979 				else if (intval == AP_COND_FAILING)
1980 					clp->ap_cond = CFGA_COND_FAILING;
1981 				else if (intval == AP_COND_FAILED)
1982 					clp->ap_cond = CFGA_COND_FAILED;
1983 				else if (intval == AP_COND_UNUSABLE)
1984 					clp->ap_cond = CFGA_COND_UNUSABLE;
1985 				else if (intval == AP_COND_UNKNOWN)
1986 					clp->ap_cond = CFGA_COND_UNKNOWN;
1987 				DPRINTF("cfga_list_ext: Name = %s, "
1988 				    "condition = %x\n", name, intval);
1989 				++count;
1990 			}
1991 
1992 			clp->ap_class[0] = '\0'; /* Filled by libcfgadm */
1993 			clp->ap_busy = 0;
1994 			clp->ap_status_time = (time_t)-1;
1995 		} /* end of while */
1996 	}
1997 
1998 	S_FREE(snap_data);
1999 	if (nvl)
2000 		nvlist_free(nvl);
2001 
2002 	/*
2003 	 * if a cmdline specified ap_id doesn't match the known list of ap_ids
2004 	 * then report an error right away
2005 	 */
2006 	rv = (apid_matched ==  B_TRUE) ? CFGA_IB_OK : CFGA_IB_AP_ERR;
2007 	return (ib_err_msg(errstring, rv, ap_id, errno));
2008 }
2009 
2010 
2011 /*
2012  * Function:
2013  *	cfga_msg
2014  * Input:
2015  *	msgp		- cfgadm error message for this plugin
2016  *	str		- string to be passed on to the message
2017  * Output:
2018  *	NONE
2019  * Returns:
2020  *	NONE
2021  * Description:
2022  *	This routine accepts a variable number of message IDs and
2023  *	constructs a corresponding error string which is printed
2024  *	via the message print routine argument.
2025  */
2026 void
2027 cfga_msg(struct cfga_msg *msgp, const char *str)
2028 {
2029 	int len;
2030 	char *q;
2031 
2032 	if (msgp == NULL || msgp->message_routine == NULL) {
2033 		DPRINTF("cfga_msg: msg\n");
2034 		return;
2035 	}
2036 
2037 	if ((len = strlen(str)) == 0) {
2038 		DPRINTF("cfga_msg: null str\n");
2039 		return;
2040 	}
2041 
2042 	if ((q = (char *)calloc(len + 1, 1)) == NULL) {
2043 		DPRINTF("cfga_msg: null q\n");
2044 		return;
2045 	}
2046 
2047 	(void) strlcpy(q, str, len + 1);
2048 	(*msgp->message_routine)(msgp->appdata_ptr, q);
2049 
2050 	free(q);
2051 }
2052 
2053 
2054 /*
2055  * Function:
2056  *	cfga_help
2057  * Input:
2058  *	msgp		- Help message passed on to cfgadm(1M)
2059  *	options		- Help message options passed on to cfgadm(1M)
2060  *	flags		- Cfgadm(1m) flags
2061  * Output:
2062  *	NONE
2063  * Returns:
2064  *	Were we able to print cfgadm help or not for this plugin
2065  * Description:
2066  *	Print cfgadm help for this plugin
2067  */
2068 /* ARGSUSED */
2069 cfga_err_t
2070 cfga_help(struct cfga_msg *msgp, const char *options, cfga_flags_t flags)
2071 {
2072 	DPRINTF("cfga_help:\n");
2073 
2074 	if (options) {
2075 		cfga_msg(msgp, dgettext(TEXT_DOMAIN, ib_help[
2076 		    CFGA_IB_HELP_UNKNOWN]));
2077 		cfga_msg(msgp, options);
2078 	}
2079 
2080 	/* Print messages array */
2081 	cfga_msg(msgp, dgettext(TEXT_DOMAIN, ib_help[CFGA_IB_HELP_HEADER]));
2082 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_CONFIG]);
2083 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_LIST]);
2084 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_UPD_PKEY]);
2085 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_CONF_FILE1]);
2086 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_CONF_FILE2]);
2087 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_UPD_IOC_CONF]);
2088 	cfga_msg(msgp, ib_help[CFGA_IB_HELP_UNCFG_CLNTS]);
2089 
2090 	return (CFGA_OK);
2091 }
2092 
2093 
2094 /*
2095  * Function:
2096  *	ib_confirm
2097  * Input:
2098  *	confp		- The "cfga" structure that confirms a cfgadm query
2099  *	msg		- The message that needs confirmation
2100  * Output:
2101  *	None
2102  * Returns:
2103  *	If a user entered YES or NO
2104  * Description:
2105  *	Queries a user if it is ok to proceed with an operation or not.
2106  *	Returns user's response.
2107  */
2108 static int
2109 ib_confirm(struct cfga_confirm *confp, char *msg)
2110 {
2111 	int rval;
2112 
2113 	/* check that "confirm" function exists */
2114 	if (confp == NULL || confp->confirm == NULL) {
2115 		return (0);
2116 	}
2117 
2118 	/* Call cfgadm provided "confirm" function */
2119 	rval = (*confp->confirm)(confp->appdata_ptr, msg);
2120 	DPRINTF("ib_confirm: %d\n", rval);
2121 
2122 	return (rval);
2123 }
2124 
2125 
2126 /*
2127  * Function:
2128  *	ib_get_devicepath
2129  * Input:
2130  *	ap_id		- The dynamic attachment point of an IB device
2131  * Output:
2132  *	None
2133  * Returns:
2134  *	devpath if it exists; otherwise NULL
2135  * Description:
2136  *	Returns the devicepath for a dynamic attachment point of an IB device
2137  */
2138 static char *
2139 ib_get_devicepath(const char *ap_id)
2140 {
2141 	char		*devpath = NULL;
2142 	size_t		size;
2143 
2144 	/* Get device path sizes */
2145 	if (ib_do_control_ioctl((char *)ap_id, IBNEX_DEVICE_PATH_SZ,
2146 	    IBNEX_GET_DEVICE_PATH, 0, (void **)&devpath, &size) == CFGA_IB_OK) {
2147 		DPRINTF("ib_get_devicepath: get device path ioctl ok\n");
2148 		return (devpath);
2149 
2150 	} else {
2151 		DPRINTF("ib_get_devicepath: get device path ioctl failed\n");
2152 		return ((char *)NULL);
2153 	}
2154 }
2155