1*1410cb93SJoshua M. Clulow /*
2*1410cb93SJoshua M. Clulow  * This file and its contents are supplied under the terms of the
3*1410cb93SJoshua M. Clulow  * Common Development and Distribution License ("CDDL"), version 1.0.
4*1410cb93SJoshua M. Clulow  * You may only use this file in accordance with the terms of version
5*1410cb93SJoshua M. Clulow  * 1.0 of the CDDL.
6*1410cb93SJoshua M. Clulow  *
7*1410cb93SJoshua M. Clulow  * A full copy of the text of the CDDL should have accompanied this
8*1410cb93SJoshua M. Clulow  * source.  A copy of the CDDL is also available via the Internet at
9*1410cb93SJoshua M. Clulow  * http://www.illumos.org/license/CDDL.
10*1410cb93SJoshua M. Clulow  */
11*1410cb93SJoshua M. Clulow 
12*1410cb93SJoshua M. Clulow /*
13*1410cb93SJoshua M. Clulow  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
14*1410cb93SJoshua M. Clulow  */
15*1410cb93SJoshua M. Clulow 
16*1410cb93SJoshua M. Clulow /*
17*1410cb93SJoshua M. Clulow  * Disk Lights Agent (FMA)
18*1410cb93SJoshua M. Clulow  *
19*1410cb93SJoshua M. Clulow  * This Fault Management Daemon (fmd) module periodically scans the topology
20*1410cb93SJoshua M. Clulow  * tree, enumerates all disks with associated fault indicators, and then
21*1410cb93SJoshua M. Clulow  * synchronises the fault status of resources in the FMA Resource Cache with
22*1410cb93SJoshua M. Clulow  * the indicators.  In short: it turns the fault light on for befallen disks.
23*1410cb93SJoshua M. Clulow  *
24*1410cb93SJoshua M. Clulow  * Presently, we recognise associated fault indicators for disks by looking
25*1410cb93SJoshua M. Clulow  * for the following structure in the topology tree:
26*1410cb93SJoshua M. Clulow  *
27*1410cb93SJoshua M. Clulow  *    /bay=N
28*1410cb93SJoshua M. Clulow  *      |
29*1410cb93SJoshua M. Clulow  *      +---- /disk=0   <---------------- our Disk
30*1410cb93SJoshua M. Clulow  *      |
31*1410cb93SJoshua M. Clulow  *      +---- /bay=N?indicator=fail <---- the Fault Light
32*1410cb93SJoshua M. Clulow  *      \---- /bay=N?indicator=ident
33*1410cb93SJoshua M. Clulow  *
34*1410cb93SJoshua M. Clulow  * That is: a DISK node will have a parent BAY; that BAY will itself have
35*1410cb93SJoshua M. Clulow  * child Facility nodes, one of which will be called "fail".  If any of the
36*1410cb93SJoshua M. Clulow  * above does not hold, we simply do nothing for this disk.
37*1410cb93SJoshua M. Clulow  */
38*1410cb93SJoshua M. Clulow 
39*1410cb93SJoshua M. Clulow #include <string.h>
40*1410cb93SJoshua M. Clulow #include <strings.h>
41*1410cb93SJoshua M. Clulow #include <libnvpair.h>
42*1410cb93SJoshua M. Clulow #include <fm/libtopo.h>
43*1410cb93SJoshua M. Clulow #include <fm/topo_list.h>
44*1410cb93SJoshua M. Clulow #include <fm/topo_hc.h>
45*1410cb93SJoshua M. Clulow #include <fm/fmd_api.h>
46*1410cb93SJoshua M. Clulow #include <sys/fm/protocol.h>
47*1410cb93SJoshua M. Clulow 
48*1410cb93SJoshua M. Clulow 
49*1410cb93SJoshua M. Clulow typedef struct disk_lights {
50*1410cb93SJoshua M. Clulow 	fmd_hdl_t *dl_fmd;
51*1410cb93SJoshua M. Clulow 	uint64_t dl_poll_interval;
52*1410cb93SJoshua M. Clulow 	uint64_t dl_coalesce_interval;
53*1410cb93SJoshua M. Clulow 	id_t dl_timer;
54*1410cb93SJoshua M. Clulow 	boolean_t dl_triggered;
55*1410cb93SJoshua M. Clulow } disk_lights_t;
56*1410cb93SJoshua M. Clulow 
57*1410cb93SJoshua M. Clulow static void disklights_topo(fmd_hdl_t *, topo_hdl_t *);
58*1410cb93SJoshua M. Clulow static void disklights_recv(fmd_hdl_t *, fmd_event_t *, nvlist_t *,
59*1410cb93SJoshua M. Clulow     const char *);
60*1410cb93SJoshua M. Clulow static void disklights_timeout(fmd_hdl_t *, id_t, void *);
61*1410cb93SJoshua M. Clulow 
62*1410cb93SJoshua M. Clulow static const fmd_hdl_ops_t fmd_ops = {
63*1410cb93SJoshua M. Clulow 	disklights_recv,	/* fmdo_recv */
64*1410cb93SJoshua M. Clulow 	disklights_timeout,	/* fmdo_timeout */
65*1410cb93SJoshua M. Clulow 	NULL,			/* fmdo_close */
66*1410cb93SJoshua M. Clulow 	NULL,			/* fmdo_stats */
67*1410cb93SJoshua M. Clulow 	NULL,			/* fmdo_gc */
68*1410cb93SJoshua M. Clulow 	NULL,			/* fmdo_send */
69*1410cb93SJoshua M. Clulow 	disklights_topo,	/* fmdo_topo */
70*1410cb93SJoshua M. Clulow };
71*1410cb93SJoshua M. Clulow 
72*1410cb93SJoshua M. Clulow /*
73*1410cb93SJoshua M. Clulow  * POLL_INTERVAL is the period after which we perform an unsolicited poll
74*1410cb93SJoshua M. Clulow  * to ensure we remain in sync with reality.
75*1410cb93SJoshua M. Clulow  */
76*1410cb93SJoshua M. Clulow #define	DL_PROP_POLL_INTERVAL		"poll-interval"
77*1410cb93SJoshua M. Clulow 
78*1410cb93SJoshua M. Clulow /*
79*1410cb93SJoshua M. Clulow  * COALESCE_INTERVAL is how long we wait after we are trigged by either a
80*1410cb93SJoshua M. Clulow  * topology change or a relevant list.* event, in order to allow a series
81*1410cb93SJoshua M. Clulow  * of events to coalesce.
82*1410cb93SJoshua M. Clulow  */
83*1410cb93SJoshua M. Clulow #define	DL_PROP_COALESCE_INTERVAL	"coalesce-interval"
84*1410cb93SJoshua M. Clulow 
85*1410cb93SJoshua M. Clulow static const fmd_prop_t fmd_props[] = {
86*1410cb93SJoshua M. Clulow 	{ DL_PROP_POLL_INTERVAL, FMD_TYPE_TIME, "5min" },
87*1410cb93SJoshua M. Clulow 	{ DL_PROP_COALESCE_INTERVAL, FMD_TYPE_TIME, "3s" },
88*1410cb93SJoshua M. Clulow 	{ NULL, 0, NULL }
89*1410cb93SJoshua M. Clulow };
90*1410cb93SJoshua M. Clulow 
91*1410cb93SJoshua M. Clulow static const fmd_hdl_info_t fmd_info = {
92*1410cb93SJoshua M. Clulow 	"Disk Lights Agent",
93*1410cb93SJoshua M. Clulow 	"1.0",
94*1410cb93SJoshua M. Clulow 	&fmd_ops,
95*1410cb93SJoshua M. Clulow 	fmd_props
96*1410cb93SJoshua M. Clulow };
97*1410cb93SJoshua M. Clulow 
98*1410cb93SJoshua M. Clulow /*
99*1410cb93SJoshua M. Clulow  * Fetch the Facility Node properties (name, type) from the FMRI
100*1410cb93SJoshua M. Clulow  * for this node, or return -1 if we can't.
101*1410cb93SJoshua M. Clulow  */
102*1410cb93SJoshua M. Clulow static int
get_facility_props(topo_hdl_t * hdl,tnode_t * node,char ** facname,char ** factype)103*1410cb93SJoshua M. Clulow get_facility_props(topo_hdl_t *hdl, tnode_t *node, char **facname,
104*1410cb93SJoshua M. Clulow     char **factype)
105*1410cb93SJoshua M. Clulow {
106*1410cb93SJoshua M. Clulow 	int e, ret = -1;
107*1410cb93SJoshua M. Clulow 	nvlist_t *fmri = NULL, *fnvl;
108*1410cb93SJoshua M. Clulow 	char *nn = NULL, *tt = NULL;
109*1410cb93SJoshua M. Clulow 
110*1410cb93SJoshua M. Clulow 	if (topo_node_resource(node, &fmri, &e) != 0)
111*1410cb93SJoshua M. Clulow 		goto out;
112*1410cb93SJoshua M. Clulow 
113*1410cb93SJoshua M. Clulow 	if (nvlist_lookup_nvlist(fmri, FM_FMRI_FACILITY, &fnvl) != 0)
114*1410cb93SJoshua M. Clulow 		goto out;
115*1410cb93SJoshua M. Clulow 
116*1410cb93SJoshua M. Clulow 	if (nvlist_lookup_string(fnvl, FM_FMRI_FACILITY_NAME, &nn) != 0)
117*1410cb93SJoshua M. Clulow 		goto out;
118*1410cb93SJoshua M. Clulow 
119*1410cb93SJoshua M. Clulow 	if (nvlist_lookup_string(fnvl, FM_FMRI_FACILITY_TYPE, &tt) != 0)
120*1410cb93SJoshua M. Clulow 		goto out;
121*1410cb93SJoshua M. Clulow 
122*1410cb93SJoshua M. Clulow 	*facname = topo_hdl_strdup(hdl, nn);
123*1410cb93SJoshua M. Clulow 	*factype = topo_hdl_strdup(hdl, tt);
124*1410cb93SJoshua M. Clulow 	ret = 0;
125*1410cb93SJoshua M. Clulow 
126*1410cb93SJoshua M. Clulow out:
127*1410cb93SJoshua M. Clulow 	nvlist_free(fmri);
128*1410cb93SJoshua M. Clulow 	return (ret);
129*1410cb93SJoshua M. Clulow }
130*1410cb93SJoshua M. Clulow 
131*1410cb93SJoshua M. Clulow typedef struct dl_fault_walk_inner {
132*1410cb93SJoshua M. Clulow 	char *fwi_name;
133*1410cb93SJoshua M. Clulow 	uint32_t fwi_mode;
134*1410cb93SJoshua M. Clulow } dl_fault_walk_inner_t;
135*1410cb93SJoshua M. Clulow 
136*1410cb93SJoshua M. Clulow static int
dl_fault_walk_inner(topo_hdl_t * thp,tnode_t * node,void * arg)137*1410cb93SJoshua M. Clulow dl_fault_walk_inner(topo_hdl_t *thp, tnode_t *node, void *arg)
138*1410cb93SJoshua M. Clulow {
139*1410cb93SJoshua M. Clulow 	dl_fault_walk_inner_t *fwi = arg;
140*1410cb93SJoshua M. Clulow 	char *facname = NULL, *factype = NULL;
141*1410cb93SJoshua M. Clulow 	int err;
142*1410cb93SJoshua M. Clulow 
143*1410cb93SJoshua M. Clulow 	/*
144*1410cb93SJoshua M. Clulow 	 * We're only interested in BAY children that are valid Facility Nodes.
145*1410cb93SJoshua M. Clulow 	 */
146*1410cb93SJoshua M. Clulow 	if (topo_node_flags(node) != TOPO_NODE_FACILITY ||
147*1410cb93SJoshua M. Clulow 	    get_facility_props(thp, node, &facname, &factype) != 0) {
148*1410cb93SJoshua M. Clulow 		goto out;
149*1410cb93SJoshua M. Clulow 	}
150*1410cb93SJoshua M. Clulow 
151*1410cb93SJoshua M. Clulow 	if (strcmp(fwi->fwi_name, facname) != 0)
152*1410cb93SJoshua M. Clulow 		goto out;
153*1410cb93SJoshua M. Clulow 
154*1410cb93SJoshua M. Clulow 	/*
155*1410cb93SJoshua M. Clulow 	 * Attempt to set the LED mode appropriately.  If this fails, give up
156*1410cb93SJoshua M. Clulow 	 * and move on.
157*1410cb93SJoshua M. Clulow 	 */
158*1410cb93SJoshua M. Clulow 	(void) topo_prop_set_uint32(node, TOPO_PGROUP_FACILITY, TOPO_LED_MODE,
159*1410cb93SJoshua M. Clulow 	    TOPO_PROP_MUTABLE, fwi->fwi_mode, &err);
160*1410cb93SJoshua M. Clulow 
161*1410cb93SJoshua M. Clulow out:
162*1410cb93SJoshua M. Clulow 	topo_hdl_strfree(thp, facname);
163*1410cb93SJoshua M. Clulow 	topo_hdl_strfree(thp, factype);
164*1410cb93SJoshua M. Clulow 	return (TOPO_WALK_NEXT);
165*1410cb93SJoshua M. Clulow }
166*1410cb93SJoshua M. Clulow 
167*1410cb93SJoshua M. Clulow static int
dl_fault_walk_outer(topo_hdl_t * thp,tnode_t * node,void * arg)168*1410cb93SJoshua M. Clulow dl_fault_walk_outer(topo_hdl_t *thp, tnode_t *node, void *arg)
169*1410cb93SJoshua M. Clulow {
170*1410cb93SJoshua M. Clulow 	disk_lights_t *dl = arg;
171*1410cb93SJoshua M. Clulow 	dl_fault_walk_inner_t fwi;
172*1410cb93SJoshua M. Clulow 	tnode_t *pnode;
173*1410cb93SJoshua M. Clulow 	int err, has_fault;
174*1410cb93SJoshua M. Clulow 	nvlist_t *fmri = NULL;
175*1410cb93SJoshua M. Clulow 
176*1410cb93SJoshua M. Clulow 	bzero(&fwi, sizeof (fwi));
177*1410cb93SJoshua M. Clulow 
178*1410cb93SJoshua M. Clulow 	/*
179*1410cb93SJoshua M. Clulow 	 * We are only looking for DISK nodes in the topology that have a parent
180*1410cb93SJoshua M. Clulow 	 * BAY.
181*1410cb93SJoshua M. Clulow 	 */
182*1410cb93SJoshua M. Clulow 	if (strcmp(DISK, topo_node_name(node)) != 0 ||
183*1410cb93SJoshua M. Clulow 	    (pnode = topo_node_parent(node)) == NULL ||
184*1410cb93SJoshua M. Clulow 	    strcmp(BAY, topo_node_name(pnode)) != 0) {
185*1410cb93SJoshua M. Clulow 		return (TOPO_WALK_NEXT);
186*1410cb93SJoshua M. Clulow 	}
187*1410cb93SJoshua M. Clulow 
188*1410cb93SJoshua M. Clulow 	/*
189*1410cb93SJoshua M. Clulow 	 * Check to see if the Resource this FMRI describes is Faulty:
190*1410cb93SJoshua M. Clulow 	 */
191*1410cb93SJoshua M. Clulow 	if (topo_node_resource(node, &fmri, &err) != 0)
192*1410cb93SJoshua M. Clulow 		return (TOPO_WALK_NEXT);
193*1410cb93SJoshua M. Clulow 	has_fault = fmd_nvl_fmri_has_fault(dl->dl_fmd, fmri,
194*1410cb93SJoshua M. Clulow 	    FMD_HAS_FAULT_RESOURCE, NULL);
195*1410cb93SJoshua M. Clulow 	nvlist_free(fmri);
196*1410cb93SJoshua M. Clulow 
197*1410cb93SJoshua M. Clulow 	/*
198*1410cb93SJoshua M. Clulow 	 * Walk the children of this BAY and flush out our fault status if
199*1410cb93SJoshua M. Clulow 	 * we find an appropriate indicator node.
200*1410cb93SJoshua M. Clulow 	 */
201*1410cb93SJoshua M. Clulow 	fwi.fwi_name = "fail";
202*1410cb93SJoshua M. Clulow 	fwi.fwi_mode = has_fault ? TOPO_LED_STATE_ON : TOPO_LED_STATE_OFF;
203*1410cb93SJoshua M. Clulow 	(void) topo_node_child_walk(thp, pnode, dl_fault_walk_inner, &fwi,
204*1410cb93SJoshua M. Clulow 	    &err);
205*1410cb93SJoshua M. Clulow 
206*1410cb93SJoshua M. Clulow 	return (TOPO_WALK_NEXT);
207*1410cb93SJoshua M. Clulow }
208*1410cb93SJoshua M. Clulow 
209*1410cb93SJoshua M. Clulow /*
210*1410cb93SJoshua M. Clulow  * Walk all of the topology nodes looking for DISKs that match the structure
211*1410cb93SJoshua M. Clulow  * described in the overview.  Once we find them, check their fault status
212*1410cb93SJoshua M. Clulow  * and update their fault indiciator accordingly.
213*1410cb93SJoshua M. Clulow  */
214*1410cb93SJoshua M. Clulow static void
dl_examine_topo(disk_lights_t * dl)215*1410cb93SJoshua M. Clulow dl_examine_topo(disk_lights_t *dl)
216*1410cb93SJoshua M. Clulow {
217*1410cb93SJoshua M. Clulow 	int err;
218*1410cb93SJoshua M. Clulow 	topo_hdl_t *thp = NULL;
219*1410cb93SJoshua M. Clulow 	topo_walk_t *twp = NULL;
220*1410cb93SJoshua M. Clulow 
221*1410cb93SJoshua M. Clulow 	thp = fmd_hdl_topo_hold(dl->dl_fmd, TOPO_VERSION);
222*1410cb93SJoshua M. Clulow 	if ((twp = topo_walk_init(thp, FM_FMRI_SCHEME_HC, dl_fault_walk_outer,
223*1410cb93SJoshua M. Clulow 	    dl, &err)) == NULL) {
224*1410cb93SJoshua M. Clulow 		fmd_hdl_error(dl->dl_fmd, "failed to get topology: %s\n",
225*1410cb93SJoshua M. Clulow 		    topo_strerror(err));
226*1410cb93SJoshua M. Clulow 		goto out;
227*1410cb93SJoshua M. Clulow 	}
228*1410cb93SJoshua M. Clulow 
229*1410cb93SJoshua M. Clulow 	if (topo_walk_step(twp, TOPO_WALK_CHILD) == TOPO_WALK_ERR) {
230*1410cb93SJoshua M. Clulow 		fmd_hdl_error(dl->dl_fmd, "failed to walk topology: %s\n",
231*1410cb93SJoshua M. Clulow 		    topo_strerror(err));
232*1410cb93SJoshua M. Clulow 		goto out;
233*1410cb93SJoshua M. Clulow 	}
234*1410cb93SJoshua M. Clulow 
235*1410cb93SJoshua M. Clulow out:
236*1410cb93SJoshua M. Clulow 	if (twp != NULL)
237*1410cb93SJoshua M. Clulow 		topo_walk_fini(twp);
238*1410cb93SJoshua M. Clulow 	if (thp != NULL)
239*1410cb93SJoshua M. Clulow 		fmd_hdl_topo_rele(dl->dl_fmd, thp);
240*1410cb93SJoshua M. Clulow }
241*1410cb93SJoshua M. Clulow 
242*1410cb93SJoshua M. Clulow static void
dl_trigger_enum(disk_lights_t * dl)243*1410cb93SJoshua M. Clulow dl_trigger_enum(disk_lights_t *dl)
244*1410cb93SJoshua M. Clulow {
245*1410cb93SJoshua M. Clulow 	/*
246*1410cb93SJoshua M. Clulow 	 * If we're already on the short-poll coalesce timer, then return
247*1410cb93SJoshua M. Clulow 	 * immediately.
248*1410cb93SJoshua M. Clulow 	 */
249*1410cb93SJoshua M. Clulow 	if (dl->dl_triggered == B_TRUE)
250*1410cb93SJoshua M. Clulow 		return;
251*1410cb93SJoshua M. Clulow 	dl->dl_triggered = B_TRUE;
252*1410cb93SJoshua M. Clulow 
253*1410cb93SJoshua M. Clulow 	/*
254*1410cb93SJoshua M. Clulow 	 * Replace existing poll timer with coalesce timer:
255*1410cb93SJoshua M. Clulow 	 */
256*1410cb93SJoshua M. Clulow 	if (dl->dl_timer != 0)
257*1410cb93SJoshua M. Clulow 		fmd_timer_remove(dl->dl_fmd, dl->dl_timer);
258*1410cb93SJoshua M. Clulow 	dl->dl_timer = fmd_timer_install(dl->dl_fmd, NULL, NULL,
259*1410cb93SJoshua M. Clulow 	    dl->dl_coalesce_interval);
260*1410cb93SJoshua M. Clulow }
261*1410cb93SJoshua M. Clulow 
262*1410cb93SJoshua M. Clulow /*ARGSUSED*/
263*1410cb93SJoshua M. Clulow static void
disklights_timeout(fmd_hdl_t * hdl,id_t id,void * data)264*1410cb93SJoshua M. Clulow disklights_timeout(fmd_hdl_t *hdl, id_t id, void *data)
265*1410cb93SJoshua M. Clulow {
266*1410cb93SJoshua M. Clulow 	disk_lights_t *dl = fmd_hdl_getspecific(hdl);
267*1410cb93SJoshua M. Clulow 
268*1410cb93SJoshua M. Clulow 	dl->dl_triggered = B_FALSE;
269*1410cb93SJoshua M. Clulow 
270*1410cb93SJoshua M. Clulow 	dl_examine_topo(dl);
271*1410cb93SJoshua M. Clulow 
272*1410cb93SJoshua M. Clulow 	/*
273*1410cb93SJoshua M. Clulow 	 * Install the long-interval timer for the next poll.
274*1410cb93SJoshua M. Clulow 	 */
275*1410cb93SJoshua M. Clulow 	dl->dl_timer = fmd_timer_install(hdl, NULL, NULL, dl->dl_poll_interval);
276*1410cb93SJoshua M. Clulow }
277*1410cb93SJoshua M. Clulow 
278*1410cb93SJoshua M. Clulow /*ARGSUSED*/
279*1410cb93SJoshua M. Clulow static void
disklights_topo(fmd_hdl_t * hdl,topo_hdl_t * thp)280*1410cb93SJoshua M. Clulow disklights_topo(fmd_hdl_t *hdl, topo_hdl_t *thp)
281*1410cb93SJoshua M. Clulow {
282*1410cb93SJoshua M. Clulow 	disk_lights_t *dl = fmd_hdl_getspecific(hdl);
283*1410cb93SJoshua M. Clulow 
284*1410cb93SJoshua M. Clulow 	dl_trigger_enum(dl);
285*1410cb93SJoshua M. Clulow }
286*1410cb93SJoshua M. Clulow 
287*1410cb93SJoshua M. Clulow /*ARGSUSED*/
288*1410cb93SJoshua M. Clulow static void
disklights_recv(fmd_hdl_t * hdl,fmd_event_t * ep,nvlist_t * nvl,const char * class)289*1410cb93SJoshua M. Clulow disklights_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl,
290*1410cb93SJoshua M. Clulow     const char *class)
291*1410cb93SJoshua M. Clulow {
292*1410cb93SJoshua M. Clulow 	disk_lights_t *dl = fmd_hdl_getspecific(hdl);
293*1410cb93SJoshua M. Clulow 
294*1410cb93SJoshua M. Clulow 	dl_trigger_enum(dl);
295*1410cb93SJoshua M. Clulow }
296*1410cb93SJoshua M. Clulow 
297*1410cb93SJoshua M. Clulow void
_fmd_init(fmd_hdl_t * hdl)298*1410cb93SJoshua M. Clulow _fmd_init(fmd_hdl_t *hdl)
299*1410cb93SJoshua M. Clulow {
300*1410cb93SJoshua M. Clulow 	disk_lights_t *dl;
301*1410cb93SJoshua M. Clulow 
302*1410cb93SJoshua M. Clulow 	if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0)
303*1410cb93SJoshua M. Clulow 		return;
304*1410cb93SJoshua M. Clulow 
305*1410cb93SJoshua M. Clulow 	dl = fmd_hdl_zalloc(hdl, sizeof (*dl), FMD_SLEEP);
306*1410cb93SJoshua M. Clulow 	fmd_hdl_setspecific(hdl, dl);
307*1410cb93SJoshua M. Clulow 
308*1410cb93SJoshua M. Clulow 	/*
309*1410cb93SJoshua M. Clulow 	 * Load Configuration:
310*1410cb93SJoshua M. Clulow 	 */
311*1410cb93SJoshua M. Clulow 	dl->dl_fmd = hdl;
312*1410cb93SJoshua M. Clulow 	dl->dl_poll_interval = fmd_prop_get_int64(hdl, DL_PROP_POLL_INTERVAL);
313*1410cb93SJoshua M. Clulow 	dl->dl_coalesce_interval = fmd_prop_get_int64(hdl,
314*1410cb93SJoshua M. Clulow 	    DL_PROP_COALESCE_INTERVAL);
315*1410cb93SJoshua M. Clulow 
316*1410cb93SJoshua M. Clulow 	/*
317*1410cb93SJoshua M. Clulow 	 * Schedule the initial enumeration:
318*1410cb93SJoshua M. Clulow 	 */
319*1410cb93SJoshua M. Clulow 	dl_trigger_enum(dl);
320*1410cb93SJoshua M. Clulow }
321*1410cb93SJoshua M. Clulow 
322*1410cb93SJoshua M. Clulow void
_fmd_fini(fmd_hdl_t * hdl)323*1410cb93SJoshua M. Clulow _fmd_fini(fmd_hdl_t *hdl)
324*1410cb93SJoshua M. Clulow {
325*1410cb93SJoshua M. Clulow 	disk_lights_t *dl = fmd_hdl_getspecific(hdl);
326*1410cb93SJoshua M. Clulow 
327*1410cb93SJoshua M. Clulow 	fmd_hdl_free(hdl, dl, sizeof (*dl));
328*1410cb93SJoshua M. Clulow }
329