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