1*fcf3ce44SJohn Forte /*
2*fcf3ce44SJohn Forte  * CDDL HEADER START
3*fcf3ce44SJohn Forte  *
4*fcf3ce44SJohn Forte  * The contents of this file are subject to the terms of the
5*fcf3ce44SJohn Forte  * Common Development and Distribution License (the "License").
6*fcf3ce44SJohn Forte  * You may not use this file except in compliance with the License.
7*fcf3ce44SJohn Forte  *
8*fcf3ce44SJohn Forte  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*fcf3ce44SJohn Forte  * or http://www.opensolaris.org/os/licensing.
10*fcf3ce44SJohn Forte  * See the License for the specific language governing permissions
11*fcf3ce44SJohn Forte  * and limitations under the License.
12*fcf3ce44SJohn Forte  *
13*fcf3ce44SJohn Forte  * When distributing Covered Code, include this CDDL HEADER in each
14*fcf3ce44SJohn Forte  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*fcf3ce44SJohn Forte  * If applicable, add the following below this CDDL HEADER, with the
16*fcf3ce44SJohn Forte  * fields enclosed by brackets "[]" replaced with your own identifying
17*fcf3ce44SJohn Forte  * information: Portions Copyright [yyyy] [name of copyright owner]
18*fcf3ce44SJohn Forte  *
19*fcf3ce44SJohn Forte  * CDDL HEADER END
20*fcf3ce44SJohn Forte  */
21*fcf3ce44SJohn Forte /*
22*fcf3ce44SJohn Forte  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23*fcf3ce44SJohn Forte  * Use is subject to license terms.
24*fcf3ce44SJohn Forte  */
25*fcf3ce44SJohn Forte 
26*fcf3ce44SJohn Forte 
27*fcf3ce44SJohn Forte #include "cfga_fp.h"
28*fcf3ce44SJohn Forte 
29*fcf3ce44SJohn Forte static fpcfga_ret_t fp_rcm_init(char *, cfga_flags_t, char **, uint_t *,
30*fcf3ce44SJohn Forte 	char **rsrc_fixed);
31*fcf3ce44SJohn Forte static int fp_rcm_process_node(di_node_t, void *);
32*fcf3ce44SJohn Forte static fpcfga_ret_t fp_rcm_info_table(rcm_info_t *, char **);
33*fcf3ce44SJohn Forte static char *chop_minor(char *);
34*fcf3ce44SJohn Forte 
35*fcf3ce44SJohn Forte #define	MAX_FORMAT	80
36*fcf3ce44SJohn Forte #define	DEVICES		"/devices"
37*fcf3ce44SJohn Forte 
38*fcf3ce44SJohn Forte typedef struct {
39*fcf3ce44SJohn Forte 	char *bus_path;
40*fcf3ce44SJohn Forte 	char *filter;
41*fcf3ce44SJohn Forte 	char **errstring;
42*fcf3ce44SJohn Forte 	fpcfga_ret_t ret;
43*fcf3ce44SJohn Forte 	cfga_flags_t flags;
44*fcf3ce44SJohn Forte 	fpcfga_ret_t (*func)(char *, char *, char **, cfga_flags_t);
45*fcf3ce44SJohn Forte } walkargs_t;
46*fcf3ce44SJohn Forte 
47*fcf3ce44SJohn Forte static fpcfga_ret_t fp_rcm_info_table(rcm_info_t *, char **);
48*fcf3ce44SJohn Forte static int fp_rcm_process_node(di_node_t, void *);
49*fcf3ce44SJohn Forte static fpcfga_ret_t fp_rcm_init(char *, cfga_flags_t, char **, uint_t *,
50*fcf3ce44SJohn Forte     char **);
51*fcf3ce44SJohn Forte static char *chop_minor(char *);
52*fcf3ce44SJohn Forte 
53*fcf3ce44SJohn Forte static rcm_handle_t *rcm_handle = NULL;
54*fcf3ce44SJohn Forte static mutex_t rcm_handle_lock;
55*fcf3ce44SJohn Forte 
56*fcf3ce44SJohn Forte /*
57*fcf3ce44SJohn Forte  * fp_rcm_offline()
58*fcf3ce44SJohn Forte  *
59*fcf3ce44SJohn Forte  *	Offline FP resource consumers.
60*fcf3ce44SJohn Forte  */
61*fcf3ce44SJohn Forte fpcfga_ret_t
fp_rcm_offline(char * rsrc,char ** errstring,cfga_flags_t flags)62*fcf3ce44SJohn Forte fp_rcm_offline(char *rsrc, char **errstring, cfga_flags_t flags)
63*fcf3ce44SJohn Forte {
64*fcf3ce44SJohn Forte 	int rret;
65*fcf3ce44SJohn Forte 	uint_t rflags = 0;
66*fcf3ce44SJohn Forte 	char *rsrc_fixed;
67*fcf3ce44SJohn Forte 	rcm_info_t *rinfo = NULL;
68*fcf3ce44SJohn Forte 	fpcfga_ret_t ret = FPCFGA_OK;
69*fcf3ce44SJohn Forte 
70*fcf3ce44SJohn Forte 	if ((ret = fp_rcm_init(rsrc, flags, errstring, &rflags, &rsrc_fixed))
71*fcf3ce44SJohn Forte 	    != FPCFGA_OK)
72*fcf3ce44SJohn Forte 		return (ret);
73*fcf3ce44SJohn Forte 
74*fcf3ce44SJohn Forte 	if ((rret = rcm_request_offline(rcm_handle, rsrc_fixed, rflags, &rinfo))
75*fcf3ce44SJohn Forte 	    != RCM_SUCCESS) {
76*fcf3ce44SJohn Forte 		cfga_err(errstring, 0, ERRARG_RCM_OFFLINE, rsrc_fixed, 0);
77*fcf3ce44SJohn Forte 		if (rinfo) {
78*fcf3ce44SJohn Forte 			(void) fp_rcm_info_table(rinfo, errstring);
79*fcf3ce44SJohn Forte 			rcm_free_info(rinfo);
80*fcf3ce44SJohn Forte 		}
81*fcf3ce44SJohn Forte 		if (rret == RCM_FAILURE)
82*fcf3ce44SJohn Forte 			(void) fp_rcm_online(rsrc, errstring, flags);
83*fcf3ce44SJohn Forte 		ret = FPCFGA_BUSY;
84*fcf3ce44SJohn Forte 	}
85*fcf3ce44SJohn Forte 
86*fcf3ce44SJohn Forte 	S_FREE(rsrc_fixed);
87*fcf3ce44SJohn Forte 
88*fcf3ce44SJohn Forte 	return (ret);
89*fcf3ce44SJohn Forte }
90*fcf3ce44SJohn Forte 
91*fcf3ce44SJohn Forte /*
92*fcf3ce44SJohn Forte  * fp_rcm_online()
93*fcf3ce44SJohn Forte  *
94*fcf3ce44SJohn Forte  *	Online FP resource consumers that were previously offlined.
95*fcf3ce44SJohn Forte  */
96*fcf3ce44SJohn Forte fpcfga_ret_t
fp_rcm_online(char * rsrc,char ** errstring,cfga_flags_t flags)97*fcf3ce44SJohn Forte fp_rcm_online(char *rsrc, char **errstring, cfga_flags_t flags)
98*fcf3ce44SJohn Forte {
99*fcf3ce44SJohn Forte 	char *rsrc_fixed;
100*fcf3ce44SJohn Forte 	rcm_info_t *rinfo = NULL;
101*fcf3ce44SJohn Forte 	fpcfga_ret_t ret = FPCFGA_OK;
102*fcf3ce44SJohn Forte 
103*fcf3ce44SJohn Forte 	if ((ret = fp_rcm_init(rsrc, flags, errstring, NULL, &rsrc_fixed))
104*fcf3ce44SJohn Forte 	    != FPCFGA_OK)
105*fcf3ce44SJohn Forte 		return (ret);
106*fcf3ce44SJohn Forte 
107*fcf3ce44SJohn Forte 	if (rcm_notify_online(rcm_handle, rsrc_fixed, 0, &rinfo)
108*fcf3ce44SJohn Forte 	    != RCM_SUCCESS && rinfo != NULL) {
109*fcf3ce44SJohn Forte 		cfga_err(errstring, 0, ERRARG_RCM_ONLINE, rsrc_fixed, 0);
110*fcf3ce44SJohn Forte 		(void) fp_rcm_info_table(rinfo, errstring);
111*fcf3ce44SJohn Forte 		rcm_free_info(rinfo);
112*fcf3ce44SJohn Forte 		ret = FPCFGA_ERR;
113*fcf3ce44SJohn Forte 	}
114*fcf3ce44SJohn Forte 
115*fcf3ce44SJohn Forte 	S_FREE(rsrc_fixed);
116*fcf3ce44SJohn Forte 
117*fcf3ce44SJohn Forte 	return (ret);
118*fcf3ce44SJohn Forte }
119*fcf3ce44SJohn Forte 
120*fcf3ce44SJohn Forte /*
121*fcf3ce44SJohn Forte  * fp_rcm_remove()
122*fcf3ce44SJohn Forte  *
123*fcf3ce44SJohn Forte  *	Remove FP resource consumers after their kernel removal.
124*fcf3ce44SJohn Forte  */
125*fcf3ce44SJohn Forte fpcfga_ret_t
fp_rcm_remove(char * rsrc,char ** errstring,cfga_flags_t flags)126*fcf3ce44SJohn Forte fp_rcm_remove(char *rsrc, char **errstring, cfga_flags_t flags)
127*fcf3ce44SJohn Forte {
128*fcf3ce44SJohn Forte 	char *rsrc_fixed;
129*fcf3ce44SJohn Forte 	rcm_info_t *rinfo = NULL;
130*fcf3ce44SJohn Forte 	fpcfga_ret_t ret = FPCFGA_OK;
131*fcf3ce44SJohn Forte 
132*fcf3ce44SJohn Forte 	if ((ret = fp_rcm_init(rsrc, flags, errstring, NULL, &rsrc_fixed))
133*fcf3ce44SJohn Forte 	    != FPCFGA_OK)
134*fcf3ce44SJohn Forte 		return (ret);
135*fcf3ce44SJohn Forte 
136*fcf3ce44SJohn Forte 	if (rcm_notify_remove(rcm_handle, rsrc_fixed, 0, &rinfo)
137*fcf3ce44SJohn Forte 	    != RCM_SUCCESS) {
138*fcf3ce44SJohn Forte 		cfga_err(errstring, 0, ERRARG_RCM_REMOVE, rsrc_fixed, 0);
139*fcf3ce44SJohn Forte 		if (rinfo) {
140*fcf3ce44SJohn Forte 			(void) fp_rcm_info_table(rinfo, errstring);
141*fcf3ce44SJohn Forte 			rcm_free_info(rinfo);
142*fcf3ce44SJohn Forte 		}
143*fcf3ce44SJohn Forte 		ret = FPCFGA_ERR;
144*fcf3ce44SJohn Forte 	}
145*fcf3ce44SJohn Forte 
146*fcf3ce44SJohn Forte 	S_FREE(rsrc_fixed);
147*fcf3ce44SJohn Forte 
148*fcf3ce44SJohn Forte 	return (ret);
149*fcf3ce44SJohn Forte }
150*fcf3ce44SJohn Forte 
151*fcf3ce44SJohn Forte /*
152*fcf3ce44SJohn Forte  * fp_rcm_suspend()
153*fcf3ce44SJohn Forte  *
154*fcf3ce44SJohn Forte  *	Suspend FP resource consumers before a bus quiesce.
155*fcf3ce44SJohn Forte  */
156*fcf3ce44SJohn Forte fpcfga_ret_t
fp_rcm_suspend(char * rsrc,char * filter,char ** errstring,cfga_flags_t flags)157*fcf3ce44SJohn Forte fp_rcm_suspend(char *rsrc, char *filter, char **errstring, cfga_flags_t flags)
158*fcf3ce44SJohn Forte {
159*fcf3ce44SJohn Forte 	int rret;
160*fcf3ce44SJohn Forte 	uint_t rflags = 0;
161*fcf3ce44SJohn Forte 	char *rsrc_fixed;
162*fcf3ce44SJohn Forte 	char *filter_fixed;
163*fcf3ce44SJohn Forte 	char *rsrc_devpath;
164*fcf3ce44SJohn Forte 	rcm_info_t *rinfo = NULL;
165*fcf3ce44SJohn Forte 	di_node_t node;
166*fcf3ce44SJohn Forte 	fpcfga_ret_t ret = FPCFGA_OK;
167*fcf3ce44SJohn Forte 	walkargs_t walkargs;
168*fcf3ce44SJohn Forte 	timespec_t zerotime = { 0, 0 };
169*fcf3ce44SJohn Forte 
170*fcf3ce44SJohn Forte 	if ((ret = fp_rcm_init(rsrc, flags, errstring, &rflags, &rsrc_fixed))
171*fcf3ce44SJohn Forte 	    != FPCFGA_OK)
172*fcf3ce44SJohn Forte 		return (ret);
173*fcf3ce44SJohn Forte 
174*fcf3ce44SJohn Forte 	/* If a filter is provided, ensure that it makes sense */
175*fcf3ce44SJohn Forte 	if (filter != NULL && strstr(filter, rsrc) != filter) {
176*fcf3ce44SJohn Forte 		S_FREE(rsrc_fixed);
177*fcf3ce44SJohn Forte 		cfga_err(errstring, 0, ERR_APID_INVAL, 0);
178*fcf3ce44SJohn Forte 		return (FPCFGA_ERR);
179*fcf3ce44SJohn Forte 	}
180*fcf3ce44SJohn Forte 
181*fcf3ce44SJohn Forte 	/*
182*fcf3ce44SJohn Forte 	 * If no filter is specified: attempt a suspension on the resource,
183*fcf3ce44SJohn Forte 	 * directly.
184*fcf3ce44SJohn Forte 	 */
185*fcf3ce44SJohn Forte 	if (filter == NULL) {
186*fcf3ce44SJohn Forte 		if ((rret = rcm_request_suspend(rcm_handle, rsrc_fixed, rflags,
187*fcf3ce44SJohn Forte 		    &zerotime, &rinfo)) != RCM_SUCCESS) {
188*fcf3ce44SJohn Forte 			cfga_err(errstring, 0, ERRARG_RCM_SUSPEND, rsrc_fixed,
189*fcf3ce44SJohn Forte 			    0);
190*fcf3ce44SJohn Forte 			if (rinfo) {
191*fcf3ce44SJohn Forte 				(void) fp_rcm_info_table(rinfo, errstring);
192*fcf3ce44SJohn Forte 				rcm_free_info(rinfo);
193*fcf3ce44SJohn Forte 			}
194*fcf3ce44SJohn Forte 			if (rret == RCM_FAILURE)
195*fcf3ce44SJohn Forte 				(void) fp_rcm_resume(rsrc, filter, errstring,
196*fcf3ce44SJohn Forte 				    (flags & (~CFGA_FLAG_FORCE)));
197*fcf3ce44SJohn Forte 			ret = FPCFGA_BUSY;
198*fcf3ce44SJohn Forte 		}
199*fcf3ce44SJohn Forte 		S_FREE(rsrc_fixed);
200*fcf3ce44SJohn Forte 		return (ret);
201*fcf3ce44SJohn Forte 	}
202*fcf3ce44SJohn Forte 
203*fcf3ce44SJohn Forte 	/*
204*fcf3ce44SJohn Forte 	 * If a filter is specified: open the resource with libdevinfo, walk
205*fcf3ce44SJohn Forte 	 * through its nodes, and attempt a suspension of each node that
206*fcf3ce44SJohn Forte 	 * mismatches the filter.
207*fcf3ce44SJohn Forte 	 */
208*fcf3ce44SJohn Forte 
209*fcf3ce44SJohn Forte 	/* Chop off the filter's minor name */
210*fcf3ce44SJohn Forte 	if ((filter_fixed = chop_minor(filter)) == NULL)
211*fcf3ce44SJohn Forte 		return (FPCFGA_ERR);
212*fcf3ce44SJohn Forte 
213*fcf3ce44SJohn Forte 	/* get a libdevinfo snapshot of the resource's subtree */
214*fcf3ce44SJohn Forte 	rsrc_devpath = rsrc_fixed;
215*fcf3ce44SJohn Forte 	if (strstr(rsrc_fixed, DEVICES) != NULL)
216*fcf3ce44SJohn Forte 		rsrc_devpath += strlen(DEVICES);
217*fcf3ce44SJohn Forte 	node = di_init(rsrc_devpath, DINFOSUBTREE | DINFOMINOR);
218*fcf3ce44SJohn Forte 	if (node == DI_NODE_NIL) {
219*fcf3ce44SJohn Forte 		cfga_err(errstring, 0, ERRARG_DEVINFO, rsrc_fixed, 0);
220*fcf3ce44SJohn Forte 		ret = FPCFGA_ERR;
221*fcf3ce44SJohn Forte 	}
222*fcf3ce44SJohn Forte 
223*fcf3ce44SJohn Forte 	/* apply the filter, and suspend all resources not filtered out */
224*fcf3ce44SJohn Forte 	if (ret == FPCFGA_OK) {
225*fcf3ce44SJohn Forte 
226*fcf3ce44SJohn Forte 		walkargs.bus_path = rsrc_fixed;
227*fcf3ce44SJohn Forte 		walkargs.filter = filter_fixed;
228*fcf3ce44SJohn Forte 		walkargs.errstring = errstring;
229*fcf3ce44SJohn Forte 		walkargs.ret = FPCFGA_OK;
230*fcf3ce44SJohn Forte 		walkargs.flags = rflags;
231*fcf3ce44SJohn Forte 		walkargs.func = fp_rcm_suspend;
232*fcf3ce44SJohn Forte 
233*fcf3ce44SJohn Forte 		if (di_walk_node(node, 0, &walkargs, fp_rcm_process_node) < 0)
234*fcf3ce44SJohn Forte 			cfga_err(errstring, 0, ERRARG_DEVINFO, rsrc_fixed, 0);
235*fcf3ce44SJohn Forte 
236*fcf3ce44SJohn Forte 		ret = walkargs.ret;
237*fcf3ce44SJohn Forte 	}
238*fcf3ce44SJohn Forte 
239*fcf3ce44SJohn Forte 	if (node != DI_NODE_NIL)
240*fcf3ce44SJohn Forte 		di_fini(node);
241*fcf3ce44SJohn Forte 
242*fcf3ce44SJohn Forte 	S_FREE(rsrc_fixed);
243*fcf3ce44SJohn Forte 	S_FREE(filter_fixed);
244*fcf3ce44SJohn Forte 
245*fcf3ce44SJohn Forte 	if (ret != FPCFGA_OK)
246*fcf3ce44SJohn Forte 		(void) fp_rcm_resume(rsrc, filter, errstring,
247*fcf3ce44SJohn Forte 		    (flags & (~CFGA_FLAG_FORCE)));
248*fcf3ce44SJohn Forte 
249*fcf3ce44SJohn Forte 	return (ret);
250*fcf3ce44SJohn Forte }
251*fcf3ce44SJohn Forte 
252*fcf3ce44SJohn Forte /*
253*fcf3ce44SJohn Forte  * fp_rcm_resume()
254*fcf3ce44SJohn Forte  *
255*fcf3ce44SJohn Forte  *	Resume FP resource consumers after a bus has been unquiesced.
256*fcf3ce44SJohn Forte  */
257*fcf3ce44SJohn Forte fpcfga_ret_t
fp_rcm_resume(char * rsrc,char * filter,char ** errstring,cfga_flags_t flags)258*fcf3ce44SJohn Forte fp_rcm_resume(char *rsrc, char *filter, char **errstring, cfga_flags_t flags)
259*fcf3ce44SJohn Forte {
260*fcf3ce44SJohn Forte 	uint_t rflags = 0;
261*fcf3ce44SJohn Forte 	char *rsrc_fixed;
262*fcf3ce44SJohn Forte 	char *filter_fixed;
263*fcf3ce44SJohn Forte 	char *rsrc_devpath;
264*fcf3ce44SJohn Forte 	rcm_info_t *rinfo = NULL;
265*fcf3ce44SJohn Forte 	di_node_t node;
266*fcf3ce44SJohn Forte 	fpcfga_ret_t ret = FPCFGA_OK;
267*fcf3ce44SJohn Forte 	walkargs_t walkargs;
268*fcf3ce44SJohn Forte 
269*fcf3ce44SJohn Forte 	if ((ret = fp_rcm_init(rsrc, flags, errstring, &rflags, &rsrc_fixed))
270*fcf3ce44SJohn Forte 	    != FPCFGA_OK)
271*fcf3ce44SJohn Forte 		return (ret);
272*fcf3ce44SJohn Forte 
273*fcf3ce44SJohn Forte 	/* If a filter is provided, ensure that it makes sense */
274*fcf3ce44SJohn Forte 	if (filter != NULL && strstr(filter, rsrc) != filter) {
275*fcf3ce44SJohn Forte 		S_FREE(rsrc_fixed);
276*fcf3ce44SJohn Forte 		cfga_err(errstring, 0, ERR_APID_INVAL, 0);
277*fcf3ce44SJohn Forte 		return (FPCFGA_ERR);
278*fcf3ce44SJohn Forte 	}
279*fcf3ce44SJohn Forte 
280*fcf3ce44SJohn Forte 	/*
281*fcf3ce44SJohn Forte 	 * If no filter is specified: resume the resource directly.
282*fcf3ce44SJohn Forte 	 */
283*fcf3ce44SJohn Forte 	if (filter == NULL) {
284*fcf3ce44SJohn Forte 		if (rcm_notify_resume(rcm_handle, rsrc_fixed, rflags, &rinfo)
285*fcf3ce44SJohn Forte 		    != RCM_SUCCESS && rinfo != NULL) {
286*fcf3ce44SJohn Forte 			cfga_err(errstring, 0, ERRARG_RCM_RESUME, rsrc_fixed,
287*fcf3ce44SJohn Forte 			    0);
288*fcf3ce44SJohn Forte 			(void) fp_rcm_info_table(rinfo, errstring);
289*fcf3ce44SJohn Forte 			rcm_free_info(rinfo);
290*fcf3ce44SJohn Forte 			ret = FPCFGA_BUSY;
291*fcf3ce44SJohn Forte 		}
292*fcf3ce44SJohn Forte 		S_FREE(rsrc_fixed);
293*fcf3ce44SJohn Forte 		return (ret);
294*fcf3ce44SJohn Forte 	}
295*fcf3ce44SJohn Forte 
296*fcf3ce44SJohn Forte 	/*
297*fcf3ce44SJohn Forte 	 * If a filter is specified: open the resource with libdevinfo, walk
298*fcf3ce44SJohn Forte 	 * through its nodes, and resume each of its nodes that mismatches
299*fcf3ce44SJohn Forte 	 * the filter.
300*fcf3ce44SJohn Forte 	 */
301*fcf3ce44SJohn Forte 
302*fcf3ce44SJohn Forte 	/* Chop off the filter's minor name */
303*fcf3ce44SJohn Forte 	if ((filter_fixed = chop_minor(filter)) == NULL)
304*fcf3ce44SJohn Forte 		return (FPCFGA_ERR);
305*fcf3ce44SJohn Forte 
306*fcf3ce44SJohn Forte 	/* get a libdevinfo snapshot of the resource's subtree */
307*fcf3ce44SJohn Forte 	rsrc_devpath = rsrc_fixed;
308*fcf3ce44SJohn Forte 	if (strstr(rsrc_fixed, DEVICES) != NULL)
309*fcf3ce44SJohn Forte 		rsrc_devpath += strlen(DEVICES);
310*fcf3ce44SJohn Forte 	node = di_init(rsrc_devpath, DINFOSUBTREE | DINFOMINOR);
311*fcf3ce44SJohn Forte 	if (node == DI_NODE_NIL) {
312*fcf3ce44SJohn Forte 		cfga_err(errstring, 0, ERRARG_DEVINFO, rsrc_fixed, 0);
313*fcf3ce44SJohn Forte 		ret = FPCFGA_ERR;
314*fcf3ce44SJohn Forte 	}
315*fcf3ce44SJohn Forte 
316*fcf3ce44SJohn Forte 	/* apply the filter, and resume all resources not filtered out */
317*fcf3ce44SJohn Forte 	if (ret == FPCFGA_OK) {
318*fcf3ce44SJohn Forte 
319*fcf3ce44SJohn Forte 		walkargs.bus_path = rsrc_fixed;
320*fcf3ce44SJohn Forte 		walkargs.filter = filter_fixed;
321*fcf3ce44SJohn Forte 		walkargs.errstring = errstring;
322*fcf3ce44SJohn Forte 		walkargs.ret = FPCFGA_OK;
323*fcf3ce44SJohn Forte 		walkargs.flags = rflags;
324*fcf3ce44SJohn Forte 		walkargs.func = fp_rcm_resume;
325*fcf3ce44SJohn Forte 
326*fcf3ce44SJohn Forte 		if (di_walk_node(node, 0, &walkargs, fp_rcm_process_node) < 0)
327*fcf3ce44SJohn Forte 			cfga_err(errstring, 0, ERRARG_DEVINFO, rsrc_fixed, 0);
328*fcf3ce44SJohn Forte 
329*fcf3ce44SJohn Forte 		ret = walkargs.ret;
330*fcf3ce44SJohn Forte 	}
331*fcf3ce44SJohn Forte 
332*fcf3ce44SJohn Forte 	if (node != DI_NODE_NIL)
333*fcf3ce44SJohn Forte 		di_fini(node);
334*fcf3ce44SJohn Forte 
335*fcf3ce44SJohn Forte 	S_FREE(rsrc_fixed);
336*fcf3ce44SJohn Forte 	S_FREE(filter_fixed);
337*fcf3ce44SJohn Forte 
338*fcf3ce44SJohn Forte 	return (ret);
339*fcf3ce44SJohn Forte }
340*fcf3ce44SJohn Forte 
341*fcf3ce44SJohn Forte /*
342*fcf3ce44SJohn Forte  * fp_rcm_info
343*fcf3ce44SJohn Forte  *
344*fcf3ce44SJohn Forte  *	Queries RCM information for resources, and formats it into a table.
345*fcf3ce44SJohn Forte  * The table is appended to the info argument.  If the info argument is a
346*fcf3ce44SJohn Forte  * null pointer, then a new string is malloc'ed.  If the info argument is
347*fcf3ce44SJohn Forte  * not a null pointer, then it is realloc'ed to the required size.
348*fcf3ce44SJohn Forte  */
349*fcf3ce44SJohn Forte fpcfga_ret_t
fp_rcm_info(char * rsrc,char ** errstring,char ** info)350*fcf3ce44SJohn Forte fp_rcm_info(char *rsrc, char **errstring, char **info)
351*fcf3ce44SJohn Forte {
352*fcf3ce44SJohn Forte 	char *rsrc_fixed;
353*fcf3ce44SJohn Forte 	rcm_info_t *rinfo = NULL;
354*fcf3ce44SJohn Forte 	fpcfga_ret_t ret = FPCFGA_OK;
355*fcf3ce44SJohn Forte 
356*fcf3ce44SJohn Forte 	if ((ret = fp_rcm_init(rsrc, 0, errstring, NULL, &rsrc_fixed))
357*fcf3ce44SJohn Forte 	    != FPCFGA_OK)
358*fcf3ce44SJohn Forte 		return (ret);
359*fcf3ce44SJohn Forte 
360*fcf3ce44SJohn Forte 	if (info == NULL) {
361*fcf3ce44SJohn Forte 		S_FREE(rsrc_fixed);
362*fcf3ce44SJohn Forte 		return (FPCFGA_ERR);
363*fcf3ce44SJohn Forte 	}
364*fcf3ce44SJohn Forte 
365*fcf3ce44SJohn Forte 	if (rcm_get_info(rcm_handle, rsrc_fixed, 0, &rinfo)
366*fcf3ce44SJohn Forte 	    != RCM_SUCCESS) {
367*fcf3ce44SJohn Forte 		cfga_err(errstring, 0, ERRARG_RCM_INFO, rsrc_fixed, 0);
368*fcf3ce44SJohn Forte 		ret = FPCFGA_ERR;
369*fcf3ce44SJohn Forte 	} else if (rinfo == NULL)
370*fcf3ce44SJohn Forte 		ret = FPCFGA_OK;
371*fcf3ce44SJohn Forte 
372*fcf3ce44SJohn Forte 	if (rinfo) {
373*fcf3ce44SJohn Forte 		if ((ret = fp_rcm_info_table(rinfo, info)) != FPCFGA_OK)
374*fcf3ce44SJohn Forte 			cfga_err(errstring, 0, ERRARG_RCM_INFO, rsrc_fixed, 0);
375*fcf3ce44SJohn Forte 		rcm_free_info(rinfo);
376*fcf3ce44SJohn Forte 	}
377*fcf3ce44SJohn Forte 
378*fcf3ce44SJohn Forte 	S_FREE(rsrc_fixed);
379*fcf3ce44SJohn Forte 
380*fcf3ce44SJohn Forte 	return (ret);
381*fcf3ce44SJohn Forte }
382*fcf3ce44SJohn Forte 
383*fcf3ce44SJohn Forte /*
384*fcf3ce44SJohn Forte  * fp_rcm_init()
385*fcf3ce44SJohn Forte  *
386*fcf3ce44SJohn Forte  *	Contains common initialization code for entering a fp_rcm_xx()
387*fcf3ce44SJohn Forte  * routine.
388*fcf3ce44SJohn Forte  */
389*fcf3ce44SJohn Forte static fpcfga_ret_t
fp_rcm_init(char * rsrc,cfga_flags_t flags,char ** errstring,uint_t * rflags,char ** rsrc_fixed)390*fcf3ce44SJohn Forte fp_rcm_init(char *rsrc, cfga_flags_t flags, char **errstring, uint_t *rflags,
391*fcf3ce44SJohn Forte 	char **rsrc_fixed)
392*fcf3ce44SJohn Forte {
393*fcf3ce44SJohn Forte 	/* Validate the rsrc argument */
394*fcf3ce44SJohn Forte 	if (rsrc == NULL) {
395*fcf3ce44SJohn Forte 		cfga_err(errstring, 0, ERR_APID_INVAL, 0);
396*fcf3ce44SJohn Forte 		return (FPCFGA_ERR);
397*fcf3ce44SJohn Forte 	}
398*fcf3ce44SJohn Forte 
399*fcf3ce44SJohn Forte 	/* Translate the cfgadm flags to RCM flags */
400*fcf3ce44SJohn Forte 	if (rflags && (flags & CFGA_FLAG_FORCE))
401*fcf3ce44SJohn Forte 		*rflags |= RCM_FORCE;
402*fcf3ce44SJohn Forte 
403*fcf3ce44SJohn Forte 	/* Get a handle for the RCM operations */
404*fcf3ce44SJohn Forte 	(void) mutex_lock(&rcm_handle_lock);
405*fcf3ce44SJohn Forte 	if (rcm_handle == NULL) {
406*fcf3ce44SJohn Forte 		if (rcm_alloc_handle(NULL, RCM_NOPID, NULL, &rcm_handle) !=
407*fcf3ce44SJohn Forte 		    RCM_SUCCESS) {
408*fcf3ce44SJohn Forte 			cfga_err(errstring, 0, ERR_RCM_HANDLE, 0);
409*fcf3ce44SJohn Forte 			(void) mutex_unlock(&rcm_handle_lock);
410*fcf3ce44SJohn Forte 			return (FPCFGA_LIB_ERR);
411*fcf3ce44SJohn Forte 		}
412*fcf3ce44SJohn Forte 	}
413*fcf3ce44SJohn Forte 	(void) mutex_unlock(&rcm_handle_lock);
414*fcf3ce44SJohn Forte 
415*fcf3ce44SJohn Forte 	/* Chop off the rsrc's minor, if it has one */
416*fcf3ce44SJohn Forte 	if ((*rsrc_fixed = chop_minor(rsrc)) == NULL)
417*fcf3ce44SJohn Forte 		return (FPCFGA_ERR);
418*fcf3ce44SJohn Forte 
419*fcf3ce44SJohn Forte 	return (FPCFGA_OK);
420*fcf3ce44SJohn Forte }
421*fcf3ce44SJohn Forte 
422*fcf3ce44SJohn Forte /*
423*fcf3ce44SJohn Forte  * fp_rcm_process_node
424*fcf3ce44SJohn Forte  *
425*fcf3ce44SJohn Forte  *	Helper routine for fp_rcm_{suspend,resume}.  This is a di_walk_node()
426*fcf3ce44SJohn Forte  * callback that will apply a filter to every node it sees, and either suspend
427*fcf3ce44SJohn Forte  * or resume it if it doesn't match the filter.
428*fcf3ce44SJohn Forte  */
429*fcf3ce44SJohn Forte static int
fp_rcm_process_node(di_node_t node,void * argp)430*fcf3ce44SJohn Forte fp_rcm_process_node(di_node_t node, void *argp)
431*fcf3ce44SJohn Forte {
432*fcf3ce44SJohn Forte 	char *devfs_path;
433*fcf3ce44SJohn Forte 	walkargs_t *walkargs;
434*fcf3ce44SJohn Forte 	fpcfga_ret_t ret = FPCFGA_OK;
435*fcf3ce44SJohn Forte 	char disk_path[MAXPATHLEN];
436*fcf3ce44SJohn Forte 
437*fcf3ce44SJohn Forte 	/* Guard against bad arguments */
438*fcf3ce44SJohn Forte 	if ((walkargs = (walkargs_t *)argp) == NULL)
439*fcf3ce44SJohn Forte 		return (DI_WALK_TERMINATE);
440*fcf3ce44SJohn Forte 	if (walkargs->filter == NULL || walkargs->errstring == NULL) {
441*fcf3ce44SJohn Forte 		walkargs->ret = FPCFGA_ERR;
442*fcf3ce44SJohn Forte 		return (DI_WALK_TERMINATE);
443*fcf3ce44SJohn Forte 	}
444*fcf3ce44SJohn Forte 
445*fcf3ce44SJohn Forte 	/* If the node has no minors, then skip it */
446*fcf3ce44SJohn Forte 	if (di_minor_next(node, DI_MINOR_NIL) == DI_MINOR_NIL)
447*fcf3ce44SJohn Forte 		return (DI_WALK_CONTINUE);
448*fcf3ce44SJohn Forte 
449*fcf3ce44SJohn Forte 	/* Construct the devices path */
450*fcf3ce44SJohn Forte 	if ((devfs_path = di_devfs_path(node)) == NULL)
451*fcf3ce44SJohn Forte 		return (DI_WALK_CONTINUE);
452*fcf3ce44SJohn Forte 	(void) snprintf(disk_path, MAXPATHLEN, "%s%s", DEVICES, devfs_path);
453*fcf3ce44SJohn Forte 	di_devfs_path_free(devfs_path);
454*fcf3ce44SJohn Forte 
455*fcf3ce44SJohn Forte 	/*
456*fcf3ce44SJohn Forte 	 * If the node does not correspond to the targeted FP bus or the
457*fcf3ce44SJohn Forte 	 * disk being filtered out, then use the appropriate suspend/resume
458*fcf3ce44SJohn Forte 	 * function.
459*fcf3ce44SJohn Forte 	 */
460*fcf3ce44SJohn Forte 	if (strcmp(disk_path, walkargs->bus_path) != 0 &&
461*fcf3ce44SJohn Forte 	    strcmp(disk_path, walkargs->filter) != 0)
462*fcf3ce44SJohn Forte 		ret = (*walkargs->func)(disk_path, NULL, walkargs->errstring,
463*fcf3ce44SJohn Forte 		    walkargs->flags);
464*fcf3ce44SJohn Forte 
465*fcf3ce44SJohn Forte 	/* Stop the walk early if the above operation failed */
466*fcf3ce44SJohn Forte 	if (ret != FPCFGA_OK) {
467*fcf3ce44SJohn Forte 		walkargs->ret = ret;
468*fcf3ce44SJohn Forte 		return (DI_WALK_TERMINATE);
469*fcf3ce44SJohn Forte 	}
470*fcf3ce44SJohn Forte 
471*fcf3ce44SJohn Forte 	return (DI_WALK_CONTINUE);
472*fcf3ce44SJohn Forte }
473*fcf3ce44SJohn Forte 
474*fcf3ce44SJohn Forte /*
475*fcf3ce44SJohn Forte  * fp_rcm_info_table
476*fcf3ce44SJohn Forte  *
477*fcf3ce44SJohn Forte  *	Takes an opaque rcm_info_t pointer and a character pointer, and appends
478*fcf3ce44SJohn Forte  * the rcm_info_t data in the form of a table to the given character pointer.
479*fcf3ce44SJohn Forte  */
480*fcf3ce44SJohn Forte static fpcfga_ret_t
fp_rcm_info_table(rcm_info_t * rinfo,char ** table)481*fcf3ce44SJohn Forte fp_rcm_info_table(rcm_info_t *rinfo, char **table)
482*fcf3ce44SJohn Forte {
483*fcf3ce44SJohn Forte 	int i;
484*fcf3ce44SJohn Forte 	size_t w;
485*fcf3ce44SJohn Forte 	size_t width = 0;
486*fcf3ce44SJohn Forte 	size_t w_rsrc = 0;
487*fcf3ce44SJohn Forte 	size_t w_info = 0;
488*fcf3ce44SJohn Forte 	size_t table_size = 0;
489*fcf3ce44SJohn Forte 	uint_t tuples = 0;
490*fcf3ce44SJohn Forte 	rcm_info_tuple_t *tuple = NULL;
491*fcf3ce44SJohn Forte 	char *rsrc;
492*fcf3ce44SJohn Forte 	char *info;
493*fcf3ce44SJohn Forte 	char *newtable;
494*fcf3ce44SJohn Forte 	static char format[MAX_FORMAT];
495*fcf3ce44SJohn Forte 	const char *info_info_str, *info_rsrc_str;
496*fcf3ce44SJohn Forte 
497*fcf3ce44SJohn Forte 	/* Protect against invalid arguments */
498*fcf3ce44SJohn Forte 	if (rinfo == NULL || table == NULL)
499*fcf3ce44SJohn Forte 		return (FPCFGA_ERR);
500*fcf3ce44SJohn Forte 
501*fcf3ce44SJohn Forte 	/* Set localized table header strings */
502*fcf3ce44SJohn Forte 	rsrc = gettext("Resource");
503*fcf3ce44SJohn Forte 	info = gettext("Information");
504*fcf3ce44SJohn Forte 
505*fcf3ce44SJohn Forte 	/* A first pass, to size up the RCM information */
506*fcf3ce44SJohn Forte 	while (tuple = rcm_info_next(rinfo, tuple)) {
507*fcf3ce44SJohn Forte 		info_info_str = rcm_info_info(tuple);
508*fcf3ce44SJohn Forte 		info_rsrc_str = rcm_info_rsrc(tuple);
509*fcf3ce44SJohn Forte 		if ((info_info_str != NULL) && (info_rsrc_str != NULL)) {
510*fcf3ce44SJohn Forte 			tuples++;
511*fcf3ce44SJohn Forte 			if ((w = strlen(info_rsrc_str)) > w_rsrc)
512*fcf3ce44SJohn Forte 				w_rsrc = w;
513*fcf3ce44SJohn Forte 			if ((w = strlen(info_info_str)) > w_info)
514*fcf3ce44SJohn Forte 				w_info = w;
515*fcf3ce44SJohn Forte 		}
516*fcf3ce44SJohn Forte 	}
517*fcf3ce44SJohn Forte 
518*fcf3ce44SJohn Forte 	/* If nothing was sized up above, stop early */
519*fcf3ce44SJohn Forte 	if (tuples == 0)
520*fcf3ce44SJohn Forte 		return (FPCFGA_OK);
521*fcf3ce44SJohn Forte 
522*fcf3ce44SJohn Forte 	/* Adjust column widths for column headings */
523*fcf3ce44SJohn Forte 	if ((w = strlen(rsrc)) > w_rsrc)
524*fcf3ce44SJohn Forte 		w_rsrc = w;
525*fcf3ce44SJohn Forte 	else if ((w_rsrc - w) % 2)
526*fcf3ce44SJohn Forte 		w_rsrc++;
527*fcf3ce44SJohn Forte 	if ((w = strlen(info)) > w_info)
528*fcf3ce44SJohn Forte 		w_info = w;
529*fcf3ce44SJohn Forte 	else if ((w_info - w) % 2)
530*fcf3ce44SJohn Forte 		w_info++;
531*fcf3ce44SJohn Forte 
532*fcf3ce44SJohn Forte 	/*
533*fcf3ce44SJohn Forte 	 * Compute the total line width of each line,
534*fcf3ce44SJohn Forte 	 * accounting for intercolumn spacing.
535*fcf3ce44SJohn Forte 	 */
536*fcf3ce44SJohn Forte 	width = w_info + w_rsrc + 4;
537*fcf3ce44SJohn Forte 
538*fcf3ce44SJohn Forte 	/* Allocate space for the table */
539*fcf3ce44SJohn Forte 	table_size = (2 + tuples) * (width + 1) + 2;
540*fcf3ce44SJohn Forte 	if (*table == NULL)
541*fcf3ce44SJohn Forte 		*table = malloc(table_size);
542*fcf3ce44SJohn Forte 	else {
543*fcf3ce44SJohn Forte 		newtable = realloc(*table, strlen(*table) + table_size);
544*fcf3ce44SJohn Forte 		if (newtable != NULL)
545*fcf3ce44SJohn Forte 			*table = newtable;
546*fcf3ce44SJohn Forte 	}
547*fcf3ce44SJohn Forte 	if (*table == NULL)
548*fcf3ce44SJohn Forte 		return (FPCFGA_ERR);
549*fcf3ce44SJohn Forte 
550*fcf3ce44SJohn Forte 	/* Place a table header into the string */
551*fcf3ce44SJohn Forte 
552*fcf3ce44SJohn Forte 	/* The resource header */
553*fcf3ce44SJohn Forte 	(void) strcat(*table, "\n");
554*fcf3ce44SJohn Forte 	w = strlen(rsrc);
555*fcf3ce44SJohn Forte 	for (i = 0; i < ((w_rsrc - w) / 2); i++)
556*fcf3ce44SJohn Forte 		(void) strcat(*table, " ");
557*fcf3ce44SJohn Forte 	(void) strcat(*table, rsrc);
558*fcf3ce44SJohn Forte 	for (i = 0; i < ((w_rsrc - w) / 2); i++)
559*fcf3ce44SJohn Forte 		(void) strcat(*table, " ");
560*fcf3ce44SJohn Forte 
561*fcf3ce44SJohn Forte 	/* The information header */
562*fcf3ce44SJohn Forte 	(void) strcat(*table, "  ");
563*fcf3ce44SJohn Forte 	w = strlen(info);
564*fcf3ce44SJohn Forte 	for (i = 0; i < ((w_info - w) / 2); i++)
565*fcf3ce44SJohn Forte 		(void) strcat(*table, " ");
566*fcf3ce44SJohn Forte 	(void) strcat(*table, info);
567*fcf3ce44SJohn Forte 	for (i = 0; i < ((w_info - w) / 2); i++)
568*fcf3ce44SJohn Forte 		(void) strcat(*table, " ");
569*fcf3ce44SJohn Forte 
570*fcf3ce44SJohn Forte 	/* Underline the headers */
571*fcf3ce44SJohn Forte 	(void) strcat(*table, "\n");
572*fcf3ce44SJohn Forte 	for (i = 0; i < w_rsrc; i++)
573*fcf3ce44SJohn Forte 		(void) strcat(*table, "-");
574*fcf3ce44SJohn Forte 	(void) strcat(*table, "  ");
575*fcf3ce44SJohn Forte 	for (i = 0; i < w_info; i++)
576*fcf3ce44SJohn Forte 		(void) strcat(*table, "-");
577*fcf3ce44SJohn Forte 
578*fcf3ce44SJohn Forte 	/* Construct the format string */
579*fcf3ce44SJohn Forte 	(void) snprintf(format, MAX_FORMAT, "%%-%ds  %%-%ds", w_rsrc, w_info);
580*fcf3ce44SJohn Forte 
581*fcf3ce44SJohn Forte 	/* Add the tuples to the table string */
582*fcf3ce44SJohn Forte 	tuple = NULL;
583*fcf3ce44SJohn Forte 	while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) {
584*fcf3ce44SJohn Forte 		info_info_str = rcm_info_info(tuple);
585*fcf3ce44SJohn Forte 		info_rsrc_str = rcm_info_rsrc(tuple);
586*fcf3ce44SJohn Forte 		if ((info_info_str != NULL) && (info_rsrc_str != NULL)) {
587*fcf3ce44SJohn Forte 			(void) strcat(*table, "\n");
588*fcf3ce44SJohn Forte 			(void) sprintf(&((*table)[strlen(*table)]),
589*fcf3ce44SJohn Forte 			    format, info_rsrc_str, info_info_str);
590*fcf3ce44SJohn Forte 		}
591*fcf3ce44SJohn Forte 	}
592*fcf3ce44SJohn Forte 
593*fcf3ce44SJohn Forte 	return (FPCFGA_OK);
594*fcf3ce44SJohn Forte }
595*fcf3ce44SJohn Forte 
596*fcf3ce44SJohn Forte /*
597*fcf3ce44SJohn Forte  * chop_minor()
598*fcf3ce44SJohn Forte  *
599*fcf3ce44SJohn Forte  *	Chops off the minor name portion of a resource.  Allocates storage for
600*fcf3ce44SJohn Forte  * the returned string.  Caller must free the storage if return is non-NULL.
601*fcf3ce44SJohn Forte  */
602*fcf3ce44SJohn Forte static char *
chop_minor(char * rsrc)603*fcf3ce44SJohn Forte chop_minor(char *rsrc)
604*fcf3ce44SJohn Forte {
605*fcf3ce44SJohn Forte 	char *rsrc_fixed;
606*fcf3ce44SJohn Forte 	char *cp;
607*fcf3ce44SJohn Forte 
608*fcf3ce44SJohn Forte 	if ((rsrc_fixed = strdup(rsrc)) == NULL)
609*fcf3ce44SJohn Forte 		return (NULL);
610*fcf3ce44SJohn Forte 	if ((cp = strrchr(rsrc_fixed, ':')) != NULL)
611*fcf3ce44SJohn Forte 		*cp = '\0';
612*fcf3ce44SJohn Forte 	return (rsrc_fixed);
613*fcf3ce44SJohn Forte }
614