170025d76Sjohnny /*
270025d76Sjohnny  * CDDL HEADER START
370025d76Sjohnny  *
470025d76Sjohnny  * The contents of this file are subject to the terms of the
570025d76Sjohnny  * Common Development and Distribution License, Version 1.0 only
670025d76Sjohnny  * (the "License").  You may not use this file except in compliance
770025d76Sjohnny  * with the License.
870025d76Sjohnny  *
970025d76Sjohnny  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1070025d76Sjohnny  * or http://www.opensolaris.org/os/licensing.
1170025d76Sjohnny  * See the License for the specific language governing permissions
1270025d76Sjohnny  * and limitations under the License.
1370025d76Sjohnny  *
1470025d76Sjohnny  * When distributing Covered Code, include this CDDL HEADER in each
1570025d76Sjohnny  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1670025d76Sjohnny  * If applicable, add the following below this CDDL HEADER, with the
1770025d76Sjohnny  * fields enclosed by brackets "[]" replaced with your own identifying
1870025d76Sjohnny  * information: Portions Copyright [yyyy] [name of copyright owner]
1970025d76Sjohnny  *
2070025d76Sjohnny  * CDDL HEADER END
2170025d76Sjohnny  */
2270025d76Sjohnny /*
2370025d76Sjohnny  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
2470025d76Sjohnny  * Use is subject to license terms.
2570025d76Sjohnny  */
2670025d76Sjohnny 
2770025d76Sjohnny #include <string.h>
2870025d76Sjohnny #include <sys/param.h>
2970025d76Sjohnny #include <assert.h>
3070025d76Sjohnny #include <pcidr.h>
3170025d76Sjohnny #include <pcidr_cfga.h>
3270025d76Sjohnny 
3370025d76Sjohnny 
3470025d76Sjohnny /*
3570025d76Sjohnny  * misc config_admin(3cfgadm) related routines
3670025d76Sjohnny  */
3770025d76Sjohnny 
3870025d76Sjohnny static struct {
3970025d76Sjohnny 	cfga_stat_t stat;
4070025d76Sjohnny 	char *name;
4170025d76Sjohnny } pcidr_cfga_stat_nametab[] = {
4270025d76Sjohnny 	{CFGA_STAT_NONE, "CFGA_STAT_NONE"},
4370025d76Sjohnny 	{CFGA_STAT_EMPTY, "CFGA_STAT_EMPTY"},
4470025d76Sjohnny 	{CFGA_STAT_DISCONNECTED, "CFGA_STAT_DISCONNECTED"},
4570025d76Sjohnny 	{CFGA_STAT_CONNECTED, "CFGA_STAT_CONNECTED"},
4670025d76Sjohnny 	{CFGA_STAT_UNCONFIGURED, "CFGA_STAT_UNCONFIGURED"},
4770025d76Sjohnny 	{CFGA_STAT_CONFIGURED, "CFGA_STAT_CONFIGURED"},
4870025d76Sjohnny };
4970025d76Sjohnny static int pcidr_cfga_stat_nametab_len =
5070025d76Sjohnny     sizeof (pcidr_cfga_stat_nametab) / sizeof (pcidr_cfga_stat_nametab[0]);
5170025d76Sjohnny 
5270025d76Sjohnny char *
pcidr_cfga_stat_name(cfga_stat_t val)5370025d76Sjohnny pcidr_cfga_stat_name(cfga_stat_t val)
5470025d76Sjohnny {
5570025d76Sjohnny 	int i;
5670025d76Sjohnny 
5770025d76Sjohnny 	for (i = 0; i < pcidr_cfga_stat_nametab_len; i++) {
5870025d76Sjohnny 		if (pcidr_cfga_stat_nametab[i].stat == val)
5970025d76Sjohnny 			return (pcidr_cfga_stat_nametab[i].name);
6070025d76Sjohnny 	}
6170025d76Sjohnny 	return (NULL);
6270025d76Sjohnny }
6370025d76Sjohnny 
6470025d76Sjohnny 
6570025d76Sjohnny static struct {
66*2c2d21e9SRichard Lowe 	cfga_cmd_t cmd;
6770025d76Sjohnny 	char *name;
6870025d76Sjohnny } pcidr_cfga_cmd_nametab[] = {
6970025d76Sjohnny 	{CFGA_CMD_NONE, "CFGA_CMD_NONE"},
7070025d76Sjohnny 	{CFGA_CMD_LOAD, "CFGA_CMD_LOAD"},
7170025d76Sjohnny 	{CFGA_CMD_UNLOAD, "CFGA_CMD_UNLOAD"},
7270025d76Sjohnny 	{CFGA_CMD_CONNECT, "CFGA_CMD_CONNECT"},
7370025d76Sjohnny 	{CFGA_CMD_DISCONNECT, "CFGA_CMD_DISCONNECT"},
7470025d76Sjohnny 	{CFGA_CMD_CONFIGURE, "CFGA_CMD_CONFIGURE"},
7570025d76Sjohnny 	{CFGA_CMD_UNCONFIGURE, "CFGA_CMD_UNCONFIGURE"},
7670025d76Sjohnny };
7770025d76Sjohnny static int pcidr_cfga_cmd_nametab_len =
7870025d76Sjohnny     sizeof (pcidr_cfga_cmd_nametab) / sizeof (pcidr_cfga_cmd_nametab[0]);
7970025d76Sjohnny 
8070025d76Sjohnny char *
pcidr_cfga_cmd_name(cfga_cmd_t val)8170025d76Sjohnny pcidr_cfga_cmd_name(cfga_cmd_t val)
8270025d76Sjohnny {
8370025d76Sjohnny 	int i;
8470025d76Sjohnny 
8570025d76Sjohnny 	for (i = 0; i < pcidr_cfga_cmd_nametab_len; i++) {
8670025d76Sjohnny 		if (pcidr_cfga_cmd_nametab[i].cmd == val)
8770025d76Sjohnny 			return (pcidr_cfga_cmd_nametab[i].name);
8870025d76Sjohnny 	}
8970025d76Sjohnny 	return (NULL);
9070025d76Sjohnny }
9170025d76Sjohnny 
9270025d76Sjohnny 
9370025d76Sjohnny static struct {
9470025d76Sjohnny 	cfga_cond_t cond;
9570025d76Sjohnny 	char *name;
9670025d76Sjohnny } pcidr_cfga_cond_nametab[] = {
9770025d76Sjohnny 	{CFGA_COND_UNKNOWN, "CFGA_COND_UNKNOWN"},
9870025d76Sjohnny 	{CFGA_COND_OK, "CFGA_COND_OK"},
9970025d76Sjohnny 	{CFGA_COND_FAILING, "CFGA_COND_FAILING"},
10070025d76Sjohnny 	{CFGA_COND_FAILED, "CFGA_COND_FAILED"},
10170025d76Sjohnny 	{CFGA_COND_UNUSABLE, "CFGA_COND_UNUSABLE"},
10270025d76Sjohnny };
10370025d76Sjohnny static int pcidr_cfga_cond_nametab_len =
10470025d76Sjohnny     sizeof (pcidr_cfga_cond_nametab) / sizeof (pcidr_cfga_cond_nametab[0]);
10570025d76Sjohnny 
10670025d76Sjohnny char *
pcidr_cfga_cond_name(cfga_cond_t val)10770025d76Sjohnny pcidr_cfga_cond_name(cfga_cond_t val)
10870025d76Sjohnny {
10970025d76Sjohnny 	int i;
11070025d76Sjohnny 
11170025d76Sjohnny 	for (i = 0; i < pcidr_cfga_cond_nametab_len; i++) {
11270025d76Sjohnny 		if (pcidr_cfga_cond_nametab[i].cond == val)
11370025d76Sjohnny 			return (pcidr_cfga_cond_nametab[i].name);
11470025d76Sjohnny 	}
11570025d76Sjohnny 	return (NULL);
11670025d76Sjohnny }
11770025d76Sjohnny 
11870025d76Sjohnny 
11970025d76Sjohnny static struct {
12070025d76Sjohnny 	cfga_err_t err;
12170025d76Sjohnny 	char *name;
12270025d76Sjohnny } pcidr_cfga_err_nametab[] = {
12370025d76Sjohnny 	{CFGA_OK, "CFGA_OK"},
12470025d76Sjohnny 	{CFGA_NACK, "CFGA_NACK"},
12570025d76Sjohnny 	{CFGA_NOTSUPP, "CFGA_NOTSUPP"},
12670025d76Sjohnny 	{CFGA_OPNOTSUPP, "CFGA_OPNOTSUPP"},
12770025d76Sjohnny 	{CFGA_PRIV, "CFGA_PRIV"},
12870025d76Sjohnny 	{CFGA_BUSY, "CFGA_BUSY"},
12970025d76Sjohnny 	{CFGA_SYSTEM_BUSY, "CFGA_SYSTEM_BUSY"},
13070025d76Sjohnny 	{CFGA_DATA_ERROR, "CFGA_DATA_ERROR"},
13170025d76Sjohnny 	{CFGA_LIB_ERROR, "CFGA_LIB_ERROR"},
13270025d76Sjohnny 	{CFGA_NO_LIB, "CFGA_NO_LIB"},
13370025d76Sjohnny 	{CFGA_INSUFFICENT_CONDITION, "CFGA_INSUFFICENT_CONDITION"},
13470025d76Sjohnny 	{CFGA_INVAL, "CFGA_INVAL"},
13570025d76Sjohnny 	{CFGA_ERROR, "CFGA_ERROR"},
13670025d76Sjohnny 	{CFGA_APID_NOEXIST, "CFGA_APID_NOEXIST"},
13770025d76Sjohnny 	{CFGA_ATTR_INVAL, "CFGA_ATTR_INVAL"},
13870025d76Sjohnny };
13970025d76Sjohnny static int pcidr_cfga_err_nametab_len =
14070025d76Sjohnny     sizeof (pcidr_cfga_err_nametab) / sizeof (pcidr_cfga_err_nametab[0]);
14170025d76Sjohnny 
14270025d76Sjohnny char *
pcidr_cfga_err_name(cfga_err_t val)14370025d76Sjohnny pcidr_cfga_err_name(cfga_err_t val)
14470025d76Sjohnny {
14570025d76Sjohnny 	int i;
14670025d76Sjohnny 
14770025d76Sjohnny 	for (i = 0; i < pcidr_cfga_err_nametab_len; i++) {
14870025d76Sjohnny 		if (pcidr_cfga_err_nametab[i].err == val)
14970025d76Sjohnny 			return (pcidr_cfga_err_nametab[i].name);
15070025d76Sjohnny 	}
15170025d76Sjohnny 	return (NULL);
15270025d76Sjohnny }
15370025d76Sjohnny 
15470025d76Sjohnny 
15570025d76Sjohnny void
pcidr_print_cfga(dlvl_t lvl,cfga_list_data_t * datap,char * prestr)15670025d76Sjohnny pcidr_print_cfga(dlvl_t lvl, cfga_list_data_t *datap, char *prestr)
15770025d76Sjohnny {
15870025d76Sjohnny 	char *str;
15970025d76Sjohnny 
16070025d76Sjohnny 	if (prestr == NULL)
16170025d76Sjohnny 		prestr = "";
16270025d76Sjohnny 
16370025d76Sjohnny 	dprint(lvl, "%slogical APID = %s\n", prestr, datap->ap_log_id);
16470025d76Sjohnny 	dprint(lvl, "%sphyiscal APID = %s\n", prestr, datap->ap_phys_id);
16570025d76Sjohnny 	dprint(lvl, "%sAP class = %s\n", prestr, datap->ap_class);
16670025d76Sjohnny 
16770025d76Sjohnny 	str = pcidr_cfga_stat_name(datap->ap_r_state);
16870025d76Sjohnny 	if (str == NULL)
16970025d76Sjohnny 		str = "(unrecognized cfga_stat_t value!)";
17070025d76Sjohnny 	dprint(lvl, "%sAP receptacle state = %s\n", prestr, str);
17170025d76Sjohnny 
17270025d76Sjohnny 	str = pcidr_cfga_stat_name(datap->ap_o_state);
17370025d76Sjohnny 	if (str == NULL)
17470025d76Sjohnny 		str = "(unrecognized cfga_stat_t value!)";
17570025d76Sjohnny 	dprint(lvl, "%sAP occupant state = %s\n", prestr, str);
17670025d76Sjohnny 
17770025d76Sjohnny 	str = pcidr_cfga_cond_name(datap->ap_cond);
17870025d76Sjohnny 	if (str == NULL)
17970025d76Sjohnny 		str = "(unrecognized cfga_cond_t value!)";
18070025d76Sjohnny 	dprint(lvl, "%sAP condition = %s\n", prestr, str);
18170025d76Sjohnny 
18270025d76Sjohnny 	dprint(lvl, "%sAP busy indicator = %d\n", prestr, datap->ap_busy);
18370025d76Sjohnny 
18470025d76Sjohnny 	str = ctime(&datap->ap_status_time);
18570025d76Sjohnny 	str[strlen(str) - 1] = '\0';	/* get rid of newline */
18670025d76Sjohnny 	dprint(lvl, "%sAP last change time = %ld (%s)\n", prestr,
18770025d76Sjohnny 	    datap->ap_status_time, str);
18870025d76Sjohnny 
18970025d76Sjohnny 	dprint(lvl, "%sAP info = %s\n", prestr, datap->ap_info);
19070025d76Sjohnny 	dprint(lvl, "%sAP type = %s\n", prestr, datap->ap_type);
19170025d76Sjohnny }
19270025d76Sjohnny 
19370025d76Sjohnny 
19470025d76Sjohnny /*
19570025d76Sjohnny  * for use with config_admin(3cfgadm) functions in their
19670025d76Sjohnny  * <struct cfga_msg *msgp> parameter
19770025d76Sjohnny  */
19870025d76Sjohnny int
pcidr_cfga_msg_func(void * datap,const char * msg)19970025d76Sjohnny pcidr_cfga_msg_func(void *datap, const char *msg)
20070025d76Sjohnny {
20170025d76Sjohnny 	pcidr_cfga_msg_data_t *dp = (pcidr_cfga_msg_data_t *)datap;
20270025d76Sjohnny 	char *prestr = dp->prestr;
20370025d76Sjohnny 
20470025d76Sjohnny 	if (prestr == NULL)
20570025d76Sjohnny 		prestr = "";
20670025d76Sjohnny 
20770025d76Sjohnny 	dprint(dp->dlvl, "%s%s", prestr, msg);
20870025d76Sjohnny 	return (0);
20970025d76Sjohnny }
21070025d76Sjohnny 
21170025d76Sjohnny 
21270025d76Sjohnny /*
21370025d76Sjohnny  * for use with config_admin(3cfgadm) functions in their
21470025d76Sjohnny  * <struct cfga_confirm *confp> parameter
21570025d76Sjohnny  */
21670025d76Sjohnny /*ARGSUSED*/
21770025d76Sjohnny int
pcidr_cfga_confirm_func(void * datap,const char * msg)21870025d76Sjohnny pcidr_cfga_confirm_func(void *datap, const char *msg)
21970025d76Sjohnny {
22070025d76Sjohnny 	return (1);
22170025d76Sjohnny }
22270025d76Sjohnny 
22370025d76Sjohnny 
22470025d76Sjohnny /*
22570025d76Sjohnny  * returns 0 if successful, -1 if unusuccesful, 1 if the AP already had
22670025d76Sjohnny  * <cmd> performed on it
22770025d76Sjohnny  */
22870025d76Sjohnny int
pcidr_cfga_do_cmd(cfga_cmd_t cmd,cfga_list_data_t * cfga_listp)22970025d76Sjohnny pcidr_cfga_do_cmd(cfga_cmd_t cmd, cfga_list_data_t *cfga_listp)
23070025d76Sjohnny {
23170025d76Sjohnny 	char *fn = "pcidr_cfga_do_cmd";
23270025d76Sjohnny 	int rv, i, j;
23370025d76Sjohnny 	char *cmdnm, *cfga_errstr, *apid, *str;
23470025d76Sjohnny 	int cmdarr[2];
23570025d76Sjohnny 	int cmdarr_len = sizeof (cmdarr) / sizeof (cmdarr[0]);
23670025d76Sjohnny 
23770025d76Sjohnny 	struct cfga_msg cfga_msg;
23870025d76Sjohnny 	pcidr_cfga_msg_data_t cfga_msg_data;
23970025d76Sjohnny 	struct cfga_confirm cfga_confirm;
24070025d76Sjohnny 	cfga_flags_t cfga_flags;
24170025d76Sjohnny 
24270025d76Sjohnny 	cmdnm = pcidr_cfga_cmd_name(cmd);
24370025d76Sjohnny 	assert(cmdnm != NULL);
24470025d76Sjohnny 
24570025d76Sjohnny 	apid = cfga_listp->ap_phys_id;
24670025d76Sjohnny 	cfga_msg_data.dlvl = DDEBUG;
24770025d76Sjohnny 	cfga_msg_data.prestr = "pcidr_cfga_do_cmd(msg): ";
24870025d76Sjohnny 	cfga_msg.message_routine = pcidr_cfga_msg_func;
24970025d76Sjohnny 	cfga_msg.appdata_ptr = (void *)&cfga_msg_data;
25070025d76Sjohnny 	cfga_confirm.confirm = pcidr_cfga_confirm_func;
25170025d76Sjohnny 	cfga_confirm.appdata_ptr = NULL;
25270025d76Sjohnny 	cfga_flags = CFGA_FLAG_VERBOSE;
25370025d76Sjohnny 
25470025d76Sjohnny 	if (cfga_listp->ap_busy != 0) {
25570025d76Sjohnny 		dprint(DDEBUG, "%s: apid = %s is busy\n",
25670025d76Sjohnny 		    fn, cfga_listp->ap_phys_id);
25770025d76Sjohnny 		return (-1);
25870025d76Sjohnny 	}
25970025d76Sjohnny 
26070025d76Sjohnny 	/*
26170025d76Sjohnny 	 * explicitly perform each step that would otherwise be done
26270025d76Sjohnny 	 * implicitly by cfgadm to isolate errors
26370025d76Sjohnny 	 */
26470025d76Sjohnny 	j = 0;
26570025d76Sjohnny 	switch (cmd) {
26670025d76Sjohnny 	case CFGA_CMD_CONFIGURE:
26770025d76Sjohnny 		if (cfga_listp->ap_o_state < CFGA_STAT_CONNECTED) {
26870025d76Sjohnny 			cmdarr[j] = CFGA_CMD_CONNECT;
26970025d76Sjohnny 			j++;
27070025d76Sjohnny 		}
27170025d76Sjohnny 		if (cfga_listp->ap_o_state < CFGA_STAT_CONFIGURED) {
27270025d76Sjohnny 			cmdarr[j] = CFGA_CMD_CONFIGURE;
27370025d76Sjohnny 			j++;
27470025d76Sjohnny 		}
27570025d76Sjohnny 		if (cfga_listp->ap_o_state >= CFGA_STAT_CONFIGURED)
27670025d76Sjohnny 			goto ALREADY;
27770025d76Sjohnny 		break;
27870025d76Sjohnny 	case CFGA_CMD_DISCONNECT:
27970025d76Sjohnny 		if (cfga_listp->ap_o_state >= CFGA_STAT_CONFIGURED) {
28070025d76Sjohnny 			cmdarr[j] = CFGA_CMD_UNCONFIGURE;
28170025d76Sjohnny 			j++;
28270025d76Sjohnny 		}
28370025d76Sjohnny 		if (cfga_listp->ap_o_state >= CFGA_STAT_CONNECTED) {
28470025d76Sjohnny 			cmdarr[j] = CFGA_CMD_DISCONNECT;
28570025d76Sjohnny 			j++;
28670025d76Sjohnny 		}
28770025d76Sjohnny 		if (cfga_listp->ap_r_state <= CFGA_STAT_DISCONNECTED)
28870025d76Sjohnny 			goto ALREADY;
28970025d76Sjohnny 		break;
29070025d76Sjohnny 	default:
29170025d76Sjohnny 		dprint(DDEBUG, "%s: unsupported cmd %d\n", cmd);
29270025d76Sjohnny 		return (-1);
29370025d76Sjohnny 	}
29470025d76Sjohnny 	assert(j <= cmdarr_len);
29570025d76Sjohnny 
29670025d76Sjohnny 	for (i = 0; i < j; i++) {
29770025d76Sjohnny 		cmd = cmdarr[i];
29870025d76Sjohnny 		cmdnm = pcidr_cfga_cmd_name(cmd);
29970025d76Sjohnny 		assert(cmdnm != NULL);
30070025d76Sjohnny 
30170025d76Sjohnny 		rv = config_change_state(cmd, 1, &apid, NULL, &cfga_confirm,
30270025d76Sjohnny 		    &cfga_msg, &cfga_errstr, cfga_flags);
30370025d76Sjohnny 		if (rv != CFGA_OK) {
30470025d76Sjohnny 			dprint(DDEBUG, "%s: command %s failed on apid %s",
30570025d76Sjohnny 			    fn, cmdnm, apid);
30670025d76Sjohnny 
30770025d76Sjohnny 			str = pcidr_cfga_err_name(rv);
30870025d76Sjohnny 			if (str == NULL)
30970025d76Sjohnny 				str = "unrecognized rv!";
31070025d76Sjohnny 			dprint(DDEBUG, ": rv = %d (%s)", rv, str);
31170025d76Sjohnny 
31270025d76Sjohnny 			if (cfga_errstr != NULL) {
31370025d76Sjohnny 				dprint(DDEBUG, ", error string = "
31470025d76Sjohnny 				    "\"%s\"", cfga_errstr);
31570025d76Sjohnny 				free(cfga_errstr);
31670025d76Sjohnny 			}
31770025d76Sjohnny 			dprint(DDEBUG, "\n");
31870025d76Sjohnny 			return (-1);
31970025d76Sjohnny 		}
32070025d76Sjohnny 	}
32170025d76Sjohnny 
32270025d76Sjohnny 	return (0);
32370025d76Sjohnny 	/*NOTREACHED*/
32470025d76Sjohnny ALREADY:
32570025d76Sjohnny 	dprint(DDEBUG, "%s: command %s already done on apid %s\n",
32670025d76Sjohnny 	    fn, cmdnm, apid);
32770025d76Sjohnny 	return (1);
32870025d76Sjohnny }
329