xref: /illumos-gate/usr/src/cmd/fm/fmd/common/fmd_dr.c (revision 24db46411fd54f70c35b94bb952eb7ba040e43b4)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5724365f7Ssethg  * Common Development and Distribution License (the "License").
6724365f7Ssethg  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*24db4641Seschrock  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * FMD Dynamic Reconfiguration (DR) Event Handling
307c478bd9Sstevel@tonic-gate  *
317c478bd9Sstevel@tonic-gate  * Fault manager scheme plug-ins must track characteristics of individual
327c478bd9Sstevel@tonic-gate  * pieces of hardware.  As these components can be added or removed by a DR
337c478bd9Sstevel@tonic-gate  * operation, we need to provide a means by which plug-ins can determine when
347c478bd9Sstevel@tonic-gate  * they need to re-examine the current configuration.  We provide a simple
357c478bd9Sstevel@tonic-gate  * mechanism whereby this task can be implemented using lazy evaluation: a
367c478bd9Sstevel@tonic-gate  * simple 64-bit generation counter is maintained and incremented on *any* DR.
377c478bd9Sstevel@tonic-gate  * Schemes can store the generation number in scheme-specific data structures,
387c478bd9Sstevel@tonic-gate  * and then revalidate their contents if the current generation number has
397c478bd9Sstevel@tonic-gate  * changed since the resource information was cached.  This method saves time,
407c478bd9Sstevel@tonic-gate  * avoids the complexity of direct participation in DR, avoids the need for
417c478bd9Sstevel@tonic-gate  * resource-specific processing of DR events, and is relatively easy to port
427c478bd9Sstevel@tonic-gate  * to other systems that support dynamic reconfiguration.
43*24db4641Seschrock  *
44*24db4641Seschrock  * The dr generation is only incremented in response to hardware changes.  Since
45*24db4641Seschrock  * ASRUs can be in any scheme, including the device scheme, we must also be
46*24db4641Seschrock  * aware of software configuration changes which may affect the resource cache.
47*24db4641Seschrock  * In addition, we take a snapshot of the topology whenever a reconfiguration
48*24db4641Seschrock  * event occurs and notify any modules of the change.
497c478bd9Sstevel@tonic-gate  */
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate #include <sys/types.h>
52*24db4641Seschrock #include <sys/sunddi.h>
537c478bd9Sstevel@tonic-gate #include <sys/sysevent/dr.h>
547c478bd9Sstevel@tonic-gate #include <sys/sysevent/eventdefs.h>
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate #include <stdio.h>
57*24db4641Seschrock #include <string.h>
58d9638e54Smws #include <unistd.h>
597c478bd9Sstevel@tonic-gate #include <libsysevent.h>
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate #undef MUTEX_HELD
627c478bd9Sstevel@tonic-gate #undef RW_READ_HELD
637c478bd9Sstevel@tonic-gate #undef RW_WRITE_HELD
647c478bd9Sstevel@tonic-gate 
65724365f7Ssethg #include <fmd_asru.h>
667c478bd9Sstevel@tonic-gate #include <fmd_error.h>
67*24db4641Seschrock #include <fmd_event.h>
68724365f7Ssethg #include <fmd_fmri.h>
69*24db4641Seschrock #include <fmd_module.h>
707c478bd9Sstevel@tonic-gate #include <fmd_subr.h>
71*24db4641Seschrock #include <fmd_topo.h>
727c478bd9Sstevel@tonic-gate #include <fmd.h>
737c478bd9Sstevel@tonic-gate 
74724365f7Ssethg static void
75*24db4641Seschrock fmd_dr_event(sysevent_t *sep)
76724365f7Ssethg {
77*24db4641Seschrock 	uint64_t gen;
78*24db4641Seschrock 	fmd_event_t *e;
79*24db4641Seschrock 	const char *class = sysevent_get_class_name(sep);
80*24db4641Seschrock 	hrtime_t evtime;
81*24db4641Seschrock 	fmd_topo_t *ftp, *prev;
82*24db4641Seschrock 	boolean_t update_topo = B_FALSE;
83724365f7Ssethg 
84724365f7Ssethg 	/*
85*24db4641Seschrock 	 * The dr generation is only changed in response to DR events.
86724365f7Ssethg 	 */
87*24db4641Seschrock 	if (strcmp(class, EC_DR) == 0) {
88*24db4641Seschrock 		update_topo = B_TRUE;
89724365f7Ssethg 
90*24db4641Seschrock 		(void) pthread_mutex_lock(&fmd.d_stats_lock);
91*24db4641Seschrock 		gen = fmd.d_stats->ds_dr_gen.fmds_value.ui64++;
92*24db4641Seschrock 		(void) pthread_mutex_unlock(&fmd.d_stats_lock);
93*24db4641Seschrock 
94*24db4641Seschrock 		TRACE((FMD_DBG_XPRT, "dr event %p, gen=%llu",
95*24db4641Seschrock 		    (void *)sep, gen));
96*24db4641Seschrock 	}
977c478bd9Sstevel@tonic-gate 
98724365f7Ssethg 	/*
99*24db4641Seschrock 	 * Take a topo snapshot and notify modules of the change.  Picking an
100*24db4641Seschrock 	 * accurate time here is difficult.  On one hand, we have the timestamp
101*24db4641Seschrock 	 * of the underlying sysevent, indicating when the reconfiguration event
102*24db4641Seschrock 	 * occurred.  On the other hand, we are taking the topo snapshot
103*24db4641Seschrock 	 * asynchronously, and hence the timestamp of the snapshot is the
104*24db4641Seschrock 	 * current time.  Pretending this topo snapshot was valid at the time
105*24db4641Seschrock 	 * the sysevent was posted seems wrong, so we instead opt for the
106*24db4641Seschrock 	 * current time as an upper bound on the snapshot validity.
107*24db4641Seschrock 	 *
108*24db4641Seschrock 	 * Along these lines, we keep track of the last time we dispatched a
109*24db4641Seschrock 	 * topo snapshot.  If the sysevent occurred before the last topo
110*24db4641Seschrock 	 * snapshot, then don't bother dispatching another topo change event.
111*24db4641Seschrock 	 * We've already indicated (to the best of our ability) the change in
112*24db4641Seschrock 	 * topology.  This prevents endless topo snapshots in response to a
113*24db4641Seschrock 	 * flurry of sysevents.
114724365f7Ssethg 	 */
115*24db4641Seschrock 	sysevent_get_time(sep, &evtime);
116*24db4641Seschrock 	prev = fmd_topo_hold();
117*24db4641Seschrock 	if (evtime <= prev->ft_time &&
118*24db4641Seschrock 	    fmd.d_clockops == &fmd_timeops_native) {
119*24db4641Seschrock 		fmd_topo_rele(prev);
120*24db4641Seschrock 		return;
121*24db4641Seschrock 	}
122*24db4641Seschrock 	fmd_topo_rele(prev);
123724365f7Ssethg 
124*24db4641Seschrock 	if (update_topo)
125*24db4641Seschrock 		fmd_topo_update();
1267c478bd9Sstevel@tonic-gate 
127*24db4641Seschrock 	ftp = fmd_topo_hold();
128*24db4641Seschrock 	e = fmd_event_create(FMD_EVT_TOPO, ftp->ft_time, NULL, ftp);
129*24db4641Seschrock 	fmd_modhash_dispatch(fmd.d_mod_hash, e);
1307c478bd9Sstevel@tonic-gate }
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate void
1337c478bd9Sstevel@tonic-gate fmd_dr_init(void)
1347c478bd9Sstevel@tonic-gate {
135*24db4641Seschrock 	const char *drsubclass = ESC_DR_AP_STATE_CHANGE;
136*24db4641Seschrock 	const char *devsubclass = EC_SUB_ALL;
1377c478bd9Sstevel@tonic-gate 
138d9638e54Smws 	if (geteuid() != 0)
139d9638e54Smws 		return; /* legacy sysevent mechanism is still root-only */
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate 	if ((fmd.d_dr_hdl = sysevent_bind_handle(fmd_dr_event)) == NULL)
1427c478bd9Sstevel@tonic-gate 		fmd_error(EFMD_EXIT, "failed to bind handle for DR sysevent");
1437c478bd9Sstevel@tonic-gate 
144*24db4641Seschrock 	if (sysevent_subscribe_event(fmd.d_dr_hdl, EC_DR, &drsubclass, 1) == -1)
145*24db4641Seschrock 		fmd_error(EFMD_EXIT, "failed to subscribe to DR sysevent");
146*24db4641Seschrock 
147*24db4641Seschrock 	if (sysevent_subscribe_event(fmd.d_dr_hdl, EC_DEVFS,
148*24db4641Seschrock 	    &devsubclass, 1) == -1)
149*24db4641Seschrock 		fmd_error(EFMD_EXIT, "failed to subscribe to devfs sysevent");
1507c478bd9Sstevel@tonic-gate }
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate void
1537c478bd9Sstevel@tonic-gate fmd_dr_fini(void)
1547c478bd9Sstevel@tonic-gate {
1557c478bd9Sstevel@tonic-gate 	if (fmd.d_dr_hdl != NULL) {
1567c478bd9Sstevel@tonic-gate 		sysevent_unsubscribe_event(fmd.d_dr_hdl, EC_DR);
1577c478bd9Sstevel@tonic-gate 		sysevent_unbind_handle(fmd.d_dr_hdl);
1587c478bd9Sstevel@tonic-gate 	}
1597c478bd9Sstevel@tonic-gate }
160