1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include "cfga_ib.h"
28 
29 
30 #define	MAX_FORMAT	80	/* for info table */
31 
32 cfga_ib_ret_t		ib_rcm_offline(const char *, char **, char *,
33 			    cfga_flags_t);
34 cfga_ib_ret_t		ib_rcm_online(const char *, char **, char *,
35 			    cfga_flags_t);
36 cfga_ib_ret_t		ib_rcm_remove(const char *, char **, char *,
37 			    cfga_flags_t);
38 static cfga_ib_ret_t 	ib_rcm_info_table(rcm_info_t *, char **);
39 static cfga_ib_ret_t 	ib_rcm_init(const char *, cfga_flags_t, char **,
40 			    uint_t *);
41 
42 
43 static rcm_handle_t *rcm_handle = NULL;
44 static mutex_t rcm_handle_lock = DEFAULTMUTEX;
45 
46 
47 /*
48  * Function:
49  *	ib_rcm_offline
50  * Input:
51  *	rsrc		- Resource name (typically an ap_id)
52  *	errstring	- Error message filled in case of a failure
53  *	rsrc_fixed	- Pointer to fixed path
54  *	flags		- flags to RCM
55  * Output:
56  *	NONE
57  * Returns:
58  *	CFGA_IB_OK on success or an appropriate error
59  * Description:
60  *	Offline IB resource consumers.
61  */
62 cfga_ib_ret_t
ib_rcm_offline(const char * rsrc,char ** errstring,char * rsrc_fixed,cfga_flags_t flags)63 ib_rcm_offline(const char *rsrc, char **errstring, char *rsrc_fixed,
64     cfga_flags_t flags)
65 {
66 	int		rret;
67 	uint_t		rflags = 0;
68 	rcm_info_t	*rinfo = NULL;
69 	cfga_ib_ret_t	ret = CFGA_IB_OK;
70 
71 	DPRINTF("ib_rcm_offline:\n");
72 
73 	if ((ret = ib_rcm_init(rsrc, flags, errstring, &rflags)) !=
74 	    CFGA_IB_OK) {
75 		return (ret);
76 	}
77 
78 	DPRINTF("ib_rcm_offline: rsrc_fixed: %s\n", rsrc_fixed);
79 
80 	if ((rret = rcm_request_offline(rcm_handle, rsrc_fixed, rflags, &rinfo))
81 	    != RCM_SUCCESS) {
82 		DPRINTF("ib_rcm_offline: rcm_request_offline failed\n");
83 
84 		if (rinfo) {
85 			(void) ib_rcm_info_table(rinfo, errstring);
86 			rcm_free_info(rinfo);
87 			rinfo = NULL;
88 		}
89 
90 		DPRINTF("ib_rcm_offline: table = %s\n", *errstring);
91 
92 		if (rret == RCM_FAILURE) {
93 			(void) ib_rcm_online(rsrc, errstring,
94 			    rsrc_fixed, flags);
95 		}
96 		ret = CFGA_IB_RCM_OFFLINE_ERR;
97 	}
98 
99 	return (ret);
100 }
101 
102 
103 /*
104  * Function:
105  *	ib_rcm_online
106  * Input:
107  *	rsrc		- Resource name (typically an ap_id)
108  *	errstring	- Error message filled in case of a failure
109  *	rsrc_fixed	- Pointer to fixed path
110  *	flags		- flags to RCM
111  * Output:
112  *	NONE
113  * Returns:
114  *	CFGA_IB_OK on success or an appropriate error
115  * Description:
116  *	Online IB resource consumers that were previously offlined.
117  */
118 cfga_ib_ret_t
ib_rcm_online(const char * rsrc,char ** errstring,char * rsrc_fixed,cfga_flags_t flags)119 ib_rcm_online(const char *rsrc, char **errstring, char *rsrc_fixed,
120     cfga_flags_t flags)
121 {
122 	rcm_info_t	*rinfo = NULL;
123 	cfga_ib_ret_t	ret = CFGA_IB_OK;
124 
125 	DPRINTF("ib_rcm_online:\n");
126 
127 	if ((ret = ib_rcm_init(rsrc, flags, errstring, NULL)) != CFGA_IB_OK) {
128 		return (ret);
129 	}
130 
131 	if (rcm_notify_online(rcm_handle, rsrc_fixed, 0, &rinfo) !=
132 	    RCM_SUCCESS && (rinfo != NULL)) {
133 		DPRINTF("ib_rcm_online: rcm_notify_online failed\n");
134 
135 		(void) ib_rcm_info_table(rinfo, errstring);
136 		rcm_free_info(rinfo);
137 		rinfo = NULL;
138 		ret = CFGA_IB_RCM_ONLINE_ERR;
139 	}
140 
141 	return (ret);
142 }
143 
144 
145 /*
146  * Function:
147  *	ib_rcm_remove
148  * Input:
149  *	rsrc		- Resource name (typically an ap_id)
150  *	errstring	- Error message filled in case of a failure
151  *	rsrc_fixed	- Pointer to fixed path
152  *	flags		- flags to RCM
153  * Output:
154  *	NONE
155  * Returns:
156  *	CFGA_IB_OK on success or an appropriate error
157  * Description:
158  *	Remove IB resource consumers after their kernel removal.
159  */
160 cfga_ib_ret_t
ib_rcm_remove(const char * rsrc,char ** errstring,char * rsrc_fixed,cfga_flags_t flags)161 ib_rcm_remove(const char *rsrc, char **errstring, char *rsrc_fixed,
162     cfga_flags_t flags)
163 {
164 	rcm_info_t	*rinfo = NULL;
165 	cfga_ib_ret_t	ret = CFGA_IB_OK;
166 
167 	DPRINTF("ib_rcm_remove:\n");
168 
169 	if ((ret = ib_rcm_init(rsrc, flags, errstring, NULL)) != CFGA_IB_OK) {
170 		return (ret);
171 	}
172 
173 	if (rcm_notify_remove(rcm_handle, rsrc_fixed, 0, &rinfo) !=
174 	    RCM_SUCCESS && (rinfo != NULL)) {
175 		DPRINTF("ib_rcm_remove: rcm_notify_remove failed\n");
176 
177 		(void) ib_rcm_info_table(rinfo, errstring);
178 		rcm_free_info(rinfo);
179 		rinfo = NULL;
180 		ret = CFGA_IB_RCM_ONLINE_ERR;
181 	}
182 
183 	return (ret);
184 }
185 
186 
187 /*
188  * Function:
189  *	ib_rcm_init
190  * Input:
191  *	rsrc		- Resource name (typically an ap_id)
192  *	flags		- flags to RCM
193  *	errstring	- Error message filled in case of a failure
194  *	rflags		- Flags filled up in case of a failure
195  * Output:
196  *	NONE
197  * Returns:
198  *	CFGA_IB_OK on success or an appropriate error
199  * Description:
200  *	Contains common initialization code for entering a ib_rcm_xx() routine.
201  */
202 /* ARGSUSED */
203 static cfga_ib_ret_t
ib_rcm_init(const char * rsrc,cfga_flags_t flags,char ** errstring,uint_t * rflags)204 ib_rcm_init(const char *rsrc, cfga_flags_t flags, char **errstring,
205     uint_t *rflags)
206 {
207 	DPRINTF("ib_rcm_init:\n");
208 
209 	/* Validate the rsrc argument */
210 	if (rsrc == NULL) {
211 		DPRINTF("ib_rcm_init: rsrc is NULL\n");
212 		return (CFGA_IB_INTERNAL_ERR);
213 	}
214 
215 	/* Translate the cfgadm flags to RCM flags */
216 	if (rflags && (flags & CFGA_FLAG_FORCE)) {
217 		*rflags |= RCM_FORCE;
218 	}
219 
220 	/* Get a handle for the RCM operations */
221 	(void) mutex_lock(&rcm_handle_lock);
222 	if (rcm_handle == NULL) {
223 		if (rcm_alloc_handle(NULL, RCM_NOPID, NULL, &rcm_handle) !=
224 		    RCM_SUCCESS) {
225 			DPRINTF("ib_rcm_init: alloc_handle failed\n");
226 			(void) mutex_unlock(&rcm_handle_lock);
227 			return (CFGA_IB_RCM_HANDLE_ERR);
228 		}
229 	}
230 	(void) mutex_unlock(&rcm_handle_lock);
231 	return (CFGA_IB_OK);
232 }
233 
234 
235 /*
236  * Function:
237  *	ib_rcm_info_table
238  * Input:
239  *	rinfo		- Resource information
240  *	table		- table to be printed
241  * Output:
242  *	NONE
243  * Returns:
244  *	CFGA_IB_OK on success or an appropriate error
245  * Description:
246  *	Takes an opaque rcm_info_t pointer and a character pointer,
247  *	and appends the rcm_info_t data in the form of a table to the
248  *	given character pointer.
249  */
250 static cfga_ib_ret_t
ib_rcm_info_table(rcm_info_t * rinfo,char ** table)251 ib_rcm_info_table(rcm_info_t *rinfo, char **table)
252 {
253 	int i;
254 	size_t w;
255 	size_t width = 0;
256 	size_t w_rsrc = 0;
257 	size_t w_info = 0;
258 	size_t table_size = 0;
259 	uint_t tuples = 0;
260 	rcm_info_tuple_t *tuple = NULL;
261 	char *rsrc;
262 	char *info;
263 	char *newtable;
264 	static char format[MAX_FORMAT];
265 	const char *infostr;
266 
267 	DPRINTF("ib_rcm_info_table:\n");
268 
269 	/* Protect against invalid arguments */
270 	if (rinfo == NULL || table == NULL) {
271 		return (CFGA_IB_INTERNAL_ERR);
272 	}
273 
274 	/* Set localized table header strings */
275 	rsrc = dgettext(TEXT_DOMAIN, "Resource");
276 	info = dgettext(TEXT_DOMAIN, "Information");
277 
278 	/* A first pass, to size up the RCM information */
279 	while (tuple = rcm_info_next(rinfo, tuple)) {
280 		if ((infostr = rcm_info_info(tuple)) != NULL) {
281 			tuples++;
282 			if ((w = strlen(rcm_info_rsrc(tuple))) > w_rsrc)
283 				w_rsrc = w;
284 			if ((w = strlen(infostr)) > w_info)
285 				w_info = w;
286 		}
287 	}
288 
289 	/* If nothing was sized up above, stop early */
290 	if (tuples == 0) {
291 		DPRINTF("ib_rcm_info_table: no tuples\n");
292 		return (CFGA_IB_OK);
293 	}
294 
295 	/* Adjust column widths for column headings */
296 	if ((w = strlen(rsrc)) > w_rsrc) {
297 		w_rsrc = w;
298 	} else if ((w_rsrc - w) % 2) {
299 		w_rsrc++;
300 	}
301 
302 	if ((w = strlen(info)) > w_info) {
303 		w_info = w;
304 	} else if ((w_info - w) % 2) {
305 		w_info++;
306 	}
307 
308 	/*
309 	 * Compute the total line width of each line,
310 	 * accounting for intercolumn spacing.
311 	 */
312 	width = w_info + w_rsrc + 4;
313 
314 	/* Allocate space for the table */
315 	table_size = (2 + tuples) * (width + 1) + 2;
316 	if (*table == NULL) {
317 		*table = malloc(table_size);
318 	} else {
319 		newtable = realloc(*table, strlen(*table) + table_size);
320 		if (newtable != NULL)
321 			*table = newtable;
322 		else {
323 			free(*table);
324 			*table = NULL;
325 			return (CFGA_IB_ALLOC_FAIL);
326 		}
327 	}
328 
329 	if (*table == NULL) {
330 		DPRINTF("ib_rcm_info_table: no table\n");
331 		return (CFGA_IB_ALLOC_FAIL);
332 	}
333 
334 	/* Place a table header into the string */
335 
336 	/* The resource header */
337 	(void) strlcat(*table, "\n", sizeof (*table));
338 	w = strlen(rsrc);
339 
340 	for (i = 0; i < ((w_rsrc - w) / 2); i++) {
341 		(void) strcat(*table, " ");
342 	}
343 	(void) strlcat(*table, rsrc, sizeof (*table));
344 
345 	for (i = 0; i < ((w_rsrc - w) / 2); i++) {
346 		(void) strcat(*table, " ");
347 	}
348 
349 	/* The information header */
350 	(void) strcat(*table, "  ");
351 	w = strlen(info);
352 	for (i = 0; i < ((w_info - w) / 2); i++) {
353 		(void) strcat(*table, " ");
354 	}
355 	(void) strlcat(*table, info, sizeof (*table));
356 
357 	for (i = 0; i < ((w_info - w) / 2); i++) {
358 		(void) strcat(*table, " ");
359 	}
360 
361 	(void) strcat(*table, "\n");
362 
363 	/* Underline the headers */
364 	for (i = 0; i < w_rsrc; i++) {
365 		(void) strcat(*table, "-");
366 	}
367 
368 	(void) strcat(*table, "  ");
369 	for (i = 0; i < w_info; i++) {
370 		(void) strcat(*table, "-");
371 	}
372 
373 	(void) strcat(*table, "\n");
374 
375 	/* Construct the format string */
376 	(void) snprintf(format, MAX_FORMAT, "%%-%ds  %%-%ds",
377 	    (int)w_rsrc, (int)w_info);
378 
379 	/* Add the tuples to the table string */
380 	tuple = NULL;
381 	while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) {
382 		if ((infostr = rcm_info_info(tuple)) != NULL) {
383 			(void) sprintf(&((*table)[strlen(*table)]),
384 			    format, rcm_info_rsrc(tuple), infostr);
385 			(void) strcat(*table, "\n");
386 		}
387 	}
388 
389 	return (CFGA_IB_OK);
390 }
391