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