xref: /illumos-gate/usr/src/cmd/acpihpd/notify.c (revision f012ee0c3db17469b492c2cf757226f3d7b1ebbc)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2010, Intel Corporation.
23  * All rights reserved.
24  */
25 
26 #include <assert.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <fcntl.h>
30 #include <config_admin.h>
31 #include <strings.h>
32 #include <syslog.h>
33 #include <libsysevent.h>
34 #include <libdevinfo.h>
35 #include <libnvpair.h>
36 #include <assert.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #include <stropts.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <sys/sysevent/eventdefs.h>
43 #include <sys/sysevent/dr.h>
44 #include <sys/sbd_ioctl.h>
45 #include <sys/acpidev.h>
46 
47 #define	PMCONFIG_PATH			"/usr/sbin/pmconfig"
48 
49 #define	CFGADM_CMD_ASSIGN		"assign"
50 #define	CFGADM_CMD_POWERON		"poweron"
51 #define	CFGADM_CMD_PASSTHRU		"passthru"
52 
53 #define	STATUS_INPROGRESS		0
54 #define	STATUS_SUCCESS			1
55 #define	STATUS_FAILURE			2
56 #define	STATUS_NOOP			3
57 
58 static char *s_status_array[] = {
59 	ACPIDEV_CMD_OST_INPROGRESS,
60 	ACPIDEV_CMD_OST_SUCCESS,
61 	ACPIDEV_CMD_OST_FAILURE,
62 	ACPIDEV_CMD_OST_NOOP
63 };
64 
65 extern void debug_print(int, const char *, ...);
66 
67 /*ARGSUSED*/
68 static int
69 confirm_no(void *appdata_ptr, const char *message)
70 {
71 	return (0);
72 }
73 
74 /*ARGSUSED*/
75 static int
76 message_output(void *appdata_ptr, const char *message)
77 {
78 	debug_print(2, "cfgadm message: %s", message);
79 	return (CFGA_OK);
80 }
81 
82 static char *
83 plat_opt_str_alloc(int cmd, char *acpi_event_type, int status)
84 {
85 	char *opt;
86 	size_t len;
87 
88 	if (cmd == SBD_CMD_PASSTHRU) {
89 		len = strlen(s_status_array[status]) +
90 		    strlen(ACPIDEV_EVENT_TYPE_ATTR_NAME) +
91 		    strlen(acpi_event_type) + 10;
92 		if ((opt = malloc(len)) != NULL) {
93 			(void) snprintf(opt, len, "%s %s=%s",
94 			    s_status_array[status],
95 			    ACPIDEV_EVENT_TYPE_ATTR_NAME,
96 			    acpi_event_type);
97 			debug_print(2, "plat_opt_str_alloc = '%s'", opt);
98 		}
99 	} else {
100 		len = strlen("platform=''") +
101 		    strlen(s_status_array[status]) +
102 		    strlen(ACPIDEV_EVENT_TYPE_ATTR_NAME) +
103 		    strlen(acpi_event_type) + 10;
104 		if ((opt = malloc(len)) != NULL) {
105 			(void) snprintf(opt, len, "platform='%s %s=%s'",
106 			    s_status_array[status],
107 			    ACPIDEV_EVENT_TYPE_ATTR_NAME,
108 			    acpi_event_type);
109 			debug_print(2, "plat_opt_str_alloc = '%s'", opt);
110 		}
111 	}
112 
113 	return (opt);
114 }
115 
116 static int
117 cfgadm_cmd_wrapper(int cmd, int apid_num, char **apids,
118 	char *acpi_event_type, int status,
119 	struct cfga_confirm *confirm, struct cfga_msg *message)
120 {
121 	cfga_err_t ret;
122 	char *plat_opts;
123 	char *estrp = NULL;
124 
125 	assert(apid_num == 1);
126 	assert(apids != NULL);
127 
128 	plat_opts = plat_opt_str_alloc(cmd, acpi_event_type, status);
129 	if (plat_opts == NULL) {
130 		debug_print(0,
131 		    "failed to generate platform option string for cfgadm");
132 		return (-1);
133 	}
134 
135 	switch (cmd) {
136 	case SBD_CMD_CONNECT:
137 		ret = config_change_state(CFGA_CMD_CONNECT, apid_num, apids,
138 		    plat_opts, confirm, message, &estrp, 0);
139 		if (ret != CFGA_OK) {
140 			debug_print(0, "cfgadm('connect', '%s') failed, "
141 			    "ret = %d, errstr = '%s'", apids[0], ret, estrp);
142 		}
143 		break;
144 
145 	case SBD_CMD_CONFIGURE:
146 		ret = config_change_state(CFGA_CMD_CONFIGURE, apid_num, apids,
147 		    plat_opts, confirm, message, &estrp, 0);
148 		if (ret != CFGA_OK) {
149 			debug_print(0, "cfgadm('configure', '%s') failed, "
150 			    "ret = %d, errstr = '%s'", apids[0], ret, estrp);
151 		}
152 		break;
153 
154 	case SBD_CMD_ASSIGN:
155 		ret = config_private_func(CFGADM_CMD_ASSIGN, apid_num, apids,
156 		    plat_opts, confirm, message, &estrp, 0);
157 		if (ret != CFGA_OK) {
158 			debug_print(0, "cfgadm('assign', '%s') failed, "
159 			    "ret = %d, errstr = '%s'", apids[0], ret, estrp);
160 		}
161 		break;
162 
163 	case SBD_CMD_POWERON:
164 		ret = config_private_func(CFGADM_CMD_POWERON, apid_num, apids,
165 		    plat_opts, confirm, message, &estrp, 0);
166 		if (ret != CFGA_OK) {
167 			debug_print(0, "cfgadm('poweron', '%s') failed, "
168 			    "ret = %d, errstr = '%s'", apids[0], ret, estrp);
169 		}
170 		break;
171 
172 	case SBD_CMD_PASSTHRU:
173 		ret = config_private_func(CFGADM_CMD_PASSTHRU, apid_num, apids,
174 		    plat_opts, confirm, message, &estrp, 0);
175 		if (ret != CFGA_OK) {
176 			debug_print(0, "cfgadm('passthru', '%s') failed, "
177 			    "ret = %d, errstr = '%s'", apids[0], ret, estrp);
178 		}
179 		break;
180 
181 	default:
182 		debug_print(2, "unknown command (%d) to cfgadm_cmd_wrapper()");
183 		ret = CFGA_ERROR;
184 		break;
185 	}
186 
187 	if (plat_opts != NULL)
188 		free(plat_opts);
189 
190 	return (ret == CFGA_OK ? 0 : -1);
191 }
192 
193 static int
194 event_process(char *ap_id, char *req, char *acpi_event_type)
195 {
196 	char *apids[1];
197 	struct cfga_msg message;
198 	struct cfga_confirm confirm;
199 
200 	if (strcmp(req, DR_REQ_INCOMING_RES) != 0) {
201 		debug_print(2,
202 		    "Event is not supported (ap_id = %s, req = %s)",
203 		    ap_id, req);
204 		return (-1);
205 	}
206 
207 	apids[0] = ap_id;
208 	(void) memset(&confirm, 0, sizeof (confirm));
209 	confirm.confirm = confirm_no;
210 	(void) memset(&message, 0, sizeof (message));
211 	message.message_routine = message_output;
212 
213 	if (cfgadm_cmd_wrapper(SBD_CMD_ASSIGN, 1, apids,
214 	    acpi_event_type, STATUS_NOOP, &confirm, &message) != 0) {
215 		goto L_ERR;
216 	}
217 	syslog(LOG_NOTICE,
218 	    "board '%s' has been assigned successfully", ap_id);
219 	(void) cfgadm_cmd_wrapper(SBD_CMD_PASSTHRU, 1, apids,
220 	    acpi_event_type, STATUS_INPROGRESS, &confirm, &message);
221 
222 	if (cfgadm_cmd_wrapper(SBD_CMD_POWERON, 1, apids,
223 	    acpi_event_type, STATUS_NOOP, &confirm, &message) != 0) {
224 		goto L_ERR_SIG;
225 	}
226 	syslog(LOG_NOTICE,
227 	    "board '%s' has been powered on successfully", ap_id);
228 	(void) cfgadm_cmd_wrapper(SBD_CMD_PASSTHRU, 1, apids,
229 	    acpi_event_type, STATUS_INPROGRESS, &confirm, &message);
230 
231 	if (cfgadm_cmd_wrapper(SBD_CMD_CONNECT, 1, apids,
232 	    acpi_event_type, STATUS_INPROGRESS, &confirm, &message) != 0) {
233 		goto L_ERR_SIG;
234 	}
235 	syslog(LOG_NOTICE,
236 	    "board '%s' has been connected successfully", ap_id);
237 	(void) cfgadm_cmd_wrapper(SBD_CMD_PASSTHRU, 1, apids,
238 	    acpi_event_type, STATUS_INPROGRESS, &confirm, &message);
239 
240 	if (cfgadm_cmd_wrapper(SBD_CMD_CONFIGURE, 1, apids,
241 	    acpi_event_type, STATUS_INPROGRESS, &confirm, &message) != 0) {
242 		goto L_ERR_SIG;
243 	}
244 	syslog(LOG_NOTICE,
245 	    "board '%s' has been configured successfully", ap_id);
246 	(void) cfgadm_cmd_wrapper(SBD_CMD_PASSTHRU, 1, apids,
247 	    acpi_event_type, STATUS_SUCCESS, &confirm, &message);
248 
249 	(void) system(PMCONFIG_PATH);
250 	syslog(LOG_NOTICE,
251 	    "board '%s' has been added into system successfully", ap_id);
252 
253 	return (0);
254 
255 L_ERR_SIG:
256 	(void) cfgadm_cmd_wrapper(SBD_CMD_PASSTHRU, 1, apids,
257 	    acpi_event_type, STATUS_FAILURE, &confirm, &message);
258 L_ERR:
259 	syslog(LOG_ERR, "failed to add board '%s' into system", ap_id);
260 
261 	return (-1);
262 }
263 
264 void
265 notify_hotplug(sysevent_t *ev)
266 {
267 	char *vendor = NULL;
268 	nvlist_t *attr_list = NULL;
269 	char *class, *subclass;
270 	char *ap_id, *req, *acpi_event_type;
271 
272 	vendor = sysevent_get_vendor_name(ev);
273 	debug_print(2, "message_vendor = '%s'", vendor ? vendor : "unknown");
274 	if (vendor == NULL || strcmp(vendor, SUNW_VENDOR) != 0) {
275 		debug_print(2,
276 		    "vendor id of message is not '%s'", SUNW_VENDOR);
277 		goto L_EXIT;
278 	}
279 
280 	class = sysevent_get_class_name(ev);
281 	debug_print(2, "message_class = '%s'", class ? class : "unknown");
282 	if (class == NULL || strcmp(class, EC_DR) != 0) {
283 		debug_print(2, "class of message is not '%s'", EC_DR);
284 		goto L_EXIT;
285 	}
286 
287 	subclass = sysevent_get_subclass_name(ev);
288 	debug_print(2,
289 	    "message_subclass = '%s'", subclass ? subclass : "unknown");
290 	if (subclass == NULL || strcmp(subclass, ESC_DR_REQ) != 0) {
291 		debug_print(2,
292 		    "subclass of message is not '%s'", ESC_DR_REQ);
293 		goto L_EXIT;
294 	}
295 
296 	if (sysevent_get_attr_list(ev, &attr_list) != 0) {
297 		debug_print(2,
298 		    "can't retrieve attribute list from DR message");
299 		goto L_EXIT;
300 	}
301 
302 	if (nvlist_lookup_string(attr_list, DR_AP_ID, &ap_id) != 0) {
303 		debug_print(2,
304 		    "can't retrieve '%s' property from attribute list",
305 		    DR_AP_ID);
306 		goto L_EXIT;
307 	}
308 	debug_print(2, "%s = '%s'", DR_AP_ID, ap_id ? ap_id : "<null>");
309 	if ((ap_id == NULL) || (strlen(ap_id) == 0)) {
310 		debug_print(2, "'%s' property in message is NULL", DR_AP_ID);
311 		goto L_EXIT;
312 	}
313 
314 	if (nvlist_lookup_string(attr_list, DR_REQ_TYPE, &req) != 0) {
315 		debug_print(2,
316 		    "can't retrieve '%s' property from attribute list",
317 		    DR_REQ_TYPE);
318 		goto L_EXIT;
319 	}
320 	debug_print(2, "%s = '%s'", DR_REQ_TYPE, req ? req : "<null>");
321 	if ((req == NULL) || (strlen(req) == 0)) {
322 		debug_print(2, "'%s' property in message is NULL", DR_REQ_TYPE);
323 		goto L_EXIT;
324 	}
325 
326 	if (nvlist_lookup_string(attr_list, ACPIDEV_EVENT_TYPE_ATTR_NAME,
327 	    &acpi_event_type) != 0) {
328 		debug_print(2,
329 		    "can't retrieve '%s' property from attribute list",
330 		    ACPIDEV_EVENT_TYPE_ATTR_NAME);
331 		goto L_EXIT;
332 	}
333 	debug_print(2, "%s = '%s'", ACPIDEV_EVENT_TYPE_ATTR_NAME,
334 	    acpi_event_type ? acpi_event_type : "<null>");
335 	if ((acpi_event_type == NULL) || (strlen(acpi_event_type) == 0)) {
336 		debug_print(2, "'%s' property in message is NULL",
337 		    ACPIDEV_EVENT_TYPE_ATTR_NAME);
338 		goto L_EXIT;
339 	}
340 
341 	(void) event_process(ap_id, req, acpi_event_type);
342 
343 L_EXIT:
344 	if (vendor != NULL) {
345 		free(vendor);
346 	}
347 
348 	if (attr_list != NULL) {
349 		nvlist_free(attr_list);
350 	}
351 
352 	/* No need to free class & subclass. */
353 }
354