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