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 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * datalink syseventd module. 28 * 29 * The purpose of this module is to identify all datalink related events, 30 * and react accordingly. 31 */ 32 33 #include <errno.h> 34 #include <sys/sysevent/eventdefs.h> 35 #include <string.h> 36 #include <libnvpair.h> 37 #include <librcm.h> 38 #include <libsysevent.h> 39 40 extern void syseventd_err_print(char *, ...); 41 42 struct event_list { 43 nvlist_t *ev; 44 struct event_list *next; 45 }; 46 47 static rcm_handle_t *rcm_hdl = NULL; 48 static boolean_t dl_exiting; 49 static thread_t dl_notify_tid; 50 static mutex_t dl_mx; 51 static cond_t dl_cv; 52 static struct event_list *dl_events; 53 54 /* ARGSUSED */ 55 static void * 56 datalink_notify_thread(void *arg) 57 { 58 struct event_list *tmp_events, *ep; 59 60 (void) mutex_lock(&dl_mx); 61 62 while (! dl_exiting || dl_events != NULL) { 63 if (dl_events == NULL) { 64 (void) cond_wait(&dl_cv, &dl_mx); 65 continue; 66 } 67 68 tmp_events = dl_events; 69 dl_events = NULL; 70 71 (void) mutex_unlock(&dl_mx); 72 73 while (tmp_events != NULL) { 74 /* 75 * Send the PHYSLINK_NEW event to network_rcm to update 76 * the network devices cache accordingly. 77 */ 78 if (rcm_notify_event(rcm_hdl, RCM_RESOURCE_PHYSLINK_NEW, 79 0, tmp_events->ev, NULL) != RCM_SUCCESS) 80 syseventd_err_print("datalink_mod: Can not" 81 "notify event: %s\n", strerror(errno)); 82 83 ep = tmp_events; 84 tmp_events = tmp_events->next; 85 nvlist_free(ep->ev); 86 free(ep); 87 } 88 89 (void) mutex_lock(&dl_mx); 90 } 91 92 (void) mutex_unlock(&dl_mx); 93 94 return (NULL); 95 } 96 97 /*ARGSUSED*/ 98 static int 99 datalink_deliver_event(sysevent_t *ev, int unused) 100 { 101 const char *class = sysevent_get_class_name(ev); 102 const char *subclass = sysevent_get_subclass_name(ev); 103 nvlist_t *nvl; 104 struct event_list *newp, **elpp; 105 106 if (strcmp(class, EC_DATALINK) != 0 || 107 strcmp(subclass, ESC_DATALINK_PHYS_ADD) != 0) { 108 return (0); 109 } 110 111 if (sysevent_get_attr_list(ev, &nvl) != 0) 112 return (EINVAL); 113 114 /* 115 * rcm_notify_event() needs to be called asynchronously otherwise when 116 * sysevent queue is full, deadlock will happen. 117 */ 118 if ((newp = malloc(sizeof (struct event_list))) == NULL) 119 return (ENOMEM); 120 121 newp->ev = nvl; 122 newp->next = NULL; 123 124 /* 125 * queue up at the end of the event list and signal notify_thread to 126 * process it. 127 */ 128 (void) mutex_lock(&dl_mx); 129 elpp = &dl_events; 130 while (*elpp != NULL) 131 elpp = &(*elpp)->next; 132 *elpp = newp; 133 (void) cond_signal(&dl_cv); 134 (void) mutex_unlock(&dl_mx); 135 136 return (0); 137 } 138 139 static struct slm_mod_ops datalink_mod_ops = { 140 SE_MAJOR_VERSION, 141 SE_MINOR_VERSION, 142 SE_MAX_RETRY_LIMIT, 143 datalink_deliver_event 144 }; 145 146 struct slm_mod_ops * 147 slm_init() 148 { 149 dl_events = NULL; 150 dl_exiting = B_FALSE; 151 152 if (rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl) != RCM_SUCCESS) 153 return (NULL); 154 155 if (thr_create(NULL, 0, datalink_notify_thread, NULL, 0, 156 &dl_notify_tid) != 0) { 157 (void) rcm_free_handle(rcm_hdl); 158 return (NULL); 159 } 160 161 (void) mutex_init(&dl_mx, USYNC_THREAD, NULL); 162 (void) cond_init(&dl_cv, USYNC_THREAD, NULL); 163 164 return (&datalink_mod_ops); 165 } 166 167 void 168 slm_fini() 169 { 170 (void) mutex_lock(&dl_mx); 171 dl_exiting = B_TRUE; 172 (void) cond_signal(&dl_cv); 173 (void) mutex_unlock(&dl_mx); 174 (void) thr_join(dl_notify_tid, NULL, NULL); 175 176 (void) mutex_destroy(&dl_mx); 177 (void) cond_destroy(&dl_cv); 178 (void) rcm_free_handle(rcm_hdl); 179 rcm_hdl = NULL; 180 } 181