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