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