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  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #include "cfga_scsi.h"
27 
28 #define	MAX_FORMAT	80
29 
30 static scfga_ret_t scsi_rcm_info_table(rcm_info_t *, char **);
31 static scfga_ret_t scsi_rcm_init(uint_t, char **, rcm_handle_t **);
32 
33 /*
34  * scsi_rcm_offline()
35  *
36  *	Offline SCSI resource consumers.
37  */
38 scfga_ret_t
scsi_rcm_offline(char ** rsrclist,char ** errstring,cfga_flags_t flags)39 scsi_rcm_offline(char **rsrclist, char **errstring, cfga_flags_t flags)
40 {
41 	int rret;
42 	uint_t rflags = 0;
43 	rcm_info_t *rinfo = NULL;
44 	scfga_ret_t ret = SCFGA_OK;
45 	rcm_handle_t *rcm_handle;
46 
47 	if (rsrclist == NULL)
48 		return (ret);
49 
50 	if ((ret = scsi_rcm_init(0, errstring, &rcm_handle))
51 	    != SCFGA_OK)
52 		return (ret);
53 
54 	if (flags & CFGA_FLAG_FORCE)
55 		rflags = RCM_FORCE;
56 
57 	if ((rret = rcm_request_offline_list(rcm_handle, rsrclist, rflags,
58 	    &rinfo)) != RCM_SUCCESS) {
59 		if ((flags & FLAG_CLIENT_DEV) == FLAG_CLIENT_DEV) {
60 			cfga_err(errstring, 0, ERRARG_RCM_CLIENT_OFFLINE, 0);
61 		} else {
62 			cfga_err(errstring, 0, ERRARG_RCM_OFFLINE, 0);
63 		}
64 		if (rinfo) {
65 			(void) scsi_rcm_info_table(rinfo, errstring);
66 			rcm_free_info(rinfo);
67 		}
68 		if (rret == RCM_FAILURE)
69 			(void) rcm_notify_online_list(rcm_handle, rsrclist,
70 			    rflags & ~RCM_FORCE, NULL);
71 		ret = SCFGA_BUSY;
72 	}
73 	(void) rcm_free_handle(rcm_handle);
74 	return (ret);
75 }
76 
77 /*
78  * scsi_rcm_online()
79  *
80  *	Online SCSI resource consumers that were previously offlined.
81  */
82 /*ARGSUSED2*/
83 scfga_ret_t
scsi_rcm_online(char ** rsrclist,char ** errstring,cfga_flags_t flags)84 scsi_rcm_online(char **rsrclist, char **errstring, cfga_flags_t flags)
85 {
86 	rcm_info_t *rinfo = NULL;
87 	scfga_ret_t ret = SCFGA_OK;
88 	rcm_handle_t *rcm_handle;
89 
90 	if (rsrclist == NULL)
91 		return (ret);
92 
93 	if ((ret = scsi_rcm_init(0, errstring, &rcm_handle))
94 	    != SCFGA_OK)
95 		return (ret);
96 
97 	if (rcm_notify_online_list(rcm_handle, rsrclist, 0, &rinfo)
98 	    != RCM_SUCCESS) {
99 		cfga_err(errstring, 0, ERRARG_RCM_ONLINE, 0);
100 		if (rinfo != NULL) {
101 			(void) scsi_rcm_info_table(rinfo, errstring);
102 			rcm_free_info(rinfo);
103 		}
104 		ret = SCFGA_BUSY;
105 	}
106 	(void) rcm_free_handle(rcm_handle);
107 	return (ret);
108 }
109 
110 /*
111  * scsi_rcm_remove()
112  *
113  *	Remove SCSI resource consumers after their kernel removal.
114  */
115 /*ARGSUSED2*/
116 scfga_ret_t
scsi_rcm_remove(char ** rsrclist,char ** errstring,cfga_flags_t flags)117 scsi_rcm_remove(char **rsrclist, char **errstring, cfga_flags_t flags)
118 {
119 	rcm_info_t *rinfo = NULL;
120 	scfga_ret_t ret = SCFGA_OK;
121 	rcm_handle_t *rcm_handle;
122 
123 	if (rsrclist == NULL)
124 		return (ret);
125 
126 	if ((ret = scsi_rcm_init(0, errstring, &rcm_handle))
127 	    != SCFGA_OK)
128 		return (ret);
129 
130 	if (rcm_notify_remove_list(rcm_handle, rsrclist, 0, &rinfo)
131 	    != RCM_SUCCESS) {
132 		cfga_err(errstring, 0, ERRARG_RCM_REMOVE, 0);
133 		if (rinfo) {
134 			(void) scsi_rcm_info_table(rinfo, errstring);
135 			rcm_free_info(rinfo);
136 		}
137 		ret = SCFGA_BUSY;
138 	}
139 
140 	(void) rcm_free_handle(rcm_handle);
141 	return (ret);
142 }
143 
144 /*
145  * scsi_rcm_suspend()
146  *
147  *	Suspend SCSI resource consumers before a bus quiesce.
148  */
149 scfga_ret_t
scsi_rcm_suspend(char ** rsrclist,char ** errstring,cfga_flags_t flags,int pflag)150 scsi_rcm_suspend(char **rsrclist, char **errstring, cfga_flags_t flags,
151     int pflag)
152 {
153 	int rret;
154 	uint_t rflags = 0;
155 	rcm_info_t *rinfo = NULL;
156 	scfga_ret_t ret = SCFGA_OK;
157 	rcm_handle_t *rcm_handle;
158 	timespec_t zerotime = { 0, 0 };
159 
160 	if (rsrclist == NULL)
161 		return (ret);
162 
163 	pflag = pflag ? RCM_NOPID : 0;
164 	if ((ret = scsi_rcm_init(pflag, errstring, &rcm_handle))
165 	    != SCFGA_OK)
166 		return (ret);
167 
168 	if (flags & CFGA_FLAG_FORCE)
169 		rflags = RCM_FORCE;
170 
171 	/*
172 	 * attempt a suspension on a list of resources
173 	 */
174 	if ((rret = rcm_request_suspend_list(rcm_handle, rsrclist, rflags,
175 	    &zerotime, &rinfo)) != RCM_SUCCESS) {
176 		cfga_err(errstring, 0, ERRARG_RCM_SUSPEND, 0);
177 		if (rinfo) {
178 			(void) scsi_rcm_info_table(rinfo, errstring);
179 			rcm_free_info(rinfo);
180 		}
181 		if (rret == RCM_FAILURE)
182 			(void) rcm_notify_resume_list(rcm_handle, rsrclist,
183 			    (rflags & (~RCM_FORCE)), NULL);
184 		ret = SCFGA_BUSY;
185 	}
186 	(void) rcm_free_handle(rcm_handle);
187 	return (ret);
188 }
189 
190 /*
191  * scsi_rcm_resume()
192  *
193  *	Resume SCSI resource consumers after a bus has been unquiesced.
194  */
195 /*ARGSUSED2*/
196 scfga_ret_t
scsi_rcm_resume(char ** rsrclist,char ** errstring,cfga_flags_t flags,int pflag)197 scsi_rcm_resume(char **rsrclist, char **errstring, cfga_flags_t flags,
198     int pflag)
199 {
200 	rcm_info_t *rinfo = NULL;
201 	scfga_ret_t ret = SCFGA_OK;
202 	rcm_handle_t *rcm_handle;
203 
204 	if (rsrclist == NULL)
205 		return (ret);
206 
207 	pflag = pflag ? RCM_NOPID : 0;
208 	if ((ret = scsi_rcm_init(pflag, errstring, &rcm_handle))
209 	    != SCFGA_OK)
210 		return (ret);
211 
212 	/*
213 	 * resume the resource list.
214 	 */
215 	if (rcm_notify_resume_list(rcm_handle, rsrclist, 0, &rinfo)
216 	    != RCM_SUCCESS) {
217 		cfga_err(errstring, 0, ERRARG_RCM_RESUME, 0);
218 		if (rinfo != NULL) {
219 			(void) scsi_rcm_info_table(rinfo, errstring);
220 			rcm_free_info(rinfo);
221 		}
222 		ret = SCFGA_BUSY;
223 	}
224 	(void) rcm_free_handle(rcm_handle);
225 	return (ret);
226 }
227 
228 /*
229  * scsi_rcm_init()
230  *
231  *	Contains common initialization code for entering a scsi_rcm_xx()
232  * routine.
233  */
234 static scfga_ret_t
scsi_rcm_init(uint_t rcm_flag,char ** errstring,rcm_handle_t ** hdlp)235 scsi_rcm_init(uint_t rcm_flag, char **errstring, rcm_handle_t **hdlp)
236 {
237 	/* Get a handle for the RCM operations */
238 	if (rcm_alloc_handle(NULL, rcm_flag, NULL, hdlp) != RCM_SUCCESS) {
239 		cfga_err(errstring, 0, ERR_RCM_HANDLE, 0);
240 		return (SCFGA_LIB_ERR);
241 	}
242 
243 	return (SCFGA_OK);
244 }
245 
246 /*
247  * scsi_rcm_info_table
248  *
249  *	Takes an opaque rcm_info_t pointer and a character pointer, and appends
250  * the rcm_info_t data in the form of a table to the given character pointer.
251  */
252 static scfga_ret_t
scsi_rcm_info_table(rcm_info_t * rinfo,char ** table)253 scsi_rcm_info_table(rcm_info_t *rinfo, char **table)
254 {
255 	int i;
256 	size_t w;
257 	size_t width = 0;
258 	size_t w_rsrc = 0;
259 	size_t w_info = 0;
260 	size_t table_size = 0;
261 	uint_t tuples = 0;
262 	rcm_info_tuple_t *tuple = NULL;
263 	char *rsrc;
264 	char *info;
265 	char *newtable;
266 	static char format[MAX_FORMAT];
267 	const char *infostr;
268 
269 	/* Protect against invalid arguments */
270 	if (rinfo == NULL || table == NULL)
271 		return (SCFGA_ERR);
272 
273 	/* Set localized table header strings */
274 	rsrc = dgettext(TEXT_DOMAIN, "Resource");
275 	info = dgettext(TEXT_DOMAIN, "Information");
276 
277 	/* A first pass, to size up the RCM information */
278 	while (tuple = rcm_info_next(rinfo, tuple)) {
279 		if ((infostr = rcm_info_info(tuple)) != NULL) {
280 			tuples++;
281 			if ((w = strlen(rcm_info_rsrc(tuple))) > w_rsrc)
282 				w_rsrc = w;
283 			if ((w = strlen(infostr)) > w_info)
284 				w_info = w;
285 		}
286 	}
287 
288 	/* If nothing was sized up above, stop early */
289 	if (tuples == 0)
290 		return (SCFGA_OK);
291 
292 	/* Adjust column widths for column headings */
293 	if ((w = strlen(rsrc)) > w_rsrc)
294 		w_rsrc = w;
295 	else if ((w_rsrc - w) % 2)
296 		w_rsrc++;
297 	if ((w = strlen(info)) > w_info)
298 		w_info = w;
299 	else if ((w_info - w) % 2)
300 		w_info++;
301 
302 	/*
303 	 * Compute the total line width of each line,
304 	 * accounting for intercolumn spacing.
305 	 */
306 	width = w_info + w_rsrc + 4;
307 
308 	/* Allocate space for the table */
309 	table_size = (2 + tuples) * (width + 1) + 2;
310 	if (*table == NULL) {
311 		/* zero fill for the strcat() call below */
312 		*table = calloc(table_size, sizeof (char));
313 		if (*table == NULL)
314 			return (SCFGA_ERR);
315 	} else {
316 		newtable = realloc(*table, strlen(*table) + table_size);
317 		if (newtable == NULL)
318 			return (SCFGA_ERR);
319 		else
320 			*table = newtable;
321 	}
322 
323 	/* Place a table header into the string */
324 
325 	/* The resource header */
326 	(void) strcat(*table, "\n");
327 	w = strlen(rsrc);
328 	for (i = 0; i < ((w_rsrc - w) / 2); i++)
329 		(void) strcat(*table, " ");
330 	(void) strcat(*table, rsrc);
331 	for (i = 0; i < ((w_rsrc - w) / 2); i++)
332 		(void) strcat(*table, " ");
333 
334 	/* The information header */
335 	(void) strcat(*table, "  ");
336 	w = strlen(info);
337 	for (i = 0; i < ((w_info - w) / 2); i++)
338 		(void) strcat(*table, " ");
339 	(void) strcat(*table, info);
340 	for (i = 0; i < ((w_info - w) / 2); i++)
341 		(void) strcat(*table, " ");
342 
343 	/* Underline the headers */
344 	(void) strcat(*table, "\n");
345 	for (i = 0; i < w_rsrc; i++)
346 		(void) strcat(*table, "-");
347 	(void) strcat(*table, "  ");
348 	for (i = 0; i < w_info; i++)
349 		(void) strcat(*table, "-");
350 
351 	/* Construct the format string */
352 	(void) snprintf(format, MAX_FORMAT, "%%-%ds  %%-%ds",
353 	    (int)w_rsrc, (int)w_info);
354 
355 	/* Add the tuples to the table string */
356 	tuple = NULL;
357 	while ((tuple = rcm_info_next(rinfo, tuple)) != NULL) {
358 		if ((infostr = rcm_info_info(tuple)) != NULL) {
359 			(void) strcat(*table, "\n");
360 			(void) sprintf(&((*table)[strlen(*table)]),
361 			    format, rcm_info_rsrc(tuple),
362 			    infostr);
363 		}
364 	}
365 
366 	return (SCFGA_OK);
367 }
368