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