4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
29 static fpcfga_ret_t
fp_rcm_init(char *, cfga_flags_t
, char **, uint_t
*,
31 static int fp_rcm_process_node(di_node_t
, void *);
32 static fpcfga_ret_t
fp_rcm_info_table(rcm_info_t
*, char **);
33 static char *chop_minor(char *);
36 #define DEVICES "/devices"
44 fpcfga_ret_t (*func
)(char *, char *, char **, cfga_flags_t
);
47 static fpcfga_ret_t
fp_rcm_info_table(rcm_info_t
*, char **);
48 static int fp_rcm_process_node(di_node_t
, void *);
49 static fpcfga_ret_t
fp_rcm_init(char *, cfga_flags_t
, char **, uint_t
*,
51 static char *chop_minor(char *);
53 static rcm_handle_t
*rcm_handle
= NULL
;
54 static mutex_t rcm_handle_lock
;
59 * Offline FP resource consumers.
62 fp_rcm_offline(char *rsrc
, char **errstring
, cfga_flags_t flags
)
67 rcm_info_t
*rinfo
= NULL
;
68 fpcfga_ret_t ret
= FPCFGA_OK
;
70 if ((ret
= fp_rcm_init(rsrc
, flags
, errstring
, &rflags
, &rsrc_fixed
))
74 if ((rret
= rcm_request_offline(rcm_handle
, rsrc_fixed
, rflags
, &rinfo
))
76 cfga_err(errstring
, 0, ERRARG_RCM_OFFLINE
, rsrc_fixed
, 0);
78 (void) fp_rcm_info_table(rinfo
, errstring
);
81 if (rret
== RCM_FAILURE
)
82 (void) fp_rcm_online(rsrc
, errstring
, flags
);
94 * Online FP resource consumers that were previously offlined.
97 fp_rcm_online(char *rsrc
, char **errstring
, cfga_flags_t flags
)
100 rcm_info_t
*rinfo
= NULL
;
101 fpcfga_ret_t ret
= FPCFGA_OK
;
103 if ((ret
= fp_rcm_init(rsrc
, flags
, errstring
, NULL
, &rsrc_fixed
))
107 if (rcm_notify_online(rcm_handle
, rsrc_fixed
, 0, &rinfo
)
108 != RCM_SUCCESS
&& rinfo
!= NULL
) {
109 cfga_err(errstring
, 0, ERRARG_RCM_ONLINE
, rsrc_fixed
, 0);
110 (void) fp_rcm_info_table(rinfo
, errstring
);
111 rcm_free_info(rinfo
);
123 * Remove FP resource consumers after their kernel removal.
126 fp_rcm_remove(char *rsrc
, char **errstring
, cfga_flags_t flags
)
129 rcm_info_t
*rinfo
= NULL
;
130 fpcfga_ret_t ret
= FPCFGA_OK
;
132 if ((ret
= fp_rcm_init(rsrc
, flags
, errstring
, NULL
, &rsrc_fixed
))
136 if (rcm_notify_remove(rcm_handle
, rsrc_fixed
, 0, &rinfo
)
138 cfga_err(errstring
, 0, ERRARG_RCM_REMOVE
, rsrc_fixed
, 0);
140 (void) fp_rcm_info_table(rinfo
, errstring
);
141 rcm_free_info(rinfo
);
154 * Suspend FP resource consumers before a bus quiesce.
157 fp_rcm_suspend(char *rsrc
, char *filter
, char **errstring
, cfga_flags_t flags
)
164 rcm_info_t
*rinfo
= NULL
;
166 fpcfga_ret_t ret
= FPCFGA_OK
;
168 timespec_t zerotime
= { 0, 0 };
170 if ((ret
= fp_rcm_init(rsrc
, flags
, errstring
, &rflags
, &rsrc_fixed
))
174 /* If a filter is provided, ensure that it makes sense */
175 if (filter
!= NULL
&& strstr(filter
, rsrc
) != filter
) {
177 cfga_err(errstring
, 0, ERR_APID_INVAL
, 0);
182 * If no filter is specified: attempt a suspension on the resource,
185 if (filter
== NULL
) {
186 if ((rret
= rcm_request_suspend(rcm_handle
, rsrc_fixed
, rflags
,
187 &zerotime
, &rinfo
)) != RCM_SUCCESS
) {
188 cfga_err(errstring
, 0, ERRARG_RCM_SUSPEND
, rsrc_fixed
,
191 (void) fp_rcm_info_table(rinfo
, errstring
);
192 rcm_free_info(rinfo
);
194 if (rret
== RCM_FAILURE
)
195 (void) fp_rcm_resume(rsrc
, filter
, errstring
,
196 (flags
& (~CFGA_FLAG_FORCE
)));
204 * If a filter is specified: open the resource with libdevinfo, walk
205 * through its nodes, and attempt a suspension of each node that
206 * mismatches the filter.
209 /* Chop off the filter's minor name */
210 if ((filter_fixed
= chop_minor(filter
)) == NULL
)
213 /* get a libdevinfo snapshot of the resource's subtree */
214 rsrc_devpath
= rsrc_fixed
;
215 if (strstr(rsrc_fixed
, DEVICES
) != NULL
)
216 rsrc_devpath
+= strlen(DEVICES
);
217 node
= di_init(rsrc_devpath
, DINFOSUBTREE
| DINFOMINOR
);
218 if (node
== DI_NODE_NIL
) {
219 cfga_err(errstring
, 0, ERRARG_DEVINFO
, rsrc_fixed
, 0);
223 /* apply the filter, and suspend all resources not filtered out */
224 if (ret
== FPCFGA_OK
) {
226 walkargs
.bus_path
= rsrc_fixed
;
227 walkargs
.filter
= filter_fixed
;
228 walkargs
.errstring
= errstring
;
229 walkargs
.ret
= FPCFGA_OK
;
230 walkargs
.flags
= rflags
;
231 walkargs
.func
= fp_rcm_suspend
;
233 if (di_walk_node(node
, 0, &walkargs
, fp_rcm_process_node
) < 0)
234 cfga_err(errstring
, 0, ERRARG_DEVINFO
, rsrc_fixed
, 0);
239 if (node
!= DI_NODE_NIL
)
243 S_FREE(filter_fixed
);
245 if (ret
!= FPCFGA_OK
)
246 (void) fp_rcm_resume(rsrc
, filter
, errstring
,
247 (flags
& (~CFGA_FLAG_FORCE
)));
255 * Resume FP resource consumers after a bus has been unquiesced.
258 fp_rcm_resume(char *rsrc
, char *filter
, char **errstring
, cfga_flags_t flags
)
264 rcm_info_t
*rinfo
= NULL
;
266 fpcfga_ret_t ret
= FPCFGA_OK
;
269 if ((ret
= fp_rcm_init(rsrc
, flags
, errstring
, &rflags
, &rsrc_fixed
))
273 /* If a filter is provided, ensure that it makes sense */
274 if (filter
!= NULL
&& strstr(filter
, rsrc
) != filter
) {
276 cfga_err(errstring
, 0, ERR_APID_INVAL
, 0);
281 * If no filter is specified: resume the resource directly.
283 if (filter
== NULL
) {
284 if (rcm_notify_resume(rcm_handle
, rsrc_fixed
, rflags
, &rinfo
)
285 != RCM_SUCCESS
&& rinfo
!= NULL
) {
286 cfga_err(errstring
, 0, ERRARG_RCM_RESUME
, rsrc_fixed
,
288 (void) fp_rcm_info_table(rinfo
, errstring
);
289 rcm_free_info(rinfo
);
297 * If a filter is specified: open the resource with libdevinfo, walk
298 * through its nodes, and resume each of its nodes that mismatches
302 /* Chop off the filter's minor name */
303 if ((filter_fixed
= chop_minor(filter
)) == NULL
)
306 /* get a libdevinfo snapshot of the resource's subtree */
307 rsrc_devpath
= rsrc_fixed
;
308 if (strstr(rsrc_fixed
, DEVICES
) != NULL
)
309 rsrc_devpath
+= strlen(DEVICES
);
310 node
= di_init(rsrc_devpath
, DINFOSUBTREE
| DINFOMINOR
);
311 if (node
== DI_NODE_NIL
) {
312 cfga_err(errstring
, 0, ERRARG_DEVINFO
, rsrc_fixed
, 0);
316 /* apply the filter, and resume all resources not filtered out */
317 if (ret
== FPCFGA_OK
) {
319 walkargs
.bus_path
= rsrc_fixed
;
320 walkargs
.filter
= filter_fixed
;
321 walkargs
.errstring
= errstring
;
322 walkargs
.ret
= FPCFGA_OK
;
323 walkargs
.flags
= rflags
;
324 walkargs
.func
= fp_rcm_resume
;
326 if (di_walk_node(node
, 0, &walkargs
, fp_rcm_process_node
) < 0)
327 cfga_err(errstring
, 0, ERRARG_DEVINFO
, rsrc_fixed
, 0);
332 if (node
!= DI_NODE_NIL
)
336 S_FREE(filter_fixed
);
344 * Queries RCM information for resources, and formats it into a table.
345 * The table is appended to the info argument. If the info argument is a
346 * null pointer, then a new string is malloc'ed. If the info argument is
347 * not a null pointer, then it is realloc'ed to the required size.
350 fp_rcm_info(char *rsrc
, char **errstring
, char **info
)
353 rcm_info_t
*rinfo
= NULL
;
354 fpcfga_ret_t ret
= FPCFGA_OK
;
356 if ((ret
= fp_rcm_init(rsrc
, 0, errstring
, NULL
, &rsrc_fixed
))
365 if (rcm_get_info(rcm_handle
, rsrc_fixed
, 0, &rinfo
)
367 cfga_err(errstring
, 0, ERRARG_RCM_INFO
, rsrc_fixed
, 0);
369 } else if (rinfo
== NULL
)
373 if ((ret
= fp_rcm_info_table(rinfo
, info
)) != FPCFGA_OK
)
374 cfga_err(errstring
, 0, ERRARG_RCM_INFO
, rsrc_fixed
, 0);
375 rcm_free_info(rinfo
);
386 * Contains common initialization code for entering a fp_rcm_xx()
390 fp_rcm_init(char *rsrc
, cfga_flags_t flags
, char **errstring
, uint_t
*rflags
,
393 /* Validate the rsrc argument */
395 cfga_err(errstring
, 0, ERR_APID_INVAL
, 0);
399 /* Translate the cfgadm flags to RCM flags */
400 if (rflags
&& (flags
& CFGA_FLAG_FORCE
))
401 *rflags
|= RCM_FORCE
;
403 /* Get a handle for the RCM operations */
404 (void) mutex_lock(&rcm_handle_lock
);
405 if (rcm_handle
== NULL
) {
406 if (rcm_alloc_handle(NULL
, RCM_NOPID
, NULL
, &rcm_handle
) !=
408 cfga_err(errstring
, 0, ERR_RCM_HANDLE
, 0);
409 (void) mutex_unlock(&rcm_handle_lock
);
410 return (FPCFGA_LIB_ERR
);
413 (void) mutex_unlock(&rcm_handle_lock
);
415 /* Chop off the rsrc's minor, if it has one */
416 if ((*rsrc_fixed
= chop_minor(rsrc
)) == NULL
)
423 * fp_rcm_process_node
425 * Helper routine for fp_rcm_{suspend,resume}. This is a di_walk_node()
426 * callback that will apply a filter to every node it sees, and either suspend
427 * or resume it if it doesn't match the filter.
430 fp_rcm_process_node(di_node_t node
, void *argp
)
433 walkargs_t
*walkargs
;
434 fpcfga_ret_t ret
= FPCFGA_OK
;
435 char disk_path
[MAXPATHLEN
];
437 /* Guard against bad arguments */
438 if ((walkargs
= (walkargs_t
*)argp
) == NULL
)
439 return (DI_WALK_TERMINATE
);
440 if (walkargs
->filter
== NULL
|| walkargs
->errstring
== NULL
) {
441 walkargs
->ret
= FPCFGA_ERR
;
442 return (DI_WALK_TERMINATE
);
445 /* If the node has no minors, then skip it */
446 if (di_minor_next(node
, DI_MINOR_NIL
) == DI_MINOR_NIL
)
447 return (DI_WALK_CONTINUE
);
449 /* Construct the devices path */
450 if ((devfs_path
= di_devfs_path(node
)) == NULL
)
451 return (DI_WALK_CONTINUE
);
452 (void) snprintf(disk_path
, MAXPATHLEN
, "%s%s", DEVICES
, devfs_path
);
453 di_devfs_path_free(devfs_path
);
456 * If the node does not correspond to the targeted FP bus or the
457 * disk being filtered out, then use the appropriate suspend/resume
460 if (strcmp(disk_path
, walkargs
->bus_path
) != 0 &&
461 strcmp(disk_path
, walkargs
->filter
) != 0)
462 ret
= (*walkargs
->func
)(disk_path
, NULL
, walkargs
->errstring
,
465 /* Stop the walk early if the above operation failed */
466 if (ret
!= FPCFGA_OK
) {
468 return (DI_WALK_TERMINATE
);
471 return (DI_WALK_CONTINUE
);
477 * Takes an opaque rcm_info_t pointer and a character pointer, and appends
478 * the rcm_info_t data in the form of a table to the given character pointer.
481 fp_rcm_info_table(rcm_info_t
*rinfo
, char **table
)
488 size_t table_size
= 0;
490 rcm_info_tuple_t
*tuple
= NULL
;
494 static char format
[MAX_FORMAT
];
495 const char *info_info_str
, *info_rsrc_str
;
497 /* Protect against invalid arguments */
498 if (rinfo
== NULL
|| table
== NULL
)
501 /* Set localized table header strings */
502 rsrc
= gettext("Resource");
503 info
= gettext("Information");
505 /* A first pass, to size up the RCM information */
506 while (tuple
= rcm_info_next(rinfo
, tuple
)) {
507 info_info_str
= rcm_info_info(tuple
);
508 info_rsrc_str
= rcm_info_rsrc(tuple
);
509 if ((info_info_str
!= NULL
) && (info_rsrc_str
!= NULL
)) {
511 if ((w
= strlen(info_rsrc_str
)) > w_rsrc
)
513 if ((w
= strlen(info_info_str
)) > w_info
)
518 /* If nothing was sized up above, stop early */
522 /* Adjust column widths for column headings */
523 if ((w
= strlen(rsrc
)) > w_rsrc
)
525 else if ((w_rsrc
- w
) % 2)
527 if ((w
= strlen(info
)) > w_info
)
529 else if ((w_info
- w
) % 2)
533 * Compute the total line width of each line,
534 * accounting for intercolumn spacing.
536 width
= w_info
+ w_rsrc
+ 4;
538 /* Allocate space for the table */
539 table_size
= (2 + tuples
) * (width
+ 1) + 2;
541 *table
= malloc(table_size
);
543 newtable
= realloc(*table
, strlen(*table
) + table_size
);
544 if (newtable
!= NULL
)
550 /* Place a table header into the string */
552 /* The resource header */
553 (void) strcat(*table
, "\n");
555 for (i
= 0; i
< ((w_rsrc
- w
) / 2); i
++)
556 (void) strcat(*table
, " ");
557 (void) strcat(*table
, rsrc
);
558 for (i
= 0; i
< ((w_rsrc
- w
) / 2); i
++)
559 (void) strcat(*table
, " ");
561 /* The information header */
562 (void) strcat(*table
, " ");
564 for (i
= 0; i
< ((w_info
- w
) / 2); i
++)
565 (void) strcat(*table
, " ");
566 (void) strcat(*table
, info
);
567 for (i
= 0; i
< ((w_info
- w
) / 2); i
++)
568 (void) strcat(*table
, " ");
570 /* Underline the headers */
571 (void) strcat(*table
, "\n");
572 for (i
= 0; i
< w_rsrc
; i
++)
573 (void) strcat(*table
, "-");
574 (void) strcat(*table
, " ");
575 for (i
= 0; i
< w_info
; i
++)
576 (void) strcat(*table
, "-");
578 /* Construct the format string */
579 (void) snprintf(format
, MAX_FORMAT
, "%%-%ds %%-%ds", w_rsrc
, w_info
);
581 /* Add the tuples to the table string */
583 while ((tuple
= rcm_info_next(rinfo
, tuple
)) != NULL
) {
584 info_info_str
= rcm_info_info(tuple
);
585 info_rsrc_str
= rcm_info_rsrc(tuple
);
586 if ((info_info_str
!= NULL
) && (info_rsrc_str
!= NULL
)) {
587 (void) strcat(*table
, "\n");
588 (void) sprintf(&((*table
)[strlen(*table
)]),
589 format
, info_rsrc_str
, info_info_str
);
599 * Chops off the minor name portion of a resource. Allocates storage for
600 * the returned string. Caller must free the storage if return is non-NULL.
603 chop_minor(char *rsrc
)
608 if ((rsrc_fixed
= strdup(rsrc
)) == NULL
)
610 if ((cp
= strrchr(rsrc_fixed
, ':')) != NULL
)