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