1*184cd04cScth /*
2*184cd04cScth * CDDL HEADER START
3*184cd04cScth *
4*184cd04cScth * The contents of this file are subject to the terms of the
5*184cd04cScth * Common Development and Distribution License (the "License").
6*184cd04cScth * You may not use this file except in compliance with the License.
7*184cd04cScth *
8*184cd04cScth * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*184cd04cScth * or http://www.opensolaris.org/os/licensing.
10*184cd04cScth * See the License for the specific language governing permissions
11*184cd04cScth * and limitations under the License.
12*184cd04cScth *
13*184cd04cScth * When distributing Covered Code, include this CDDL HEADER in each
14*184cd04cScth * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*184cd04cScth * If applicable, add the following below this CDDL HEADER, with the
16*184cd04cScth * fields enclosed by brackets "[]" replaced with your own identifying
17*184cd04cScth * information: Portions Copyright [yyyy] [name of copyright owner]
18*184cd04cScth *
19*184cd04cScth * CDDL HEADER END
20*184cd04cScth */
21*184cd04cScth
22*184cd04cScth /*
23*184cd04cScth * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24*184cd04cScth * Use is subject to license terms.
25*184cd04cScth */
26*184cd04cScth
27*184cd04cScth #include <string.h>
28*184cd04cScth #include <inttypes.h>
29*184cd04cScth #include <atomic.h>
30*184cd04cScth #include <fm/fmd_api.h>
31*184cd04cScth #include <sys/fm/protocol.h>
32*184cd04cScth
33*184cd04cScth #include "disk_monitor.h"
34*184cd04cScth #include "schg_mgr.h"
35*184cd04cScth #include "hotplug_mgr.h"
36*184cd04cScth #include "topo_gather.h"
37*184cd04cScth #include "dm_platform.h"
38*184cd04cScth
39*184cd04cScth /* State-change event processing thread data */
40*184cd04cScth static pthread_t g_schg_tid;
41*184cd04cScth static thread_state_t g_schgt_state = TS_NOT_RUNNING;
42*184cd04cScth static pthread_mutex_t g_schgt_state_mutex = PTHREAD_MUTEX_INITIALIZER;
43*184cd04cScth static pthread_cond_t g_schgt_state_cvar = PTHREAD_COND_INITIALIZER;
44*184cd04cScth static pthread_mutex_t g_schgt_add_mutex = PTHREAD_MUTEX_INITIALIZER;
45*184cd04cScth static qu_t *g_schg_queue = NULL;
46*184cd04cScth
47*184cd04cScth static void dm_state_change_nolock(diskmon_t *diskp, hotplug_state_t newstate);
48*184cd04cScth
49*184cd04cScth /*
50*184cd04cScth * Each disk state change is described by an instance of the following
51*184cd04cScth * structure (which includes the disk object and the new state)
52*184cd04cScth */
53*184cd04cScth typedef struct disk_statechg {
54*184cd04cScth diskmon_t *diskp;
55*184cd04cScth hotplug_state_t newstate;
56*184cd04cScth } disk_statechg_t;
57*184cd04cScth
58*184cd04cScth static disk_statechg_t *
new_statechange(diskmon_t * diskp,hotplug_state_t state)59*184cd04cScth new_statechange(diskmon_t *diskp, hotplug_state_t state)
60*184cd04cScth {
61*184cd04cScth disk_statechg_t *dscp =
62*184cd04cScth (disk_statechg_t *)dmalloc(sizeof (disk_statechg_t));
63*184cd04cScth
64*184cd04cScth /*
65*184cd04cScth * The states are additive -- we don't need to preserve
66*184cd04cScth * the current faulted state in the newstate:
67*184cd04cScth */
68*184cd04cScth dscp->diskp = diskp;
69*184cd04cScth dscp->newstate = state;
70*184cd04cScth
71*184cd04cScth return (dscp);
72*184cd04cScth }
73*184cd04cScth
74*184cd04cScth static void
free_statechange(void * dscp)75*184cd04cScth free_statechange(void *dscp)
76*184cd04cScth {
77*184cd04cScth dfree(dscp, sizeof (disk_statechg_t));
78*184cd04cScth }
79*184cd04cScth
80*184cd04cScth static void
add_to_statechange_queue(diskmon_t * diskp,hotplug_state_t newstate)81*184cd04cScth add_to_statechange_queue(diskmon_t *diskp, hotplug_state_t newstate)
82*184cd04cScth {
83*184cd04cScth queue_add(g_schg_queue, new_statechange(diskp, newstate));
84*184cd04cScth }
85*184cd04cScth
86*184cd04cScth static const char *
lookup_action_string(indicator_t * ind_listp,ind_state_t state,char * name)87*184cd04cScth lookup_action_string(indicator_t *ind_listp, ind_state_t state, char *name)
88*184cd04cScth {
89*184cd04cScth const char *str = NULL;
90*184cd04cScth
91*184cd04cScth while (ind_listp != NULL) {
92*184cd04cScth
93*184cd04cScth if (state == ind_listp->ind_state &&
94*184cd04cScth strcasecmp(ind_listp->ind_name, name) == 0) {
95*184cd04cScth
96*184cd04cScth str = ind_listp->ind_instr_spec;
97*184cd04cScth break;
98*184cd04cScth }
99*184cd04cScth
100*184cd04cScth ind_listp = ind_listp->next;
101*184cd04cScth }
102*184cd04cScth
103*184cd04cScth return (str);
104*184cd04cScth }
105*184cd04cScth
106*184cd04cScth void
dm_fault_indicator_set(diskmon_t * diskp,ind_state_t istate)107*184cd04cScth dm_fault_indicator_set(diskmon_t *diskp, ind_state_t istate)
108*184cd04cScth {
109*184cd04cScth const char *astring;
110*184cd04cScth
111*184cd04cScth dm_assert(pthread_mutex_lock(&diskp->fault_indicator_mutex) == 0);
112*184cd04cScth
113*184cd04cScth /*
114*184cd04cScth * No need to execute redundant indicator actions
115*184cd04cScth */
116*184cd04cScth if (istate == INDICATOR_UNKNOWN ||
117*184cd04cScth diskp->fault_indicator_state == istate) {
118*184cd04cScth dm_assert(pthread_mutex_unlock(&diskp->fault_indicator_mutex)
119*184cd04cScth == 0);
120*184cd04cScth return;
121*184cd04cScth }
122*184cd04cScth
123*184cd04cScth astring = lookup_action_string(diskp->ind_list, istate,
124*184cd04cScth INDICATOR_FAULT_IDENTIFIER);
125*184cd04cScth
126*184cd04cScth if (astring != NULL) {
127*184cd04cScth log_msg(MM_SCHGMGR, "Executing action `%s'\n", astring);
128*184cd04cScth
129*184cd04cScth if (dm_platform_indicator_execute(astring) != 0) {
130*184cd04cScth log_warn("[Disk in %s] Action `%s' did not complete "
131*184cd04cScth "successfully.\n",
132*184cd04cScth diskp->location,
133*184cd04cScth astring);
134*184cd04cScth } else {
135*184cd04cScth
136*184cd04cScth diskp->fault_indicator_state = istate;
137*184cd04cScth
138*184cd04cScth log_msg(MM_SCHGMGR, "Action `%s' executed "
139*184cd04cScth "successfully\n", astring);
140*184cd04cScth }
141*184cd04cScth }
142*184cd04cScth
143*184cd04cScth dm_assert(pthread_mutex_unlock(&diskp->fault_indicator_mutex) == 0);
144*184cd04cScth }
145*184cd04cScth
146*184cd04cScth static void
schg_execute_state_change_action(diskmon_t * diskp,hotplug_state_t oldstate,hotplug_state_t newstate)147*184cd04cScth schg_execute_state_change_action(diskmon_t *diskp, hotplug_state_t oldstate,
148*184cd04cScth hotplug_state_t newstate)
149*184cd04cScth {
150*184cd04cScth indrule_t *rulelist;
151*184cd04cScth ind_action_t *actions;
152*184cd04cScth const char *astring;
153*184cd04cScth
154*184cd04cScth log_msg(MM_SCHGMGR, "[Disk in %s] State change action: %s -> %s\n",
155*184cd04cScth diskp->location,
156*184cd04cScth hotplug_state_string(oldstate),
157*184cd04cScth hotplug_state_string(newstate));
158*184cd04cScth
159*184cd04cScth /*
160*184cd04cScth * Find the list of actions that correspond to this state change.
161*184cd04cScth * If the old state is UNKNOWN, then we'll match to first action
162*184cd04cScth * whose transition state is the new state.
163*184cd04cScth */
164*184cd04cScth rulelist = diskp->indrule_list;
165*184cd04cScth
166*184cd04cScth while (rulelist != NULL) {
167*184cd04cScth
168*184cd04cScth if ((oldstate == HPS_UNKNOWN ||
169*184cd04cScth rulelist->strans.begin == oldstate) &&
170*184cd04cScth rulelist->strans.end == newstate)
171*184cd04cScth break;
172*184cd04cScth
173*184cd04cScth rulelist = rulelist->next;
174*184cd04cScth }
175*184cd04cScth
176*184cd04cScth if (rulelist != NULL) {
177*184cd04cScth /* Now we have a set of actions to perform: */
178*184cd04cScth actions = rulelist->action_list;
179*184cd04cScth
180*184cd04cScth while (actions != NULL) {
181*184cd04cScth
182*184cd04cScth astring = lookup_action_string(diskp->ind_list,
183*184cd04cScth actions->ind_state, actions->ind_name);
184*184cd04cScth
185*184cd04cScth dm_assert(astring != NULL);
186*184cd04cScth
187*184cd04cScth log_msg(MM_SCHGMGR, "Executing action `%s'\n", astring);
188*184cd04cScth
189*184cd04cScth if (dm_platform_indicator_execute(astring) != 0) {
190*184cd04cScth log_warn("[Disk in %s][State transition from "
191*184cd04cScth "%s to %s] Action `%s' did not complete "
192*184cd04cScth "successfully.\n",
193*184cd04cScth diskp->location,
194*184cd04cScth hotplug_state_string(oldstate),
195*184cd04cScth hotplug_state_string(newstate),
196*184cd04cScth astring);
197*184cd04cScth
198*184cd04cScth } else
199*184cd04cScth log_msg(MM_SCHGMGR,
200*184cd04cScth "Action `%s' executed successfully\n",
201*184cd04cScth astring);
202*184cd04cScth
203*184cd04cScth actions = actions->next;
204*184cd04cScth }
205*184cd04cScth }
206*184cd04cScth
207*184cd04cScth }
208*184cd04cScth
209*184cd04cScth static void
schg_send_fru_update(diskmon_t * diskp,dm_fru_t * frup)210*184cd04cScth schg_send_fru_update(diskmon_t *diskp, dm_fru_t *frup)
211*184cd04cScth {
212*184cd04cScth const char *action = dm_prop_lookup(diskp->props, DISK_PROP_FRUACTION);
213*184cd04cScth
214*184cd04cScth if (action == NULL) {
215*184cd04cScth log_msg(MM_SCHGMGR|MM_NOTE, "No FRU update action for disk "
216*184cd04cScth "in %s\n", diskp->location);
217*184cd04cScth return;
218*184cd04cScth }
219*184cd04cScth
220*184cd04cScth if (dm_platform_update_fru(action, frup) != 0) {
221*184cd04cScth log_warn("Error updating FRU information for disk in %s.\n",
222*184cd04cScth diskp->location);
223*184cd04cScth }
224*184cd04cScth }
225*184cd04cScth
226*184cd04cScth static void
schg_update_fru_info(diskmon_t * diskp)227*184cd04cScth schg_update_fru_info(diskmon_t *diskp)
228*184cd04cScth {
229*184cd04cScth if (diskp->initial_configuration ||
230*184cd04cScth update_configuration_from_topo(g_fm_hdl, diskp) == TOPO_SUCCESS) {
231*184cd04cScth diskp->initial_configuration = B_FALSE;
232*184cd04cScth dm_assert(pthread_mutex_lock(&diskp->fru_mutex) == 0);
233*184cd04cScth if (diskp->frup != NULL)
234*184cd04cScth schg_send_fru_update(diskp, diskp->frup);
235*184cd04cScth else
236*184cd04cScth log_warn("frup unexpectedly went away: not updating "
237*184cd04cScth "FRU information for disk %s!\n", diskp->location);
238*184cd04cScth dm_assert(pthread_mutex_unlock(&diskp->fru_mutex) == 0);
239*184cd04cScth } else {
240*184cd04cScth log_warn_e("Error retrieving FRU information "
241*184cd04cScth "for disk in %s", diskp->location);
242*184cd04cScth }
243*184cd04cScth }
244*184cd04cScth
245*184cd04cScth void
block_state_change_events(void)246*184cd04cScth block_state_change_events(void)
247*184cd04cScth {
248*184cd04cScth dm_assert(pthread_mutex_lock(&g_schgt_add_mutex) == 0);
249*184cd04cScth }
250*184cd04cScth
251*184cd04cScth void
unblock_state_change_events(void)252*184cd04cScth unblock_state_change_events(void)
253*184cd04cScth {
254*184cd04cScth dm_assert(pthread_mutex_unlock(&g_schgt_add_mutex) == 0);
255*184cd04cScth }
256*184cd04cScth
257*184cd04cScth static void
disk_state_change_first_time(diskmon_t * diskp)258*184cd04cScth disk_state_change_first_time(diskmon_t *diskp)
259*184cd04cScth {
260*184cd04cScth hotplug_state_t firststate;
261*184cd04cScth
262*184cd04cScth /*
263*184cd04cScth * Grab the current state of the attachment point to initialize the
264*184cd04cScth * initial disk state. Create a disk state change with this new
265*184cd04cScth * state so it will be processed in the loop below. If we can't get
266*184cd04cScth * the initial state for some reason, then we'll just end up doing it
267*184cd04cScth * later when we get a state change from the hotplug monitor or the
268*184cd04cScth * fault monitor.
269*184cd04cScth */
270*184cd04cScth firststate = disk_ap_state_to_hotplug_state(diskp);
271*184cd04cScth if (firststate != HPS_UNKNOWN)
272*184cd04cScth dm_state_change_nolock(diskp, firststate);
273*184cd04cScth
274*184cd04cScth /*
275*184cd04cScth * The fault indicators will be updated when faults are replayed
276*184cd04cScth * based on the state of the disk as faulty in the fmd resource cache.
277*184cd04cScth * A FAULTED state change will come from the _recv function when the
278*184cd04cScth * fault component event is replayed.
279*184cd04cScth */
280*184cd04cScth }
281*184cd04cScth
282*184cd04cScth static void
disk_state_change_thread(void * vdisklistp)283*184cd04cScth disk_state_change_thread(void *vdisklistp)
284*184cd04cScth {
285*184cd04cScth diskmon_t *disklistp = (diskmon_t *)vdisklistp;
286*184cd04cScth diskmon_t *diskp;
287*184cd04cScth disk_statechg_t *dscp;
288*184cd04cScth hotplug_state_t nextstate;
289*184cd04cScth const char *pth;
290*184cd04cScth
291*184cd04cScth /*
292*184cd04cScth * Perform startup activities to initialize the state of the
293*184cd04cScth * indicators for each disk.
294*184cd04cScth */
295*184cd04cScth diskp = disklistp;
296*184cd04cScth while (diskp != NULL) {
297*184cd04cScth disk_state_change_first_time(diskp);
298*184cd04cScth diskp = diskp->next;
299*184cd04cScth }
300*184cd04cScth
301*184cd04cScth unblock_state_change_events();
302*184cd04cScth
303*184cd04cScth dm_assert(pthread_mutex_lock(&g_schgt_state_mutex) == 0);
304*184cd04cScth if (g_schgt_state != TS_EXIT_REQUESTED) {
305*184cd04cScth g_schgt_state = TS_RUNNING;
306*184cd04cScth dm_assert(pthread_cond_broadcast(&g_schgt_state_cvar) == 0);
307*184cd04cScth }
308*184cd04cScth dm_assert(pthread_mutex_unlock(&g_schgt_state_mutex) == 0);
309*184cd04cScth
310*184cd04cScth while (g_schgt_state != TS_EXIT_REQUESTED) {
311*184cd04cScth
312*184cd04cScth if ((dscp = (disk_statechg_t *)queue_remove(g_schg_queue))
313*184cd04cScth == NULL) {
314*184cd04cScth dm_assert(g_schgt_state == TS_EXIT_REQUESTED);
315*184cd04cScth continue;
316*184cd04cScth }
317*184cd04cScth
318*184cd04cScth diskp = dscp->diskp;
319*184cd04cScth
320*184cd04cScth /*
321*184cd04cScth * If the new state is the faulted state, add that state to
322*184cd04cScth * the disk's current state.
323*184cd04cScth */
324*184cd04cScth if (dscp->newstate == HPS_FAULTED) {
325*184cd04cScth
326*184cd04cScth /*
327*184cd04cScth * If the disk wasn't previously in the faulted state,
328*184cd04cScth * execute the generic fault action. Even if we're
329*184cd04cScth * in the faulted state, accept additional faults.
330*184cd04cScth */
331*184cd04cScth nextstate = DISK_STATE(diskp->state) | HPS_FAULTED;
332*184cd04cScth
333*184cd04cScth } else if (dscp->newstate == HPS_REPAIRED) {
334*184cd04cScth nextstate = DISK_STATE(diskp->state);
335*184cd04cScth
336*184cd04cScth } else if (dscp->newstate == HPS_ABSENT) {
337*184cd04cScth /*
338*184cd04cScth * If the new state is ABSENT, forget any faults
339*184cd04cScth */
340*184cd04cScth
341*184cd04cScth nextstate = HPS_ABSENT;
342*184cd04cScth } else
343*184cd04cScth nextstate = dscp->newstate | DISK_FAULTED(diskp->state);
344*184cd04cScth
345*184cd04cScth /*
346*184cd04cScth * When a new disk is inserted and reaches the CONFIGURED state,
347*184cd04cScth * the following actions must be done in the following order:
348*184cd04cScth *
349*184cd04cScth * (1) Execute the configuration-specified action on the
350*184cd04cScth * state change.
351*184cd04cScth * (2) Retreive the FRU information from the disk and execute
352*184cd04cScth * the FRU-update action specified,
353*184cd04cScth * (3) Initialize the fault monitor state associated with
354*184cd04cScth * the new drive.
355*184cd04cScth *
356*184cd04cScth * Once the disk is no longer "new" (a disk is "new" when it
357*184cd04cScth * has not yet reached the CONFIGURED state), subsequent
358*184cd04cScth * transitions away and back to CONFIGURED (as long as the
359*184cd04cScth * disk is not physically removed) will result in the
360*184cd04cScth * execution of the predefined action ONLY.
361*184cd04cScth *
362*184cd04cScth */
363*184cd04cScth
364*184cd04cScth if (dscp->newstate != HPS_FAULTED &&
365*184cd04cScth DISK_STATE(nextstate) != HPS_UNKNOWN &&
366*184cd04cScth dscp->newstate != HPS_REPAIRED) {
367*184cd04cScth
368*184cd04cScth schg_execute_state_change_action(diskp,
369*184cd04cScth DISK_STATE(diskp->state), DISK_STATE(nextstate));
370*184cd04cScth }
371*184cd04cScth
372*184cd04cScth if (!diskp->configured_yet &&
373*184cd04cScth DISK_STATE(nextstate) == HPS_CONFIGURED) {
374*184cd04cScth
375*184cd04cScth schg_update_fru_info(diskp);
376*184cd04cScth
377*184cd04cScth /*
378*184cd04cScth * If this state transition is lagging the true
379*184cd04cScth * state of the system (e.g. if the true state of
380*184cd04cScth * the disk is UNCONFIGURED, there's another
381*184cd04cScth * state change somewhere later in the queue), then
382*184cd04cScth * it's possible for the disk path property to not
383*184cd04cScth * exist.
384*184cd04cScth */
385*184cd04cScth if (dm_prop_lookup(diskp->props,
386*184cd04cScth DISK_PROP_DEVPATH) == NULL) {
387*184cd04cScth
388*184cd04cScth log_msg(MM_SCHGMGR,
389*184cd04cScth "Processed stale state change "
390*184cd04cScth "for disk %s\n", diskp->location);
391*184cd04cScth
392*184cd04cScth } else {
393*184cd04cScth diskp->configured_yet = B_TRUE;
394*184cd04cScth }
395*184cd04cScth
396*184cd04cScth }
397*184cd04cScth
398*184cd04cScth dm_assert(pthread_mutex_lock(&diskp->manager_mutex) == 0);
399*184cd04cScth
400*184cd04cScth /*
401*184cd04cScth * Make the new state visible to all observers
402*184cd04cScth */
403*184cd04cScth diskp->state = nextstate;
404*184cd04cScth
405*184cd04cScth /*
406*184cd04cScth * Now, update the diskmon if the disk is now absent -- it's
407*184cd04cScth * essential to do this after the state is set (above) so that
408*184cd04cScth * state observers in other threads don't try to access the
409*184cd04cScth * data structures that we're freeing here.
410*184cd04cScth */
411*184cd04cScth
412*184cd04cScth if (diskp->configured_yet &&
413*184cd04cScth DISK_STATE(nextstate) == HPS_ABSENT) {
414*184cd04cScth /*
415*184cd04cScth * When the disk is removed, the fault monitor state is
416*184cd04cScth * useless, so discard it.
417*184cd04cScth */
418*184cd04cScth dm_assert(DISK_STATE(nextstate) != HPS_CONFIGURED);
419*184cd04cScth
420*184cd04cScth diskp->configured_yet = B_FALSE;
421*184cd04cScth
422*184cd04cScth }
423*184cd04cScth dm_assert(pthread_mutex_unlock(&diskp->manager_mutex) == 0);
424*184cd04cScth
425*184cd04cScth pth = dm_prop_lookup(diskp->props, DISK_PROP_DEVPATH);
426*184cd04cScth
427*184cd04cScth log_msg(MM_SCHGMGR,
428*184cd04cScth "[State change #%d][%s]: Disk path = %s\n",
429*184cd04cScth diskp->state_change_count,
430*184cd04cScth diskp->location, pth == NULL ? "Unknown" : pth);
431*184cd04cScth
432*184cd04cScth log_msg(MM_SCHGMGR,
433*184cd04cScth "[State change #%d][%s]: New state = %s%s\n",
434*184cd04cScth diskp->state_change_count, diskp->location,
435*184cd04cScth hotplug_state_string(diskp->state),
436*184cd04cScth DISK_FAULTED(diskp->state) ? "+FAULTED" : "");
437*184cd04cScth
438*184cd04cScth atomic_inc_uint(&diskp->state_change_count);
439*184cd04cScth
440*184cd04cScth /* The caller is responsible for freeing the state change: */
441*184cd04cScth free_statechange(dscp);
442*184cd04cScth }
443*184cd04cScth dm_assert(pthread_mutex_lock(&g_schgt_state_mutex) == 0);
444*184cd04cScth g_schgt_state = TS_EXITED;
445*184cd04cScth dm_assert(pthread_cond_broadcast(&g_schgt_state_cvar) == 0);
446*184cd04cScth dm_assert(pthread_mutex_unlock(&g_schgt_state_mutex) == 0);
447*184cd04cScth
448*184cd04cScth log_msg(MM_SCHGMGR, "State change thread exiting...\n");
449*184cd04cScth }
450*184cd04cScth
451*184cd04cScth static void
dm_state_change_nolock(diskmon_t * diskp,hotplug_state_t newstate)452*184cd04cScth dm_state_change_nolock(diskmon_t *diskp, hotplug_state_t newstate)
453*184cd04cScth {
454*184cd04cScth /* Enqueue a new state change for the state-change thread */
455*184cd04cScth add_to_statechange_queue(diskp, newstate);
456*184cd04cScth }
457*184cd04cScth
458*184cd04cScth void
dm_state_change(diskmon_t * diskp,hotplug_state_t newstate)459*184cd04cScth dm_state_change(diskmon_t *diskp, hotplug_state_t newstate)
460*184cd04cScth {
461*184cd04cScth dm_assert(pthread_mutex_lock(&g_schgt_add_mutex) == 0);
462*184cd04cScth dm_state_change_nolock(diskp, newstate);
463*184cd04cScth dm_assert(pthread_mutex_unlock(&g_schgt_add_mutex) == 0);
464*184cd04cScth }
465*184cd04cScth
466*184cd04cScth int
init_state_change_manager(cfgdata_t * cfgdatap)467*184cd04cScth init_state_change_manager(cfgdata_t *cfgdatap)
468*184cd04cScth {
469*184cd04cScth /* new_queue() is guaranteed to succeed */
470*184cd04cScth g_schg_queue = new_queue(B_TRUE, dmalloc, dfree, free_statechange);
471*184cd04cScth
472*184cd04cScth dm_assert(pthread_mutex_lock(&g_schgt_state_mutex) == 0);
473*184cd04cScth g_schg_tid = fmd_thr_create(g_fm_hdl, disk_state_change_thread,
474*184cd04cScth cfgdatap->disk_list);
475*184cd04cScth
476*184cd04cScth /*
477*184cd04cScth * Now, wait for the thread to enter the TS_RUNNING state. This
478*184cd04cScth * is important because we want the state-change thread to pull the
479*184cd04cScth * initial state of the disks on startup (without the wait, we could
480*184cd04cScth * have the hotplug event handler race and deliver a state change
481*184cd04cScth * before the state-change thread initialized the initial disk state).
482*184cd04cScth */
483*184cd04cScth
484*184cd04cScth while (g_schgt_state != TS_RUNNING) {
485*184cd04cScth (void) pthread_cond_wait(&g_schgt_state_cvar,
486*184cd04cScth &g_schgt_state_mutex);
487*184cd04cScth }
488*184cd04cScth
489*184cd04cScth dm_assert(pthread_mutex_unlock(&g_schgt_state_mutex) == 0);
490*184cd04cScth
491*184cd04cScth return (0);
492*184cd04cScth }
493*184cd04cScth
494*184cd04cScth /*ARGSUSED*/
495*184cd04cScth void
cleanup_state_change_manager(cfgdata_t * cfgdatap)496*184cd04cScth cleanup_state_change_manager(cfgdata_t *cfgdatap)
497*184cd04cScth {
498*184cd04cScth if (g_schgt_state != TS_RUNNING)
499*184cd04cScth return;
500*184cd04cScth
501*184cd04cScth g_schgt_state = TS_EXIT_REQUESTED;
502*184cd04cScth queue_add(g_schg_queue, NULL);
503*184cd04cScth dm_assert(pthread_mutex_lock(&g_schgt_state_mutex) == 0);
504*184cd04cScth while (g_schgt_state != TS_EXITED)
505*184cd04cScth dm_assert(pthread_cond_wait(&g_schgt_state_cvar,
506*184cd04cScth &g_schgt_state_mutex) == 0);
507*184cd04cScth dm_assert(pthread_mutex_unlock(&g_schgt_state_mutex) == 0);
508*184cd04cScth (void) pthread_join(g_schg_tid, NULL);
509*184cd04cScth fmd_thr_destroy(g_fm_hdl, g_schg_tid);
510*184cd04cScth queue_free(&g_schg_queue);
511*184cd04cScth g_schgt_state = TS_NOT_RUNNING;
512*184cd04cScth }
513