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