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