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 *
pcidr_cfga_stat_name(cfga_stat_t val)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 *
pcidr_cfga_cmd_name(cfga_cmd_t val)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 *
pcidr_cfga_cond_name(cfga_cond_t val)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 *
pcidr_cfga_err_name(cfga_err_t val)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
pcidr_print_cfga(dlvl_t lvl,cfga_list_data_t * datap,char * prestr)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
pcidr_cfga_msg_func(void * datap,const char * msg)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
pcidr_cfga_confirm_func(void * datap,const char * msg)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
pcidr_cfga_do_cmd(cfga_cmd_t cmd,cfga_list_data_t * cfga_listp)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