/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. */ #include "mp_utils.h" #include #ifndef OIDLIST #define OIDLIST "oid" #endif /* Remove these 5 when this source can compile with sunddi.h */ #ifndef EC_DDI #define EC_DDI "EC_ddi" #endif #ifndef ESC_DDI_INITIATOR_REGISTER #define ESC_DDI_INITIATOR_REGISTER "ESC_ddi_initiator_register" #endif #ifndef ESC_DDI_INITIATOR_UNREGISTER #define ESC_DDI_INITIATOR_UNREGISTER "ESC_ddi_initiator_unregister" #endif #ifndef DDI_DRIVER_MAJOR #define DDI_DRIVER_MAJOR "ddi.major" #endif #ifndef DDI_INSTANCE #define DDI_INSTANCE "ddi.instance" #endif #define VISA_CHANGE 1 #define PROP_CHANGE 2 MP_STATUS getStatus4ErrorCode(int driverError) { MP_STATUS mpStatus = MP_STATUS_FAILED; log(LOG_INFO, "getStatus4ErrorCode()", "- enter"); switch (driverError) { case MP_DRVR_INVALID_ID: log(LOG_INFO, "getStatus4ErrorCode()", " received mp_errno=MP_DRVR_INVALID_ID" " from driver call."); log(LOG_INFO, "getStatus4ErrorCode()", " returning MP_STATUS_OBJECT_NOT_FOUND" " to caller."); mpStatus = MP_STATUS_OBJECT_NOT_FOUND; break; case MP_DRVR_ID_OBSOLETE: log(LOG_INFO, "getStatus4ErrorCode()", " received mp_errno=MP_DRVR_ID_OBSOLETE" " from driver call."); log(LOG_INFO, "getStatus4ErrorCode()", " returning MP_STATUS_OBJECT_NOT_FOUND" " to caller."); mpStatus = MP_STATUS_OBJECT_NOT_FOUND; break; case MP_DRVR_ACCESS_SYMMETRIC: log(LOG_INFO, "getStatus4ErrorCode()", " received mp_errno=MP_DRVR_ACCESS_SYMMETRIC" " from driver call."); log(LOG_INFO, "getStatus4ErrorCode()", " returning MP_STATUS_INVALID_PARAMETER" " to caller."); mpStatus = MP_STATUS_INVALID_PARAMETER; break; case MP_DRVR_PATH_UNAVAILABLE: log(LOG_INFO, "getStatus4ErrorCode()", " received mp_errno=MP_DRVR_PATH_UNAVAILABLE" " from driver call."); log(LOG_INFO, "getStatus4ErrorCode()", " returning MP_STATUS_PATH_NONOPERATIONAL" " to caller."); mpStatus = MP_STATUS_PATH_NONOPERATIONAL; break; case MP_DRVR_IDS_NOT_ASSOCIATED: log(LOG_INFO, "getStatus4ErrorCode()", " received mp_errno=MP_DRVR_IDS_NOT_ASSOCIATED" " from driver call."); log(LOG_INFO, "getStatus4ErrorCode()", " returning MP_STATUS_INVALID_PARAMETER" " to caller."); mpStatus = MP_STATUS_INVALID_PARAMETER; break; case MP_DRVR_ILLEGAL_ACCESS_STATE_REQUEST: log(LOG_INFO, "getStatus4ErrorCode()", " received mp_errno=" "MP_DRVR_ILLEGAL_ACCESS_STATE_REQUEST" " from driver call."); log(LOG_INFO, "getStatus4ErrorCode()", " returning MP_STATUS_INVALID_PARAMETER" " to caller."); mpStatus = MP_STATUS_ACCESS_STATE_INVALID; break; default: log(LOG_INFO, "getStatus4ErrorCode()", " - received (unsupported) mp_errno=%d from" " driver call.", driverError); log(LOG_INFO, "getStatus4ErrorCode()", " - returning MP_STATUS_FAILED to caller."); mpStatus = MP_STATUS_FAILED; } log(LOG_INFO, "getStatus4ErrorCode()", "- exit"); return (mpStatus); } MP_OID_LIST *createOidList(int size) { MP_OID_LIST *pOidList = NULL; log(LOG_INFO, "createOidList()", "- enter"); if (size < 1) { log(LOG_INFO, "createOidList()", "requested size is less than 1"); log(LOG_INFO, "createOidList()", " - error exit"); return (NULL); } else { pOidList = (MP_OID_LIST*)calloc(1, sizeof (MP_OID_LIST) + ((size - 1) * sizeof (MP_OID))); if (NULL == pOidList) { log(LOG_INFO, "createOidList()", "no memory for pOidList"); log(LOG_INFO, "createOidList()", " - error exit"); return (NULL); } log(LOG_INFO, "createOidList()", "- exit(%d)", size); return (pOidList); } } /* Calls the client callback function, if one is registered */ static void notifyClient(sysevent_t *ev) { nvlist_t *attr_list = NULL; uint64_t *val = NULL; int32_t *instance = NULL; int32_t *major = NULL; int valAllocated = 0; uint_t nelem = 0; int i = 0; int eventType = 0; int index = -1; void *pCallerData = NULL; char subClassName[256]; MP_BOOL becomingVisible = MP_FALSE; MP_OID_LIST *oidList = NULL; log(LOG_INFO, "notifyClient()", "- enter"); (void) strncpy(subClassName, sysevent_get_subclass_name(ev), 256); if (strstr(subClassName, "change")) { eventType = PROP_CHANGE; log(LOG_INFO, "notifyClient()", "- got a change event"); log(LOG_INFO, "notifyClient()", ": [%s]", subClassName); if (strncmp(subClassName, ESC_SUN_MP_PLUGIN_CHANGE, 255) == 0) { index = MP_OBJECT_TYPE_PLUGIN; } else if (strncmp(subClassName, ESC_SUN_MP_LU_CHANGE, 255) == 0) { index = MP_OBJECT_TYPE_MULTIPATH_LU; } else if (strncmp(subClassName, ESC_SUN_MP_PATH_CHANGE, 255) == 0) { index = MP_OBJECT_TYPE_PATH_LU; } else if (strncmp(subClassName, ESC_SUN_MP_INIT_PORT_CHANGE, 255) == 0) { index = MP_OBJECT_TYPE_INITIATOR_PORT; } else if (strncmp(subClassName, ESC_SUN_MP_TPG_CHANGE, 255) == 0) { index = MP_OBJECT_TYPE_TARGET_PORT_GROUP; } else if (strncmp(subClassName, ESC_SUN_MP_TARGET_PORT_CHANGE, 255) == 0) { index = MP_OBJECT_TYPE_TARGET_PORT; } else if (strncmp(subClassName, ESC_SUN_MP_DEV_PROD_CHANGE, 255) == 0) { index = MP_OBJECT_TYPE_DEVICE_PRODUCT; } } else if ((strstr(subClassName, "add")) || (strstr(subClassName, "initiator_register"))) { eventType = VISA_CHANGE; becomingVisible = MP_TRUE; log(LOG_INFO, "notifyClient()", "- got a visibility" " add event"); log(LOG_INFO, "notifyClient()", ": [%s]", subClassName); if (strncmp(subClassName, ESC_SUN_MP_LU_ADD, 255) == 0) { index = MP_OBJECT_TYPE_MULTIPATH_LU; } else if (strncmp(subClassName, ESC_SUN_MP_PATH_ADD, 255) == 0) { index = MP_OBJECT_TYPE_PATH_LU; } else if (strncmp(subClassName, ESC_DDI_INITIATOR_REGISTER, 244) == 0) { index = MP_OBJECT_TYPE_INITIATOR_PORT; } else if (strncmp(subClassName, ESC_SUN_MP_TPG_ADD, 255) == 0) { index = MP_OBJECT_TYPE_TARGET_PORT_GROUP; } else if (strncmp(subClassName, ESC_SUN_MP_TARGET_PORT_ADD, 255) == 0) { index = MP_OBJECT_TYPE_TARGET_PORT; } else if (strncmp(subClassName, ESC_SUN_MP_DEV_PROD_ADD, 255) == 0) { index = MP_OBJECT_TYPE_DEVICE_PRODUCT; } } else if ((strstr(subClassName, "remove")) || (strstr(subClassName, "initiator_unregister"))) { eventType = VISA_CHANGE; becomingVisible = MP_FALSE; log(LOG_INFO, "notifyClient()", "- got a visibility" " remove event"); log(LOG_INFO, "notifyClient()", ": [%s]", subClassName); if (strncmp(subClassName, ESC_SUN_MP_LU_REMOVE, 255) == 0) { index = MP_OBJECT_TYPE_MULTIPATH_LU; } else if (strncmp(subClassName, ESC_SUN_MP_PATH_REMOVE, 255) == 0) { index = MP_OBJECT_TYPE_PATH_LU; } else if (strncmp(subClassName, ESC_DDI_INITIATOR_UNREGISTER, 255) == 0) { index = MP_OBJECT_TYPE_INITIATOR_PORT; } else if (strncmp(subClassName, ESC_SUN_MP_TPG_REMOVE, 255) == 0) { index = MP_OBJECT_TYPE_TARGET_PORT_GROUP; } else if (strncmp(subClassName, ESC_SUN_MP_TARGET_PORT_REMOVE, 255) == 0) { index = MP_OBJECT_TYPE_TARGET_PORT; } else if (strncmp(subClassName, ESC_SUN_MP_DEV_PROD_REMOVE, 255) == 0) { index = MP_OBJECT_TYPE_DEVICE_PRODUCT; } } else { log(LOG_INFO, "notifyClient()", "- got an unsupported event"); return; } if (index < 0) { log(LOG_INFO, "notifyClient()", "- index is less than zero"); return; } if (eventType == VISA_CHANGE) { (void) pthread_mutex_lock(&g_visa_mutex); if (NULL == g_Visibility_Callback_List[index].pClientFn) { log(LOG_INFO, "notifyClient()", "- no visibility change callback to notify"); (void) pthread_mutex_unlock(&g_visa_mutex); return; } (void) pthread_mutex_unlock(&g_visa_mutex); } if (eventType == PROP_CHANGE) { (void) pthread_mutex_lock(&g_prop_mutex); if (NULL == g_Property_Callback_List[index].pClientFn) { log(LOG_INFO, "notifyClient()", "- no property change callback to notify"); (void) pthread_mutex_unlock(&g_prop_mutex); return; } (void) pthread_mutex_unlock(&g_prop_mutex); } (void) sysevent_get_attr_list(ev, &attr_list); if (NULL != attr_list) { if ((VISA_CHANGE == eventType) && (MP_OBJECT_TYPE_PLUGIN == index)) { val = (uint64_t *)malloc(sizeof (uint64_t)); valAllocated = 1; /* * We have no well-defined way to determine our OSN. * Currently the common library uses 0 as OSN for every * plugin, so just use 0. If the OSN assigned by the * common library changed, this code would have to be * updated. */ *val = 0; nelem = 1; } else if ((VISA_CHANGE == eventType) && (MP_OBJECT_TYPE_INITIATOR_PORT == index)) { (void) nvlist_lookup_int32_array(attr_list, DDI_INSTANCE, &instance, &nelem); log(LOG_INFO, "notifyClient()", "- event (PHCI_INSTANCE) has [%d] elements", nelem); (void) nvlist_lookup_int32_array(attr_list, DDI_DRIVER_MAJOR, &major, &nelem); log(LOG_INFO, "notifyClient()", "- event (PHCI_DRIVER_MAJOR) has [%d] elements", nelem); if ((NULL != instance) & (NULL != major)) { val = (uint64_t *)malloc(sizeof (uint64_t)); valAllocated = 1; *val = 0; *val = MP_STORE_INST_TO_ID(*instance, *val); *val = MP_STORE_MAJOR_TO_ID(*major, *val); nelem = 1; } else { nelem = 0; } } else { (void) nvlist_lookup_uint64_array(attr_list, OIDLIST, &val, &nelem); log(LOG_INFO, "notifyClient()", "- event has [%d] elements", nelem); } if (nelem > 0) { for (i = 0; i < nelem; i++) { log(LOG_INFO, "notifyClient()", "- event [%d] = %llx", i, val[i]); } oidList = createOidList(nelem); if (NULL == oidList) { log(LOG_INFO, "notifyClient()", "- unable to create MP_OID_LIST"); log(LOG_INFO, "notifyClient()", "- error exit"); nvlist_free(attr_list); return; } oidList->oidCount = nelem; for (i = 0; i < nelem; i++) { oidList->oids[i].objectType = index; oidList->oids[i].ownerId = g_pluginOwnerID; oidList->oids[i].objectSequenceNumber = val[i]; } if (valAllocated) { free(val); } for (i = 0; i < oidList->oidCount; i++) { log(LOG_INFO, "notifyClient()", "oidList->oids[%d].objectType" " = %d", i, oidList->oids[i].objectType); log(LOG_INFO, "notifyClient()", "oidList->oids[%d].ownerId" " = %d", i, oidList->oids[i].ownerId); log(LOG_INFO, "notifyClient()", "oidList->oids[%d].objectSequenceNumber" " = %llx", i, oidList->oids[i].objectSequenceNumber); } if (eventType == PROP_CHANGE) { (void) pthread_mutex_lock(&g_prop_mutex); pCallerData = g_Property_Callback_List[index]. pCallerData; (g_Property_Callback_List[index].pClientFn) (oidList, pCallerData); (void) pthread_mutex_unlock(&g_prop_mutex); } else if (eventType == VISA_CHANGE) { (void) pthread_mutex_lock(&g_visa_mutex); pCallerData = g_Visibility_Callback_List[index]. pCallerData; (g_Visibility_Callback_List[index].pClientFn) (becomingVisible, oidList, pCallerData); (void) pthread_mutex_unlock(&g_visa_mutex); } } nvlist_free(attr_list); } log(LOG_INFO, "notifyClient()", "- exit"); } /* Event handler called by system */ static void sysevent_handler(sysevent_t *ev) { log(LOG_INFO, "sysevent_handler()", "- enter"); /* Is the event one of ours? */ if ((strncmp(EC_SUN_MP, sysevent_get_class_name(ev), 9) != 0) && (strncmp(EC_DDI, sysevent_get_class_name(ev), 6) != 0)) { return; } /* Notify client if it cares */ notifyClient(ev); log(LOG_INFO, "sysevent_handler()", "- exit"); } /* Registers the plugin to the sysevent framework */ MP_STATUS init_sysevents(void) { const char *subclass_list[] = { ESC_SUN_MP_PLUGIN_CHANGE, ESC_SUN_MP_LU_CHANGE, ESC_SUN_MP_LU_ADD, ESC_SUN_MP_LU_REMOVE, ESC_SUN_MP_PATH_CHANGE, ESC_SUN_MP_PATH_ADD, ESC_SUN_MP_PATH_REMOVE, ESC_SUN_MP_INIT_PORT_CHANGE, ESC_SUN_MP_TPG_CHANGE, ESC_SUN_MP_TPG_ADD, ESC_SUN_MP_TPG_REMOVE, ESC_SUN_MP_TARGET_PORT_CHANGE, ESC_SUN_MP_TARGET_PORT_ADD, ESC_SUN_MP_TARGET_PORT_REMOVE, ESC_SUN_MP_DEV_PROD_CHANGE, ESC_SUN_MP_DEV_PROD_ADD, ESC_SUN_MP_DEV_PROD_REMOVE }; const char *init_port_subclass_list[] = { ESC_DDI_INITIATOR_REGISTER, ESC_DDI_INITIATOR_UNREGISTER }; log(LOG_INFO, "init_sysevents()", "- enter"); g_SysEventHandle = sysevent_bind_handle(sysevent_handler); if (g_SysEventHandle == NULL) { log(LOG_INFO, "init_sysevents()", "- sysevent_bind_handle() failed"); log(LOG_INFO, "init_sysevents()", "- error exit"); return (MP_STATUS_FAILED); } if (sysevent_subscribe_event(g_SysEventHandle, EC_SUN_MP, subclass_list, sizeof (subclass_list) / sizeof (subclass_list[0])) != 0) { log(LOG_INFO, "init_sysevents()", "- sysevent_subscribe_event() failed for subclass_list"); log(LOG_INFO, "init_sysevents()", "- error exit"); sysevent_unbind_handle(g_SysEventHandle); return (MP_STATUS_FAILED); } if (sysevent_subscribe_event(g_SysEventHandle, EC_DDI, init_port_subclass_list, sizeof (init_port_subclass_list) / sizeof (init_port_subclass_list[0])) != 0) { log(LOG_INFO, "init_sysevents()", "- sysevent_subscribe_event() failed " "for init_port_subclass_list"); log(LOG_INFO, "init_sysevents()", "- error exit"); sysevent_unbind_handle(g_SysEventHandle); return (MP_STATUS_FAILED); } log(LOG_INFO, "init_sysevents()", "- exit"); return (MP_STATUS_SUCCESS); }