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