xref: /illumos-gate/usr/src/cmd/fm/fmd/common/fmd_asru.c (revision 705e9f42)
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