dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / lib / cfgadm_plugins / fp / common / cfga_rcm.c
blob5fbf41c96b9358be45ae3e736a8bdc6546a0b33b
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 #include "cfga_fp.h"
29 static fpcfga_ret_t fp_rcm_init(char *, cfga_flags_t, char **, uint_t *,
30 char **rsrc_fixed);
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 *);
35 #define MAX_FORMAT 80
36 #define DEVICES "/devices"
38 typedef struct {
39 char *bus_path;
40 char *filter;
41 char **errstring;
42 fpcfga_ret_t ret;
43 cfga_flags_t flags;
44 fpcfga_ret_t (*func)(char *, char *, char **, cfga_flags_t);
45 } walkargs_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 *,
50 char **);
51 static char *chop_minor(char *);
53 static rcm_handle_t *rcm_handle = NULL;
54 static mutex_t rcm_handle_lock;
57 * fp_rcm_offline()
59 * Offline FP resource consumers.
61 fpcfga_ret_t
62 fp_rcm_offline(char *rsrc, char **errstring, cfga_flags_t flags)
64 int rret;
65 uint_t rflags = 0;
66 char *rsrc_fixed;
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))
71 != FPCFGA_OK)
72 return (ret);
74 if ((rret = rcm_request_offline(rcm_handle, rsrc_fixed, rflags, &rinfo))
75 != RCM_SUCCESS) {
76 cfga_err(errstring, 0, ERRARG_RCM_OFFLINE, rsrc_fixed, 0);
77 if (rinfo) {
78 (void) fp_rcm_info_table(rinfo, errstring);
79 rcm_free_info(rinfo);
81 if (rret == RCM_FAILURE)
82 (void) fp_rcm_online(rsrc, errstring, flags);
83 ret = FPCFGA_BUSY;
86 S_FREE(rsrc_fixed);
88 return (ret);
92 * fp_rcm_online()
94 * Online FP resource consumers that were previously offlined.
96 fpcfga_ret_t
97 fp_rcm_online(char *rsrc, char **errstring, cfga_flags_t flags)
99 char *rsrc_fixed;
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))
104 != FPCFGA_OK)
105 return (ret);
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);
112 ret = FPCFGA_ERR;
115 S_FREE(rsrc_fixed);
117 return (ret);
121 * fp_rcm_remove()
123 * Remove FP resource consumers after their kernel removal.
125 fpcfga_ret_t
126 fp_rcm_remove(char *rsrc, char **errstring, cfga_flags_t flags)
128 char *rsrc_fixed;
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))
133 != FPCFGA_OK)
134 return (ret);
136 if (rcm_notify_remove(rcm_handle, rsrc_fixed, 0, &rinfo)
137 != RCM_SUCCESS) {
138 cfga_err(errstring, 0, ERRARG_RCM_REMOVE, rsrc_fixed, 0);
139 if (rinfo) {
140 (void) fp_rcm_info_table(rinfo, errstring);
141 rcm_free_info(rinfo);
143 ret = FPCFGA_ERR;
146 S_FREE(rsrc_fixed);
148 return (ret);
152 * fp_rcm_suspend()
154 * Suspend FP resource consumers before a bus quiesce.
156 fpcfga_ret_t
157 fp_rcm_suspend(char *rsrc, char *filter, char **errstring, cfga_flags_t flags)
159 int rret;
160 uint_t rflags = 0;
161 char *rsrc_fixed;
162 char *filter_fixed;
163 char *rsrc_devpath;
164 rcm_info_t *rinfo = NULL;
165 di_node_t node;
166 fpcfga_ret_t ret = FPCFGA_OK;
167 walkargs_t walkargs;
168 timespec_t zerotime = { 0, 0 };
170 if ((ret = fp_rcm_init(rsrc, flags, errstring, &rflags, &rsrc_fixed))
171 != FPCFGA_OK)
172 return (ret);
174 /* If a filter is provided, ensure that it makes sense */
175 if (filter != NULL && strstr(filter, rsrc) != filter) {
176 S_FREE(rsrc_fixed);
177 cfga_err(errstring, 0, ERR_APID_INVAL, 0);
178 return (FPCFGA_ERR);
182 * If no filter is specified: attempt a suspension on the resource,
183 * directly.
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,
190 if (rinfo) {
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)));
197 ret = FPCFGA_BUSY;
199 S_FREE(rsrc_fixed);
200 return (ret);
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)
211 return (FPCFGA_ERR);
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);
220 ret = FPCFGA_ERR;
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);
236 ret = walkargs.ret;
239 if (node != DI_NODE_NIL)
240 di_fini(node);
242 S_FREE(rsrc_fixed);
243 S_FREE(filter_fixed);
245 if (ret != FPCFGA_OK)
246 (void) fp_rcm_resume(rsrc, filter, errstring,
247 (flags & (~CFGA_FLAG_FORCE)));
249 return (ret);
253 * fp_rcm_resume()
255 * Resume FP resource consumers after a bus has been unquiesced.
257 fpcfga_ret_t
258 fp_rcm_resume(char *rsrc, char *filter, char **errstring, cfga_flags_t flags)
260 uint_t rflags = 0;
261 char *rsrc_fixed;
262 char *filter_fixed;
263 char *rsrc_devpath;
264 rcm_info_t *rinfo = NULL;
265 di_node_t node;
266 fpcfga_ret_t ret = FPCFGA_OK;
267 walkargs_t walkargs;
269 if ((ret = fp_rcm_init(rsrc, flags, errstring, &rflags, &rsrc_fixed))
270 != FPCFGA_OK)
271 return (ret);
273 /* If a filter is provided, ensure that it makes sense */
274 if (filter != NULL && strstr(filter, rsrc) != filter) {
275 S_FREE(rsrc_fixed);
276 cfga_err(errstring, 0, ERR_APID_INVAL, 0);
277 return (FPCFGA_ERR);
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);
290 ret = FPCFGA_BUSY;
292 S_FREE(rsrc_fixed);
293 return (ret);
297 * If a filter is specified: open the resource with libdevinfo, walk
298 * through its nodes, and resume each of its nodes that mismatches
299 * the filter.
302 /* Chop off the filter's minor name */
303 if ((filter_fixed = chop_minor(filter)) == NULL)
304 return (FPCFGA_ERR);
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);
313 ret = FPCFGA_ERR;
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);
329 ret = walkargs.ret;
332 if (node != DI_NODE_NIL)
333 di_fini(node);
335 S_FREE(rsrc_fixed);
336 S_FREE(filter_fixed);
338 return (ret);
342 * fp_rcm_info
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.
349 fpcfga_ret_t
350 fp_rcm_info(char *rsrc, char **errstring, char **info)
352 char *rsrc_fixed;
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))
357 != FPCFGA_OK)
358 return (ret);
360 if (info == NULL) {
361 S_FREE(rsrc_fixed);
362 return (FPCFGA_ERR);
365 if (rcm_get_info(rcm_handle, rsrc_fixed, 0, &rinfo)
366 != RCM_SUCCESS) {
367 cfga_err(errstring, 0, ERRARG_RCM_INFO, rsrc_fixed, 0);
368 ret = FPCFGA_ERR;
369 } else if (rinfo == NULL)
370 ret = FPCFGA_OK;
372 if (rinfo) {
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);
378 S_FREE(rsrc_fixed);
380 return (ret);
384 * fp_rcm_init()
386 * Contains common initialization code for entering a fp_rcm_xx()
387 * routine.
389 static fpcfga_ret_t
390 fp_rcm_init(char *rsrc, cfga_flags_t flags, char **errstring, uint_t *rflags,
391 char **rsrc_fixed)
393 /* Validate the rsrc argument */
394 if (rsrc == NULL) {
395 cfga_err(errstring, 0, ERR_APID_INVAL, 0);
396 return (FPCFGA_ERR);
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) !=
407 RCM_SUCCESS) {
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)
417 return (FPCFGA_ERR);
419 return (FPCFGA_OK);
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.
429 static int
430 fp_rcm_process_node(di_node_t node, void *argp)
432 char *devfs_path;
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
458 * function.
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,
463 walkargs->flags);
465 /* Stop the walk early if the above operation failed */
466 if (ret != FPCFGA_OK) {
467 walkargs->ret = ret;
468 return (DI_WALK_TERMINATE);
471 return (DI_WALK_CONTINUE);
475 * fp_rcm_info_table
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.
480 static fpcfga_ret_t
481 fp_rcm_info_table(rcm_info_t *rinfo, char **table)
483 int i;
484 size_t w;
485 size_t width = 0;
486 size_t w_rsrc = 0;
487 size_t w_info = 0;
488 size_t table_size = 0;
489 uint_t tuples = 0;
490 rcm_info_tuple_t *tuple = NULL;
491 char *rsrc;
492 char *info;
493 char *newtable;
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)
499 return (FPCFGA_ERR);
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)) {
510 tuples++;
511 if ((w = strlen(info_rsrc_str)) > w_rsrc)
512 w_rsrc = w;
513 if ((w = strlen(info_info_str)) > w_info)
514 w_info = w;
518 /* If nothing was sized up above, stop early */
519 if (tuples == 0)
520 return (FPCFGA_OK);
522 /* Adjust column widths for column headings */
523 if ((w = strlen(rsrc)) > w_rsrc)
524 w_rsrc = w;
525 else if ((w_rsrc - w) % 2)
526 w_rsrc++;
527 if ((w = strlen(info)) > w_info)
528 w_info = w;
529 else if ((w_info - w) % 2)
530 w_info++;
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;
540 if (*table == NULL)
541 *table = malloc(table_size);
542 else {
543 newtable = realloc(*table, strlen(*table) + table_size);
544 if (newtable != NULL)
545 *table = newtable;
547 if (*table == NULL)
548 return (FPCFGA_ERR);
550 /* Place a table header into the string */
552 /* The resource header */
553 (void) strcat(*table, "\n");
554 w = strlen(rsrc);
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, " ");
563 w = strlen(info);
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 */
582 tuple = NULL;
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);
593 return (FPCFGA_OK);
597 * chop_minor()
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.
602 static char *
603 chop_minor(char *rsrc)
605 char *rsrc_fixed;
606 char *cp;
608 if ((rsrc_fixed = strdup(rsrc)) == NULL)
609 return (NULL);
610 if ((cp = strrchr(rsrc_fixed, ':')) != NULL)
611 *cp = '\0';
612 return (rsrc_fixed);