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
544743693Sstephh * Common Development and Distribution License (the "License").
644743693Sstephh * 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 */
21d9638e54Smws
227c478bd9Sstevel@tonic-gate /*
23*705e9f42SStephen Hanson * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
247c478bd9Sstevel@tonic-gate * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate */
267c478bd9Sstevel@tonic-gate
277c478bd9Sstevel@tonic-gate #include <sys/fm/protocol.h>
287c478bd9Sstevel@tonic-gate #include <uuid/uuid.h>
297c478bd9Sstevel@tonic-gate
307c478bd9Sstevel@tonic-gate #include <dirent.h>
317c478bd9Sstevel@tonic-gate #include <limits.h>
327c478bd9Sstevel@tonic-gate #include <unistd.h>
337c478bd9Sstevel@tonic-gate #include <alloca.h>
34567cc2e6Sstephh #include <stddef.h>
35940d71d2Seschrock #include <fm/libtopo.h>
367c478bd9Sstevel@tonic-gate
377c478bd9Sstevel@tonic-gate #include <fmd_alloc.h>
387c478bd9Sstevel@tonic-gate #include <fmd_string.h>
397c478bd9Sstevel@tonic-gate #include <fmd_error.h>
407c478bd9Sstevel@tonic-gate #include <fmd_subr.h>
417c478bd9Sstevel@tonic-gate #include <fmd_protocol.h>
427c478bd9Sstevel@tonic-gate #include <fmd_event.h>
437c478bd9Sstevel@tonic-gate #include <fmd_conf.h>
447c478bd9Sstevel@tonic-gate #include <fmd_fmri.h>
457c478bd9Sstevel@tonic-gate #include <fmd_dispq.h>
46d9638e54Smws #include <fmd_case.h>
47d9638e54Smws #include <fmd_module.h>
487c478bd9Sstevel@tonic-gate #include <fmd_asru.h>
497c478bd9Sstevel@tonic-gate
507c478bd9Sstevel@tonic-gate #include <fmd.h>
517c478bd9Sstevel@tonic-gate
527c478bd9Sstevel@tonic-gate static const char *const _fmd_asru_events[] = {
53d9638e54Smws FMD_RSRC_CLASS "asru.ok", /* UNUSABLE=0 FAULTED=0 */
54d9638e54Smws FMD_RSRC_CLASS "asru.degraded", /* UNUSABLE=0 FAULTED=1 */
55d9638e54Smws FMD_RSRC_CLASS "asru.unknown", /* UNUSABLE=1 FAULTED=0 */
56d9638e54Smws FMD_RSRC_CLASS "asru.faulted" /* UNUSABLE=1 FAULTED=1 */
577c478bd9Sstevel@tonic-gate };
587c478bd9Sstevel@tonic-gate
597c478bd9Sstevel@tonic-gate static const char *const _fmd_asru_snames[] = {
607c478bd9Sstevel@tonic-gate "uf", "uF", "Uf", "UF" /* same order as above */
617c478bd9Sstevel@tonic-gate };
627c478bd9Sstevel@tonic-gate
6344743693Sstephh volatile uint32_t fmd_asru_fake_not_present = 0;
6444743693Sstephh
65940d71d2Seschrock static uint_t
fmd_asru_strhash(fmd_asru_hash_t * ahp,const char * val)66940d71d2Seschrock fmd_asru_strhash(fmd_asru_hash_t *ahp, const char *val)
67940d71d2Seschrock {
68940d71d2Seschrock return (topo_fmri_strhash(ahp->ah_topo->ft_hdl, val) % ahp->ah_hashlen);
69940d71d2Seschrock }
70940d71d2Seschrock
71940d71d2Seschrock static boolean_t
fmd_asru_strcmp(fmd_asru_hash_t * ahp,const char * a,const char * b)72940d71d2Seschrock fmd_asru_strcmp(fmd_asru_hash_t *ahp, const char *a, const char *b)
73940d71d2Seschrock {
74940d71d2Seschrock return (topo_fmri_strcmp(ahp->ah_topo->ft_hdl, a, b));
75940d71d2Seschrock }
76940d71d2Seschrock
777c478bd9Sstevel@tonic-gate static fmd_asru_t *
fmd_asru_create(fmd_asru_hash_t * ahp,const char * uuid,const char * name,nvlist_t * fmri)787c478bd9Sstevel@tonic-gate fmd_asru_create(fmd_asru_hash_t *ahp, const char *uuid,
797c478bd9Sstevel@tonic-gate const char *name, nvlist_t *fmri)
807c478bd9Sstevel@tonic-gate {
81567cc2e6Sstephh fmd_asru_t *ap = fmd_zalloc(sizeof (fmd_asru_t), FMD_SLEEP);
827c478bd9Sstevel@tonic-gate char *s;
837c478bd9Sstevel@tonic-gate
847c478bd9Sstevel@tonic-gate (void) pthread_mutex_init(&ap->asru_lock, NULL);
857c478bd9Sstevel@tonic-gate (void) pthread_cond_init(&ap->asru_cv, NULL);
867c478bd9Sstevel@tonic-gate
877c478bd9Sstevel@tonic-gate ap->asru_name = fmd_strdup(name, FMD_SLEEP);
88567cc2e6Sstephh if (fmri)
897c478bd9Sstevel@tonic-gate (void) nvlist_xdup(fmri, &ap->asru_fmri, &fmd.d_nva);
907c478bd9Sstevel@tonic-gate ap->asru_root = fmd_strdup(ahp->ah_dirpath, FMD_SLEEP);
917c478bd9Sstevel@tonic-gate ap->asru_uuid = fmd_strdup(uuid, FMD_SLEEP);
927c478bd9Sstevel@tonic-gate ap->asru_uuidlen = ap->asru_uuid ? strlen(ap->asru_uuid) : 0;
937c478bd9Sstevel@tonic-gate ap->asru_refs = 1;
947c478bd9Sstevel@tonic-gate
95567cc2e6Sstephh if (fmri && nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &s) == 0 &&
967c478bd9Sstevel@tonic-gate strcmp(s, FM_FMRI_SCHEME_FMD) == 0)
977c478bd9Sstevel@tonic-gate ap->asru_flags |= FMD_ASRU_INTERNAL;
987c478bd9Sstevel@tonic-gate
997c478bd9Sstevel@tonic-gate return (ap);
1007c478bd9Sstevel@tonic-gate }
1017c478bd9Sstevel@tonic-gate
1027c478bd9Sstevel@tonic-gate static void
fmd_asru_destroy(fmd_asru_t * ap)1037c478bd9Sstevel@tonic-gate fmd_asru_destroy(fmd_asru_t *ap)
1047c478bd9Sstevel@tonic-gate {
1057c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ap->asru_lock));
1067c478bd9Sstevel@tonic-gate ASSERT(ap->asru_refs == 0);
1077c478bd9Sstevel@tonic-gate
108162ba6eaSmws nvlist_free(ap->asru_event);
1097c478bd9Sstevel@tonic-gate fmd_strfree(ap->asru_name);
1107c478bd9Sstevel@tonic-gate nvlist_free(ap->asru_fmri);
1117c478bd9Sstevel@tonic-gate fmd_strfree(ap->asru_root);
1127c478bd9Sstevel@tonic-gate fmd_free(ap->asru_uuid, ap->asru_uuidlen + 1);
1137c478bd9Sstevel@tonic-gate fmd_free(ap, sizeof (fmd_asru_t));
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate
1167c478bd9Sstevel@tonic-gate static void
fmd_asru_hash_insert(fmd_asru_hash_t * ahp,fmd_asru_t * ap)1177c478bd9Sstevel@tonic-gate fmd_asru_hash_insert(fmd_asru_hash_t *ahp, fmd_asru_t *ap)
1187c478bd9Sstevel@tonic-gate {
119940d71d2Seschrock uint_t h = fmd_asru_strhash(ahp, ap->asru_name);
1207c478bd9Sstevel@tonic-gate
1217c478bd9Sstevel@tonic-gate ASSERT(RW_WRITE_HELD(&ahp->ah_lock));
1227c478bd9Sstevel@tonic-gate ap->asru_next = ahp->ah_hash[h];
1237c478bd9Sstevel@tonic-gate ahp->ah_hash[h] = ap;
1247c478bd9Sstevel@tonic-gate ahp->ah_count++;
1257c478bd9Sstevel@tonic-gate }
1267c478bd9Sstevel@tonic-gate
1277c478bd9Sstevel@tonic-gate static fmd_asru_t *
fmd_asru_hold(fmd_asru_t * ap)1287c478bd9Sstevel@tonic-gate fmd_asru_hold(fmd_asru_t *ap)
1297c478bd9Sstevel@tonic-gate {
1307c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ap->asru_lock);
1317c478bd9Sstevel@tonic-gate ap->asru_refs++;
1327c478bd9Sstevel@tonic-gate ASSERT(ap->asru_refs != 0);
1337c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ap->asru_lock);
1347c478bd9Sstevel@tonic-gate return (ap);
1357c478bd9Sstevel@tonic-gate }
1367c478bd9Sstevel@tonic-gate
1377c478bd9Sstevel@tonic-gate /*
1387c478bd9Sstevel@tonic-gate * Lookup an asru in the hash by name and place a hold on it. If the asru is
1397c478bd9Sstevel@tonic-gate * not found, no entry is created and NULL is returned. This internal function
1407c478bd9Sstevel@tonic-gate * is for callers who have the ah_lock held and is used by lookup_name below.
1417c478bd9Sstevel@tonic-gate */
1427c478bd9Sstevel@tonic-gate fmd_asru_t *
fmd_asru_hash_lookup(fmd_asru_hash_t * ahp,const char * name)1437c478bd9Sstevel@tonic-gate fmd_asru_hash_lookup(fmd_asru_hash_t *ahp, const char *name)
1447c478bd9Sstevel@tonic-gate {
1457c478bd9Sstevel@tonic-gate fmd_asru_t *ap;
1467c478bd9Sstevel@tonic-gate uint_t h;
1477c478bd9Sstevel@tonic-gate
1487c478bd9Sstevel@tonic-gate ASSERT(RW_LOCK_HELD(&ahp->ah_lock));
149940d71d2Seschrock h = fmd_asru_strhash(ahp, name);
1507c478bd9Sstevel@tonic-gate
1517c478bd9Sstevel@tonic-gate for (ap = ahp->ah_hash[h]; ap != NULL; ap = ap->asru_next) {
152940d71d2Seschrock if (fmd_asru_strcmp(ahp, ap->asru_name, name))
1537c478bd9Sstevel@tonic-gate break;
1547c478bd9Sstevel@tonic-gate }
1557c478bd9Sstevel@tonic-gate
1567c478bd9Sstevel@tonic-gate if (ap != NULL)
1577c478bd9Sstevel@tonic-gate (void) fmd_asru_hold(ap);
1587c478bd9Sstevel@tonic-gate else
1597c478bd9Sstevel@tonic-gate (void) fmd_set_errno(EFMD_ASRU_NOENT);
1607c478bd9Sstevel@tonic-gate
1617c478bd9Sstevel@tonic-gate return (ap);
1627c478bd9Sstevel@tonic-gate }
1637c478bd9Sstevel@tonic-gate
164cbf75e67SStephen Hanson #define HC_ONLY_FALSE 0
165cbf75e67SStephen Hanson #define HC_ONLY_TRUE 1
166cbf75e67SStephen Hanson
167567cc2e6Sstephh static int
fmd_asru_replacement_state(nvlist_t * event,int hc_only)168cbf75e67SStephen Hanson fmd_asru_replacement_state(nvlist_t *event, int hc_only)
169567cc2e6Sstephh {
170567cc2e6Sstephh int ps = -1;
171567cc2e6Sstephh nvlist_t *asru, *fru, *rsrc;
172cbf75e67SStephen Hanson char *s;
173567cc2e6Sstephh
174567cc2e6Sstephh /*
175567cc2e6Sstephh * Check if there is evidence that this object is no longer present.
176567cc2e6Sstephh * In general fmd_fmri_present() should be supported on resources and/or
177567cc2e6Sstephh * frus, as those are the things that are physically present or not
178567cc2e6Sstephh * present - an asru can be spread over a number of frus some of which
179567cc2e6Sstephh * are present and some not, so fmd_fmri_present() is not generally
180567cc2e6Sstephh * meaningful. However retain a check for asru first for compatibility.
181567cc2e6Sstephh * If we have checked all three and we still get -1 then nothing knows
182567cc2e6Sstephh * whether it's present or not, so err on the safe side and treat it
183567cc2e6Sstephh * as still present.
184cbf75e67SStephen Hanson *
185cbf75e67SStephen Hanson * Note that if hc_only is set, then we only check status using fmris
186cbf75e67SStephen Hanson * that are in hc-scheme.
187567cc2e6Sstephh */
188567cc2e6Sstephh if (fmd_asru_fake_not_present)
18925c6ff4bSstephh return (fmd_asru_fake_not_present);
190cbf75e67SStephen Hanson if (nvlist_lookup_nvlist(event, FM_FAULT_ASRU, &asru) == 0 &&
191cbf75e67SStephen Hanson (hc_only == HC_ONLY_FALSE || (nvlist_lookup_string(asru,
192cbf75e67SStephen Hanson FM_FMRI_SCHEME, &s) == 0 && strcmp(s, FM_FMRI_SCHEME_HC) == 0)))
19325c6ff4bSstephh ps = fmd_fmri_replaced(asru);
194cbf75e67SStephen Hanson if (ps == -1 || ps == FMD_OBJ_STATE_UNKNOWN) {
19525c6ff4bSstephh if (nvlist_lookup_nvlist(event, FM_FAULT_RESOURCE,
196cbf75e67SStephen Hanson &rsrc) == 0 && (hc_only == HC_ONLY_FALSE ||
197cbf75e67SStephen Hanson (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &s) == 0 &&
198cbf75e67SStephen Hanson strcmp(s, FM_FMRI_SCHEME_HC) == 0))) {
199cbf75e67SStephen Hanson if (ps == -1) {
200cbf75e67SStephen Hanson ps = fmd_fmri_replaced(rsrc);
201cbf75e67SStephen Hanson } else {
202cbf75e67SStephen Hanson /* see if we can improve on UNKNOWN */
20325c6ff4bSstephh int ps2 = fmd_fmri_replaced(rsrc);
20425c6ff4bSstephh if (ps2 == FMD_OBJ_STATE_STILL_PRESENT ||
20525c6ff4bSstephh ps2 == FMD_OBJ_STATE_REPLACED)
20625c6ff4bSstephh ps = ps2;
20725c6ff4bSstephh }
20825c6ff4bSstephh }
209cbf75e67SStephen Hanson }
210cbf75e67SStephen Hanson if (ps == -1 || ps == FMD_OBJ_STATE_UNKNOWN) {
211cbf75e67SStephen Hanson if (nvlist_lookup_nvlist(event, FM_FAULT_FRU, &fru) == 0 &&
212cbf75e67SStephen Hanson (hc_only == HC_ONLY_FALSE || (nvlist_lookup_string(fru,
213cbf75e67SStephen Hanson FM_FMRI_SCHEME, &s) == 0 &&
214cbf75e67SStephen Hanson strcmp(s, FM_FMRI_SCHEME_HC) == 0))) {
21525c6ff4bSstephh if (ps == -1) {
21625c6ff4bSstephh ps = fmd_fmri_replaced(fru);
217cbf75e67SStephen Hanson } else {
21825c6ff4bSstephh /* see if we can improve on UNKNOWN */
21925c6ff4bSstephh int ps2 = fmd_fmri_replaced(fru);
22025c6ff4bSstephh if (ps2 == FMD_OBJ_STATE_STILL_PRESENT ||
22125c6ff4bSstephh ps2 == FMD_OBJ_STATE_REPLACED)
22225c6ff4bSstephh ps = ps2;
22325c6ff4bSstephh }
22425c6ff4bSstephh }
225cbf75e67SStephen Hanson }
226567cc2e6Sstephh if (ps == -1)
22725c6ff4bSstephh ps = FMD_OBJ_STATE_UNKNOWN;
228567cc2e6Sstephh return (ps);
229567cc2e6Sstephh }
230567cc2e6Sstephh
231567cc2e6Sstephh static void
fmd_asru_asru_hash_insert(fmd_asru_hash_t * ahp,fmd_asru_link_t * alp,char * name)232567cc2e6Sstephh fmd_asru_asru_hash_insert(fmd_asru_hash_t *ahp, fmd_asru_link_t *alp,
233567cc2e6Sstephh char *name)
234567cc2e6Sstephh {
235940d71d2Seschrock uint_t h = fmd_asru_strhash(ahp, name);
236567cc2e6Sstephh
237567cc2e6Sstephh ASSERT(RW_WRITE_HELD(&ahp->ah_lock));
238567cc2e6Sstephh alp->al_asru_next = ahp->ah_asru_hash[h];
239567cc2e6Sstephh ahp->ah_asru_hash[h] = alp;
240567cc2e6Sstephh ahp->ah_al_count++;
241567cc2e6Sstephh }
242567cc2e6Sstephh
243567cc2e6Sstephh static void
fmd_asru_case_hash_insert(fmd_asru_hash_t * ahp,fmd_asru_link_t * alp,char * name)244567cc2e6Sstephh fmd_asru_case_hash_insert(fmd_asru_hash_t *ahp, fmd_asru_link_t *alp,
245567cc2e6Sstephh char *name)
246567cc2e6Sstephh {
247940d71d2Seschrock uint_t h = fmd_asru_strhash(ahp, name);
248567cc2e6Sstephh
249567cc2e6Sstephh ASSERT(RW_WRITE_HELD(&ahp->ah_lock));
250567cc2e6Sstephh alp->al_case_next = ahp->ah_case_hash[h];
251567cc2e6Sstephh ahp->ah_case_hash[h] = alp;
252567cc2e6Sstephh }
253567cc2e6Sstephh
254567cc2e6Sstephh static void
fmd_asru_fru_hash_insert(fmd_asru_hash_t * ahp,fmd_asru_link_t * alp,char * name)255567cc2e6Sstephh fmd_asru_fru_hash_insert(fmd_asru_hash_t *ahp, fmd_asru_link_t *alp, char *name)
256567cc2e6Sstephh {
257940d71d2Seschrock uint_t h = fmd_asru_strhash(ahp, name);
258567cc2e6Sstephh
259567cc2e6Sstephh ASSERT(RW_WRITE_HELD(&ahp->ah_lock));
260567cc2e6Sstephh alp->al_fru_next = ahp->ah_fru_hash[h];
261567cc2e6Sstephh ahp->ah_fru_hash[h] = alp;
262567cc2e6Sstephh }
263567cc2e6Sstephh
264567cc2e6Sstephh static void
fmd_asru_label_hash_insert(fmd_asru_hash_t * ahp,fmd_asru_link_t * alp,char * name)265567cc2e6Sstephh fmd_asru_label_hash_insert(fmd_asru_hash_t *ahp, fmd_asru_link_t *alp,
266567cc2e6Sstephh char *name)
267567cc2e6Sstephh {
268940d71d2Seschrock uint_t h = fmd_asru_strhash(ahp, name);
269567cc2e6Sstephh
270567cc2e6Sstephh ASSERT(RW_WRITE_HELD(&ahp->ah_lock));
271567cc2e6Sstephh alp->al_label_next = ahp->ah_label_hash[h];
272567cc2e6Sstephh ahp->ah_label_hash[h] = alp;
273567cc2e6Sstephh }
274567cc2e6Sstephh
275567cc2e6Sstephh static void
fmd_asru_rsrc_hash_insert(fmd_asru_hash_t * ahp,fmd_asru_link_t * alp,char * name)276567cc2e6Sstephh fmd_asru_rsrc_hash_insert(fmd_asru_hash_t *ahp, fmd_asru_link_t *alp,
277567cc2e6Sstephh char *name)
278567cc2e6Sstephh {
279940d71d2Seschrock uint_t h = fmd_asru_strhash(ahp, name);
280567cc2e6Sstephh
281567cc2e6Sstephh ASSERT(RW_WRITE_HELD(&ahp->ah_lock));
282567cc2e6Sstephh alp->al_rsrc_next = ahp->ah_rsrc_hash[h];
283567cc2e6Sstephh ahp->ah_rsrc_hash[h] = alp;
284567cc2e6Sstephh }
285567cc2e6Sstephh
286567cc2e6Sstephh static void
fmd_asru_al_destroy(fmd_asru_link_t * alp)287567cc2e6Sstephh fmd_asru_al_destroy(fmd_asru_link_t *alp)
288567cc2e6Sstephh {
289567cc2e6Sstephh ASSERT(alp->al_refs == 0);
290567cc2e6Sstephh ASSERT(MUTEX_HELD(&alp->al_asru->asru_lock));
291567cc2e6Sstephh
292567cc2e6Sstephh if (alp->al_log != NULL)
293567cc2e6Sstephh fmd_log_rele(alp->al_log);
294567cc2e6Sstephh
295567cc2e6Sstephh fmd_free(alp->al_uuid, alp->al_uuidlen + 1);
296567cc2e6Sstephh nvlist_free(alp->al_event);
297567cc2e6Sstephh fmd_strfree(alp->al_rsrc_name);
298567cc2e6Sstephh fmd_strfree(alp->al_case_uuid);
299567cc2e6Sstephh fmd_strfree(alp->al_fru_name);
300567cc2e6Sstephh fmd_strfree(alp->al_asru_name);
301567cc2e6Sstephh fmd_strfree(alp->al_label);
302567cc2e6Sstephh nvlist_free(alp->al_asru_fmri);
303567cc2e6Sstephh fmd_free(alp, sizeof (fmd_asru_link_t));
304567cc2e6Sstephh }
305567cc2e6Sstephh
306567cc2e6Sstephh static fmd_asru_link_t *
fmd_asru_al_hold(fmd_asru_link_t * alp)307567cc2e6Sstephh fmd_asru_al_hold(fmd_asru_link_t *alp)
308567cc2e6Sstephh {
309567cc2e6Sstephh fmd_asru_t *ap = alp->al_asru;
310567cc2e6Sstephh
311567cc2e6Sstephh (void) pthread_mutex_lock(&ap->asru_lock);
312567cc2e6Sstephh ap->asru_refs++;
313567cc2e6Sstephh alp->al_refs++;
314567cc2e6Sstephh ASSERT(alp->al_refs != 0);
315567cc2e6Sstephh (void) pthread_mutex_unlock(&ap->asru_lock);
316567cc2e6Sstephh return (alp);
317567cc2e6Sstephh }
318567cc2e6Sstephh
319567cc2e6Sstephh static void fmd_asru_destroy(fmd_asru_t *ap);
320567cc2e6Sstephh
321567cc2e6Sstephh /*ARGSUSED*/
322567cc2e6Sstephh static void
fmd_asru_al_hash_release(fmd_asru_hash_t * ahp,fmd_asru_link_t * alp)323567cc2e6Sstephh fmd_asru_al_hash_release(fmd_asru_hash_t *ahp, fmd_asru_link_t *alp)
324567cc2e6Sstephh {
325567cc2e6Sstephh fmd_asru_t *ap = alp->al_asru;
326567cc2e6Sstephh
327567cc2e6Sstephh (void) pthread_mutex_lock(&ap->asru_lock);
328567cc2e6Sstephh ASSERT(alp->al_refs != 0);
329567cc2e6Sstephh if (--alp->al_refs == 0)
330567cc2e6Sstephh fmd_asru_al_destroy(alp);
331567cc2e6Sstephh ASSERT(ap->asru_refs != 0);
332567cc2e6Sstephh if (--ap->asru_refs == 0)
333567cc2e6Sstephh fmd_asru_destroy(ap);
334567cc2e6Sstephh else
335567cc2e6Sstephh (void) pthread_mutex_unlock(&ap->asru_lock);
336567cc2e6Sstephh }
337567cc2e6Sstephh
338567cc2e6Sstephh static int
fmd_asru_get_namestr(nvlist_t * nvl,char ** name,ssize_t * namelen)339567cc2e6Sstephh fmd_asru_get_namestr(nvlist_t *nvl, char **name, ssize_t *namelen)
340567cc2e6Sstephh {
341567cc2e6Sstephh if ((*namelen = fmd_fmri_nvl2str(nvl, NULL, 0)) == -1)
342567cc2e6Sstephh return (EFMD_ASRU_FMRI);
343567cc2e6Sstephh *name = fmd_alloc(*namelen + 1, FMD_SLEEP);
344567cc2e6Sstephh if (fmd_fmri_nvl2str(nvl, *name, *namelen + 1) == -1) {
345567cc2e6Sstephh if (*name != NULL)
346567cc2e6Sstephh fmd_free(*name, *namelen + 1);
347567cc2e6Sstephh return (EFMD_ASRU_FMRI);
348567cc2e6Sstephh }
349567cc2e6Sstephh return (0);
350567cc2e6Sstephh }
351567cc2e6Sstephh
352567cc2e6Sstephh static fmd_asru_link_t *
fmd_asru_al_create(fmd_asru_hash_t * ahp,nvlist_t * nvl,fmd_case_t * cp,const char * al_uuid)353567cc2e6Sstephh fmd_asru_al_create(fmd_asru_hash_t *ahp, nvlist_t *nvl, fmd_case_t *cp,
354567cc2e6Sstephh const char *al_uuid)
355567cc2e6Sstephh {
356567cc2e6Sstephh nvlist_t *asru = NULL, *fru, *rsrc;
357567cc2e6Sstephh int got_rsrc = 0, got_asru = 0, got_fru = 0;
358567cc2e6Sstephh ssize_t fru_namelen, rsrc_namelen, asru_namelen;
359567cc2e6Sstephh char *asru_name, *rsrc_name, *fru_name, *name, *label;
360567cc2e6Sstephh fmd_asru_link_t *alp;
361567cc2e6Sstephh fmd_asru_t *ap;
362567cc2e6Sstephh boolean_t msg;
363567cc2e6Sstephh fmd_case_impl_t *cip = (fmd_case_impl_t *)cp;
364567cc2e6Sstephh
365567cc2e6Sstephh if (nvlist_lookup_nvlist(nvl, FM_FAULT_ASRU, &asru) == 0 &&
366567cc2e6Sstephh fmd_asru_get_namestr(asru, &asru_name, &asru_namelen) == 0)
367567cc2e6Sstephh got_asru = 1;
368567cc2e6Sstephh if (nvlist_lookup_nvlist(nvl, FM_FAULT_FRU, &fru) == 0 &&
369567cc2e6Sstephh fmd_asru_get_namestr(fru, &fru_name, &fru_namelen) == 0)
370567cc2e6Sstephh got_fru = 1;
371567cc2e6Sstephh if (nvlist_lookup_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc) == 0 &&
372567cc2e6Sstephh fmd_asru_get_namestr(rsrc, &rsrc_name, &rsrc_namelen) == 0)
373567cc2e6Sstephh got_rsrc = 1;
374567cc2e6Sstephh if (nvlist_lookup_string(nvl, FM_FAULT_LOCATION, &label) != 0)
375567cc2e6Sstephh label = "";
376567cc2e6Sstephh
377567cc2e6Sstephh /*
378567cc2e6Sstephh * Grab the rwlock as a writer; Then create and insert the asru with
379567cc2e6Sstephh * ahp->ah_lock held and hash it in. We'll then drop the rwlock and
380567cc2e6Sstephh * proceed to initializing the asru.
381567cc2e6Sstephh */
382567cc2e6Sstephh (void) pthread_rwlock_wrlock(&ahp->ah_lock);
383567cc2e6Sstephh
384567cc2e6Sstephh /*
385567cc2e6Sstephh * Create and initialise the per-fault "link" structure.
386567cc2e6Sstephh */
387567cc2e6Sstephh alp = fmd_zalloc(sizeof (fmd_asru_link_t), FMD_SLEEP);
388567cc2e6Sstephh if (got_asru)
389567cc2e6Sstephh (void) nvlist_xdup(asru, &alp->al_asru_fmri, &fmd.d_nva);
390567cc2e6Sstephh alp->al_uuid = fmd_strdup(al_uuid, FMD_SLEEP);
391567cc2e6Sstephh alp->al_uuidlen = strlen(alp->al_uuid);
392567cc2e6Sstephh alp->al_refs = 1;
393567cc2e6Sstephh
394567cc2e6Sstephh /*
395567cc2e6Sstephh * If this is the first fault for this asru, then create the per-asru
396567cc2e6Sstephh * structure and link into the hash.
397567cc2e6Sstephh */
398567cc2e6Sstephh name = got_asru ? asru_name : "";
399567cc2e6Sstephh if ((ap = fmd_asru_hash_lookup(ahp, name)) == NULL) {
400567cc2e6Sstephh ap = fmd_asru_create(ahp, al_uuid, name, got_asru ? asru :
401567cc2e6Sstephh NULL);
402567cc2e6Sstephh fmd_asru_hash_insert(ahp, ap);
403567cc2e6Sstephh } else
404567cc2e6Sstephh nvlist_free(ap->asru_event);
405567cc2e6Sstephh (void) nvlist_xdup(nvl, &ap->asru_event, &fmd.d_nva);
406567cc2e6Sstephh
407567cc2e6Sstephh /*
408567cc2e6Sstephh * Put the link structure on the list associated with the per-asru
409567cc2e6Sstephh * structure. Then put the link structure on the various hashes.
410567cc2e6Sstephh */
411567cc2e6Sstephh fmd_list_append(&ap->asru_list, (fmd_list_t *)alp);
412567cc2e6Sstephh alp->al_asru = ap;
413567cc2e6Sstephh alp->al_asru_name = got_asru ? asru_name : fmd_strdup("", FMD_SLEEP);
414567cc2e6Sstephh fmd_asru_asru_hash_insert(ahp, alp, alp->al_asru_name);
415567cc2e6Sstephh alp->al_fru_name = got_fru ? fru_name : fmd_strdup("", FMD_SLEEP);
416567cc2e6Sstephh fmd_asru_fru_hash_insert(ahp, alp, alp->al_fru_name);
417567cc2e6Sstephh alp->al_rsrc_name = got_rsrc ? rsrc_name : fmd_strdup("", FMD_SLEEP);
418567cc2e6Sstephh fmd_asru_rsrc_hash_insert(ahp, alp, alp->al_rsrc_name);
419567cc2e6Sstephh alp->al_label = fmd_strdup(label, FMD_SLEEP);
420567cc2e6Sstephh fmd_asru_label_hash_insert(ahp, alp, label);
421567cc2e6Sstephh alp->al_case_uuid = fmd_strdup(cip->ci_uuid, FMD_SLEEP);
422567cc2e6Sstephh fmd_asru_case_hash_insert(ahp, alp, cip->ci_uuid);
423567cc2e6Sstephh (void) pthread_mutex_lock(&ap->asru_lock);
424567cc2e6Sstephh (void) pthread_rwlock_unlock(&ahp->ah_lock);
425567cc2e6Sstephh
426567cc2e6Sstephh ap->asru_case = alp->al_case = cp;
427567cc2e6Sstephh if (nvlist_lookup_boolean_value(nvl, FM_SUSPECT_MESSAGE, &msg) == 0 &&
428567cc2e6Sstephh msg == B_FALSE)
429567cc2e6Sstephh ap->asru_flags |= FMD_ASRU_INVISIBLE;
430567cc2e6Sstephh (void) nvlist_xdup(nvl, &alp->al_event, &fmd.d_nva);
431567cc2e6Sstephh ap->asru_flags |= FMD_ASRU_VALID;
432567cc2e6Sstephh (void) pthread_cond_broadcast(&ap->asru_cv);
433567cc2e6Sstephh (void) pthread_mutex_unlock(&ap->asru_lock);
434567cc2e6Sstephh return (alp);
435567cc2e6Sstephh }
436567cc2e6Sstephh
4377c478bd9Sstevel@tonic-gate static void
fmd_asru_hash_recreate(fmd_log_t * lp,fmd_event_t * ep,fmd_asru_hash_t * ahp)4387c478bd9Sstevel@tonic-gate fmd_asru_hash_recreate(fmd_log_t *lp, fmd_event_t *ep, fmd_asru_hash_t *ahp)
4397c478bd9Sstevel@tonic-gate {
440d9638e54Smws nvlist_t *nvl = FMD_EVENT_NVL(ep);
44125c6ff4bSstephh boolean_t faulty = FMD_B_FALSE, unusable = FMD_B_FALSE;
44225c6ff4bSstephh int ps;
44325c6ff4bSstephh boolean_t repaired = FMD_B_FALSE, replaced = FMD_B_FALSE;
4445750ef5cSStephen Hanson boolean_t acquitted = FMD_B_FALSE, resolved = FMD_B_FALSE;
445567cc2e6Sstephh nvlist_t *flt, *flt_copy, *asru;
446d9638e54Smws char *case_uuid = NULL, *case_code = NULL;
4477c478bd9Sstevel@tonic-gate fmd_asru_t *ap;
448567cc2e6Sstephh fmd_asru_link_t *alp;
449567cc2e6Sstephh fmd_case_t *cp;
45044743693Sstephh int64_t *diag_time;
451cbf75e67SStephen Hanson nvlist_t *de_fmri, *de_fmri_dup;
45244743693Sstephh uint_t nelem;
453b7d3956bSstephh topo_hdl_t *thp;
454b7d3956bSstephh char *class;
455b7d3956bSstephh nvlist_t *rsrc;
456b7d3956bSstephh int err;
457540db9a9SStephen Hanson boolean_t injected;
4587c478bd9Sstevel@tonic-gate
4597c478bd9Sstevel@tonic-gate /*
460567cc2e6Sstephh * Extract the most recent values of 'faulty' from the event log.
4617c478bd9Sstevel@tonic-gate */
46225c6ff4bSstephh if (nvlist_lookup_boolean_value(nvl, FM_RSRC_ASRU_FAULTY,
46325c6ff4bSstephh &faulty) != 0) {
4647c478bd9Sstevel@tonic-gate fmd_error(EFMD_ASRU_EVENT, "failed to reload asru %s: "
4657c478bd9Sstevel@tonic-gate "invalid event log record\n", lp->log_name);
4667c478bd9Sstevel@tonic-gate ahp->ah_error = EFMD_ASRU_EVENT;
4677c478bd9Sstevel@tonic-gate return;
4687c478bd9Sstevel@tonic-gate }
469567cc2e6Sstephh if (nvlist_lookup_nvlist(nvl, FM_RSRC_ASRU_EVENT, &flt) != 0) {
470567cc2e6Sstephh fmd_error(EFMD_ASRU_EVENT, "failed to reload asru %s: "
471567cc2e6Sstephh "invalid event log record\n", lp->log_name);
472567cc2e6Sstephh ahp->ah_error = EFMD_ASRU_EVENT;
473567cc2e6Sstephh return;
474567cc2e6Sstephh }
475567cc2e6Sstephh (void) nvlist_lookup_string(nvl, FM_RSRC_ASRU_UUID, &case_uuid);
476567cc2e6Sstephh (void) nvlist_lookup_string(nvl, FM_RSRC_ASRU_CODE, &case_code);
47725c6ff4bSstephh (void) nvlist_lookup_boolean_value(nvl, FM_RSRC_ASRU_UNUSABLE,
47825c6ff4bSstephh &unusable);
47925c6ff4bSstephh (void) nvlist_lookup_boolean_value(nvl, FM_RSRC_ASRU_REPAIRED,
48025c6ff4bSstephh &repaired);
48125c6ff4bSstephh (void) nvlist_lookup_boolean_value(nvl, FM_RSRC_ASRU_REPLACED,
48225c6ff4bSstephh &replaced);
48325c6ff4bSstephh (void) nvlist_lookup_boolean_value(nvl, FM_RSRC_ASRU_ACQUITTED,
48425c6ff4bSstephh &acquitted);
4855750ef5cSStephen Hanson (void) nvlist_lookup_boolean_value(nvl, FM_RSRC_ASRU_RESOLVED,
4865750ef5cSStephen Hanson &resolved);
4877c478bd9Sstevel@tonic-gate
4887c478bd9Sstevel@tonic-gate /*
4895750ef5cSStephen Hanson * Attempt to recreate the case in CLOSED, REPAIRED or RESOLVED state
4905750ef5cSStephen Hanson * (depending on whether the faulty/resolved bits are set).
491567cc2e6Sstephh * If the case is already present, fmd_case_recreate() will return it.
492567cc2e6Sstephh * If not, we'll create a new orphaned case. Either way, we use the
493567cc2e6Sstephh * ASRU event to insert a suspect into the partially-restored case.
49444743693Sstephh */
495567cc2e6Sstephh fmd_module_lock(fmd.d_rmod);
49625c6ff4bSstephh cp = fmd_case_recreate(fmd.d_rmod, NULL, faulty ? FMD_CASE_CLOSED :
4975750ef5cSStephen Hanson resolved ? FMD_CASE_RESOLVED : FMD_CASE_REPAIRED, case_uuid,
4985750ef5cSStephen Hanson case_code);
499567cc2e6Sstephh fmd_case_hold(cp);
500567cc2e6Sstephh fmd_module_unlock(fmd.d_rmod);
501540db9a9SStephen Hanson if (nvlist_lookup_boolean_value(nvl, FM_SUSPECT_INJECTED,
502540db9a9SStephen Hanson &injected) == 0 && injected)
503540db9a9SStephen Hanson fmd_case_set_injected(cp);
504567cc2e6Sstephh if (nvlist_lookup_int64_array(nvl, FM_SUSPECT_DIAG_TIME, &diag_time,
505567cc2e6Sstephh &nelem) == 0 && nelem >= 2)
506567cc2e6Sstephh fmd_case_settime(cp, diag_time[0], diag_time[1]);
507567cc2e6Sstephh else
508567cc2e6Sstephh fmd_case_settime(cp, lp->log_stat.st_ctime, 0);
509cbf75e67SStephen Hanson if (nvlist_lookup_nvlist(nvl, FM_SUSPECT_DE, &de_fmri) == 0) {
510cbf75e67SStephen Hanson (void) nvlist_xdup(de_fmri, &de_fmri_dup, &fmd.d_nva);
511cbf75e67SStephen Hanson fmd_case_set_de_fmri(cp, de_fmri_dup);
512cbf75e67SStephen Hanson }
513567cc2e6Sstephh (void) nvlist_xdup(flt, &flt_copy, &fmd.d_nva);
514b7d3956bSstephh
515b7d3956bSstephh /*
516b7d3956bSstephh * For faults with a resource, re-evaluate the asru from the resource.
517b7d3956bSstephh */
518b7d3956bSstephh thp = fmd_fmri_topo_hold(TOPO_VERSION);
519b7d3956bSstephh if (nvlist_lookup_string(flt_copy, FM_CLASS, &class) == 0 &&
520b7d3956bSstephh strncmp(class, "fault", 5) == 0 &&
521b7d3956bSstephh nvlist_lookup_nvlist(flt_copy, FM_FAULT_RESOURCE, &rsrc) == 0 &&
522*705e9f42SStephen Hanson rsrc != NULL &&
523*705e9f42SStephen Hanson (fmd_fmri_replaced(rsrc) != FMD_OBJ_STATE_REPLACED) &&
524*705e9f42SStephen Hanson topo_fmri_asru(thp, rsrc, &asru, &err) == 0) {
525b7d3956bSstephh (void) nvlist_remove(flt_copy, FM_FAULT_ASRU, DATA_TYPE_NVLIST);
526b7d3956bSstephh (void) nvlist_add_nvlist(flt_copy, FM_FAULT_ASRU, asru);
527b7d3956bSstephh nvlist_free(asru);
528b7d3956bSstephh }
529b7d3956bSstephh fmd_fmri_topo_rele(thp);
530b7d3956bSstephh
531b7d3956bSstephh (void) nvlist_xdup(flt_copy, &flt, &fmd.d_nva);
532b7d3956bSstephh
533567cc2e6Sstephh fmd_case_recreate_suspect(cp, flt_copy);
534567cc2e6Sstephh
535567cc2e6Sstephh /*
536567cc2e6Sstephh * Now create the resource cache entries.
537567cc2e6Sstephh */
538567cc2e6Sstephh alp = fmd_asru_al_create(ahp, flt, cp, fmd_strbasename(lp->log_name));
539567cc2e6Sstephh ap = alp->al_asru;
54044743693Sstephh
54144743693Sstephh /*
54225c6ff4bSstephh * Check to see if the resource is still present in the system.
5437c478bd9Sstevel@tonic-gate */
544cbf75e67SStephen Hanson ps = fmd_asru_replacement_state(flt, HC_ONLY_FALSE);
545e4b86885SCheng Sean Ye if (ps == FMD_OBJ_STATE_REPLACED) {
54625c6ff4bSstephh replaced = FMD_B_TRUE;
547e4b86885SCheng Sean Ye } else if (ps == FMD_OBJ_STATE_STILL_PRESENT ||
548e4b86885SCheng Sean Ye ps == FMD_OBJ_STATE_UNKNOWN) {
549e4b86885SCheng Sean Ye ap->asru_flags |= FMD_ASRU_PRESENT;
550e4b86885SCheng Sean Ye if (nvlist_lookup_nvlist(alp->al_event, FM_FAULT_ASRU,
551e4b86885SCheng Sean Ye &asru) == 0) {
552e4b86885SCheng Sean Ye int us;
553e4b86885SCheng Sean Ye
554e4b86885SCheng Sean Ye switch (fmd_fmri_service_state(asru)) {
555e4b86885SCheng Sean Ye case FMD_SERVICE_STATE_UNUSABLE:
556e4b86885SCheng Sean Ye unusable = FMD_B_TRUE;
557e4b86885SCheng Sean Ye break;
558e4b86885SCheng Sean Ye case FMD_SERVICE_STATE_OK:
5598e7248e5SStephen Hanson case FMD_SERVICE_STATE_ISOLATE_PENDING:
560e4b86885SCheng Sean Ye case FMD_SERVICE_STATE_DEGRADED:
561e4b86885SCheng Sean Ye unusable = FMD_B_FALSE;
562e4b86885SCheng Sean Ye break;
563e4b86885SCheng Sean Ye case FMD_SERVICE_STATE_UNKNOWN:
564e4b86885SCheng Sean Ye case -1:
565e4b86885SCheng Sean Ye /* not supported by scheme */
566e4b86885SCheng Sean Ye us = fmd_fmri_unusable(asru);
567e4b86885SCheng Sean Ye if (us > 0)
568e4b86885SCheng Sean Ye unusable = FMD_B_TRUE;
569e4b86885SCheng Sean Ye else if (us == 0)
570e4b86885SCheng Sean Ye unusable = FMD_B_FALSE;
571e4b86885SCheng Sean Ye break;
572e4b86885SCheng Sean Ye }
573e4b86885SCheng Sean Ye }
574e4b86885SCheng Sean Ye }
5757c478bd9Sstevel@tonic-gate
576b7d3956bSstephh nvlist_free(flt);
577b7d3956bSstephh
5780b9e3e76Smws ap->asru_flags |= FMD_ASRU_RECREATED;
57925c6ff4bSstephh if (faulty) {
580567cc2e6Sstephh alp->al_flags |= FMD_ASRU_FAULTY;
5817c478bd9Sstevel@tonic-gate ap->asru_flags |= FMD_ASRU_FAULTY;
582567cc2e6Sstephh }
58325c6ff4bSstephh if (unusable) {
584567cc2e6Sstephh alp->al_flags |= FMD_ASRU_UNUSABLE;
5857c478bd9Sstevel@tonic-gate ap->asru_flags |= FMD_ASRU_UNUSABLE;
586567cc2e6Sstephh }
58725c6ff4bSstephh if (replaced)
58825c6ff4bSstephh alp->al_reason = FMD_ASRU_REPLACED;
58925c6ff4bSstephh else if (repaired)
59025c6ff4bSstephh alp->al_reason = FMD_ASRU_REPAIRED;
59125c6ff4bSstephh else if (acquitted)
59225c6ff4bSstephh alp->al_reason = FMD_ASRU_ACQUITTED;
5935750ef5cSStephen Hanson else
5945750ef5cSStephen Hanson alp->al_reason = FMD_ASRU_REMOVED;
5957c478bd9Sstevel@tonic-gate
596567cc2e6Sstephh TRACE((FMD_DBG_ASRU, "asru %s recreated as %p (%s)", alp->al_uuid,
5977c478bd9Sstevel@tonic-gate (void *)ap, _fmd_asru_snames[ap->asru_flags & FMD_ASRU_STATE]));
5987c478bd9Sstevel@tonic-gate }
5997c478bd9Sstevel@tonic-gate
6007c478bd9Sstevel@tonic-gate static void
fmd_asru_hash_discard(fmd_asru_hash_t * ahp,const char * uuid,int err)6017c478bd9Sstevel@tonic-gate fmd_asru_hash_discard(fmd_asru_hash_t *ahp, const char *uuid, int err)
6027c478bd9Sstevel@tonic-gate {
6037c478bd9Sstevel@tonic-gate char src[PATH_MAX], dst[PATH_MAX];
6047c478bd9Sstevel@tonic-gate
6057c478bd9Sstevel@tonic-gate (void) snprintf(src, PATH_MAX, "%s/%s", ahp->ah_dirpath, uuid);
6067c478bd9Sstevel@tonic-gate (void) snprintf(dst, PATH_MAX, "%s/%s-", ahp->ah_dirpath, uuid);
6077c478bd9Sstevel@tonic-gate
6087c478bd9Sstevel@tonic-gate if (err != 0)
6097c478bd9Sstevel@tonic-gate err = rename(src, dst);
6107c478bd9Sstevel@tonic-gate else
6117c478bd9Sstevel@tonic-gate err = unlink(src);
6127c478bd9Sstevel@tonic-gate
6137c478bd9Sstevel@tonic-gate if (err != 0 && errno != ENOENT)
6147c478bd9Sstevel@tonic-gate fmd_error(EFMD_ASRU_EVENT, "failed to rename log %s", src);
6157c478bd9Sstevel@tonic-gate }
6167c478bd9Sstevel@tonic-gate
6177c478bd9Sstevel@tonic-gate /*
6187c478bd9Sstevel@tonic-gate * Open a saved log file and restore it into the ASRU hash. If we can't even
6197c478bd9Sstevel@tonic-gate * open the log, rename the log file to <uuid>- to indicate it is corrupt. If
6207c478bd9Sstevel@tonic-gate * fmd_log_replay() fails, we either delete the file (if it has reached the
6217c478bd9Sstevel@tonic-gate * upper limit on cache age) or rename it for debugging if it was corrupted.
6227c478bd9Sstevel@tonic-gate */
6237c478bd9Sstevel@tonic-gate static void
fmd_asru_hash_logopen(fmd_asru_hash_t * ahp,const char * uuid)6247c478bd9Sstevel@tonic-gate fmd_asru_hash_logopen(fmd_asru_hash_t *ahp, const char *uuid)
6257c478bd9Sstevel@tonic-gate {
6267c478bd9Sstevel@tonic-gate fmd_log_t *lp = fmd_log_tryopen(ahp->ah_dirpath, uuid, FMD_LOG_ASRU);
6277c478bd9Sstevel@tonic-gate uint_t n;
6287c478bd9Sstevel@tonic-gate
6297c478bd9Sstevel@tonic-gate if (lp == NULL) {
6307c478bd9Sstevel@tonic-gate fmd_asru_hash_discard(ahp, uuid, errno);
6317c478bd9Sstevel@tonic-gate return;
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate
6347c478bd9Sstevel@tonic-gate ahp->ah_error = 0;
635567cc2e6Sstephh n = ahp->ah_al_count;
6367c478bd9Sstevel@tonic-gate
6377c478bd9Sstevel@tonic-gate fmd_log_replay(lp, (fmd_log_f *)fmd_asru_hash_recreate, ahp);
6387c478bd9Sstevel@tonic-gate fmd_log_rele(lp);
6397c478bd9Sstevel@tonic-gate
640567cc2e6Sstephh if (ahp->ah_al_count == n)
6417c478bd9Sstevel@tonic-gate fmd_asru_hash_discard(ahp, uuid, ahp->ah_error);
6427c478bd9Sstevel@tonic-gate }
6437c478bd9Sstevel@tonic-gate
6447c478bd9Sstevel@tonic-gate void
fmd_asru_hash_refresh(fmd_asru_hash_t * ahp)6457c478bd9Sstevel@tonic-gate fmd_asru_hash_refresh(fmd_asru_hash_t *ahp)
6467c478bd9Sstevel@tonic-gate {
6474bc0a2efScasper struct dirent *dp;
6487c478bd9Sstevel@tonic-gate DIR *dirp;
6497c478bd9Sstevel@tonic-gate int zero;
6507c478bd9Sstevel@tonic-gate
6517c478bd9Sstevel@tonic-gate if ((dirp = opendir(ahp->ah_dirpath)) == NULL) {
6527c478bd9Sstevel@tonic-gate fmd_error(EFMD_ASRU_NODIR,
6537c478bd9Sstevel@tonic-gate "failed to open asru cache directory %s", ahp->ah_dirpath);
6547c478bd9Sstevel@tonic-gate return;
6557c478bd9Sstevel@tonic-gate }
6567c478bd9Sstevel@tonic-gate
6577c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "rsrc.zero", &zero);
6587c478bd9Sstevel@tonic-gate
6597c478bd9Sstevel@tonic-gate (void) pthread_rwlock_wrlock(&ahp->ah_lock);
6607c478bd9Sstevel@tonic-gate
6614bc0a2efScasper while ((dp = readdir(dirp)) != NULL) {
6627c478bd9Sstevel@tonic-gate if (dp->d_name[0] == '.')
6637c478bd9Sstevel@tonic-gate continue; /* skip "." and ".." */
6647c478bd9Sstevel@tonic-gate
6657c478bd9Sstevel@tonic-gate if (zero)
6667c478bd9Sstevel@tonic-gate fmd_asru_hash_discard(ahp, dp->d_name, 0);
6677c478bd9Sstevel@tonic-gate else if (!fmd_strmatch(dp->d_name, "*-"))
6687c478bd9Sstevel@tonic-gate fmd_asru_hash_logopen(ahp, dp->d_name);
6697c478bd9Sstevel@tonic-gate }
6707c478bd9Sstevel@tonic-gate
6717c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&ahp->ah_lock);
6727c478bd9Sstevel@tonic-gate (void) closedir(dirp);
6737c478bd9Sstevel@tonic-gate }
6747c478bd9Sstevel@tonic-gate
675162ba6eaSmws /*
676162ba6eaSmws * If the resource is present and faulty but not unusable, replay the fault
677162ba6eaSmws * event that caused it be marked faulty. This will cause the agent
678162ba6eaSmws * subscribing to this fault class to again disable the resource.
679162ba6eaSmws */
680162ba6eaSmws /*ARGSUSED*/
681162ba6eaSmws static void
fmd_asru_hash_replay_asru(fmd_asru_t * ap,void * data)682162ba6eaSmws fmd_asru_hash_replay_asru(fmd_asru_t *ap, void *data)
683162ba6eaSmws {
684162ba6eaSmws fmd_event_t *e;
685162ba6eaSmws nvlist_t *nvl;
686162ba6eaSmws char *class;
687162ba6eaSmws
688162ba6eaSmws if (ap->asru_event != NULL && (ap->asru_flags & (FMD_ASRU_STATE |
689162ba6eaSmws FMD_ASRU_PRESENT)) == (FMD_ASRU_FAULTY | FMD_ASRU_PRESENT)) {
690162ba6eaSmws
691162ba6eaSmws fmd_dprintf(FMD_DBG_ASRU,
692162ba6eaSmws "replaying fault event for %s", ap->asru_name);
693162ba6eaSmws
694162ba6eaSmws (void) nvlist_xdup(ap->asru_event, &nvl, &fmd.d_nva);
695162ba6eaSmws (void) nvlist_lookup_string(nvl, FM_CLASS, &class);
696162ba6eaSmws
697162ba6eaSmws (void) nvlist_add_string(nvl, FMD_EVN_UUID,
698162ba6eaSmws ((fmd_case_impl_t *)ap->asru_case)->ci_uuid);
699162ba6eaSmws
700162ba6eaSmws e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class);
701162ba6eaSmws fmd_dispq_dispatch(fmd.d_disp, e, class);
702162ba6eaSmws }
703162ba6eaSmws }
704162ba6eaSmws
705162ba6eaSmws void
fmd_asru_hash_replay(fmd_asru_hash_t * ahp)706162ba6eaSmws fmd_asru_hash_replay(fmd_asru_hash_t *ahp)
707162ba6eaSmws {
708162ba6eaSmws fmd_asru_hash_apply(ahp, fmd_asru_hash_replay_asru, NULL);
709162ba6eaSmws }
710162ba6eaSmws
711567cc2e6Sstephh /*
712567cc2e6Sstephh * Check if the resource is still present. If not, and if the rsrc.age time
713567cc2e6Sstephh * has expired, then do an implicit repair on the resource.
714567cc2e6Sstephh */
71525c6ff4bSstephh /*ARGSUSED*/
716567cc2e6Sstephh static void
fmd_asru_repair_if_aged(fmd_asru_link_t * alp,void * arg)71725c6ff4bSstephh fmd_asru_repair_if_aged(fmd_asru_link_t *alp, void *arg)
718567cc2e6Sstephh {
719567cc2e6Sstephh struct timeval tv;
720567cc2e6Sstephh fmd_log_t *lp;
721567cc2e6Sstephh hrtime_t hrt;
72225c6ff4bSstephh int ps;
72325c6ff4bSstephh int err;
724cbf75e67SStephen Hanson fmd_asru_rep_arg_t fara;
725567cc2e6Sstephh
7265750ef5cSStephen Hanson if (!(alp->al_flags & FMD_ASRU_FAULTY))
7275750ef5cSStephen Hanson return;
7285750ef5cSStephen Hanson
729cbf75e67SStephen Hanson /*
730cbf75e67SStephen Hanson * Checking for aged resources only happens on the diagnosing side
731cbf75e67SStephen Hanson * not on a proxy.
732cbf75e67SStephen Hanson */
733cbf75e67SStephen Hanson if (alp->al_flags & FMD_ASRU_PROXY)
734cbf75e67SStephen Hanson return;
735cbf75e67SStephen Hanson
736cbf75e67SStephen Hanson ps = fmd_asru_replacement_state(alp->al_event, HC_ONLY_FALSE);
73725c6ff4bSstephh if (ps == FMD_OBJ_STATE_REPLACED) {
738cbf75e67SStephen Hanson fara.fara_reason = FMD_ASRU_REPLACED;
739cbf75e67SStephen Hanson fara.fara_bywhat = FARA_ALL;
740cbf75e67SStephen Hanson fara.fara_rval = &err;
741cbf75e67SStephen Hanson fmd_asru_repaired(alp, &fara);
74225c6ff4bSstephh } else if (ps == FMD_OBJ_STATE_NOT_PRESENT) {
743567cc2e6Sstephh fmd_time_gettimeofday(&tv);
74425c6ff4bSstephh lp = fmd_log_open(alp->al_asru->asru_root, alp->al_uuid,
74525c6ff4bSstephh FMD_LOG_ASRU);
746b0daa853SStephen Hanson if (lp == NULL)
747b0daa853SStephen Hanson return;
748567cc2e6Sstephh hrt = (hrtime_t)(tv.tv_sec - lp->log_stat.st_mtime);
749567cc2e6Sstephh fmd_log_rele(lp);
750cbf75e67SStephen Hanson if (hrt * NANOSEC >= fmd.d_asrus->ah_lifetime) {
751cbf75e67SStephen Hanson fara.fara_reason = FMD_ASRU_REMOVED;
752cbf75e67SStephen Hanson fara.fara_bywhat = FARA_ALL;
753cbf75e67SStephen Hanson fara.fara_rval = &err;
754cbf75e67SStephen Hanson fmd_asru_repaired(alp, &fara);
755cbf75e67SStephen Hanson }
75625c6ff4bSstephh }
757567cc2e6Sstephh }
758567cc2e6Sstephh
7595750ef5cSStephen Hanson /*ARGSUSED*/
7605750ef5cSStephen Hanson void
fmd_asru_check_if_aged(fmd_asru_link_t * alp,void * arg)7615750ef5cSStephen Hanson fmd_asru_check_if_aged(fmd_asru_link_t *alp, void *arg)
7625750ef5cSStephen Hanson {
7635750ef5cSStephen Hanson struct timeval tv;
7645750ef5cSStephen Hanson fmd_log_t *lp;
7655750ef5cSStephen Hanson hrtime_t hrt;
7665750ef5cSStephen Hanson
7675750ef5cSStephen Hanson /*
7685750ef5cSStephen Hanson * Case must be in resolved state for this to be called. So modified
7695750ef5cSStephen Hanson * time on resource cache entry should be the time the resolve occurred.
7705750ef5cSStephen Hanson * Return 0 if not yet hit rsrc.aged.
7715750ef5cSStephen Hanson */
7725750ef5cSStephen Hanson fmd_time_gettimeofday(&tv);
7735750ef5cSStephen Hanson lp = fmd_log_open(alp->al_asru->asru_root, alp->al_uuid, FMD_LOG_ASRU);
7745750ef5cSStephen Hanson if (lp == NULL)
7755750ef5cSStephen Hanson return;
7765750ef5cSStephen Hanson hrt = (hrtime_t)(tv.tv_sec - lp->log_stat.st_mtime);
7775750ef5cSStephen Hanson fmd_log_rele(lp);
7785750ef5cSStephen Hanson if (hrt * NANOSEC < fmd.d_asrus->ah_lifetime)
7795750ef5cSStephen Hanson *(int *)arg = 0;
7805750ef5cSStephen Hanson }
7815750ef5cSStephen Hanson
7825750ef5cSStephen Hanson /*ARGSUSED*/
7835750ef5cSStephen Hanson void
fmd_asru_most_recent(fmd_asru_link_t * alp,void * arg)7845750ef5cSStephen Hanson fmd_asru_most_recent(fmd_asru_link_t *alp, void *arg)
7855750ef5cSStephen Hanson {
7865750ef5cSStephen Hanson fmd_log_t *lp;
7875750ef5cSStephen Hanson uint64_t hrt;
7885750ef5cSStephen Hanson
7895750ef5cSStephen Hanson /*
7905750ef5cSStephen Hanson * Find most recent modified time of a set of resource cache entries.
7915750ef5cSStephen Hanson */
7925750ef5cSStephen Hanson lp = fmd_log_open(alp->al_asru->asru_root, alp->al_uuid, FMD_LOG_ASRU);
7935750ef5cSStephen Hanson if (lp == NULL)
7945750ef5cSStephen Hanson return;
7955750ef5cSStephen Hanson hrt = lp->log_stat.st_mtime;
7965750ef5cSStephen Hanson fmd_log_rele(lp);
7975750ef5cSStephen Hanson if (*(uint64_t *)arg < hrt)
7985750ef5cSStephen Hanson *(uint64_t *)arg = hrt;
7995750ef5cSStephen Hanson }
8005750ef5cSStephen Hanson
801567cc2e6Sstephh void
fmd_asru_clear_aged_rsrcs()802567cc2e6Sstephh fmd_asru_clear_aged_rsrcs()
803567cc2e6Sstephh {
8045750ef5cSStephen Hanson int check_if_aged = 1;
80525c6ff4bSstephh fmd_asru_al_hash_apply(fmd.d_asrus, fmd_asru_repair_if_aged, NULL);
8065750ef5cSStephen Hanson fmd_case_hash_apply(fmd.d_cases, fmd_case_discard_resolved,
8075750ef5cSStephen Hanson &check_if_aged);
808567cc2e6Sstephh }
809567cc2e6Sstephh
8107c478bd9Sstevel@tonic-gate fmd_asru_hash_t *
fmd_asru_hash_create(const char * root,const char * dir)8117c478bd9Sstevel@tonic-gate fmd_asru_hash_create(const char *root, const char *dir)
8127c478bd9Sstevel@tonic-gate {
8137c478bd9Sstevel@tonic-gate fmd_asru_hash_t *ahp;
8147c478bd9Sstevel@tonic-gate char path[PATH_MAX];
8157c478bd9Sstevel@tonic-gate
8167c478bd9Sstevel@tonic-gate ahp = fmd_alloc(sizeof (fmd_asru_hash_t), FMD_SLEEP);
8177c478bd9Sstevel@tonic-gate (void) pthread_rwlock_init(&ahp->ah_lock, NULL);
8187c478bd9Sstevel@tonic-gate ahp->ah_hashlen = fmd.d_str_buckets;
8197c478bd9Sstevel@tonic-gate ahp->ah_hash = fmd_zalloc(sizeof (void *) * ahp->ah_hashlen, FMD_SLEEP);
820567cc2e6Sstephh ahp->ah_asru_hash = fmd_zalloc(sizeof (void *) * ahp->ah_hashlen,
821567cc2e6Sstephh FMD_SLEEP);
822567cc2e6Sstephh ahp->ah_case_hash = fmd_zalloc(sizeof (void *) * ahp->ah_hashlen,
823567cc2e6Sstephh FMD_SLEEP);
824567cc2e6Sstephh ahp->ah_fru_hash = fmd_zalloc(sizeof (void *) * ahp->ah_hashlen,
825567cc2e6Sstephh FMD_SLEEP);
826567cc2e6Sstephh ahp->ah_label_hash = fmd_zalloc(sizeof (void *) * ahp->ah_hashlen,
827567cc2e6Sstephh FMD_SLEEP);
828567cc2e6Sstephh ahp->ah_rsrc_hash = fmd_zalloc(sizeof (void *) * ahp->ah_hashlen,
829567cc2e6Sstephh FMD_SLEEP);
8307c478bd9Sstevel@tonic-gate (void) snprintf(path, sizeof (path), "%s/%s", root, dir);
8317c478bd9Sstevel@tonic-gate ahp->ah_dirpath = fmd_strdup(path, FMD_SLEEP);
8327c478bd9Sstevel@tonic-gate (void) fmd_conf_getprop(fmd.d_conf, "rsrc.age", &ahp->ah_lifetime);
83344743693Sstephh (void) fmd_conf_getprop(fmd.d_conf, "fakenotpresent",
83444743693Sstephh (uint32_t *)&fmd_asru_fake_not_present);
835567cc2e6Sstephh ahp->ah_al_count = 0;
8367c478bd9Sstevel@tonic-gate ahp->ah_count = 0;
8377c478bd9Sstevel@tonic-gate ahp->ah_error = 0;
838940d71d2Seschrock ahp->ah_topo = fmd_topo_hold();
8397c478bd9Sstevel@tonic-gate
8407c478bd9Sstevel@tonic-gate return (ahp);
8417c478bd9Sstevel@tonic-gate }
8427c478bd9Sstevel@tonic-gate
8437c478bd9Sstevel@tonic-gate void
fmd_asru_hash_destroy(fmd_asru_hash_t * ahp)8447c478bd9Sstevel@tonic-gate fmd_asru_hash_destroy(fmd_asru_hash_t *ahp)
8457c478bd9Sstevel@tonic-gate {
846567cc2e6Sstephh fmd_asru_link_t *alp, *np;
8477c478bd9Sstevel@tonic-gate uint_t i;
8487c478bd9Sstevel@tonic-gate
8497c478bd9Sstevel@tonic-gate for (i = 0; i < ahp->ah_hashlen; i++) {
850567cc2e6Sstephh for (alp = ahp->ah_case_hash[i]; alp != NULL; alp = np) {
851567cc2e6Sstephh np = alp->al_case_next;
852567cc2e6Sstephh alp->al_case_next = NULL;
853567cc2e6Sstephh fmd_case_rele(alp->al_case);
854567cc2e6Sstephh alp->al_case = NULL;
855567cc2e6Sstephh fmd_asru_al_hash_release(ahp, alp);
8567c478bd9Sstevel@tonic-gate }
8577c478bd9Sstevel@tonic-gate }
8587c478bd9Sstevel@tonic-gate
8597c478bd9Sstevel@tonic-gate fmd_strfree(ahp->ah_dirpath);
8607c478bd9Sstevel@tonic-gate fmd_free(ahp->ah_hash, sizeof (void *) * ahp->ah_hashlen);
861567cc2e6Sstephh fmd_free(ahp->ah_asru_hash, sizeof (void *) * ahp->ah_hashlen);
862567cc2e6Sstephh fmd_free(ahp->ah_case_hash, sizeof (void *) * ahp->ah_hashlen);
863567cc2e6Sstephh fmd_free(ahp->ah_fru_hash, sizeof (void *) * ahp->ah_hashlen);
864567cc2e6Sstephh fmd_free(ahp->ah_label_hash, sizeof (void *) * ahp->ah_hashlen);
865567cc2e6Sstephh fmd_free(ahp->ah_rsrc_hash, sizeof (void *) * ahp->ah_hashlen);
866940d71d2Seschrock fmd_topo_rele(ahp->ah_topo);
8677c478bd9Sstevel@tonic-gate fmd_free(ahp, sizeof (fmd_asru_hash_t));
8687c478bd9Sstevel@tonic-gate }
8697c478bd9Sstevel@tonic-gate
8707c478bd9Sstevel@tonic-gate /*
8717c478bd9Sstevel@tonic-gate * Take a snapshot of the ASRU database by placing an additional hold on each
8727c478bd9Sstevel@tonic-gate * member in an auxiliary array, and then call 'func' for each ASRU.
8737c478bd9Sstevel@tonic-gate */
8747c478bd9Sstevel@tonic-gate void
fmd_asru_hash_apply(fmd_asru_hash_t * ahp,void (* func)(fmd_asru_t *,void *),void * arg)8757c478bd9Sstevel@tonic-gate fmd_asru_hash_apply(fmd_asru_hash_t *ahp,
8767c478bd9Sstevel@tonic-gate void (*func)(fmd_asru_t *, void *), void *arg)
8777c478bd9Sstevel@tonic-gate {
8787c478bd9Sstevel@tonic-gate fmd_asru_t *ap, **aps, **app;
8797c478bd9Sstevel@tonic-gate uint_t apc, i;
8807c478bd9Sstevel@tonic-gate
8817c478bd9Sstevel@tonic-gate (void) pthread_rwlock_rdlock(&ahp->ah_lock);
8827c478bd9Sstevel@tonic-gate
8837c478bd9Sstevel@tonic-gate aps = app = fmd_alloc(ahp->ah_count * sizeof (fmd_asru_t *), FMD_SLEEP);
8847c478bd9Sstevel@tonic-gate apc = ahp->ah_count;
8857c478bd9Sstevel@tonic-gate
8867c478bd9Sstevel@tonic-gate for (i = 0; i < ahp->ah_hashlen; i++) {
8877c478bd9Sstevel@tonic-gate for (ap = ahp->ah_hash[i]; ap != NULL; ap = ap->asru_next)
8887c478bd9Sstevel@tonic-gate *app++ = fmd_asru_hold(ap);
8897c478bd9Sstevel@tonic-gate }
8907c478bd9Sstevel@tonic-gate
8917c478bd9Sstevel@tonic-gate ASSERT(app == aps + apc);
8927c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&ahp->ah_lock);
8937c478bd9Sstevel@tonic-gate
8947c478bd9Sstevel@tonic-gate for (i = 0; i < apc; i++) {
895567cc2e6Sstephh if (aps[i]->asru_fmri != NULL)
8967c478bd9Sstevel@tonic-gate func(aps[i], arg);
8977c478bd9Sstevel@tonic-gate fmd_asru_hash_release(ahp, aps[i]);
8987c478bd9Sstevel@tonic-gate }
8997c478bd9Sstevel@tonic-gate
9007c478bd9Sstevel@tonic-gate fmd_free(aps, apc * sizeof (fmd_asru_t *));
9017c478bd9Sstevel@tonic-gate }
9027c478bd9Sstevel@tonic-gate
903567cc2e6Sstephh void
fmd_asru_al_hash_apply(fmd_asru_hash_t * ahp,void (* func)(fmd_asru_link_t *,void *),void * arg)904567cc2e6Sstephh fmd_asru_al_hash_apply(fmd_asru_hash_t *ahp,
905567cc2e6Sstephh void (*func)(fmd_asru_link_t *, void *), void *arg)
906567cc2e6Sstephh {
907567cc2e6Sstephh fmd_asru_link_t *alp, **alps, **alpp;
908567cc2e6Sstephh uint_t alpc, i;
909567cc2e6Sstephh
910567cc2e6Sstephh (void) pthread_rwlock_rdlock(&ahp->ah_lock);
911567cc2e6Sstephh
912567cc2e6Sstephh alps = alpp = fmd_alloc(ahp->ah_al_count * sizeof (fmd_asru_link_t *),
913567cc2e6Sstephh FMD_SLEEP);
914567cc2e6Sstephh alpc = ahp->ah_al_count;
915567cc2e6Sstephh
916567cc2e6Sstephh for (i = 0; i < ahp->ah_hashlen; i++) {
917567cc2e6Sstephh for (alp = ahp->ah_case_hash[i]; alp != NULL;
918567cc2e6Sstephh alp = alp->al_case_next)
919567cc2e6Sstephh *alpp++ = fmd_asru_al_hold(alp);
920567cc2e6Sstephh }
921567cc2e6Sstephh
922567cc2e6Sstephh ASSERT(alpp == alps + alpc);
923567cc2e6Sstephh (void) pthread_rwlock_unlock(&ahp->ah_lock);
924567cc2e6Sstephh
925567cc2e6Sstephh for (i = 0; i < alpc; i++) {
926567cc2e6Sstephh func(alps[i], arg);
927567cc2e6Sstephh fmd_asru_al_hash_release(ahp, alps[i]);
928567cc2e6Sstephh }
929567cc2e6Sstephh
930567cc2e6Sstephh fmd_free(alps, alpc * sizeof (fmd_asru_link_t *));
931567cc2e6Sstephh }
932567cc2e6Sstephh
933567cc2e6Sstephh static void
fmd_asru_do_hash_apply(fmd_asru_hash_t * ahp,const char * name,void (* func)(fmd_asru_link_t *,void *),void * arg,fmd_asru_link_t ** hash,size_t match_offset,size_t next_offset)93407312882SEric Schrock fmd_asru_do_hash_apply(fmd_asru_hash_t *ahp, const char *name,
935567cc2e6Sstephh void (*func)(fmd_asru_link_t *, void *), void *arg,
936567cc2e6Sstephh fmd_asru_link_t **hash, size_t match_offset, size_t next_offset)
937567cc2e6Sstephh {
938567cc2e6Sstephh fmd_asru_link_t *alp, **alps, **alpp;
939567cc2e6Sstephh uint_t alpc = 0, i;
940567cc2e6Sstephh uint_t h;
941567cc2e6Sstephh
942567cc2e6Sstephh (void) pthread_rwlock_rdlock(&ahp->ah_lock);
943567cc2e6Sstephh
944940d71d2Seschrock h = fmd_asru_strhash(ahp, name);
945567cc2e6Sstephh
946567cc2e6Sstephh for (alp = hash[h]; alp != NULL; alp =
947567cc2e6Sstephh /* LINTED pointer alignment */
948567cc2e6Sstephh FMD_ASRU_AL_HASH_NEXT(alp, next_offset))
949940d71d2Seschrock if (fmd_asru_strcmp(ahp,
950567cc2e6Sstephh /* LINTED pointer alignment */
951940d71d2Seschrock FMD_ASRU_AL_HASH_NAME(alp, match_offset), name))
952567cc2e6Sstephh alpc++;
953567cc2e6Sstephh
954567cc2e6Sstephh alps = alpp = fmd_alloc(alpc * sizeof (fmd_asru_link_t *), FMD_SLEEP);
955567cc2e6Sstephh
956567cc2e6Sstephh for (alp = hash[h]; alp != NULL; alp =
957567cc2e6Sstephh /* LINTED pointer alignment */
958567cc2e6Sstephh FMD_ASRU_AL_HASH_NEXT(alp, next_offset))
959940d71d2Seschrock if (fmd_asru_strcmp(ahp,
960567cc2e6Sstephh /* LINTED pointer alignment */
961940d71d2Seschrock FMD_ASRU_AL_HASH_NAME(alp, match_offset), name))
962567cc2e6Sstephh *alpp++ = fmd_asru_al_hold(alp);
963567cc2e6Sstephh
964567cc2e6Sstephh ASSERT(alpp == alps + alpc);
965567cc2e6Sstephh (void) pthread_rwlock_unlock(&ahp->ah_lock);
966567cc2e6Sstephh
967567cc2e6Sstephh for (i = 0; i < alpc; i++) {
968567cc2e6Sstephh func(alps[i], arg);
969567cc2e6Sstephh fmd_asru_al_hash_release(ahp, alps[i]);
970567cc2e6Sstephh }
971567cc2e6Sstephh
972567cc2e6Sstephh fmd_free(alps, alpc * sizeof (fmd_asru_link_t *));
973567cc2e6Sstephh }
974567cc2e6Sstephh
975567cc2e6Sstephh void
fmd_asru_hash_apply_by_asru(fmd_asru_hash_t * ahp,const char * name,void (* func)(fmd_asru_link_t *,void *),void * arg)97607312882SEric Schrock fmd_asru_hash_apply_by_asru(fmd_asru_hash_t *ahp, const char *name,
977567cc2e6Sstephh void (*func)(fmd_asru_link_t *, void *), void *arg)
978567cc2e6Sstephh {
979567cc2e6Sstephh fmd_asru_do_hash_apply(ahp, name, func, arg, ahp->ah_asru_hash,
980567cc2e6Sstephh offsetof(fmd_asru_link_t, al_asru_name),
981567cc2e6Sstephh offsetof(fmd_asru_link_t, al_asru_next));
982567cc2e6Sstephh }
983567cc2e6Sstephh
984567cc2e6Sstephh void
fmd_asru_hash_apply_by_case(fmd_asru_hash_t * ahp,fmd_case_t * cp,void (* func)(fmd_asru_link_t *,void *),void * arg)985567cc2e6Sstephh fmd_asru_hash_apply_by_case(fmd_asru_hash_t *ahp, fmd_case_t *cp,
986567cc2e6Sstephh void (*func)(fmd_asru_link_t *, void *), void *arg)
987567cc2e6Sstephh {
988567cc2e6Sstephh fmd_asru_do_hash_apply(ahp, ((fmd_case_impl_t *)cp)->ci_uuid, func, arg,
989567cc2e6Sstephh ahp->ah_case_hash, offsetof(fmd_asru_link_t, al_case_uuid),
990567cc2e6Sstephh offsetof(fmd_asru_link_t, al_case_next));
991567cc2e6Sstephh }
992567cc2e6Sstephh
993567cc2e6Sstephh void
fmd_asru_hash_apply_by_fru(fmd_asru_hash_t * ahp,const char * name,void (* func)(fmd_asru_link_t *,void *),void * arg)99407312882SEric Schrock fmd_asru_hash_apply_by_fru(fmd_asru_hash_t *ahp, const char *name,
995567cc2e6Sstephh void (*func)(fmd_asru_link_t *, void *), void *arg)
996567cc2e6Sstephh {
997567cc2e6Sstephh fmd_asru_do_hash_apply(ahp, name, func, arg, ahp->ah_fru_hash,
998567cc2e6Sstephh offsetof(fmd_asru_link_t, al_fru_name),
999567cc2e6Sstephh offsetof(fmd_asru_link_t, al_fru_next));
1000567cc2e6Sstephh }
1001567cc2e6Sstephh
1002567cc2e6Sstephh void
fmd_asru_hash_apply_by_rsrc(fmd_asru_hash_t * ahp,const char * name,void (* func)(fmd_asru_link_t *,void *),void * arg)100307312882SEric Schrock fmd_asru_hash_apply_by_rsrc(fmd_asru_hash_t *ahp, const char *name,
1004567cc2e6Sstephh void (*func)(fmd_asru_link_t *, void *), void *arg)
1005567cc2e6Sstephh {
1006567cc2e6Sstephh fmd_asru_do_hash_apply(ahp, name, func, arg, ahp->ah_rsrc_hash,
1007567cc2e6Sstephh offsetof(fmd_asru_link_t, al_rsrc_name),
1008567cc2e6Sstephh offsetof(fmd_asru_link_t, al_rsrc_next));
1009567cc2e6Sstephh }
1010567cc2e6Sstephh
1011567cc2e6Sstephh void
fmd_asru_hash_apply_by_label(fmd_asru_hash_t * ahp,const char * name,void (* func)(fmd_asru_link_t *,void *),void * arg)101207312882SEric Schrock fmd_asru_hash_apply_by_label(fmd_asru_hash_t *ahp, const char *name,
1013567cc2e6Sstephh void (*func)(fmd_asru_link_t *, void *), void *arg)
1014567cc2e6Sstephh {
1015567cc2e6Sstephh fmd_asru_do_hash_apply(ahp, name, func, arg, ahp->ah_label_hash,
1016567cc2e6Sstephh offsetof(fmd_asru_link_t, al_label),
1017567cc2e6Sstephh offsetof(fmd_asru_link_t, al_label_next));
1018567cc2e6Sstephh }
1019567cc2e6Sstephh
10207c478bd9Sstevel@tonic-gate /*
10217c478bd9Sstevel@tonic-gate * Lookup an asru in the hash by name and place a hold on it. If the asru is
10227c478bd9Sstevel@tonic-gate * not found, no entry is created and NULL is returned.
10237c478bd9Sstevel@tonic-gate */
10247c478bd9Sstevel@tonic-gate fmd_asru_t *
fmd_asru_hash_lookup_name(fmd_asru_hash_t * ahp,const char * name)10257c478bd9Sstevel@tonic-gate fmd_asru_hash_lookup_name(fmd_asru_hash_t *ahp, const char *name)
10267c478bd9Sstevel@tonic-gate {
10277c478bd9Sstevel@tonic-gate fmd_asru_t *ap;
10287c478bd9Sstevel@tonic-gate
10297c478bd9Sstevel@tonic-gate (void) pthread_rwlock_rdlock(&ahp->ah_lock);
10307c478bd9Sstevel@tonic-gate ap = fmd_asru_hash_lookup(ahp, name);
10317c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&ahp->ah_lock);
10327c478bd9Sstevel@tonic-gate
10337c478bd9Sstevel@tonic-gate return (ap);
10347c478bd9Sstevel@tonic-gate }
10357c478bd9Sstevel@tonic-gate
10367c478bd9Sstevel@tonic-gate /*
1037567cc2e6Sstephh * Create a resource cache entry using the fault event "nvl" for one of the
1038567cc2e6Sstephh * suspects from the case "cp".
1039567cc2e6Sstephh *
1040567cc2e6Sstephh * The fault event can have the following components : FM_FAULT_ASRU,
1041567cc2e6Sstephh * FM_FAULT_FRU, FM_FAULT_RESOURCE. These should be set by the Diagnosis Engine
1042567cc2e6Sstephh * when calling fmd_nvl_create_fault(). In the general case, these are all
1043567cc2e6Sstephh * optional and an entry will always be added into the cache even if one or all
1044567cc2e6Sstephh * of these fields is missing.
1045567cc2e6Sstephh *
1046567cc2e6Sstephh * However, for hardware faults the recommended practice is that the fault
1047567cc2e6Sstephh * event should always have the FM_FAULT_RESOURCE field present and that this
1048567cc2e6Sstephh * should be represented in hc-scheme.
1049567cc2e6Sstephh *
1050567cc2e6Sstephh * Currently the DE should also add the FM_FAULT_ASRU and FM_FAULT_FRU fields
1051567cc2e6Sstephh * where known, though at some future stage fmd might be able to fill these
1052567cc2e6Sstephh * in automatically from the topology.
10537c478bd9Sstevel@tonic-gate */
1054567cc2e6Sstephh fmd_asru_link_t *
fmd_asru_hash_create_entry(fmd_asru_hash_t * ahp,fmd_case_t * cp,nvlist_t * nvl)1055567cc2e6Sstephh fmd_asru_hash_create_entry(fmd_asru_hash_t *ahp, fmd_case_t *cp, nvlist_t *nvl)
1056567cc2e6Sstephh {
1057567cc2e6Sstephh char *parsed_uuid;
10587c478bd9Sstevel@tonic-gate uuid_t uuid;
1059567cc2e6Sstephh int uuidlen;
1060567cc2e6Sstephh fmd_asru_link_t *alp;
10617c478bd9Sstevel@tonic-gate
10627c478bd9Sstevel@tonic-gate /*
10637c478bd9Sstevel@tonic-gate * Generate a UUID for the ASRU. libuuid cleverly gives us no
10647c478bd9Sstevel@tonic-gate * interface for specifying or learning the buffer size. Sigh.
10657c478bd9Sstevel@tonic-gate * The spec says 36 bytes but we use a tunable just to be safe.
10667c478bd9Sstevel@tonic-gate */
1067567cc2e6Sstephh (void) fmd_conf_getprop(fmd.d_conf, "uuidlen", &uuidlen);
1068567cc2e6Sstephh parsed_uuid = fmd_zalloc(uuidlen + 1, FMD_SLEEP);
10697c478bd9Sstevel@tonic-gate uuid_generate(uuid);
1070567cc2e6Sstephh uuid_unparse(uuid, parsed_uuid);
10717c478bd9Sstevel@tonic-gate
1072567cc2e6Sstephh /*
1073567cc2e6Sstephh * Now create the resource cache entries.
1074567cc2e6Sstephh */
1075567cc2e6Sstephh fmd_case_hold_locked(cp);
1076567cc2e6Sstephh alp = fmd_asru_al_create(ahp, nvl, cp, parsed_uuid);
10777c478bd9Sstevel@tonic-gate TRACE((FMD_DBG_ASRU, "asru %s created as %p",
1078567cc2e6Sstephh alp->al_uuid, (void *)alp->al_asru));
10797c478bd9Sstevel@tonic-gate
1080567cc2e6Sstephh fmd_free(parsed_uuid, uuidlen + 1);
1081567cc2e6Sstephh return (alp);
10827c478bd9Sstevel@tonic-gate
10837c478bd9Sstevel@tonic-gate }
10847c478bd9Sstevel@tonic-gate
10857c478bd9Sstevel@tonic-gate /*
10867c478bd9Sstevel@tonic-gate * Release the reference count on an asru obtained using fmd_asru_hash_lookup.
10877c478bd9Sstevel@tonic-gate * We take 'ahp' for symmetry and in case we need to use it in future work.
10887c478bd9Sstevel@tonic-gate */
10897c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10907c478bd9Sstevel@tonic-gate void
fmd_asru_hash_release(fmd_asru_hash_t * ahp,fmd_asru_t * ap)10917c478bd9Sstevel@tonic-gate fmd_asru_hash_release(fmd_asru_hash_t *ahp, fmd_asru_t *ap)
10927c478bd9Sstevel@tonic-gate {
10937c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ap->asru_lock);
10947c478bd9Sstevel@tonic-gate
10957c478bd9Sstevel@tonic-gate ASSERT(ap->asru_refs != 0);
10967c478bd9Sstevel@tonic-gate if (--ap->asru_refs == 0)
10977c478bd9Sstevel@tonic-gate fmd_asru_destroy(ap);
10987c478bd9Sstevel@tonic-gate else
10997c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ap->asru_lock);
11007c478bd9Sstevel@tonic-gate }
11017c478bd9Sstevel@tonic-gate
1102567cc2e6Sstephh static void
fmd_asru_do_delete_entry(fmd_asru_hash_t * ahp,fmd_case_t * cp,fmd_asru_link_t ** hash,size_t next_offset,char * name)1103567cc2e6Sstephh fmd_asru_do_delete_entry(fmd_asru_hash_t *ahp, fmd_case_t *cp,
1104567cc2e6Sstephh fmd_asru_link_t **hash, size_t next_offset, char *name)
11057c478bd9Sstevel@tonic-gate {
11067c478bd9Sstevel@tonic-gate uint_t h;
1107567cc2e6Sstephh fmd_asru_link_t *alp, **pp, *alpnext, **alpnextp;
11087c478bd9Sstevel@tonic-gate
11097c478bd9Sstevel@tonic-gate (void) pthread_rwlock_wrlock(&ahp->ah_lock);
1110940d71d2Seschrock h = fmd_asru_strhash(ahp, name);
1111567cc2e6Sstephh pp = &hash[h];
1112567cc2e6Sstephh for (alp = *pp; alp != NULL; alp = alpnext) {
1113567cc2e6Sstephh /* LINTED pointer alignment */
1114567cc2e6Sstephh alpnextp = FMD_ASRU_AL_HASH_NEXTP(alp, next_offset);
1115567cc2e6Sstephh alpnext = *alpnextp;
1116567cc2e6Sstephh if (alp->al_case == cp) {
1117567cc2e6Sstephh *pp = *alpnextp;
1118567cc2e6Sstephh *alpnextp = NULL;
1119567cc2e6Sstephh } else
1120567cc2e6Sstephh pp = alpnextp;
11217c478bd9Sstevel@tonic-gate }
11227c478bd9Sstevel@tonic-gate (void) pthread_rwlock_unlock(&ahp->ah_lock);
11237c478bd9Sstevel@tonic-gate }
11247c478bd9Sstevel@tonic-gate
11257c478bd9Sstevel@tonic-gate static void
fmd_asru_do_hash_delete(fmd_asru_hash_t * ahp,fmd_case_susp_t * cis,fmd_case_t * cp,fmd_asru_link_t ** hash,size_t next_offset,char * nvname)1126567cc2e6Sstephh fmd_asru_do_hash_delete(fmd_asru_hash_t *ahp, fmd_case_susp_t *cis,
1127567cc2e6Sstephh fmd_case_t *cp, fmd_asru_link_t **hash, size_t next_offset, char *nvname)
11287c478bd9Sstevel@tonic-gate {
1129567cc2e6Sstephh nvlist_t *nvl;
1130567cc2e6Sstephh char *name = NULL;
1131567cc2e6Sstephh ssize_t namelen;
1132567cc2e6Sstephh
1133567cc2e6Sstephh if (nvlist_lookup_nvlist(cis->cis_nvl, nvname, &nvl) == 0 &&
1134567cc2e6Sstephh (namelen = fmd_fmri_nvl2str(nvl, NULL, 0)) != -1 &&
1135567cc2e6Sstephh (name = fmd_alloc(namelen + 1, FMD_SLEEP)) != NULL) {
1136567cc2e6Sstephh if (fmd_fmri_nvl2str(nvl, name, namelen + 1) != -1)
1137567cc2e6Sstephh fmd_asru_do_delete_entry(ahp, cp, hash, next_offset,
1138567cc2e6Sstephh name);
1139567cc2e6Sstephh fmd_free(name, namelen + 1);
1140567cc2e6Sstephh } else
1141567cc2e6Sstephh fmd_asru_do_delete_entry(ahp, cp, hash, next_offset, "");
1142567cc2e6Sstephh }
1143567cc2e6Sstephh
1144567cc2e6Sstephh void
fmd_asru_hash_delete_case(fmd_asru_hash_t * ahp,fmd_case_t * cp)1145567cc2e6Sstephh fmd_asru_hash_delete_case(fmd_asru_hash_t *ahp, fmd_case_t *cp)
1146567cc2e6Sstephh {
1147567cc2e6Sstephh fmd_case_impl_t *cip = (fmd_case_impl_t *)cp;
1148567cc2e6Sstephh fmd_case_susp_t *cis;
1149567cc2e6Sstephh fmd_asru_link_t *alp, **plp, *alpnext;
1150567cc2e6Sstephh fmd_asru_t *ap;
1151567cc2e6Sstephh char path[PATH_MAX];
1152567cc2e6Sstephh char *label;
1153567cc2e6Sstephh uint_t h;
1154567cc2e6Sstephh
1155567cc2e6Sstephh /*
1156567cc2e6Sstephh * first delete hash entries for each suspect
1157567cc2e6Sstephh */
1158567cc2e6Sstephh for (cis = cip->ci_suspects; cis != NULL; cis = cis->cis_next) {
1159567cc2e6Sstephh fmd_asru_do_hash_delete(ahp, cis, cp, ahp->ah_fru_hash,
1160567cc2e6Sstephh offsetof(fmd_asru_link_t, al_fru_next), FM_FAULT_FRU);
1161567cc2e6Sstephh fmd_asru_do_hash_delete(ahp, cis, cp, ahp->ah_rsrc_hash,
1162567cc2e6Sstephh offsetof(fmd_asru_link_t, al_rsrc_next), FM_FAULT_RESOURCE);
1163567cc2e6Sstephh if (nvlist_lookup_string(cis->cis_nvl, FM_FAULT_LOCATION,
1164567cc2e6Sstephh &label) != 0)
1165567cc2e6Sstephh label = "";
1166567cc2e6Sstephh fmd_asru_do_delete_entry(ahp, cp, ahp->ah_label_hash,
1167567cc2e6Sstephh offsetof(fmd_asru_link_t, al_label_next), label);
1168567cc2e6Sstephh fmd_asru_do_hash_delete(ahp, cis, cp, ahp->ah_asru_hash,
1169567cc2e6Sstephh offsetof(fmd_asru_link_t, al_asru_next), FM_FAULT_ASRU);
1170567cc2e6Sstephh }
1171567cc2e6Sstephh
1172567cc2e6Sstephh /*
1173567cc2e6Sstephh * then delete associated case hash entries
1174567cc2e6Sstephh */
1175567cc2e6Sstephh (void) pthread_rwlock_wrlock(&ahp->ah_lock);
1176940d71d2Seschrock h = fmd_asru_strhash(ahp, cip->ci_uuid);
1177567cc2e6Sstephh plp = &ahp->ah_case_hash[h];
1178567cc2e6Sstephh for (alp = *plp; alp != NULL; alp = alpnext) {
1179567cc2e6Sstephh alpnext = alp->al_case_next;
1180567cc2e6Sstephh if (alp->al_case == cp) {
1181567cc2e6Sstephh *plp = alp->al_case_next;
1182567cc2e6Sstephh alp->al_case_next = NULL;
1183567cc2e6Sstephh ASSERT(ahp->ah_al_count != 0);
1184567cc2e6Sstephh ahp->ah_al_count--;
1185567cc2e6Sstephh
1186567cc2e6Sstephh /*
1187567cc2e6Sstephh * decrement case ref.
1188567cc2e6Sstephh */
1189567cc2e6Sstephh fmd_case_rele_locked(cp);
1190567cc2e6Sstephh alp->al_case = NULL;
1191567cc2e6Sstephh
1192567cc2e6Sstephh /*
1193567cc2e6Sstephh * If we found a matching ASRU, unlink its log file and
1194567cc2e6Sstephh * then release the hash entry. Note that it may still
1195567cc2e6Sstephh * be referenced if another thread is manipulating it;
1196567cc2e6Sstephh * this is ok because once we unlink, the log file will
1197567cc2e6Sstephh * not be restored, and the log data will be freed when
1198567cc2e6Sstephh * all of the referencing threads release their
1199567cc2e6Sstephh * respective references.
1200567cc2e6Sstephh */
1201567cc2e6Sstephh (void) snprintf(path, sizeof (path), "%s/%s",
1202567cc2e6Sstephh ahp->ah_dirpath, alp->al_uuid);
1203cbf75e67SStephen Hanson if (cip->ci_xprt == NULL && unlink(path) != 0)
1204567cc2e6Sstephh fmd_error(EFMD_ASRU_UNLINK,
1205567cc2e6Sstephh "failed to unlink asru %s", path);
1206567cc2e6Sstephh
1207567cc2e6Sstephh /*
1208567cc2e6Sstephh * Now unlink from the global per-resource cache
1209567cc2e6Sstephh * and if this is the last link then remove that from
1210567cc2e6Sstephh * it's own hash too.
1211567cc2e6Sstephh */
1212567cc2e6Sstephh ap = alp->al_asru;
1213567cc2e6Sstephh (void) pthread_mutex_lock(&ap->asru_lock);
1214567cc2e6Sstephh fmd_list_delete(&ap->asru_list, alp);
1215567cc2e6Sstephh if (ap->asru_list.l_next == NULL) {
1216567cc2e6Sstephh uint_t h;
1217567cc2e6Sstephh fmd_asru_t *ap2, **pp;
1218567cc2e6Sstephh fmd_asru_t *apnext, **apnextp;
1219567cc2e6Sstephh
1220567cc2e6Sstephh ASSERT(ahp->ah_count != 0);
1221567cc2e6Sstephh ahp->ah_count--;
1222940d71d2Seschrock h = fmd_asru_strhash(ahp, ap->asru_name);
1223567cc2e6Sstephh pp = &ahp->ah_hash[h];
1224567cc2e6Sstephh for (ap2 = *pp; ap2 != NULL; ap2 = apnext) {
1225567cc2e6Sstephh apnextp = &ap2->asru_next;
1226567cc2e6Sstephh apnext = *apnextp;
1227567cc2e6Sstephh if (ap2 == ap) {
1228567cc2e6Sstephh *pp = *apnextp;
1229567cc2e6Sstephh *apnextp = NULL;
1230567cc2e6Sstephh } else
1231567cc2e6Sstephh pp = apnextp;
1232567cc2e6Sstephh }
1233567cc2e6Sstephh }
1234567cc2e6Sstephh (void) pthread_mutex_unlock(&ap->asru_lock);
1235567cc2e6Sstephh fmd_asru_al_hash_release(ahp, alp);
1236567cc2e6Sstephh } else
1237567cc2e6Sstephh plp = &alp->al_case_next;
1238567cc2e6Sstephh }
1239567cc2e6Sstephh (void) pthread_rwlock_unlock(&ahp->ah_lock);
1240567cc2e6Sstephh }
1241567cc2e6Sstephh
1242cbf75e67SStephen Hanson typedef struct {
1243cbf75e67SStephen Hanson nvlist_t *farc_parent_fmri;
1244cbf75e67SStephen Hanson uint8_t farc_reason;
1245cbf75e67SStephen Hanson } fmd_asru_farc_t;
1246cbf75e67SStephen Hanson
1247567cc2e6Sstephh static void
fmd_asru_repair_containee(fmd_asru_link_t * alp,void * arg)1248cbf75e67SStephen Hanson fmd_asru_repair_containee(fmd_asru_link_t *alp, void *arg)
1249567cc2e6Sstephh {
1250cbf75e67SStephen Hanson fmd_asru_farc_t *farcp = (fmd_asru_farc_t *)arg;
1251cbf75e67SStephen Hanson
1252cbf75e67SStephen Hanson if ((alp->al_asru->asru_flags & FMD_ASRU_INVISIBLE) &&
1253cbf75e67SStephen Hanson alp->al_asru_fmri &&
1254cbf75e67SStephen Hanson fmd_fmri_contains(farcp->farc_parent_fmri, alp->al_asru_fmri) > 0) {
1255cbf75e67SStephen Hanson if (fmd_asru_clrflags(alp, FMD_ASRU_FAULTY,
1256cbf75e67SStephen Hanson farcp->farc_reason)) {
1257cbf75e67SStephen Hanson if (alp->al_flags & FMD_ASRU_PROXY)
1258cbf75e67SStephen Hanson fmd_case_xprt_updated(alp->al_case);
1259cbf75e67SStephen Hanson else
1260567cc2e6Sstephh fmd_case_update(alp->al_case);
1261567cc2e6Sstephh }
1262cbf75e67SStephen Hanson }
1263cbf75e67SStephen Hanson }
1264567cc2e6Sstephh
1265cbf75e67SStephen Hanson static void
fmd_asru_do_repair_containees(fmd_asru_link_t * alp,uint8_t reason)1266cbf75e67SStephen Hanson fmd_asru_do_repair_containees(fmd_asru_link_t *alp, uint8_t reason)
1267567cc2e6Sstephh {
1268567cc2e6Sstephh int flags;
1269567cc2e6Sstephh
1270567cc2e6Sstephh /*
1271cbf75e67SStephen Hanson * Check if all entries associated with this asru are acquitted and
1272cbf75e67SStephen Hanson * if so acquit containees. Don't try to repair containees on proxy
1273cbf75e67SStephen Hanson * side unless we have local asru.
1274567cc2e6Sstephh */
1275cbf75e67SStephen Hanson if (alp->al_asru_fmri != NULL && (!(alp->al_flags & FMD_ASRU_PROXY) ||
1276cbf75e67SStephen Hanson (alp->al_flags & FMD_ASRU_PROXY_WITH_ASRU))) {
1277567cc2e6Sstephh (void) pthread_mutex_lock(&alp->al_asru->asru_lock);
1278567cc2e6Sstephh flags = alp->al_asru->asru_flags;
1279567cc2e6Sstephh (void) pthread_mutex_unlock(&alp->al_asru->asru_lock);
1280cbf75e67SStephen Hanson if (!(flags & (FMD_ASRU_FAULTY | FMD_ASRU_INVISIBLE))) {
1281cbf75e67SStephen Hanson fmd_asru_farc_t farc;
1282567cc2e6Sstephh
1283cbf75e67SStephen Hanson farc.farc_parent_fmri = alp->al_asru_fmri;
1284cbf75e67SStephen Hanson farc.farc_reason = reason;
1285cbf75e67SStephen Hanson fmd_asru_al_hash_apply(fmd.d_asrus,
1286cbf75e67SStephen Hanson fmd_asru_repair_containee, &farc);
1287567cc2e6Sstephh }
1288567cc2e6Sstephh }
128925c6ff4bSstephh }
129025c6ff4bSstephh
129125c6ff4bSstephh void
fmd_asru_repaired(fmd_asru_link_t * alp,void * arg)1292cbf75e67SStephen Hanson fmd_asru_repaired(fmd_asru_link_t *alp, void *arg)
129325c6ff4bSstephh {
1294cbf75e67SStephen Hanson int cleared;
1295cbf75e67SStephen Hanson fmd_asru_rep_arg_t *farap = (fmd_asru_rep_arg_t *)arg;
129625c6ff4bSstephh
129725c6ff4bSstephh /*
1298cbf75e67SStephen Hanson * don't allow remote repair over readonly transport
129925c6ff4bSstephh */
1300cbf75e67SStephen Hanson if (alp->al_flags & FMD_ASRU_PROXY_RDONLY)
130125c6ff4bSstephh return;
130225c6ff4bSstephh
130325c6ff4bSstephh /*
1304cbf75e67SStephen Hanson * don't allow repair etc by asru on proxy unless asru is local
130525c6ff4bSstephh */
1306cbf75e67SStephen Hanson if (farap->fara_bywhat == FARA_BY_ASRU &&
1307cbf75e67SStephen Hanson (alp->al_flags & FMD_ASRU_PROXY) &&
1308cbf75e67SStephen Hanson !(alp->al_flags & FMD_ASRU_PROXY_WITH_ASRU))
1309cbf75e67SStephen Hanson return;
1310cbf75e67SStephen Hanson /*
1311cbf75e67SStephen Hanson * For acquit, need to check both name and uuid if specified
1312cbf75e67SStephen Hanson */
1313cbf75e67SStephen Hanson if (farap->fara_reason == FMD_ASRU_ACQUITTED &&
1314cbf75e67SStephen Hanson farap->fara_rval != NULL && strcmp(farap->fara_uuid, "") != 0 &&
1315cbf75e67SStephen Hanson strcmp(farap->fara_uuid, alp->al_case_uuid) != 0)
1316cbf75e67SStephen Hanson return;
131725c6ff4bSstephh
131825c6ff4bSstephh /*
13196e1fa242SStephen Hanson * For replaced, verify it has been replaced if we have serial number.
13206e1fa242SStephen Hanson * If not set *farap->fara_rval to FARA_ERR_RSRCNOTR.
132125c6ff4bSstephh */
1322cbf75e67SStephen Hanson if (farap->fara_reason == FMD_ASRU_REPLACED &&
1323cbf75e67SStephen Hanson !(alp->al_flags & FMD_ASRU_PROXY_EXTERNAL) &&
1324cbf75e67SStephen Hanson fmd_asru_replacement_state(alp->al_event,
1325cbf75e67SStephen Hanson (alp->al_flags & FMD_ASRU_PROXY) ? HC_ONLY_TRUE : HC_ONLY_FALSE) ==
1326cbf75e67SStephen Hanson FMD_OBJ_STATE_STILL_PRESENT) {
13276e1fa242SStephen Hanson if (farap->fara_rval)
13286e1fa242SStephen Hanson *farap->fara_rval = FARA_ERR_RSRCNOTR;
1329cbf75e67SStephen Hanson return;
133025c6ff4bSstephh }
133125c6ff4bSstephh
1332cbf75e67SStephen Hanson cleared = fmd_asru_clrflags(alp, FMD_ASRU_FAULTY, farap->fara_reason);
1333cbf75e67SStephen Hanson fmd_asru_do_repair_containees(alp, farap->fara_reason);
1334cbf75e67SStephen Hanson
1335cbf75e67SStephen Hanson /*
1336cbf75e67SStephen Hanson * if called from fmd_adm_*() and we really did clear the bit then
1337cbf75e67SStephen Hanson * we need to do a case update to see if the associated case can be
1338cbf75e67SStephen Hanson * repaired. No need to do this if called from fmd_case_*() (ie
1339cbf75e67SStephen Hanson * when arg is NULL) as the case will be explicitly repaired anyway.
1340cbf75e67SStephen Hanson */
1341cbf75e67SStephen Hanson if (farap->fara_rval) {
13426e1fa242SStephen Hanson /*
13436e1fa242SStephen Hanson * *farap->fara_rval defaults to FARA_ERR_RSRCNOTF (not found).
13446e1fa242SStephen Hanson * If we find a valid cache entry which we repair then we
13456e1fa242SStephen Hanson * set it to FARA_OK. However we don't want to do this if
13466e1fa242SStephen Hanson * we have already set it to FARA_ERR_RSRCNOTR (not replaced)
13476e1fa242SStephen Hanson * in a previous iteration (see above). So only set it to
13486e1fa242SStephen Hanson * FARA_OK if the current value is still FARA_ERR_RSRCNOTF.
13496e1fa242SStephen Hanson */
13506e1fa242SStephen Hanson if (*farap->fara_rval == FARA_ERR_RSRCNOTF)
13516e1fa242SStephen Hanson *farap->fara_rval = FARA_OK;
1352cbf75e67SStephen Hanson if (cleared) {
1353cbf75e67SStephen Hanson if (alp->al_flags & FMD_ASRU_PROXY)
1354cbf75e67SStephen Hanson fmd_case_xprt_updated(alp->al_case);
1355cbf75e67SStephen Hanson else
135625c6ff4bSstephh fmd_case_update(alp->al_case);
135725c6ff4bSstephh }
1358cbf75e67SStephen Hanson }
1359cbf75e67SStephen Hanson }
136025c6ff4bSstephh
1361cbf75e67SStephen Hanson /*
13625750ef5cSStephen Hanson * Discard the case associated with this alp if it is in resolved state.
13635750ef5cSStephen Hanson * Called on "fmadm flush".
13645750ef5cSStephen Hanson */
13655750ef5cSStephen Hanson /*ARGSUSED*/
13665750ef5cSStephen Hanson void
fmd_asru_flush(fmd_asru_link_t * alp,void * arg)13675750ef5cSStephen Hanson fmd_asru_flush(fmd_asru_link_t *alp, void *arg)
13685750ef5cSStephen Hanson {
13695750ef5cSStephen Hanson int check_if_aged = 0;
13705750ef5cSStephen Hanson int *rval = (int *)arg;
13715750ef5cSStephen Hanson
13725750ef5cSStephen Hanson if (alp->al_case)
13735750ef5cSStephen Hanson fmd_case_discard_resolved(alp->al_case, &check_if_aged);
13745750ef5cSStephen Hanson *rval = 0;
13755750ef5cSStephen Hanson }
13765750ef5cSStephen Hanson
13775750ef5cSStephen Hanson /*
1378cbf75e67SStephen Hanson * This is only called for proxied faults. Set various flags so we can
1379cbf75e67SStephen Hanson * find the nature of the transport from the resource cache code.
1380cbf75e67SStephen Hanson */
1381cbf75e67SStephen Hanson /*ARGSUSED*/
138225c6ff4bSstephh void
fmd_asru_set_on_proxy(fmd_asru_link_t * alp,void * arg)1383cbf75e67SStephen Hanson fmd_asru_set_on_proxy(fmd_asru_link_t *alp, void *arg)
138425c6ff4bSstephh {
1385cbf75e67SStephen Hanson fmd_asru_set_on_proxy_t *entryp = (fmd_asru_set_on_proxy_t *)arg;
1386cbf75e67SStephen Hanson
1387cbf75e67SStephen Hanson if (*entryp->fasp_countp >= entryp->fasp_maxcount)
1388cbf75e67SStephen Hanson return;
138925c6ff4bSstephh
139025c6ff4bSstephh /*
1391cbf75e67SStephen Hanson * Note that this is a proxy fault and save whetehr transport is
1392cbf75e67SStephen Hanson * RDONLY or EXTERNAL.
139325c6ff4bSstephh */
1394cbf75e67SStephen Hanson alp->al_flags |= FMD_ASRU_PROXY;
1395cbf75e67SStephen Hanson alp->al_asru->asru_flags |= FMD_ASRU_PROXY;
1396cbf75e67SStephen Hanson
1397cbf75e67SStephen Hanson if (entryp->fasp_proxy_external) {
1398cbf75e67SStephen Hanson alp->al_flags |= FMD_ASRU_PROXY_EXTERNAL;
1399cbf75e67SStephen Hanson alp->al_asru->asru_flags |= FMD_ASRU_PROXY_EXTERNAL;
1400cbf75e67SStephen Hanson }
1401cbf75e67SStephen Hanson
1402cbf75e67SStephen Hanson if (entryp->fasp_proxy_rdonly)
1403cbf75e67SStephen Hanson alp->al_flags |= FMD_ASRU_PROXY_RDONLY;
140425c6ff4bSstephh
140525c6ff4bSstephh /*
1406cbf75e67SStephen Hanson * Save whether asru is accessible in local domain
140725c6ff4bSstephh */
1408cbf75e67SStephen Hanson if (entryp->fasp_proxy_asru[*entryp->fasp_countp]) {
1409cbf75e67SStephen Hanson alp->al_flags |= FMD_ASRU_PROXY_WITH_ASRU;
1410cbf75e67SStephen Hanson alp->al_asru->asru_flags |= FMD_ASRU_PROXY_WITH_ASRU;
1411cbf75e67SStephen Hanson }
1412cbf75e67SStephen Hanson (*entryp->fasp_countp)++;
1413cbf75e67SStephen Hanson }
1414cbf75e67SStephen Hanson
1415cbf75e67SStephen Hanson /*ARGSUSED*/
1416cbf75e67SStephen Hanson void
fmd_asru_update_containees(fmd_asru_link_t * alp,void * arg)1417cbf75e67SStephen Hanson fmd_asru_update_containees(fmd_asru_link_t *alp, void *arg)
1418cbf75e67SStephen Hanson {
1419cbf75e67SStephen Hanson fmd_asru_do_repair_containees(alp, alp->al_reason);
1420cbf75e67SStephen Hanson }
1421cbf75e67SStephen Hanson
1422cbf75e67SStephen Hanson /*
1423cbf75e67SStephen Hanson * This function is used for fault proxying. It updates the resource status in
1424cbf75e67SStephen Hanson * the resource cache based on information that has come from the other side of
1425cbf75e67SStephen Hanson * the transport. This can be called on either the proxy side or the
1426cbf75e67SStephen Hanson * diagnosing side.
1427cbf75e67SStephen Hanson */
1428cbf75e67SStephen Hanson void
fmd_asru_update_status(fmd_asru_link_t * alp,void * arg)1429cbf75e67SStephen Hanson fmd_asru_update_status(fmd_asru_link_t *alp, void *arg)
1430cbf75e67SStephen Hanson {
1431cbf75e67SStephen Hanson fmd_asru_update_status_t *entryp = (fmd_asru_update_status_t *)arg;
1432cbf75e67SStephen Hanson uint8_t status;
1433cbf75e67SStephen Hanson
1434cbf75e67SStephen Hanson if (*entryp->faus_countp >= entryp->faus_maxcount)
1435cbf75e67SStephen Hanson return;
1436cbf75e67SStephen Hanson
1437cbf75e67SStephen Hanson status = entryp->faus_ba[*entryp->faus_countp];
1438cbf75e67SStephen Hanson
1439cbf75e67SStephen Hanson /*
1440cbf75e67SStephen Hanson * For proxy, if there is no asru on the proxy side, but there is on
1441cbf75e67SStephen Hanson * the diag side, then take the diag side asru status.
1442cbf75e67SStephen Hanson * For diag, if there is an asru on the proxy side, then take the proxy
1443cbf75e67SStephen Hanson * side asru status.
1444cbf75e67SStephen Hanson */
1445cbf75e67SStephen Hanson if (entryp->faus_is_proxy ?
1446cbf75e67SStephen Hanson (entryp->faus_diag_asru[*entryp->faus_countp] &&
1447cbf75e67SStephen Hanson !entryp->faus_proxy_asru[*entryp->faus_countp]) :
1448cbf75e67SStephen Hanson entryp->faus_proxy_asru[*entryp->faus_countp]) {
1449cbf75e67SStephen Hanson if (status & FM_SUSPECT_DEGRADED)
1450cbf75e67SStephen Hanson alp->al_flags |= FMD_ASRU_DEGRADED;
1451cbf75e67SStephen Hanson else
1452cbf75e67SStephen Hanson alp->al_flags &= ~FMD_ASRU_DEGRADED;
1453cbf75e67SStephen Hanson if (status & FM_SUSPECT_UNUSABLE)
1454cbf75e67SStephen Hanson (void) fmd_asru_setflags(alp, FMD_ASRU_UNUSABLE);
1455cbf75e67SStephen Hanson else
1456cbf75e67SStephen Hanson (void) fmd_asru_clrflags(alp, FMD_ASRU_UNUSABLE, 0);
1457cbf75e67SStephen Hanson }
1458cbf75e67SStephen Hanson
1459cbf75e67SStephen Hanson /*
1460cbf75e67SStephen Hanson * Update the faulty status too.
1461cbf75e67SStephen Hanson */
1462cbf75e67SStephen Hanson if (!(status & FM_SUSPECT_FAULTY))
1463cbf75e67SStephen Hanson (void) fmd_asru_clrflags(alp, FMD_ASRU_FAULTY,
1464cbf75e67SStephen Hanson (status & FM_SUSPECT_REPAIRED) ? FMD_ASRU_REPAIRED :
1465cbf75e67SStephen Hanson (status & FM_SUSPECT_REPLACED) ? FMD_ASRU_REPLACED :
1466cbf75e67SStephen Hanson (status & FM_SUSPECT_ACQUITTED) ? FMD_ASRU_ACQUITTED :
1467cbf75e67SStephen Hanson FMD_ASRU_REMOVED);
1468cbf75e67SStephen Hanson else if (entryp->faus_is_proxy)
1469cbf75e67SStephen Hanson (void) fmd_asru_setflags(alp, FMD_ASRU_FAULTY);
1470cbf75e67SStephen Hanson
1471cbf75e67SStephen Hanson /*
1472cbf75e67SStephen Hanson * for proxy only, update the present status too.
1473cbf75e67SStephen Hanson */
1474cbf75e67SStephen Hanson if (entryp->faus_is_proxy) {
1475cbf75e67SStephen Hanson if (!(status & FM_SUSPECT_NOT_PRESENT)) {
1476cbf75e67SStephen Hanson alp->al_flags |= FMD_ASRU_PRESENT;
1477cbf75e67SStephen Hanson alp->al_asru->asru_flags |= FMD_ASRU_PRESENT;
1478cbf75e67SStephen Hanson } else {
1479cbf75e67SStephen Hanson alp->al_flags &= ~FMD_ASRU_PRESENT;
1480cbf75e67SStephen Hanson alp->al_asru->asru_flags &= ~FMD_ASRU_PRESENT;
1481cbf75e67SStephen Hanson }
1482cbf75e67SStephen Hanson }
1483cbf75e67SStephen Hanson (*entryp->faus_countp)++;
1484cbf75e67SStephen Hanson }
1485cbf75e67SStephen Hanson
1486cbf75e67SStephen Hanson /*
1487cbf75e67SStephen Hanson * This function is called on the diagnosing side when fault proxying is
1488cbf75e67SStephen Hanson * in use and the proxy has sent a uuclose. It updates the status of the
1489cbf75e67SStephen Hanson * resource cache entries.
1490cbf75e67SStephen Hanson */
1491cbf75e67SStephen Hanson void
fmd_asru_close_status(fmd_asru_link_t * alp,void * arg)1492cbf75e67SStephen Hanson fmd_asru_close_status(fmd_asru_link_t *alp, void *arg)
1493cbf75e67SStephen Hanson {
1494cbf75e67SStephen Hanson fmd_asru_close_status_t *entryp = (fmd_asru_close_status_t *)arg;
1495cbf75e67SStephen Hanson
1496cbf75e67SStephen Hanson if (*entryp->facs_countp >= entryp->facs_maxcount)
1497cbf75e67SStephen Hanson return;
1498cbf75e67SStephen Hanson alp->al_flags &= ~FMD_ASRU_DEGRADED;
1499cbf75e67SStephen Hanson (void) fmd_asru_setflags(alp, FMD_ASRU_UNUSABLE);
1500cbf75e67SStephen Hanson (*entryp->facs_countp)++;
150125c6ff4bSstephh }
150225c6ff4bSstephh
150325c6ff4bSstephh static void
fmd_asru_logevent(fmd_asru_link_t * alp)1504567cc2e6Sstephh fmd_asru_logevent(fmd_asru_link_t *alp)
1505567cc2e6Sstephh {
1506567cc2e6Sstephh fmd_asru_t *ap = alp->al_asru;
150725c6ff4bSstephh boolean_t faulty = (alp->al_flags & FMD_ASRU_FAULTY) != 0;
150825c6ff4bSstephh boolean_t unusable = (alp->al_flags & FMD_ASRU_UNUSABLE) != 0;
150925c6ff4bSstephh boolean_t message = (ap->asru_flags & FMD_ASRU_INVISIBLE) == 0;
151025c6ff4bSstephh boolean_t repaired = (alp->al_reason == FMD_ASRU_REPAIRED);
151125c6ff4bSstephh boolean_t replaced = (alp->al_reason == FMD_ASRU_REPLACED);
151225c6ff4bSstephh boolean_t acquitted = (alp->al_reason == FMD_ASRU_ACQUITTED);
15137c478bd9Sstevel@tonic-gate
1514d9638e54Smws fmd_case_impl_t *cip;
15157c478bd9Sstevel@tonic-gate fmd_event_t *e;
15167c478bd9Sstevel@tonic-gate fmd_log_t *lp;
15177c478bd9Sstevel@tonic-gate nvlist_t *nvl;
15187c478bd9Sstevel@tonic-gate char *class;
15197c478bd9Sstevel@tonic-gate
15207c478bd9Sstevel@tonic-gate ASSERT(MUTEX_HELD(&ap->asru_lock));
1521567cc2e6Sstephh cip = (fmd_case_impl_t *)alp->al_case;
152244743693Sstephh ASSERT(cip != NULL);
15237c478bd9Sstevel@tonic-gate
1524cbf75e67SStephen Hanson /*
1525cbf75e67SStephen Hanson * Don't log to disk on proxy side
1526cbf75e67SStephen Hanson */
1527cbf75e67SStephen Hanson if (cip->ci_xprt != NULL)
1528cbf75e67SStephen Hanson return;
1529cbf75e67SStephen Hanson
1530567cc2e6Sstephh if ((lp = alp->al_log) == NULL)
1531567cc2e6Sstephh lp = fmd_log_open(ap->asru_root, alp->al_uuid, FMD_LOG_ASRU);
15327c478bd9Sstevel@tonic-gate
15337c478bd9Sstevel@tonic-gate if (lp == NULL)
15347c478bd9Sstevel@tonic-gate return; /* can't log events if we can't open the log */
15357c478bd9Sstevel@tonic-gate
153625c6ff4bSstephh nvl = fmd_protocol_rsrc_asru(_fmd_asru_events[faulty | (unusable << 1)],
153725c6ff4bSstephh alp->al_asru_fmri, cip->ci_uuid, cip->ci_code, faulty, unusable,
1538cbf75e67SStephen Hanson message, alp->al_event, &cip->ci_tv, repaired, replaced, acquitted,
15395750ef5cSStephen Hanson cip->ci_state == FMD_CASE_RESOLVED, cip->ci_diag_de == NULL ?
1540540db9a9SStephen Hanson cip->ci_mod->mod_fmri : cip->ci_diag_de, cip->ci_injected == 1);
15417c478bd9Sstevel@tonic-gate
15427c478bd9Sstevel@tonic-gate (void) nvlist_lookup_string(nvl, FM_CLASS, &class);
15437c478bd9Sstevel@tonic-gate e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class);
15447c478bd9Sstevel@tonic-gate
15457c478bd9Sstevel@tonic-gate fmd_event_hold(e);
15467c478bd9Sstevel@tonic-gate fmd_log_append(lp, e, NULL);
15477c478bd9Sstevel@tonic-gate fmd_event_rele(e);
15487c478bd9Sstevel@tonic-gate
15497c478bd9Sstevel@tonic-gate /*
15507c478bd9Sstevel@tonic-gate * For now, we close the log file after every update to conserve file
15517c478bd9Sstevel@tonic-gate * descriptors and daemon overhead. If this becomes a performance
15527c478bd9Sstevel@tonic-gate * issue this code can change to keep a fixed-size LRU cache of logs.
15537c478bd9Sstevel@tonic-gate */
15547c478bd9Sstevel@tonic-gate fmd_log_rele(lp);
1555567cc2e6Sstephh alp->al_log = NULL;
15567c478bd9Sstevel@tonic-gate }
15577c478bd9Sstevel@tonic-gate
15587c478bd9Sstevel@tonic-gate int
fmd_asru_setflags(fmd_asru_link_t * alp,uint_t sflag)1559567cc2e6Sstephh fmd_asru_setflags(fmd_asru_link_t *alp, uint_t sflag)
15607c478bd9Sstevel@tonic-gate {
1561567cc2e6Sstephh fmd_asru_t *ap = alp->al_asru;
15627c478bd9Sstevel@tonic-gate uint_t nstate, ostate;
15637c478bd9Sstevel@tonic-gate
15647c478bd9Sstevel@tonic-gate ASSERT(!(sflag & ~FMD_ASRU_STATE));
15657c478bd9Sstevel@tonic-gate ASSERT(sflag != FMD_ASRU_STATE);
15667c478bd9Sstevel@tonic-gate
15677c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ap->asru_lock);
15687c478bd9Sstevel@tonic-gate
1569567cc2e6Sstephh ostate = alp->al_flags & FMD_ASRU_STATE;
1570567cc2e6Sstephh alp->al_flags |= sflag;
1571567cc2e6Sstephh nstate = alp->al_flags & FMD_ASRU_STATE;
1572567cc2e6Sstephh
1573567cc2e6Sstephh if (nstate == ostate) {
1574567cc2e6Sstephh (void) pthread_mutex_unlock(&ap->asru_lock);
1575567cc2e6Sstephh return (0);
1576567cc2e6Sstephh }
1577567cc2e6Sstephh
15787c478bd9Sstevel@tonic-gate ap->asru_flags |= sflag;
1579567cc2e6Sstephh TRACE((FMD_DBG_ASRU, "asru %s %s->%s", alp->al_uuid,
15807c478bd9Sstevel@tonic-gate _fmd_asru_snames[ostate], _fmd_asru_snames[nstate]));
15817c478bd9Sstevel@tonic-gate
1582567cc2e6Sstephh fmd_asru_logevent(alp);
1583d9638e54Smws
15847c478bd9Sstevel@tonic-gate (void) pthread_cond_broadcast(&ap->asru_cv);
1585d9638e54Smws (void) pthread_mutex_unlock(&ap->asru_lock);
15867c478bd9Sstevel@tonic-gate return (1);
15877c478bd9Sstevel@tonic-gate }
15887c478bd9Sstevel@tonic-gate
15897c478bd9Sstevel@tonic-gate int
fmd_asru_clrflags(fmd_asru_link_t * alp,uint_t sflag,uint8_t reason)159025c6ff4bSstephh fmd_asru_clrflags(fmd_asru_link_t *alp, uint_t sflag, uint8_t reason)
15917c478bd9Sstevel@tonic-gate {
1592567cc2e6Sstephh fmd_asru_t *ap = alp->al_asru;
1593567cc2e6Sstephh fmd_asru_link_t *nalp;
1594567cc2e6Sstephh uint_t nstate, ostate, flags = 0;
15957c478bd9Sstevel@tonic-gate
15967c478bd9Sstevel@tonic-gate ASSERT(!(sflag & ~FMD_ASRU_STATE));
15977c478bd9Sstevel@tonic-gate ASSERT(sflag != FMD_ASRU_STATE);
15987c478bd9Sstevel@tonic-gate
15997c478bd9Sstevel@tonic-gate (void) pthread_mutex_lock(&ap->asru_lock);
16007c478bd9Sstevel@tonic-gate
1601567cc2e6Sstephh ostate = alp->al_flags & FMD_ASRU_STATE;
1602567cc2e6Sstephh alp->al_flags &= ~sflag;
1603567cc2e6Sstephh nstate = alp->al_flags & FMD_ASRU_STATE;
16047c478bd9Sstevel@tonic-gate
1605d9638e54Smws if (nstate == ostate) {
16065750ef5cSStephen Hanson if (reason > alp->al_reason &&
16075750ef5cSStephen Hanson ((fmd_case_impl_t *)alp->al_case)->ci_state <
16085750ef5cSStephen Hanson FMD_CASE_REPAIRED) {
160925c6ff4bSstephh alp->al_reason = reason;
161025c6ff4bSstephh fmd_asru_logevent(alp);
161125c6ff4bSstephh (void) pthread_cond_broadcast(&ap->asru_cv);
161225c6ff4bSstephh }
1613d9638e54Smws (void) pthread_mutex_unlock(&ap->asru_lock);
1614d9638e54Smws return (0);
16157c478bd9Sstevel@tonic-gate }
161625c6ff4bSstephh if (reason > alp->al_reason)
161725c6ff4bSstephh alp->al_reason = reason;
16187c478bd9Sstevel@tonic-gate
1619567cc2e6Sstephh if (sflag == FMD_ASRU_UNUSABLE)
1620567cc2e6Sstephh ap->asru_flags &= ~sflag;
1621567cc2e6Sstephh else if (sflag == FMD_ASRU_FAULTY) {
1622567cc2e6Sstephh /*
1623567cc2e6Sstephh * only clear the faulty bit if all links are clear
1624567cc2e6Sstephh */
1625567cc2e6Sstephh for (nalp = fmd_list_next(&ap->asru_list); nalp != NULL;
1626567cc2e6Sstephh nalp = fmd_list_next(nalp))
1627567cc2e6Sstephh flags |= nalp->al_flags;
1628567cc2e6Sstephh if (!(flags & FMD_ASRU_FAULTY))
1629567cc2e6Sstephh ap->asru_flags &= ~sflag;
1630d9638e54Smws }
1631d9638e54Smws
1632567cc2e6Sstephh TRACE((FMD_DBG_ASRU, "asru %s %s->%s", alp->al_uuid,
16337c478bd9Sstevel@tonic-gate _fmd_asru_snames[ostate], _fmd_asru_snames[nstate]));
1634d9638e54Smws
1635567cc2e6Sstephh fmd_asru_logevent(alp);
16367c478bd9Sstevel@tonic-gate
1637d9638e54Smws (void) pthread_cond_broadcast(&ap->asru_cv);
16387c478bd9Sstevel@tonic-gate (void) pthread_mutex_unlock(&ap->asru_lock);
1639d9638e54Smws
1640567cc2e6Sstephh return (1);
1641d9638e54Smws }
1642d9638e54Smws
16435750ef5cSStephen Hanson /*ARGSUSED*/
16445750ef5cSStephen Hanson void
fmd_asru_log_resolved(fmd_asru_link_t * alp,void * unused)16455750ef5cSStephen Hanson fmd_asru_log_resolved(fmd_asru_link_t *alp, void *unused)
16465750ef5cSStephen Hanson {
16475750ef5cSStephen Hanson fmd_asru_t *ap = alp->al_asru;
16485750ef5cSStephen Hanson
16495750ef5cSStephen Hanson (void) pthread_mutex_lock(&ap->asru_lock);
16505750ef5cSStephen Hanson fmd_asru_logevent(alp);
16515750ef5cSStephen Hanson (void) pthread_cond_broadcast(&ap->asru_cv);
16525750ef5cSStephen Hanson (void) pthread_mutex_unlock(&ap->asru_lock);
16535750ef5cSStephen Hanson }
16545750ef5cSStephen Hanson
1655567cc2e6Sstephh /*
1656567cc2e6Sstephh * Report the current known state of the link entry (ie this particular fault
1657567cc2e6Sstephh * affecting this particular ASRU).
1658567cc2e6Sstephh */
1659567cc2e6Sstephh int
fmd_asru_al_getstate(fmd_asru_link_t * alp)1660567cc2e6Sstephh fmd_asru_al_getstate(fmd_asru_link_t *alp)
1661567cc2e6Sstephh {
1662cbf75e67SStephen Hanson int us, st = (alp->al_flags & (FMD_ASRU_FAULTY | FMD_ASRU_UNUSABLE));
1663567cc2e6Sstephh nvlist_t *asru;
1664cbf75e67SStephen Hanson int ps = FMD_OBJ_STATE_UNKNOWN;
1665162ba6eaSmws
1666cbf75e67SStephen Hanson /*
1667cbf75e67SStephen Hanson * For fault proxying with an EXTERNAL transport, believe the presence
1668cbf75e67SStephen Hanson * state as sent by the diagnosing side. Otherwise find the presence
1669cbf75e67SStephen Hanson * state here. Note that if fault proxying with an INTERNAL transport
1670cbf75e67SStephen Hanson * we can only trust the presence state where we are using hc-scheme
1671cbf75e67SStephen Hanson * fmris which should be consistant across domains in the same system -
1672cbf75e67SStephen Hanson * other schemes can refer to different devices in different domains.
1673cbf75e67SStephen Hanson */
1674cbf75e67SStephen Hanson if (!(alp->al_flags & FMD_ASRU_PROXY_EXTERNAL)) {
1675cbf75e67SStephen Hanson ps = fmd_asru_replacement_state(alp->al_event, (alp->al_flags &
1676cbf75e67SStephen Hanson FMD_ASRU_PROXY)? HC_ONLY_TRUE : HC_ONLY_FALSE);
167725c6ff4bSstephh if (ps == FMD_OBJ_STATE_NOT_PRESENT)
1678cbf75e67SStephen Hanson return (st | FMD_ASRU_UNUSABLE);
167925c6ff4bSstephh if (ps == FMD_OBJ_STATE_REPLACED) {
168025c6ff4bSstephh if (alp->al_reason < FMD_ASRU_REPLACED)
168125c6ff4bSstephh alp->al_reason = FMD_ASRU_REPLACED;
1682cbf75e67SStephen Hanson return (st | FMD_ASRU_UNUSABLE);
168325c6ff4bSstephh }
1684cbf75e67SStephen Hanson }
1685cbf75e67SStephen Hanson if (ps == FMD_OBJ_STATE_UNKNOWN && (alp->al_flags & FMD_ASRU_PROXY))
1686cbf75e67SStephen Hanson st |= (alp->al_flags & (FMD_ASRU_DEGRADED | FMD_ASRU_PRESENT));
1687cbf75e67SStephen Hanson else
1688cbf75e67SStephen Hanson st |= (alp->al_flags & (FMD_ASRU_DEGRADED)) | FMD_ASRU_PRESENT;
1689567cc2e6Sstephh
1690cbf75e67SStephen Hanson /*
1691cbf75e67SStephen Hanson * For fault proxying, unless we have a local ASRU, then believe the
1692cbf75e67SStephen Hanson * service state sent by the diagnosing side. Otherwise find the service
1693cbf75e67SStephen Hanson * state here. Try fmd_fmri_service_state() first, but if that's not
1694cbf75e67SStephen Hanson * supported by the scheme then fall back to fmd_fmri_unusable().
1695cbf75e67SStephen Hanson */
1696cbf75e67SStephen Hanson if ((!(alp->al_flags & FMD_ASRU_PROXY) ||
1697cbf75e67SStephen Hanson (alp->al_flags & FMD_ASRU_PROXY_WITH_ASRU)) &&
1698cbf75e67SStephen Hanson nvlist_lookup_nvlist(alp->al_event, FM_FAULT_ASRU, &asru) == 0) {
169925c6ff4bSstephh us = fmd_fmri_service_state(asru);
170025c6ff4bSstephh if (us == -1 || us == FMD_SERVICE_STATE_UNKNOWN) {
170125c6ff4bSstephh /* not supported by scheme - try fmd_fmri_unusable */
170225c6ff4bSstephh us = fmd_fmri_unusable(asru);
1703567cc2e6Sstephh if (us > 0)
1704567cc2e6Sstephh st |= FMD_ASRU_UNUSABLE;
1705567cc2e6Sstephh else if (us == 0)
1706567cc2e6Sstephh st &= ~FMD_ASRU_UNUSABLE;
1707cbf75e67SStephen Hanson } else {
1708cbf75e67SStephen Hanson if (us == FMD_SERVICE_STATE_UNUSABLE) {
1709cbf75e67SStephen Hanson st &= ~FMD_ASRU_DEGRADED;
1710cbf75e67SStephen Hanson st |= FMD_ASRU_UNUSABLE;
1711cbf75e67SStephen Hanson } else if (us == FMD_SERVICE_STATE_OK) {
1712cbf75e67SStephen Hanson st &= ~(FMD_ASRU_DEGRADED | FMD_ASRU_UNUSABLE);
1713cbf75e67SStephen Hanson } else if (us == FMD_SERVICE_STATE_ISOLATE_PENDING) {
1714cbf75e67SStephen Hanson st &= ~(FMD_ASRU_DEGRADED | FMD_ASRU_UNUSABLE);
1715cbf75e67SStephen Hanson } else if (us == FMD_SERVICE_STATE_DEGRADED) {
1716cbf75e67SStephen Hanson st &= ~FMD_ASRU_UNUSABLE;
1717cbf75e67SStephen Hanson st |= FMD_ASRU_DEGRADED;
1718cbf75e67SStephen Hanson }
1719cbf75e67SStephen Hanson }
1720cbf75e67SStephen Hanson }
1721567cc2e6Sstephh return (st);
17227c478bd9Sstevel@tonic-gate }
17237c478bd9Sstevel@tonic-gate
17247c478bd9Sstevel@tonic-gate /*
17257c478bd9Sstevel@tonic-gate * Report the current known state of the ASRU by refreshing its unusable status
17267c478bd9Sstevel@tonic-gate * based upon the routines provided by the scheme module. If the unusable bit
17277c478bd9Sstevel@tonic-gate * is different, we do *not* generate a state change here because that change
17287c478bd9Sstevel@tonic-gate * may be unrelated to fmd activities and therefore we have no case or event.
17297c478bd9Sstevel@tonic-gate * The absence of the transition is harmless as this function is only provided
17307c478bd9Sstevel@tonic-gate * for RPC observability and fmd's clients are only concerned with ASRU_FAULTY.
17317c478bd9Sstevel@tonic-gate */
17327c478bd9Sstevel@tonic-gate int
fmd_asru_getstate(fmd_asru_t * ap)17337c478bd9Sstevel@tonic-gate fmd_asru_getstate(fmd_asru_t *ap)
17347c478bd9Sstevel@tonic-gate {
1735cbf75e67SStephen Hanson int us, st, p = -1;
1736cbf75e67SStephen Hanson char *s;
17377c478bd9Sstevel@tonic-gate
1738cbf75e67SStephen Hanson /* do not report non-fmd non-present resources */
1739cbf75e67SStephen Hanson if (!(ap->asru_flags & FMD_ASRU_INTERNAL)) {
1740cbf75e67SStephen Hanson /*
1741cbf75e67SStephen Hanson * As with fmd_asru_al_getstate(), we can only trust the
1742cbf75e67SStephen Hanson * local presence state on a proxy if the transport is
1743cbf75e67SStephen Hanson * internal and the scheme is hc. Otherwise we believe the
1744cbf75e67SStephen Hanson * state as sent by the diagnosing side.
1745cbf75e67SStephen Hanson */
1746cbf75e67SStephen Hanson if (!(ap->asru_flags & FMD_ASRU_PROXY) ||
1747cbf75e67SStephen Hanson (!(ap->asru_flags & FMD_ASRU_PROXY_EXTERNAL) &&
1748cbf75e67SStephen Hanson (nvlist_lookup_string(ap->asru_fmri, FM_FMRI_SCHEME,
1749cbf75e67SStephen Hanson &s) == 0 && strcmp(s, FM_FMRI_SCHEME_HC) == 0))) {
1750cbf75e67SStephen Hanson if (fmd_asru_fake_not_present >=
1751cbf75e67SStephen Hanson FMD_OBJ_STATE_REPLACED)
1752cbf75e67SStephen Hanson return (0);
1753cbf75e67SStephen Hanson p = fmd_fmri_present(ap->asru_fmri);
1754cbf75e67SStephen Hanson }
1755cbf75e67SStephen Hanson if (p == 0 || (p < 0 && !(ap->asru_flags & FMD_ASRU_PROXY) ||
1756cbf75e67SStephen Hanson !(ap->asru_flags & FMD_ASRU_PRESENT)))
1757cbf75e67SStephen Hanson return (0);
1758cbf75e67SStephen Hanson }
17597c478bd9Sstevel@tonic-gate
1760cbf75e67SStephen Hanson /*
1761cbf75e67SStephen Hanson * As with fmd_asru_al_getstate(), we can only trust the local unusable
1762cbf75e67SStephen Hanson * state on a proxy if there is a local ASRU.
1763cbf75e67SStephen Hanson */
1764cbf75e67SStephen Hanson st = ap->asru_flags & (FMD_ASRU_FAULTY | FMD_ASRU_UNUSABLE);
1765cbf75e67SStephen Hanson if (!(ap->asru_flags & FMD_ASRU_PROXY) ||
1766cbf75e67SStephen Hanson (ap->asru_flags & FMD_ASRU_PROXY_WITH_ASRU)) {
17677c478bd9Sstevel@tonic-gate us = fmd_fmri_unusable(ap->asru_fmri);
17687c478bd9Sstevel@tonic-gate if (us > 0)
17697c478bd9Sstevel@tonic-gate st |= FMD_ASRU_UNUSABLE;
17707c478bd9Sstevel@tonic-gate else if (us == 0)
17717c478bd9Sstevel@tonic-gate st &= ~FMD_ASRU_UNUSABLE;
1772cbf75e67SStephen Hanson }
17737c478bd9Sstevel@tonic-gate return (st);
17747c478bd9Sstevel@tonic-gate }
1775