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 <stdio.h>
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <strings.h>
31 #include <errno.h>
32 #include <sys/param.h>
33 #include <sys/systeminfo.h>
34 #include <sys/sysevent/eventdefs.h>
35 #include <sys/sysevent/dr.h>
36 #include <syslog.h>
37 #include <libnvpair.h>
38 #include <stdarg.h>
39 #include <assert.h>
40 #include <sys/stat.h>
41 #include <dlfcn.h>
42 #include <pcidr.h>
43 #include <pcidr_cfga.h>
44 
45 
PCIDR_PLUGIN_PROTO(attrlistp,optp)46 PCIDR_PLUGIN_PROTO(attrlistp, optp)
47 {
48 	char *fn = PCIDR_PLUGIN_SYMSTR;
49 	int rv = 0;
50 	char *cfga_errstr = NULL;
51 	char *str, *apid;
52 	cfga_list_data_t *cfga_listp = NULL;
53 	cfga_cmd_t cmd;
54 	int cfga_list_len;
55 	pcidr_attrs_t dr;
56 
57 	pcidr_set_logopt(&optp->logopt);
58 
59 	if (pcidr_get_attrs(attrlistp, &dr) != 0 ||
60 	    pcidr_check_attrs(&dr) != 0) {
61 		dprint(DWARN, "%s: invalid or missing attributes\n", fn);
62 		return (EINVAL);
63 	}
64 
65 	/*
66 	 * get state of APID; enforce the cfgadm pci plugin implementation of
67 	 * returning one matching AP per supplied apid string
68 	 */
69 	rv = config_list_ext(1, &dr.dr_ap_id, &cfga_listp, &cfga_list_len,
70 	    NULL, NULL, &cfga_errstr, CFGA_FLAG_LIST_ALL);
71 	if (rv != CFGA_OK) {
72 		str = pcidr_cfga_err_name(rv);
73 		if (str == NULL)
74 			str = "unrecognized rv!";
75 		dprint(DDEBUG, "%s: config_list_ext() on apid = \"%s\" "
76 		    "failed: rv = %d (%s)", fn, dr.dr_ap_id, rv, str);
77 
78 		if (cfga_errstr != NULL) {
79 			dprint(DDEBUG, ", error string = \"%s\"",
80 			    cfga_errstr);
81 			free(cfga_errstr);
82 		}
83 		dprint(DDEBUG, "\n");
84 		rv = EINVAL;
85 		goto OUT;
86 	}
87 	if (cfga_list_len != 1) {
88 		dprint(DWARN, "%s: invalid condition - more than one AP was "
89 		    "found for the APID \"%s\"\n", fn, dr.dr_ap_id);
90 		rv = EINVAL;
91 		goto OUT;
92 	}
93 
94 	/*
95 	 * perform DR
96 	 */
97 	dprint(DINFO, "%s: showing info and performing DR on APID(s) "
98 	    "matching \"%s\"\n", fn, dr.dr_ap_id);
99 
100 	cmd = CFGA_CMD_NONE;
101 	dprint(DINFO, "===========================================\n", fn);
102 	pcidr_print_cfga(DINFO, &cfga_listp[0], "  .. ");
103 	apid = cfga_listp[0].ap_phys_id;
104 
105 	if (strcmp(dr.dr_req_type, DR_REQ_OUTGOING_RES) == 0) {
106 		cmd = CFGA_CMD_DISCONNECT;
107 		dprint(DINFO, "%s: disconnecting ...\n", fn, apid);
108 
109 		rv = pcidr_cfga_do_cmd(cmd, &cfga_listp[0]);
110 		if (rv < 0) {
111 			dprint(DINFO, "%s: disconnect FAILED\n", fn);
112 			rv = EIO;
113 		}
114 		else
115 			dprint(DINFO, "%s: disconnect OK\n", fn);
116 
117 		goto OUT;
118 	}
119 	if (strcmp(dr.dr_req_type, DR_REQ_INCOMING_RES) == 0) {
120 		cmd = CFGA_CMD_CONFIGURE;
121 		dprint(DINFO, "%s: configuring ...\n", fn, apid);
122 
123 		rv = pcidr_cfga_do_cmd(cmd, &cfga_listp[0]);
124 		if (rv < 0) {
125 			dprint(DINFO, "%s: configure FAILED\n", fn);
126 			rv = EIO;
127 		} else
128 			dprint(DINFO, "%s: configure OK\n", fn);
129 
130 		goto OUT;
131 	}
132 
133 	/* we should not get here if pcidr_check_attrs() is correct */
134 	dprint(DWARN, "%s: invalid dr_req_type = %s\n", fn, dr.dr_req_type);
135 	assert(cmd != CFGA_CMD_NONE);
136 	return (EINVAL);
137 	/*NOTREACHED*/
138 OUT:
139 	if (cfga_listp != NULL)
140 		free(cfga_listp);
141 	return (rv);
142 }
143