10dc974a9SCathy Zhou /*
20dc974a9SCathy Zhou  * CDDL HEADER START
30dc974a9SCathy Zhou  *
40dc974a9SCathy Zhou  * The contents of this file are subject to the terms of the
50dc974a9SCathy Zhou  * Common Development and Distribution License (the "License").
60dc974a9SCathy Zhou  * You may not use this file except in compliance with the License.
70dc974a9SCathy Zhou  *
80dc974a9SCathy Zhou  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90dc974a9SCathy Zhou  * or http://www.opensolaris.org/os/licensing.
100dc974a9SCathy Zhou  * See the License for the specific language governing permissions
110dc974a9SCathy Zhou  * and limitations under the License.
120dc974a9SCathy Zhou  *
130dc974a9SCathy Zhou  * When distributing Covered Code, include this CDDL HEADER in each
140dc974a9SCathy Zhou  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150dc974a9SCathy Zhou  * If applicable, add the following below this CDDL HEADER, with the
160dc974a9SCathy Zhou  * fields enclosed by brackets "[]" replaced with your own identifying
170dc974a9SCathy Zhou  * information: Portions Copyright [yyyy] [name of copyright owner]
180dc974a9SCathy Zhou  *
190dc974a9SCathy Zhou  * CDDL HEADER END
200dc974a9SCathy Zhou  */
21*0756cc70SYuri Pankov 
220dc974a9SCathy Zhou /*
235093e103SCathy Zhou  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
240dc974a9SCathy Zhou  * Use is subject to license terms.
25*0756cc70SYuri Pankov  * Copyright 2016 Nexenta Systems, Inc.
260dc974a9SCathy Zhou  */
270dc974a9SCathy Zhou 
280dc974a9SCathy Zhou /*
290dc974a9SCathy Zhou  * datalink syseventd module.
300dc974a9SCathy Zhou  *
310dc974a9SCathy Zhou  * The purpose of this module is to identify all datalink related events,
320dc974a9SCathy Zhou  * and react accordingly.
330dc974a9SCathy Zhou  */
340dc974a9SCathy Zhou 
350dc974a9SCathy Zhou #include <errno.h>
360dc974a9SCathy Zhou #include <sys/sysevent/eventdefs.h>
370dc974a9SCathy Zhou #include <string.h>
380dc974a9SCathy Zhou #include <libnvpair.h>
390dc974a9SCathy Zhou #include <librcm.h>
400dc974a9SCathy Zhou #include <libsysevent.h>
415ad1f010SStephen Hanson #include "sysevent_signal.h"
420dc974a9SCathy Zhou 
434dc92747SCheng Sean Ye extern void syseventd_err_print(char *, ...);
444dc92747SCheng Sean Ye 
454dc92747SCheng Sean Ye struct event_list {
464dc92747SCheng Sean Ye 	nvlist_t *ev;
474dc92747SCheng Sean Ye 	struct event_list *next;
484dc92747SCheng Sean Ye };
494dc92747SCheng Sean Ye 
500dc974a9SCathy Zhou static rcm_handle_t *rcm_hdl = NULL;
514dc92747SCheng Sean Ye static boolean_t dl_exiting;
524dc92747SCheng Sean Ye static thread_t dl_notify_tid;
534dc92747SCheng Sean Ye static mutex_t dl_mx;
544dc92747SCheng Sean Ye static cond_t dl_cv;
554dc92747SCheng Sean Ye static struct event_list *dl_events;
564dc92747SCheng Sean Ye 
574dc92747SCheng Sean Ye /* ARGSUSED */
584dc92747SCheng Sean Ye static void *
datalink_notify_thread(void * arg)594dc92747SCheng Sean Ye datalink_notify_thread(void *arg)
604dc92747SCheng Sean Ye {
614dc92747SCheng Sean Ye 	struct event_list *tmp_events, *ep;
624dc92747SCheng Sean Ye 
634dc92747SCheng Sean Ye 	(void) mutex_lock(&dl_mx);
644dc92747SCheng Sean Ye 
654dc92747SCheng Sean Ye 	while (! dl_exiting || dl_events != NULL) {
664dc92747SCheng Sean Ye 		if (dl_events == NULL) {
674dc92747SCheng Sean Ye 			(void) cond_wait(&dl_cv, &dl_mx);
684dc92747SCheng Sean Ye 			continue;
694dc92747SCheng Sean Ye 		}
704dc92747SCheng Sean Ye 
714dc92747SCheng Sean Ye 		tmp_events = dl_events;
724dc92747SCheng Sean Ye 		dl_events = NULL;
734dc92747SCheng Sean Ye 
744dc92747SCheng Sean Ye 		(void) mutex_unlock(&dl_mx);
754dc92747SCheng Sean Ye 
764dc92747SCheng Sean Ye 		while (tmp_events != NULL) {
775ad1f010SStephen Hanson 			struct sigaction cbuf, dfl;
785ad1f010SStephen Hanson 
795ad1f010SStephen Hanson 			/*
805ad1f010SStephen Hanson 			 * Ignore SIGCLD for the
815ad1f010SStephen Hanson 			 * duration of the rcm_notify_event call.
825ad1f010SStephen Hanson 			 */
835ad1f010SStephen Hanson 			(void) memset(&dfl, 0, sizeof (dfl));
845ad1f010SStephen Hanson 			dfl.sa_handler = SIG_IGN;
855ad1f010SStephen Hanson 			(void) sigaction(SIGCHLD, &dfl, &cbuf);
865ad1f010SStephen Hanson 
874dc92747SCheng Sean Ye 			/*
884dc92747SCheng Sean Ye 			 * Send the PHYSLINK_NEW event to network_rcm to update
894dc92747SCheng Sean Ye 			 * the network devices cache accordingly.
904dc92747SCheng Sean Ye 			 */
914dc92747SCheng Sean Ye 			if (rcm_notify_event(rcm_hdl, RCM_RESOURCE_PHYSLINK_NEW,
924dc92747SCheng Sean Ye 			    0, tmp_events->ev, NULL) != RCM_SUCCESS)
935ad1f010SStephen Hanson 				syseventd_err_print("datalink_mod: Can not "
944dc92747SCheng Sean Ye 				    "notify event: %s\n", strerror(errno));
954dc92747SCheng Sean Ye 
965ad1f010SStephen Hanson 			(void) sigaction(SIGCHLD, &cbuf, NULL);
974dc92747SCheng Sean Ye 			ep = tmp_events;
984dc92747SCheng Sean Ye 			tmp_events = tmp_events->next;
994dc92747SCheng Sean Ye 			nvlist_free(ep->ev);
1004dc92747SCheng Sean Ye 			free(ep);
1014dc92747SCheng Sean Ye 		}
1024dc92747SCheng Sean Ye 
1034dc92747SCheng Sean Ye 		(void) mutex_lock(&dl_mx);
1044dc92747SCheng Sean Ye 	}
1054dc92747SCheng Sean Ye 
1064dc92747SCheng Sean Ye 	(void) mutex_unlock(&dl_mx);
1074dc92747SCheng Sean Ye 
1084dc92747SCheng Sean Ye 	return (NULL);
1094dc92747SCheng Sean Ye }
1100dc974a9SCathy Zhou 
1110dc974a9SCathy Zhou /*ARGSUSED*/
1120dc974a9SCathy Zhou static int
datalink_deliver_event(sysevent_t * ev,int unused)1130dc974a9SCathy Zhou datalink_deliver_event(sysevent_t *ev, int unused)
1140dc974a9SCathy Zhou {
1150dc974a9SCathy Zhou 	const char *class = sysevent_get_class_name(ev);
1160dc974a9SCathy Zhou 	const char *subclass = sysevent_get_subclass_name(ev);
1170dc974a9SCathy Zhou 	nvlist_t *nvl;
1184dc92747SCheng Sean Ye 	struct event_list *newp, **elpp;
1190dc974a9SCathy Zhou 
1200dc974a9SCathy Zhou 	if (strcmp(class, EC_DATALINK) != 0 ||
1210dc974a9SCathy Zhou 	    strcmp(subclass, ESC_DATALINK_PHYS_ADD) != 0) {
1220dc974a9SCathy Zhou 		return (0);
1230dc974a9SCathy Zhou 	}
1240dc974a9SCathy Zhou 
1250dc974a9SCathy Zhou 	if (sysevent_get_attr_list(ev, &nvl) != 0)
1260dc974a9SCathy Zhou 		return (EINVAL);
1270dc974a9SCathy Zhou 
1285093e103SCathy Zhou 	/*
1294dc92747SCheng Sean Ye 	 * rcm_notify_event() needs to be called asynchronously otherwise when
1304dc92747SCheng Sean Ye 	 * sysevent queue is full, deadlock will happen.
1315093e103SCathy Zhou 	 */
1324dc92747SCheng Sean Ye 	if ((newp = malloc(sizeof (struct event_list))) == NULL)
1334dc92747SCheng Sean Ye 		return (ENOMEM);
1344dc92747SCheng Sean Ye 
1354dc92747SCheng Sean Ye 	newp->ev = nvl;
1364dc92747SCheng Sean Ye 	newp->next = NULL;
1374dc92747SCheng Sean Ye 
1384dc92747SCheng Sean Ye 	/*
1394dc92747SCheng Sean Ye 	 * queue up at the end of the event list and signal notify_thread to
1404dc92747SCheng Sean Ye 	 * process it.
1414dc92747SCheng Sean Ye 	 */
1424dc92747SCheng Sean Ye 	(void) mutex_lock(&dl_mx);
1434dc92747SCheng Sean Ye 	elpp = &dl_events;
1444dc92747SCheng Sean Ye 	while (*elpp !=  NULL)
1454dc92747SCheng Sean Ye 		elpp = &(*elpp)->next;
1464dc92747SCheng Sean Ye 	*elpp = newp;
1474dc92747SCheng Sean Ye 	(void) cond_signal(&dl_cv);
1484dc92747SCheng Sean Ye 	(void) mutex_unlock(&dl_mx);
1490dc974a9SCathy Zhou 
1504dc92747SCheng Sean Ye 	return (0);
1510dc974a9SCathy Zhou }
1520dc974a9SCathy Zhou 
1530dc974a9SCathy Zhou static struct slm_mod_ops datalink_mod_ops = {
1540dc974a9SCathy Zhou 	SE_MAJOR_VERSION,
1550dc974a9SCathy Zhou 	SE_MINOR_VERSION,
1560dc974a9SCathy Zhou 	SE_MAX_RETRY_LIMIT,
1570dc974a9SCathy Zhou 	datalink_deliver_event
1580dc974a9SCathy Zhou };
1590dc974a9SCathy Zhou 
1600dc974a9SCathy Zhou struct slm_mod_ops *
slm_init()1610dc974a9SCathy Zhou slm_init()
1620dc974a9SCathy Zhou {
1634dc92747SCheng Sean Ye 	dl_events = NULL;
1644dc92747SCheng Sean Ye 	dl_exiting = B_FALSE;
1654dc92747SCheng Sean Ye 
1660dc974a9SCathy Zhou 	if (rcm_alloc_handle(NULL, 0, NULL, &rcm_hdl) != RCM_SUCCESS)
1670dc974a9SCathy Zhou 		return (NULL);
1680dc974a9SCathy Zhou 
169*0756cc70SYuri Pankov 	(void) mutex_init(&dl_mx, USYNC_THREAD, NULL);
170*0756cc70SYuri Pankov 	(void) cond_init(&dl_cv, USYNC_THREAD, NULL);
171*0756cc70SYuri Pankov 
1724dc92747SCheng Sean Ye 	if (thr_create(NULL, 0,  datalink_notify_thread, NULL, 0,
1734dc92747SCheng Sean Ye 	    &dl_notify_tid) != 0) {
1744dc92747SCheng Sean Ye 		(void) rcm_free_handle(rcm_hdl);
175*0756cc70SYuri Pankov 		(void) mutex_destroy(&dl_mx);
176*0756cc70SYuri Pankov 		(void) cond_destroy(&dl_cv);
1774dc92747SCheng Sean Ye 		return (NULL);
1784dc92747SCheng Sean Ye 	}
1794dc92747SCheng Sean Ye 
1800dc974a9SCathy Zhou 	return (&datalink_mod_ops);
1810dc974a9SCathy Zhou }
1820dc974a9SCathy Zhou 
1830dc974a9SCathy Zhou void
slm_fini()1840dc974a9SCathy Zhou slm_fini()
1850dc974a9SCathy Zhou {
1864dc92747SCheng Sean Ye 	(void) mutex_lock(&dl_mx);
1874dc92747SCheng Sean Ye 	dl_exiting = B_TRUE;
1884dc92747SCheng Sean Ye 	(void) cond_signal(&dl_cv);
1894dc92747SCheng Sean Ye 	(void) mutex_unlock(&dl_mx);
1904dc92747SCheng Sean Ye 	(void) thr_join(dl_notify_tid, NULL, NULL);
1914dc92747SCheng Sean Ye 
1924dc92747SCheng Sean Ye 	(void) mutex_destroy(&dl_mx);
1934dc92747SCheng Sean Ye 	(void) cond_destroy(&dl_cv);
1940dc974a9SCathy Zhou 	(void) rcm_free_handle(rcm_hdl);
1950dc974a9SCathy Zhou 	rcm_hdl = NULL;
1960dc974a9SCathy Zhou }
197