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