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