xref: /illumos-gate/usr/src/cmd/pcidr/plugins/default/pcidr_cfga.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 2005 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 <string.h>
30 #include <sys/param.h>
31 #include <assert.h>
32 #include <pcidr.h>
33 #include <pcidr_cfga.h>
34 
35 
36 /*
37  * misc config_admin(3cfgadm) related routines
38  */
39 
40 static struct {
41 	cfga_stat_t stat;
42 	char *name;
43 } pcidr_cfga_stat_nametab[] = {
44 	{CFGA_STAT_NONE, "CFGA_STAT_NONE"},
45 	{CFGA_STAT_EMPTY, "CFGA_STAT_EMPTY"},
46 	{CFGA_STAT_DISCONNECTED, "CFGA_STAT_DISCONNECTED"},
47 	{CFGA_STAT_CONNECTED, "CFGA_STAT_CONNECTED"},
48 	{CFGA_STAT_UNCONFIGURED, "CFGA_STAT_UNCONFIGURED"},
49 	{CFGA_STAT_CONFIGURED, "CFGA_STAT_CONFIGURED"},
50 };
51 static int pcidr_cfga_stat_nametab_len =
52     sizeof (pcidr_cfga_stat_nametab) / sizeof (pcidr_cfga_stat_nametab[0]);
53 
54 char *
55 pcidr_cfga_stat_name(cfga_stat_t val)
56 {
57 	int i;
58 
59 	for (i = 0; i < pcidr_cfga_stat_nametab_len; i++) {
60 		if (pcidr_cfga_stat_nametab[i].stat == val)
61 			return (pcidr_cfga_stat_nametab[i].name);
62 	}
63 	return (NULL);
64 }
65 
66 
67 static struct {
68 	cfga_stat_t cmd;
69 	char *name;
70 } pcidr_cfga_cmd_nametab[] = {
71 	{CFGA_CMD_NONE, "CFGA_CMD_NONE"},
72 	{CFGA_CMD_LOAD, "CFGA_CMD_LOAD"},
73 	{CFGA_CMD_UNLOAD, "CFGA_CMD_UNLOAD"},
74 	{CFGA_CMD_CONNECT, "CFGA_CMD_CONNECT"},
75 	{CFGA_CMD_DISCONNECT, "CFGA_CMD_DISCONNECT"},
76 	{CFGA_CMD_CONFIGURE, "CFGA_CMD_CONFIGURE"},
77 	{CFGA_CMD_UNCONFIGURE, "CFGA_CMD_UNCONFIGURE"},
78 };
79 static int pcidr_cfga_cmd_nametab_len =
80     sizeof (pcidr_cfga_cmd_nametab) / sizeof (pcidr_cfga_cmd_nametab[0]);
81 
82 char *
83 pcidr_cfga_cmd_name(cfga_cmd_t val)
84 {
85 	int i;
86 
87 	for (i = 0; i < pcidr_cfga_cmd_nametab_len; i++) {
88 		if (pcidr_cfga_cmd_nametab[i].cmd == val)
89 			return (pcidr_cfga_cmd_nametab[i].name);
90 	}
91 	return (NULL);
92 }
93 
94 
95 static struct {
96 	cfga_cond_t cond;
97 	char *name;
98 } pcidr_cfga_cond_nametab[] = {
99 	{CFGA_COND_UNKNOWN, "CFGA_COND_UNKNOWN"},
100 	{CFGA_COND_OK, "CFGA_COND_OK"},
101 	{CFGA_COND_FAILING, "CFGA_COND_FAILING"},
102 	{CFGA_COND_FAILED, "CFGA_COND_FAILED"},
103 	{CFGA_COND_UNUSABLE, "CFGA_COND_UNUSABLE"},
104 };
105 static int pcidr_cfga_cond_nametab_len =
106     sizeof (pcidr_cfga_cond_nametab) / sizeof (pcidr_cfga_cond_nametab[0]);
107 
108 char *
109 pcidr_cfga_cond_name(cfga_cond_t val)
110 {
111 	int i;
112 
113 	for (i = 0; i < pcidr_cfga_cond_nametab_len; i++) {
114 		if (pcidr_cfga_cond_nametab[i].cond == val)
115 			return (pcidr_cfga_cond_nametab[i].name);
116 	}
117 	return (NULL);
118 }
119 
120 
121 static struct {
122 	cfga_err_t err;
123 	char *name;
124 } pcidr_cfga_err_nametab[] = {
125 	{CFGA_OK, "CFGA_OK"},
126 	{CFGA_NACK, "CFGA_NACK"},
127 	{CFGA_NOTSUPP, "CFGA_NOTSUPP"},
128 	{CFGA_OPNOTSUPP, "CFGA_OPNOTSUPP"},
129 	{CFGA_PRIV, "CFGA_PRIV"},
130 	{CFGA_BUSY, "CFGA_BUSY"},
131 	{CFGA_SYSTEM_BUSY, "CFGA_SYSTEM_BUSY"},
132 	{CFGA_DATA_ERROR, "CFGA_DATA_ERROR"},
133 	{CFGA_LIB_ERROR, "CFGA_LIB_ERROR"},
134 	{CFGA_NO_LIB, "CFGA_NO_LIB"},
135 	{CFGA_INSUFFICENT_CONDITION, "CFGA_INSUFFICENT_CONDITION"},
136 	{CFGA_INVAL, "CFGA_INVAL"},
137 	{CFGA_ERROR, "CFGA_ERROR"},
138 	{CFGA_APID_NOEXIST, "CFGA_APID_NOEXIST"},
139 	{CFGA_ATTR_INVAL, "CFGA_ATTR_INVAL"},
140 };
141 static int pcidr_cfga_err_nametab_len =
142     sizeof (pcidr_cfga_err_nametab) / sizeof (pcidr_cfga_err_nametab[0]);
143 
144 char *
145 pcidr_cfga_err_name(cfga_err_t val)
146 {
147 	int i;
148 
149 	for (i = 0; i < pcidr_cfga_err_nametab_len; i++) {
150 		if (pcidr_cfga_err_nametab[i].err == val)
151 			return (pcidr_cfga_err_nametab[i].name);
152 	}
153 	return (NULL);
154 }
155 
156 
157 void
158 pcidr_print_cfga(dlvl_t lvl, cfga_list_data_t *datap, char *prestr)
159 {
160 	char *str;
161 
162 	if (prestr == NULL)
163 		prestr = "";
164 
165 	dprint(lvl, "%slogical APID = %s\n", prestr, datap->ap_log_id);
166 	dprint(lvl, "%sphyiscal APID = %s\n", prestr, datap->ap_phys_id);
167 	dprint(lvl, "%sAP class = %s\n", prestr, datap->ap_class);
168 
169 	str = pcidr_cfga_stat_name(datap->ap_r_state);
170 	if (str == NULL)
171 		str = "(unrecognized cfga_stat_t value!)";
172 	dprint(lvl, "%sAP receptacle state = %s\n", prestr, str);
173 
174 	str = pcidr_cfga_stat_name(datap->ap_o_state);
175 	if (str == NULL)
176 		str = "(unrecognized cfga_stat_t value!)";
177 	dprint(lvl, "%sAP occupant state = %s\n", prestr, str);
178 
179 	str = pcidr_cfga_cond_name(datap->ap_cond);
180 	if (str == NULL)
181 		str = "(unrecognized cfga_cond_t value!)";
182 	dprint(lvl, "%sAP condition = %s\n", prestr, str);
183 
184 	dprint(lvl, "%sAP busy indicator = %d\n", prestr, datap->ap_busy);
185 
186 	str = ctime(&datap->ap_status_time);
187 	str[strlen(str) - 1] = '\0';	/* get rid of newline */
188 	dprint(lvl, "%sAP last change time = %ld (%s)\n", prestr,
189 	    datap->ap_status_time, str);
190 
191 	dprint(lvl, "%sAP info = %s\n", prestr, datap->ap_info);
192 	dprint(lvl, "%sAP type = %s\n", prestr, datap->ap_type);
193 }
194 
195 
196 /*
197  * for use with config_admin(3cfgadm) functions in their
198  * <struct cfga_msg *msgp> parameter
199  */
200 int
201 pcidr_cfga_msg_func(void *datap, const char *msg)
202 {
203 	pcidr_cfga_msg_data_t *dp = (pcidr_cfga_msg_data_t *)datap;
204 	char *prestr = dp->prestr;
205 
206 	if (prestr == NULL)
207 		prestr = "";
208 
209 	dprint(dp->dlvl, "%s%s", prestr, msg);
210 	return (0);
211 }
212 
213 
214 /*
215  * for use with config_admin(3cfgadm) functions in their
216  * <struct cfga_confirm *confp> parameter
217  */
218 /*ARGSUSED*/
219 int
220 pcidr_cfga_confirm_func(void *datap, const char *msg)
221 {
222 	return (1);
223 }
224 
225 
226 /*
227  * returns 0 if successful, -1 if unusuccesful, 1 if the AP already had
228  * <cmd> performed on it
229  */
230 int
231 pcidr_cfga_do_cmd(cfga_cmd_t cmd, cfga_list_data_t *cfga_listp)
232 {
233 	char *fn = "pcidr_cfga_do_cmd";
234 	int rv, i, j;
235 	char *cmdnm, *cfga_errstr, *apid, *str;
236 	int cmdarr[2];
237 	int cmdarr_len = sizeof (cmdarr) / sizeof (cmdarr[0]);
238 
239 	struct cfga_msg cfga_msg;
240 	pcidr_cfga_msg_data_t cfga_msg_data;
241 	struct cfga_confirm cfga_confirm;
242 	cfga_flags_t cfga_flags;
243 
244 	cmdnm = pcidr_cfga_cmd_name(cmd);
245 	assert(cmdnm != NULL);
246 
247 	apid = cfga_listp->ap_phys_id;
248 	cfga_msg_data.dlvl = DDEBUG;
249 	cfga_msg_data.prestr = "pcidr_cfga_do_cmd(msg): ";
250 	cfga_msg.message_routine = pcidr_cfga_msg_func;
251 	cfga_msg.appdata_ptr = (void *)&cfga_msg_data;
252 	cfga_confirm.confirm = pcidr_cfga_confirm_func;
253 	cfga_confirm.appdata_ptr = NULL;
254 	cfga_flags = CFGA_FLAG_VERBOSE;
255 
256 	if (cfga_listp->ap_busy != 0) {
257 		dprint(DDEBUG, "%s: apid = %s is busy\n",
258 		    fn, cfga_listp->ap_phys_id);
259 		return (-1);
260 	}
261 
262 	/*
263 	 * explicitly perform each step that would otherwise be done
264 	 * implicitly by cfgadm to isolate errors
265 	 */
266 	j = 0;
267 	switch (cmd) {
268 	case CFGA_CMD_CONFIGURE:
269 		if (cfga_listp->ap_o_state < CFGA_STAT_CONNECTED) {
270 			cmdarr[j] = CFGA_CMD_CONNECT;
271 			j++;
272 		}
273 		if (cfga_listp->ap_o_state < CFGA_STAT_CONFIGURED) {
274 			cmdarr[j] = CFGA_CMD_CONFIGURE;
275 			j++;
276 		}
277 		if (cfga_listp->ap_o_state >= CFGA_STAT_CONFIGURED)
278 			goto ALREADY;
279 		break;
280 	case CFGA_CMD_DISCONNECT:
281 		if (cfga_listp->ap_o_state >= CFGA_STAT_CONFIGURED) {
282 			cmdarr[j] = CFGA_CMD_UNCONFIGURE;
283 			j++;
284 		}
285 		if (cfga_listp->ap_o_state >= CFGA_STAT_CONNECTED) {
286 			cmdarr[j] = CFGA_CMD_DISCONNECT;
287 			j++;
288 		}
289 		if (cfga_listp->ap_r_state <= CFGA_STAT_DISCONNECTED)
290 			goto ALREADY;
291 		break;
292 	default:
293 		dprint(DDEBUG, "%s: unsupported cmd %d\n", cmd);
294 		return (-1);
295 	}
296 	assert(j <= cmdarr_len);
297 
298 	for (i = 0; i < j; i++) {
299 		cmd = cmdarr[i];
300 		cmdnm = pcidr_cfga_cmd_name(cmd);
301 		assert(cmdnm != NULL);
302 
303 		rv = config_change_state(cmd, 1, &apid, NULL, &cfga_confirm,
304 		    &cfga_msg, &cfga_errstr, cfga_flags);
305 		if (rv != CFGA_OK) {
306 			dprint(DDEBUG, "%s: command %s failed on apid %s",
307 			    fn, cmdnm, apid);
308 
309 			str = pcidr_cfga_err_name(rv);
310 			if (str == NULL)
311 				str = "unrecognized rv!";
312 			dprint(DDEBUG, ": rv = %d (%s)", rv, str);
313 
314 			if (cfga_errstr != NULL) {
315 				dprint(DDEBUG, ", error string = "
316 				    "\"%s\"", cfga_errstr);
317 				free(cfga_errstr);
318 			}
319 			dprint(DDEBUG, "\n");
320 			return (-1);
321 		}
322 	}
323 
324 	return (0);
325 	/*NOTREACHED*/
326 ALREADY:
327 	dprint(DDEBUG, "%s: command %s already done on apid %s\n",
328 	    fn, cmdnm, apid);
329 	return (1);
330 }
331