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 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include "cfga_sata.h"
30 
31 
32 
33 #define	MAX_FORMAT	80	/* for info table */
34 
35 cfga_sata_ret_t	sata_rcm_offline(const char *, char **, char *,
36 				cfga_flags_t);
37 cfga_sata_ret_t	sata_rcm_online(const char *, char **, char *,
38 				cfga_flags_t);
39 cfga_sata_ret_t	sata_rcm_remove(const char *, char **, char *,
40 				cfga_flags_t);
41 static cfga_sata_ret_t	sata_rcm_info_table(rcm_info_t *, char **);
42 static cfga_sata_ret_t	sata_rcm_init(const char *, cfga_flags_t, char **,
43 				uint_t *);
44 
45 
46 static rcm_handle_t *rcm_handle = NULL;
47 static mutex_t rcm_handle_lock = DEFAULTMUTEX;
48 
49 /*
50  * sata_rcm_offline:
51  *      Offline SATA resource consumers.
52  */
53 cfga_sata_ret_t
sata_rcm_offline(const char * rsrc,char ** errstring,char * rsrc_fixed,cfga_flags_t flags)54 sata_rcm_offline(const char *rsrc, char **errstring, char *rsrc_fixed,
55 		cfga_flags_t flags)
56 {
57 	int		rret;
58 	uint_t		rflags = 0;
59 	rcm_info_t	*rinfo = NULL;
60 	cfga_sata_ret_t	ret = CFGA_SATA_OK;
61 
62 	if ((ret = sata_rcm_init(rsrc, flags, errstring, &rflags)) !=
63 	    CFGA_SATA_OK) {
64 
65 		return (ret);
66 	}
67 
68 	if ((rret = rcm_request_offline(rcm_handle, rsrc_fixed, rflags,
69 	    &rinfo)) != RCM_SUCCESS) {
70 		if (rinfo) {
71 			(void) sata_rcm_info_table(rinfo, errstring);
72 			rcm_free_info(rinfo);
73 			rinfo = NULL;
74 		}
75 
76 		if (rret == RCM_FAILURE) {
77 			(void) sata_rcm_online(rsrc, errstring,
78 					rsrc_fixed, flags);
79 		}
80 		ret = CFGA_SATA_RCM_OFFLINE;
81 	}
82 	return (ret);
83 }
84 
85 
86 /*
87  * sata_rcm_online:
88  *      Online SATA resource consumers that were previously offlined.
89  */
90 cfga_sata_ret_t
sata_rcm_online(const char * rsrc,char ** errstring,char * rsrc_fixed,cfga_flags_t flags)91 sata_rcm_online(const char *rsrc, char **errstring, char *rsrc_fixed,
92 		cfga_flags_t flags)
93 {
94 	rcm_info_t	*rinfo = NULL;
95 	cfga_sata_ret_t	ret = CFGA_SATA_OK;
96 
97 	if ((ret = sata_rcm_init(rsrc, flags, errstring, NULL)) !=
98 	    CFGA_SATA_OK) {
99 
100 		return (ret);
101 	}
102 
103 	if (rcm_notify_online(rcm_handle, rsrc_fixed, 0, &rinfo) !=
104 	    RCM_SUCCESS && (rinfo != NULL)) {
105 		(void) sata_rcm_info_table(rinfo, errstring);
106 		rcm_free_info(rinfo);
107 		rinfo = NULL;
108 		ret = CFGA_SATA_RCM_ONLINE;
109 	}
110 
111 	return (ret);
112 }
113 
114 /*
115  * sata_rcm_remove:
116  *      Remove SATA resource consumers after their kernel removal.
117  */
118 cfga_sata_ret_t
sata_rcm_remove(const char * rsrc,char ** errstring,char * rsrc_fixed,cfga_flags_t flags)119 sata_rcm_remove(const char *rsrc, char **errstring, char *rsrc_fixed,
120 		cfga_flags_t flags)
121 {
122 	rcm_info_t	*rinfo = NULL;
123 	cfga_sata_ret_t	ret = CFGA_SATA_OK;
124 
125 	if ((ret = sata_rcm_init(rsrc, flags, errstring, NULL)) !=
126 	    CFGA_SATA_OK) {
127 
128 		return (ret);
129 	}
130 
131 	if (rcm_notify_remove(rcm_handle, rsrc_fixed, 0, &rinfo) !=
132 	    RCM_SUCCESS && (rinfo != NULL)) {
133 
134 		(void) sata_rcm_info_table(rinfo, errstring);
135 		rcm_free_info(rinfo);
136 		rinfo = NULL;
137 		ret = CFGA_SATA_RCM_ONLINE;
138 	}
139 
140 	return (ret);
141 }
142 
143 
144 /*
145  * sata_rcm_init:
146  * Contains common initialization code for entering a sata_rcm_xx() routine.
147  */
148 /* ARGSUSED */
149 static cfga_sata_ret_t
sata_rcm_init(const char * rsrc,cfga_flags_t flags,char ** errstring,uint_t * rflags)150 sata_rcm_init(const char *rsrc, cfga_flags_t flags, char **errstring,
151 		uint_t *rflags)
152 {
153 	/* Validate the rsrc argument */
154 	if (rsrc == NULL) {
155 		return (CFGA_SATA_INTERNAL_ERROR);
156 	}
157 
158 	/* Translate the cfgadm flags to RCM flags */
159 	if (rflags && (flags & CFGA_FLAG_FORCE)) {
160 		*rflags |= RCM_FORCE;
161 	}
162 
163 	/* Get a handle for the RCM operations */
164 	(void) mutex_lock(&rcm_handle_lock);
165 	if (rcm_handle == NULL) {
166 		if (rcm_alloc_handle(NULL, RCM_NOPID, NULL, &rcm_handle) !=
167 		    RCM_SUCCESS) {
168 			(void) mutex_unlock(&rcm_handle_lock);
169 
170 			return (CFGA_SATA_RCM_HANDLE);
171 		}
172 	}
173 	(void) mutex_unlock(&rcm_handle_lock);
174 
175 	return (CFGA_SATA_OK);
176 }
177 
178 
179 /*
180  * sata_rcm_info_table:
181  * Takes an opaque rcm_info_t pointer and a character pointer,
182  * and appends the rcm_info_t data in the form of a table to the
183  * given character pointer.
184  */
185 static cfga_sata_ret_t
sata_rcm_info_table(rcm_info_t * rinfo,char ** table)186 sata_rcm_info_table(rcm_info_t *rinfo, char **table)
187 {
188 	int i;
189 	size_t w;
190 	size_t width = 0;
191 	size_t w_rsrc = 0;
192 	size_t w_info = 0;
193 	size_t table_size = 0;
194 	uint_t tuples = 0;
195 	rcm_info_tuple_t *tuple = NULL;
196 	char *rsrc;
197 	char *info;
198 	char *newtable;
199 	static char format[MAX_FORMAT];
200 	const char *infostr;
201 
202 	/* Protect against invalid arguments */
203 	if (rinfo == NULL || table == NULL) {
204 		return (CFGA_SATA_INTERNAL_ERROR);
205 	}
206 
207 	/* Set localized table header strings */
208 	rsrc = dgettext(TEXT_DOMAIN, "Resource");
209 	info = dgettext(TEXT_DOMAIN, "Information");
210 
211 
212 	/* A first pass, to size up the RCM information */
213 	while (tuple = rcm_info_next(rinfo, tuple)) {
214 		if ((infostr = rcm_info_info(tuple)) != NULL) {
215 			tuples++;
216 			if ((w = strlen(rcm_info_rsrc(tuple))) > w_rsrc)
217 				w_rsrc = w;
218 			if ((w = strlen(infostr)) > w_info)
219 				w_info = w;
220 		}
221 	}
222 
223 	/* If nothing was sized up above, stop early */
224 	if (tuples == 0) {
225 		return (CFGA_SATA_OK);
226 	}
227 
228 	/* Adjust column widths for column headings */
229 	if ((w = strlen(rsrc)) > w_rsrc) {
230 		w_rsrc = w;
231 	} else if ((w_rsrc - w) % 2) {
232 		w_rsrc++;
233 	}
234 
235 	if ((w = strlen(info)) > w_info) {
236 		w_info = w;
237 	} else if ((w_info - w) % 2) {
238 		w_info++;
239 	}
240 
241 
242 	/*
243 	 * Compute the total line width of each line,
244 	 * accounting for intercolumn spacing.
245 	 */
246 	width = w_info + w_rsrc + 4;
247 
248 	/* Allocate space for the table */
249 	table_size = (2 + tuples) * (width + 1) + 2;
250 	if (*table == NULL) {
251 		/* zero fill for the strcat() call below */
252 		*table = calloc(table_size, sizeof (char));
253 		if (*table == NULL) {
254 			return (CFGA_SATA_ALLOC_FAIL);
255 		}
256 	} else {
257 		newtable = realloc(*table, strlen(*table) + table_size);
258 		if (newtable == NULL) {
259 			return (CFGA_SATA_ALLOC_FAIL);
260 		} else {
261 			*table = newtable;
262 		}
263 	}
264 
265 	/* Place a table header into the string */
266 
267 
268 	/* The resource header */
269 	(void) strcat(*table, "\n");
270 	w = strlen(rsrc);
271 
272 	for (i = 0; i < ((w_rsrc - w) / 2); i++) {
273 		(void) strcat(*table, " ");
274 	}
275 	(void) strcat(*table, rsrc);
276 
277 	for (i = 0; i < ((w_rsrc - w) / 2); i++) {
278 		(void) strcat(*table, " ");
279 	}
280 
281 	/* The information header */
282 	(void) strcat(*table, "  ");
283 	w = strlen(info);
284 	for (i = 0; i < ((w_info - w) / 2); i++) {
285 		(void) strcat(*table, " ");
286 	}
287 	(void) strcat(*table, info);
288 
289 	for (i = 0; i < ((w_info - w) / 2); i++) {
290 		(void) strcat(*table, " ");
291 	}
292 
293 	(void) strcat(*table, "\n");
294 
295 	/* Underline the headers */
296 	for (i = 0; i < w_rsrc; i++) {
297 		(void) strcat(*table, "-");
298 	}
299 
300 	(void) strcat(*table, "  ");
301 	for (i = 0; i < w_info; i++) {
302 		(void) strcat(*table, "-");
303 	}
304 
305 
306 	(void) strcat(*table, "\n");
307 
308 	/* Construct the format string */
309 	(void) snprintf(format, MAX_FORMAT, "%%-%ds  %%-%ds",
310 			(int)w_rsrc, (int)w_info);
311 
312 	/* Add the tuples to the table string */
313 	tuple = NULL;
314 	while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) {
315 		if ((infostr = rcm_info_info(tuple)) != NULL) {
316 			(void) sprintf(&((*table)[strlen(*table)]),
317 					format, rcm_info_rsrc(tuple), infostr);
318 			(void) strcat(*table, "\n");
319 		}
320 	}
321 
322 	return (CFGA_SATA_OK);
323 }
324