xref: /onnv-gate/usr/src/cmd/fm/fmd/common/fmd_asru.c (revision 11416:c13e2db06244)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
55255Sstephh  * Common Development and Distribution License (the "License").
65255Sstephh  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211193Smws 
220Sstevel@tonic-gate /*
23*11416SStephen.Hanson@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #include <sys/fm/protocol.h>
280Sstevel@tonic-gate #include <uuid/uuid.h>
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <dirent.h>
310Sstevel@tonic-gate #include <limits.h>
320Sstevel@tonic-gate #include <unistd.h>
330Sstevel@tonic-gate #include <alloca.h>
346228Sstephh #include <stddef.h>
356869Seschrock #include <fm/libtopo.h>
360Sstevel@tonic-gate 
370Sstevel@tonic-gate #include <fmd_alloc.h>
380Sstevel@tonic-gate #include <fmd_string.h>
390Sstevel@tonic-gate #include <fmd_error.h>
400Sstevel@tonic-gate #include <fmd_subr.h>
410Sstevel@tonic-gate #include <fmd_protocol.h>
420Sstevel@tonic-gate #include <fmd_event.h>
430Sstevel@tonic-gate #include <fmd_conf.h>
440Sstevel@tonic-gate #include <fmd_fmri.h>
450Sstevel@tonic-gate #include <fmd_dispq.h>
461193Smws #include <fmd_case.h>
471193Smws #include <fmd_module.h>
480Sstevel@tonic-gate #include <fmd_asru.h>
490Sstevel@tonic-gate 
500Sstevel@tonic-gate #include <fmd.h>
510Sstevel@tonic-gate 
520Sstevel@tonic-gate static const char *const _fmd_asru_events[] = {
531193Smws 	FMD_RSRC_CLASS "asru.ok",		/* UNUSABLE=0 FAULTED=0 */
541193Smws 	FMD_RSRC_CLASS "asru.degraded",		/* UNUSABLE=0 FAULTED=1 */
551193Smws 	FMD_RSRC_CLASS "asru.unknown",		/* UNUSABLE=1 FAULTED=0 */
561193Smws 	FMD_RSRC_CLASS "asru.faulted"		/* UNUSABLE=1 FAULTED=1 */
570Sstevel@tonic-gate };
580Sstevel@tonic-gate 
590Sstevel@tonic-gate static const char *const _fmd_asru_snames[] = {
600Sstevel@tonic-gate 	"uf", "uF", "Uf", "UF"			/* same order as above */
610Sstevel@tonic-gate };
620Sstevel@tonic-gate 
635255Sstephh volatile uint32_t fmd_asru_fake_not_present = 0;
645255Sstephh 
656869Seschrock static uint_t
fmd_asru_strhash(fmd_asru_hash_t * ahp,const char * val)666869Seschrock fmd_asru_strhash(fmd_asru_hash_t *ahp, const char *val)
676869Seschrock {
686869Seschrock 	return (topo_fmri_strhash(ahp->ah_topo->ft_hdl, val) % ahp->ah_hashlen);
696869Seschrock }
706869Seschrock 
716869Seschrock static boolean_t
fmd_asru_strcmp(fmd_asru_hash_t * ahp,const char * a,const char * b)726869Seschrock fmd_asru_strcmp(fmd_asru_hash_t *ahp, const char *a, const char *b)
736869Seschrock {
746869Seschrock 	return (topo_fmri_strcmp(ahp->ah_topo->ft_hdl, a, b));
756869Seschrock }
766869Seschrock 
770Sstevel@tonic-gate static fmd_asru_t *
fmd_asru_create(fmd_asru_hash_t * ahp,const char * uuid,const char * name,nvlist_t * fmri)780Sstevel@tonic-gate fmd_asru_create(fmd_asru_hash_t *ahp, const char *uuid,
790Sstevel@tonic-gate     const char *name, nvlist_t *fmri)
800Sstevel@tonic-gate {
816228Sstephh 	fmd_asru_t *ap = fmd_zalloc(sizeof (fmd_asru_t), FMD_SLEEP);
820Sstevel@tonic-gate 	char *s;
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 	(void) pthread_mutex_init(&ap->asru_lock, NULL);
850Sstevel@tonic-gate 	(void) pthread_cond_init(&ap->asru_cv, NULL);
860Sstevel@tonic-gate 
870Sstevel@tonic-gate 	ap->asru_name = fmd_strdup(name, FMD_SLEEP);
886228Sstephh 	if (fmri)
896228Sstephh 		(void) nvlist_xdup(fmri, &ap->asru_fmri, &fmd.d_nva);
900Sstevel@tonic-gate 	ap->asru_root = fmd_strdup(ahp->ah_dirpath, FMD_SLEEP);
910Sstevel@tonic-gate 	ap->asru_uuid = fmd_strdup(uuid, FMD_SLEEP);
920Sstevel@tonic-gate 	ap->asru_uuidlen = ap->asru_uuid ? strlen(ap->asru_uuid) : 0;
930Sstevel@tonic-gate 	ap->asru_refs = 1;
940Sstevel@tonic-gate 
956228Sstephh 	if (fmri && nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &s) == 0 &&
960Sstevel@tonic-gate 	    strcmp(s, FM_FMRI_SCHEME_FMD) == 0)
970Sstevel@tonic-gate 		ap->asru_flags |= FMD_ASRU_INTERNAL;
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	return (ap);
1000Sstevel@tonic-gate }
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate static void
fmd_asru_destroy(fmd_asru_t * ap)1030Sstevel@tonic-gate fmd_asru_destroy(fmd_asru_t *ap)
1040Sstevel@tonic-gate {
1050Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ap->asru_lock));
1060Sstevel@tonic-gate 	ASSERT(ap->asru_refs == 0);
1070Sstevel@tonic-gate 
1081552Smws 	nvlist_free(ap->asru_event);
1090Sstevel@tonic-gate 	fmd_strfree(ap->asru_name);
1100Sstevel@tonic-gate 	nvlist_free(ap->asru_fmri);
1110Sstevel@tonic-gate 	fmd_strfree(ap->asru_root);
1120Sstevel@tonic-gate 	fmd_free(ap->asru_uuid, ap->asru_uuidlen + 1);
1130Sstevel@tonic-gate 	fmd_free(ap, sizeof (fmd_asru_t));
1140Sstevel@tonic-gate }
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate static void
fmd_asru_hash_insert(fmd_asru_hash_t * ahp,fmd_asru_t * ap)1170Sstevel@tonic-gate fmd_asru_hash_insert(fmd_asru_hash_t *ahp, fmd_asru_t *ap)
1180Sstevel@tonic-gate {
1196869Seschrock 	uint_t h = fmd_asru_strhash(ahp, ap->asru_name);
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	ASSERT(RW_WRITE_HELD(&ahp->ah_lock));
1220Sstevel@tonic-gate 	ap->asru_next = ahp->ah_hash[h];
1230Sstevel@tonic-gate 	ahp->ah_hash[h] = ap;
1240Sstevel@tonic-gate 	ahp->ah_count++;
1250Sstevel@tonic-gate }
1260Sstevel@tonic-gate 
1270Sstevel@tonic-gate static fmd_asru_t *
fmd_asru_hold(fmd_asru_t * ap)1280Sstevel@tonic-gate fmd_asru_hold(fmd_asru_t *ap)
1290Sstevel@tonic-gate {
1300Sstevel@tonic-gate 	(void) pthread_mutex_lock(&ap->asru_lock);
1310Sstevel@tonic-gate 	ap->asru_refs++;
1320Sstevel@tonic-gate 	ASSERT(ap->asru_refs != 0);
1330Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&ap->asru_lock);
1340Sstevel@tonic-gate 	return (ap);
1350Sstevel@tonic-gate }
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate /*
1380Sstevel@tonic-gate  * Lookup an asru in the hash by name and place a hold on it.  If the asru is
1390Sstevel@tonic-gate  * not found, no entry is created and NULL is returned.  This internal function
1400Sstevel@tonic-gate  * is for callers who have the ah_lock held and is used by lookup_name below.
1410Sstevel@tonic-gate  */
1420Sstevel@tonic-gate fmd_asru_t *
fmd_asru_hash_lookup(fmd_asru_hash_t * ahp,const char * name)1430Sstevel@tonic-gate fmd_asru_hash_lookup(fmd_asru_hash_t *ahp, const char *name)
1440Sstevel@tonic-gate {
1450Sstevel@tonic-gate 	fmd_asru_t *ap;
1460Sstevel@tonic-gate 	uint_t h;
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	ASSERT(RW_LOCK_HELD(&ahp->ah_lock));
1496869Seschrock 	h = fmd_asru_strhash(ahp, name);
1500Sstevel@tonic-gate 
1510Sstevel@tonic-gate 	for (ap = ahp->ah_hash[h]; ap != NULL; ap = ap->asru_next) {
1526869Seschrock 		if (fmd_asru_strcmp(ahp, ap->asru_name, name))
1530Sstevel@tonic-gate 			break;
1540Sstevel@tonic-gate 	}
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 	if (ap != NULL)
1570Sstevel@tonic-gate 		(void) fmd_asru_hold(ap);
1580Sstevel@tonic-gate 	else
1590Sstevel@tonic-gate 		(void) fmd_set_errno(EFMD_ASRU_NOENT);
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	return (ap);
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate 
1649120SStephen.Hanson@Sun.COM #define	HC_ONLY_FALSE	0
1659120SStephen.Hanson@Sun.COM #define	HC_ONLY_TRUE	1
1669120SStephen.Hanson@Sun.COM 
1676228Sstephh static int
fmd_asru_replacement_state(nvlist_t * event,int hc_only)1689120SStephen.Hanson@Sun.COM fmd_asru_replacement_state(nvlist_t *event, int hc_only)
1696228Sstephh {
1706228Sstephh 	int ps = -1;
1716228Sstephh 	nvlist_t *asru, *fru, *rsrc;
1729120SStephen.Hanson@Sun.COM 	char *s;
1736228Sstephh 
1746228Sstephh 	/*
1756228Sstephh 	 * Check if there is evidence that this object is no longer present.
1766228Sstephh 	 * In general fmd_fmri_present() should be supported on resources and/or
1776228Sstephh 	 * frus, as those are the things that are physically present or not
1786228Sstephh 	 * present - an asru can be spread over a number of frus some of which
1796228Sstephh 	 * are present and some not, so fmd_fmri_present() is not generally
1806228Sstephh 	 * meaningful. However retain a check for asru first for compatibility.
1816228Sstephh 	 * If we have checked all three and we still get -1 then nothing knows
1826228Sstephh 	 * whether it's present or not, so err on the safe side and treat it
1836228Sstephh 	 * as still present.
1849120SStephen.Hanson@Sun.COM 	 *
1859120SStephen.Hanson@Sun.COM 	 * Note that if hc_only is set, then we only check status using fmris
1869120SStephen.Hanson@Sun.COM 	 * that are in hc-scheme.
1876228Sstephh 	 */
1886228Sstephh 	if (fmd_asru_fake_not_present)
1897275Sstephh 		return (fmd_asru_fake_not_present);
1909120SStephen.Hanson@Sun.COM 	if (nvlist_lookup_nvlist(event, FM_FAULT_ASRU, &asru) == 0 &&
1919120SStephen.Hanson@Sun.COM 	    (hc_only == HC_ONLY_FALSE || (nvlist_lookup_string(asru,
1929120SStephen.Hanson@Sun.COM 	    FM_FMRI_SCHEME, &s) == 0 && strcmp(s, FM_FMRI_SCHEME_HC) == 0)))
1937275Sstephh 		ps = fmd_fmri_replaced(asru);
1949120SStephen.Hanson@Sun.COM 	if (ps == -1 || ps == FMD_OBJ_STATE_UNKNOWN) {
1957275Sstephh 		if (nvlist_lookup_nvlist(event, FM_FAULT_RESOURCE,
1969120SStephen.Hanson@Sun.COM 		    &rsrc) == 0 && (hc_only == HC_ONLY_FALSE ||
1979120SStephen.Hanson@Sun.COM 		    (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &s) == 0 &&
1989120SStephen.Hanson@Sun.COM 		    strcmp(s, FM_FMRI_SCHEME_HC) == 0))) {
1999120SStephen.Hanson@Sun.COM 			if (ps == -1) {
2009120SStephen.Hanson@Sun.COM 				ps = fmd_fmri_replaced(rsrc);
2019120SStephen.Hanson@Sun.COM 			} else {
2029120SStephen.Hanson@Sun.COM 				/* see if we can improve on UNKNOWN */
2039120SStephen.Hanson@Sun.COM 				int ps2 = fmd_fmri_replaced(rsrc);
2049120SStephen.Hanson@Sun.COM 				if (ps2 == FMD_OBJ_STATE_STILL_PRESENT ||
2059120SStephen.Hanson@Sun.COM 				    ps2 == FMD_OBJ_STATE_REPLACED)
2069120SStephen.Hanson@Sun.COM 					ps = ps2;
2079120SStephen.Hanson@Sun.COM 			}
2087275Sstephh 		}
2097275Sstephh 	}
2109120SStephen.Hanson@Sun.COM 	if (ps == -1 || ps == FMD_OBJ_STATE_UNKNOWN) {
2119120SStephen.Hanson@Sun.COM 		if (nvlist_lookup_nvlist(event, FM_FAULT_FRU, &fru) == 0 &&
2129120SStephen.Hanson@Sun.COM 		    (hc_only == HC_ONLY_FALSE || (nvlist_lookup_string(fru,
2139120SStephen.Hanson@Sun.COM 		    FM_FMRI_SCHEME, &s) == 0 &&
2149120SStephen.Hanson@Sun.COM 		    strcmp(s, FM_FMRI_SCHEME_HC) == 0))) {
2159120SStephen.Hanson@Sun.COM 			if (ps == -1) {
2169120SStephen.Hanson@Sun.COM 				ps = fmd_fmri_replaced(fru);
2179120SStephen.Hanson@Sun.COM 			} else {
2189120SStephen.Hanson@Sun.COM 				/* see if we can improve on UNKNOWN */
2199120SStephen.Hanson@Sun.COM 				int ps2 = fmd_fmri_replaced(fru);
2209120SStephen.Hanson@Sun.COM 				if (ps2 == FMD_OBJ_STATE_STILL_PRESENT ||
2219120SStephen.Hanson@Sun.COM 				    ps2 == FMD_OBJ_STATE_REPLACED)
2229120SStephen.Hanson@Sun.COM 					ps = ps2;
2239120SStephen.Hanson@Sun.COM 			}
2247275Sstephh 		}
2257275Sstephh 	}
2266228Sstephh 	if (ps == -1)
2277275Sstephh 		ps = FMD_OBJ_STATE_UNKNOWN;
2286228Sstephh 	return (ps);
2296228Sstephh }
2306228Sstephh 
2316228Sstephh static void
fmd_asru_asru_hash_insert(fmd_asru_hash_t * ahp,fmd_asru_link_t * alp,char * name)2326228Sstephh fmd_asru_asru_hash_insert(fmd_asru_hash_t *ahp, fmd_asru_link_t *alp,
2336228Sstephh     char *name)
2346228Sstephh {
2356869Seschrock 	uint_t h = fmd_asru_strhash(ahp, name);
2366228Sstephh 
2376228Sstephh 	ASSERT(RW_WRITE_HELD(&ahp->ah_lock));
2386228Sstephh 	alp->al_asru_next = ahp->ah_asru_hash[h];
2396228Sstephh 	ahp->ah_asru_hash[h] = alp;
2406228Sstephh 	ahp->ah_al_count++;
2416228Sstephh }
2426228Sstephh 
2436228Sstephh static void
fmd_asru_case_hash_insert(fmd_asru_hash_t * ahp,fmd_asru_link_t * alp,char * name)2446228Sstephh fmd_asru_case_hash_insert(fmd_asru_hash_t *ahp, fmd_asru_link_t *alp,
2456228Sstephh     char *name)
2466228Sstephh {
2476869Seschrock 	uint_t h = fmd_asru_strhash(ahp, name);
2486228Sstephh 
2496228Sstephh 	ASSERT(RW_WRITE_HELD(&ahp->ah_lock));
2506228Sstephh 	alp->al_case_next = ahp->ah_case_hash[h];
2516228Sstephh 	ahp->ah_case_hash[h] = alp;
2526228Sstephh }
2536228Sstephh 
2546228Sstephh static void
fmd_asru_fru_hash_insert(fmd_asru_hash_t * ahp,fmd_asru_link_t * alp,char * name)2556228Sstephh fmd_asru_fru_hash_insert(fmd_asru_hash_t *ahp, fmd_asru_link_t *alp, char *name)
2566228Sstephh {
2576869Seschrock 	uint_t h = fmd_asru_strhash(ahp, name);
2586228Sstephh 
2596228Sstephh 	ASSERT(RW_WRITE_HELD(&ahp->ah_lock));
2606228Sstephh 	alp->al_fru_next = ahp->ah_fru_hash[h];
2616228Sstephh 	ahp->ah_fru_hash[h] = alp;
2626228Sstephh }
2636228Sstephh 
2646228Sstephh static void
fmd_asru_label_hash_insert(fmd_asru_hash_t * ahp,fmd_asru_link_t * alp,char * name)2656228Sstephh fmd_asru_label_hash_insert(fmd_asru_hash_t *ahp, fmd_asru_link_t *alp,
2666228Sstephh     char *name)
2676228Sstephh {
2686869Seschrock 	uint_t h = fmd_asru_strhash(ahp, name);
2696228Sstephh 
2706228Sstephh 	ASSERT(RW_WRITE_HELD(&ahp->ah_lock));
2716228Sstephh 	alp->al_label_next = ahp->ah_label_hash[h];
2726228Sstephh 	ahp->ah_label_hash[h] = alp;
2736228Sstephh }
2746228Sstephh 
2756228Sstephh static void
fmd_asru_rsrc_hash_insert(fmd_asru_hash_t * ahp,fmd_asru_link_t * alp,char * name)2766228Sstephh fmd_asru_rsrc_hash_insert(fmd_asru_hash_t *ahp, fmd_asru_link_t *alp,
2776228Sstephh     char *name)
2786228Sstephh {
2796869Seschrock 	uint_t h = fmd_asru_strhash(ahp, name);
2806228Sstephh 
2816228Sstephh 	ASSERT(RW_WRITE_HELD(&ahp->ah_lock));
2826228Sstephh 	alp->al_rsrc_next = ahp->ah_rsrc_hash[h];
2836228Sstephh 	ahp->ah_rsrc_hash[h] = alp;
2846228Sstephh }
2856228Sstephh 
2866228Sstephh static void
fmd_asru_al_destroy(fmd_asru_link_t * alp)2876228Sstephh fmd_asru_al_destroy(fmd_asru_link_t *alp)
2886228Sstephh {
2896228Sstephh 	ASSERT(alp->al_refs == 0);
2906228Sstephh 	ASSERT(MUTEX_HELD(&alp->al_asru->asru_lock));
2916228Sstephh 
2926228Sstephh 	if (alp->al_log != NULL)
2936228Sstephh 		fmd_log_rele(alp->al_log);
2946228Sstephh 
2956228Sstephh 	fmd_free(alp->al_uuid, alp->al_uuidlen + 1);
2966228Sstephh 	nvlist_free(alp->al_event);
2976228Sstephh 	fmd_strfree(alp->al_rsrc_name);
2986228Sstephh 	fmd_strfree(alp->al_case_uuid);
2996228Sstephh 	fmd_strfree(alp->al_fru_name);
3006228Sstephh 	fmd_strfree(alp->al_asru_name);
3016228Sstephh 	fmd_strfree(alp->al_label);
3026228Sstephh 	nvlist_free(alp->al_asru_fmri);
3036228Sstephh 	fmd_free(alp, sizeof (fmd_asru_link_t));
3046228Sstephh }
3056228Sstephh 
3066228Sstephh static fmd_asru_link_t *
fmd_asru_al_hold(fmd_asru_link_t * alp)3076228Sstephh fmd_asru_al_hold(fmd_asru_link_t *alp)
3086228Sstephh {
3096228Sstephh 	fmd_asru_t *ap = alp->al_asru;
3106228Sstephh 
3116228Sstephh 	(void) pthread_mutex_lock(&ap->asru_lock);
3126228Sstephh 	ap->asru_refs++;
3136228Sstephh 	alp->al_refs++;
3146228Sstephh 	ASSERT(alp->al_refs != 0);
3156228Sstephh 	(void) pthread_mutex_unlock(&ap->asru_lock);
3166228Sstephh 	return (alp);
3176228Sstephh }
3186228Sstephh 
3196228Sstephh static void fmd_asru_destroy(fmd_asru_t *ap);
3206228Sstephh 
3216228Sstephh /*ARGSUSED*/
3226228Sstephh static void
fmd_asru_al_hash_release(fmd_asru_hash_t * ahp,fmd_asru_link_t * alp)3236228Sstephh fmd_asru_al_hash_release(fmd_asru_hash_t *ahp, fmd_asru_link_t *alp)
3246228Sstephh {
3256228Sstephh 	fmd_asru_t *ap = alp->al_asru;
3266228Sstephh 
3276228Sstephh 	(void) pthread_mutex_lock(&ap->asru_lock);
3286228Sstephh 	ASSERT(alp->al_refs != 0);
3296228Sstephh 	if (--alp->al_refs == 0)
3306228Sstephh 		fmd_asru_al_destroy(alp);
3316228Sstephh 	ASSERT(ap->asru_refs != 0);
3326228Sstephh 	if (--ap->asru_refs == 0)
3336228Sstephh 		fmd_asru_destroy(ap);
3346228Sstephh 	else
3356228Sstephh 		(void) pthread_mutex_unlock(&ap->asru_lock);
3366228Sstephh }
3376228Sstephh 
3386228Sstephh static int
fmd_asru_get_namestr(nvlist_t * nvl,char ** name,ssize_t * namelen)3396228Sstephh fmd_asru_get_namestr(nvlist_t *nvl, char **name, ssize_t *namelen)
3406228Sstephh {
3416228Sstephh 	if ((*namelen = fmd_fmri_nvl2str(nvl, NULL, 0)) == -1)
3426228Sstephh 		return (EFMD_ASRU_FMRI);
3436228Sstephh 	*name = fmd_alloc(*namelen + 1, FMD_SLEEP);
3446228Sstephh 	if (fmd_fmri_nvl2str(nvl, *name, *namelen + 1) == -1) {
3456228Sstephh 		if (*name != NULL)
3466228Sstephh 			fmd_free(*name, *namelen + 1);
3476228Sstephh 		return (EFMD_ASRU_FMRI);
3486228Sstephh 	}
3496228Sstephh 	return (0);
3506228Sstephh }
3516228Sstephh 
3526228Sstephh 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)3536228Sstephh fmd_asru_al_create(fmd_asru_hash_t *ahp, nvlist_t *nvl, fmd_case_t *cp,
3546228Sstephh     const char *al_uuid)
3556228Sstephh {
3566228Sstephh 	nvlist_t *asru = NULL, *fru, *rsrc;
3576228Sstephh 	int got_rsrc = 0, got_asru = 0, got_fru = 0;
3586228Sstephh 	ssize_t fru_namelen, rsrc_namelen, asru_namelen;
3596228Sstephh 	char *asru_name, *rsrc_name, *fru_name, *name, *label;
3606228Sstephh 	fmd_asru_link_t *alp;
3616228Sstephh 	fmd_asru_t *ap;
3626228Sstephh 	boolean_t msg;
3636228Sstephh 	fmd_case_impl_t *cip = (fmd_case_impl_t *)cp;
3646228Sstephh 
3656228Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_ASRU, &asru) == 0 &&
3666228Sstephh 	    fmd_asru_get_namestr(asru, &asru_name, &asru_namelen) == 0)
3676228Sstephh 		got_asru = 1;
3686228Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_FRU, &fru) == 0 &&
3696228Sstephh 	    fmd_asru_get_namestr(fru, &fru_name, &fru_namelen) == 0)
3706228Sstephh 		got_fru = 1;
3716228Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc) == 0 &&
3726228Sstephh 	    fmd_asru_get_namestr(rsrc, &rsrc_name, &rsrc_namelen) == 0)
3736228Sstephh 		got_rsrc = 1;
3746228Sstephh 	if (nvlist_lookup_string(nvl, FM_FAULT_LOCATION, &label) != 0)
3756228Sstephh 		label = "";
3766228Sstephh 
3776228Sstephh 	/*
3786228Sstephh 	 * Grab the rwlock as a writer; Then create and insert the asru with
3796228Sstephh 	 * ahp->ah_lock held and hash it in. We'll then drop the rwlock and
3806228Sstephh 	 * proceed to initializing the asru.
3816228Sstephh 	 */
3826228Sstephh 	(void) pthread_rwlock_wrlock(&ahp->ah_lock);
3836228Sstephh 
3846228Sstephh 	/*
3856228Sstephh 	 * Create and initialise the per-fault "link" structure.
3866228Sstephh 	 */
3876228Sstephh 	alp = fmd_zalloc(sizeof (fmd_asru_link_t), FMD_SLEEP);
3886228Sstephh 	if (got_asru)
3896228Sstephh 		(void) nvlist_xdup(asru, &alp->al_asru_fmri, &fmd.d_nva);
3906228Sstephh 	alp->al_uuid = fmd_strdup(al_uuid, FMD_SLEEP);
3916228Sstephh 	alp->al_uuidlen = strlen(alp->al_uuid);
3926228Sstephh 	alp->al_refs = 1;
3936228Sstephh 
3946228Sstephh 	/*
3956228Sstephh 	 * If this is the first fault for this asru, then create the per-asru
3966228Sstephh 	 * structure and link into the hash.
3976228Sstephh 	 */
3986228Sstephh 	name = got_asru ? asru_name : "";
3996228Sstephh 	if ((ap = fmd_asru_hash_lookup(ahp, name)) == NULL) {
4006228Sstephh 		ap = fmd_asru_create(ahp, al_uuid, name, got_asru ? asru :
4016228Sstephh 		    NULL);
4026228Sstephh 		fmd_asru_hash_insert(ahp, ap);
4036228Sstephh 	} else
4046228Sstephh 		nvlist_free(ap->asru_event);
4056228Sstephh 	(void) nvlist_xdup(nvl, &ap->asru_event, &fmd.d_nva);
4066228Sstephh 
4076228Sstephh 	/*
4086228Sstephh 	 * Put the link structure on the list associated with the per-asru
4096228Sstephh 	 * structure. Then put the link structure on the various hashes.
4106228Sstephh 	 */
4116228Sstephh 	fmd_list_append(&ap->asru_list, (fmd_list_t *)alp);
4126228Sstephh 	alp->al_asru = ap;
4136228Sstephh 	alp->al_asru_name = got_asru ? asru_name : fmd_strdup("", FMD_SLEEP);
4146228Sstephh 	fmd_asru_asru_hash_insert(ahp, alp, alp->al_asru_name);
4156228Sstephh 	alp->al_fru_name = got_fru ? fru_name : fmd_strdup("", FMD_SLEEP);
4166228Sstephh 	fmd_asru_fru_hash_insert(ahp, alp, alp->al_fru_name);
4176228Sstephh 	alp->al_rsrc_name = got_rsrc ? rsrc_name : fmd_strdup("", FMD_SLEEP);
4186228Sstephh 	fmd_asru_rsrc_hash_insert(ahp, alp, alp->al_rsrc_name);
4196228Sstephh 	alp->al_label = fmd_strdup(label, FMD_SLEEP);
4206228Sstephh 	fmd_asru_label_hash_insert(ahp, alp, label);
4216228Sstephh 	alp->al_case_uuid = fmd_strdup(cip->ci_uuid, FMD_SLEEP);
4226228Sstephh 	fmd_asru_case_hash_insert(ahp, alp, cip->ci_uuid);
4236228Sstephh 	(void) pthread_mutex_lock(&ap->asru_lock);
4246228Sstephh 	(void) pthread_rwlock_unlock(&ahp->ah_lock);
4256228Sstephh 
4266228Sstephh 	ap->asru_case = alp->al_case = cp;
4276228Sstephh 	if (nvlist_lookup_boolean_value(nvl, FM_SUSPECT_MESSAGE, &msg) == 0 &&
4286228Sstephh 	    msg == B_FALSE)
4296228Sstephh 		ap->asru_flags |= FMD_ASRU_INVISIBLE;
4306228Sstephh 	(void) nvlist_xdup(nvl, &alp->al_event, &fmd.d_nva);
4316228Sstephh 	ap->asru_flags |= FMD_ASRU_VALID;
4326228Sstephh 	(void) pthread_cond_broadcast(&ap->asru_cv);
4336228Sstephh 	(void) pthread_mutex_unlock(&ap->asru_lock);
4346228Sstephh 	return (alp);
4356228Sstephh }
4366228Sstephh 
4370Sstevel@tonic-gate static void
fmd_asru_hash_recreate(fmd_log_t * lp,fmd_event_t * ep,fmd_asru_hash_t * ahp)4380Sstevel@tonic-gate fmd_asru_hash_recreate(fmd_log_t *lp, fmd_event_t *ep, fmd_asru_hash_t *ahp)
4390Sstevel@tonic-gate {
4401193Smws 	nvlist_t *nvl = FMD_EVENT_NVL(ep);
4417275Sstephh 	boolean_t faulty = FMD_B_FALSE, unusable = FMD_B_FALSE;
4427275Sstephh 	int ps;
4437275Sstephh 	boolean_t repaired = FMD_B_FALSE, replaced = FMD_B_FALSE;
44410656SStephen.Hanson@Sun.COM 	boolean_t acquitted = FMD_B_FALSE, resolved = FMD_B_FALSE;
4456228Sstephh 	nvlist_t *flt, *flt_copy, *asru;
4461193Smws 	char *case_uuid = NULL, *case_code = NULL;
4470Sstevel@tonic-gate 	fmd_asru_t *ap;
4486228Sstephh 	fmd_asru_link_t *alp;
4496228Sstephh 	fmd_case_t *cp;
4505255Sstephh 	int64_t *diag_time;
4519120SStephen.Hanson@Sun.COM 	nvlist_t *de_fmri, *de_fmri_dup;
4525255Sstephh 	uint_t nelem;
4537197Sstephh 	topo_hdl_t *thp;
4547197Sstephh 	char *class;
4557197Sstephh 	nvlist_t *rsrc;
4567197Sstephh 	int err;
45710928SStephen.Hanson@Sun.COM 	boolean_t injected;
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	/*
4606228Sstephh 	 * Extract the most recent values of 'faulty' from the event log.
4610Sstevel@tonic-gate 	 */
4627275Sstephh 	if (nvlist_lookup_boolean_value(nvl, FM_RSRC_ASRU_FAULTY,
4637275Sstephh 	    &faulty) != 0) {
4640Sstevel@tonic-gate 		fmd_error(EFMD_ASRU_EVENT, "failed to reload asru %s: "
4650Sstevel@tonic-gate 		    "invalid event log record\n", lp->log_name);
4660Sstevel@tonic-gate 		ahp->ah_error = EFMD_ASRU_EVENT;
4670Sstevel@tonic-gate 		return;
4680Sstevel@tonic-gate 	}
4696228Sstephh 	if (nvlist_lookup_nvlist(nvl, FM_RSRC_ASRU_EVENT, &flt) != 0) {
4706228Sstephh 		fmd_error(EFMD_ASRU_EVENT, "failed to reload asru %s: "
4716228Sstephh 		    "invalid event log record\n", lp->log_name);
4726228Sstephh 		ahp->ah_error = EFMD_ASRU_EVENT;
4736228Sstephh 		return;
4746228Sstephh 	}
4756228Sstephh 	(void) nvlist_lookup_string(nvl, FM_RSRC_ASRU_UUID, &case_uuid);
4766228Sstephh 	(void) nvlist_lookup_string(nvl, FM_RSRC_ASRU_CODE, &case_code);
4777275Sstephh 	(void) nvlist_lookup_boolean_value(nvl, FM_RSRC_ASRU_UNUSABLE,
4787275Sstephh 	    &unusable);
4797275Sstephh 	(void) nvlist_lookup_boolean_value(nvl, FM_RSRC_ASRU_REPAIRED,
4807275Sstephh 	    &repaired);
4817275Sstephh 	(void) nvlist_lookup_boolean_value(nvl, FM_RSRC_ASRU_REPLACED,
4827275Sstephh 	    &replaced);
4837275Sstephh 	(void) nvlist_lookup_boolean_value(nvl, FM_RSRC_ASRU_ACQUITTED,
4847275Sstephh 	    &acquitted);
48510656SStephen.Hanson@Sun.COM 	(void) nvlist_lookup_boolean_value(nvl, FM_RSRC_ASRU_RESOLVED,
48610656SStephen.Hanson@Sun.COM 	    &resolved);
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	/*
48910656SStephen.Hanson@Sun.COM 	 * Attempt to recreate the case in CLOSED, REPAIRED or RESOLVED state
49010656SStephen.Hanson@Sun.COM 	 * (depending on whether the faulty/resolved bits are set).
4916228Sstephh 	 * If the case is already present, fmd_case_recreate() will return it.
4926228Sstephh 	 * If not, we'll create a new orphaned case. Either way,  we use the
4936228Sstephh 	 * ASRU event to insert a suspect into the partially-restored case.
4945255Sstephh 	 */
4956228Sstephh 	fmd_module_lock(fmd.d_rmod);
4967275Sstephh 	cp = fmd_case_recreate(fmd.d_rmod, NULL, faulty ? FMD_CASE_CLOSED :
49710656SStephen.Hanson@Sun.COM 	    resolved ? FMD_CASE_RESOLVED : FMD_CASE_REPAIRED, case_uuid,
49810656SStephen.Hanson@Sun.COM 	    case_code);
4996228Sstephh 	fmd_case_hold(cp);
5006228Sstephh 	fmd_module_unlock(fmd.d_rmod);
50110928SStephen.Hanson@Sun.COM 	if (nvlist_lookup_boolean_value(nvl, FM_SUSPECT_INJECTED,
50210928SStephen.Hanson@Sun.COM 	    &injected) == 0 && injected)
50310928SStephen.Hanson@Sun.COM 		fmd_case_set_injected(cp);
5046228Sstephh 	if (nvlist_lookup_int64_array(nvl, FM_SUSPECT_DIAG_TIME, &diag_time,
5056228Sstephh 	    &nelem) == 0 && nelem >= 2)
5066228Sstephh 		fmd_case_settime(cp, diag_time[0], diag_time[1]);
5076228Sstephh 	else
5086228Sstephh 		fmd_case_settime(cp, lp->log_stat.st_ctime, 0);
5099120SStephen.Hanson@Sun.COM 	if (nvlist_lookup_nvlist(nvl, FM_SUSPECT_DE, &de_fmri) == 0) {
5109120SStephen.Hanson@Sun.COM 		(void) nvlist_xdup(de_fmri, &de_fmri_dup, &fmd.d_nva);
5119120SStephen.Hanson@Sun.COM 		fmd_case_set_de_fmri(cp, de_fmri_dup);
5129120SStephen.Hanson@Sun.COM 	}
5136228Sstephh 	(void) nvlist_xdup(flt, &flt_copy, &fmd.d_nva);
5147197Sstephh 
5157197Sstephh 	/*
5167197Sstephh 	 * For faults with a resource, re-evaluate the asru from the resource.
5177197Sstephh 	 */
5187197Sstephh 	thp = fmd_fmri_topo_hold(TOPO_VERSION);
5197197Sstephh 	if (nvlist_lookup_string(flt_copy, FM_CLASS, &class) == 0 &&
5207197Sstephh 	    strncmp(class, "fault", 5) == 0 &&
5217197Sstephh 	    nvlist_lookup_nvlist(flt_copy, FM_FAULT_RESOURCE, &rsrc) == 0 &&
522*11416SStephen.Hanson@Sun.COM 	    rsrc != NULL &&
523*11416SStephen.Hanson@Sun.COM 	    (fmd_fmri_replaced(rsrc) != FMD_OBJ_STATE_REPLACED) &&
524*11416SStephen.Hanson@Sun.COM 	    topo_fmri_asru(thp, rsrc, &asru, &err) == 0) {
5257197Sstephh 		(void) nvlist_remove(flt_copy, FM_FAULT_ASRU, DATA_TYPE_NVLIST);
5267197Sstephh 		(void) nvlist_add_nvlist(flt_copy, FM_FAULT_ASRU, asru);
5277197Sstephh 		nvlist_free(asru);
5287197Sstephh 	}
5297197Sstephh 	fmd_fmri_topo_rele(thp);
5307197Sstephh 
5317197Sstephh 	(void) nvlist_xdup(flt_copy, &flt, &fmd.d_nva);
5327197Sstephh 
5336228Sstephh 	fmd_case_recreate_suspect(cp, flt_copy);
5346228Sstephh 
5356228Sstephh 	/*
5366228Sstephh 	 * Now create the resource cache entries.
5376228Sstephh 	 */
5386228Sstephh 	alp = fmd_asru_al_create(ahp, flt, cp, fmd_strbasename(lp->log_name));
5396228Sstephh 	ap = alp->al_asru;
5405255Sstephh 
5415255Sstephh 	/*
5427275Sstephh 	 * Check to see if the resource is still present in the system.
5430Sstevel@tonic-gate 	 */
5449120SStephen.Hanson@Sun.COM 	ps = fmd_asru_replacement_state(flt, HC_ONLY_FALSE);
5457532SSean.Ye@Sun.COM 	if (ps == FMD_OBJ_STATE_REPLACED) {
5467532SSean.Ye@Sun.COM 		replaced = FMD_B_TRUE;
5477532SSean.Ye@Sun.COM 	} else if (ps == FMD_OBJ_STATE_STILL_PRESENT ||
5487532SSean.Ye@Sun.COM 	    ps == FMD_OBJ_STATE_UNKNOWN) {
5497275Sstephh 		ap->asru_flags |= FMD_ASRU_PRESENT;
5507532SSean.Ye@Sun.COM 		if (nvlist_lookup_nvlist(alp->al_event, FM_FAULT_ASRU,
5517532SSean.Ye@Sun.COM 		    &asru) == 0) {
5527532SSean.Ye@Sun.COM 			int us;
5537532SSean.Ye@Sun.COM 
5547532SSean.Ye@Sun.COM 			switch (fmd_fmri_service_state(asru)) {
5557532SSean.Ye@Sun.COM 			case FMD_SERVICE_STATE_UNUSABLE:
5567532SSean.Ye@Sun.COM 				unusable = FMD_B_TRUE;
5577532SSean.Ye@Sun.COM 				break;
5587532SSean.Ye@Sun.COM 			case FMD_SERVICE_STATE_OK:
5598245SStephen.Hanson@Sun.COM 			case FMD_SERVICE_STATE_ISOLATE_PENDING:
5607532SSean.Ye@Sun.COM 			case FMD_SERVICE_STATE_DEGRADED:
5617532SSean.Ye@Sun.COM 				unusable = FMD_B_FALSE;
5627532SSean.Ye@Sun.COM 				break;
5637532SSean.Ye@Sun.COM 			case FMD_SERVICE_STATE_UNKNOWN:
5647532SSean.Ye@Sun.COM 			case -1:
5657532SSean.Ye@Sun.COM 				/* not supported by scheme */
5667532SSean.Ye@Sun.COM 				us = fmd_fmri_unusable(asru);
5677532SSean.Ye@Sun.COM 				if (us > 0)
5687532SSean.Ye@Sun.COM 					unusable = FMD_B_TRUE;
5697532SSean.Ye@Sun.COM 				else if (us == 0)
5707532SSean.Ye@Sun.COM 					unusable = FMD_B_FALSE;
5717532SSean.Ye@Sun.COM 				break;
5727532SSean.Ye@Sun.COM 			}
5737532SSean.Ye@Sun.COM 		}
5747532SSean.Ye@Sun.COM 	}
5750Sstevel@tonic-gate 
5767197Sstephh 	nvlist_free(flt);
5777197Sstephh 
5786228Sstephh 	ap->asru_flags |= FMD_ASRU_RECREATED;
5797275Sstephh 	if (faulty) {
5806228Sstephh 		alp->al_flags |= FMD_ASRU_FAULTY;
5816228Sstephh 		ap->asru_flags |= FMD_ASRU_FAULTY;
5820Sstevel@tonic-gate 	}
5837275Sstephh 	if (unusable) {
5846228Sstephh 		alp->al_flags |= FMD_ASRU_UNUSABLE;
5856228Sstephh 		ap->asru_flags |= FMD_ASRU_UNUSABLE;
5860Sstevel@tonic-gate 	}
5877275Sstephh 	if (replaced)
5887275Sstephh 		alp->al_reason = FMD_ASRU_REPLACED;
5897275Sstephh 	else if (repaired)
5907275Sstephh 		alp->al_reason = FMD_ASRU_REPAIRED;
5917275Sstephh 	else if (acquitted)
5927275Sstephh 		alp->al_reason = FMD_ASRU_ACQUITTED;
59310656SStephen.Hanson@Sun.COM 	else
59410656SStephen.Hanson@Sun.COM 		alp->al_reason = FMD_ASRU_REMOVED;
5950Sstevel@tonic-gate 
5966228Sstephh 	TRACE((FMD_DBG_ASRU, "asru %s recreated as %p (%s)", alp->al_uuid,
5970Sstevel@tonic-gate 	    (void *)ap, _fmd_asru_snames[ap->asru_flags & FMD_ASRU_STATE]));
5980Sstevel@tonic-gate }
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate static void
fmd_asru_hash_discard(fmd_asru_hash_t * ahp,const char * uuid,int err)6010Sstevel@tonic-gate fmd_asru_hash_discard(fmd_asru_hash_t *ahp, const char *uuid, int err)
6020Sstevel@tonic-gate {
6030Sstevel@tonic-gate 	char src[PATH_MAX], dst[PATH_MAX];
6040Sstevel@tonic-gate 
6050Sstevel@tonic-gate 	(void) snprintf(src, PATH_MAX, "%s/%s", ahp->ah_dirpath, uuid);
6060Sstevel@tonic-gate 	(void) snprintf(dst, PATH_MAX, "%s/%s-", ahp->ah_dirpath, uuid);
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 	if (err != 0)
6090Sstevel@tonic-gate 		err = rename(src, dst);
6100Sstevel@tonic-gate 	else
6110Sstevel@tonic-gate 		err = unlink(src);
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate 	if (err != 0 && errno != ENOENT)
6140Sstevel@tonic-gate 		fmd_error(EFMD_ASRU_EVENT, "failed to rename log %s", src);
6150Sstevel@tonic-gate }
6160Sstevel@tonic-gate 
6170Sstevel@tonic-gate /*
6180Sstevel@tonic-gate  * Open a saved log file and restore it into the ASRU hash.  If we can't even
6190Sstevel@tonic-gate  * open the log, rename the log file to <uuid>- to indicate it is corrupt.  If
6200Sstevel@tonic-gate  * fmd_log_replay() fails, we either delete the file (if it has reached the
6210Sstevel@tonic-gate  * upper limit on cache age) or rename it for debugging if it was corrupted.
6220Sstevel@tonic-gate  */
6230Sstevel@tonic-gate static void
fmd_asru_hash_logopen(fmd_asru_hash_t * ahp,const char * uuid)6240Sstevel@tonic-gate fmd_asru_hash_logopen(fmd_asru_hash_t *ahp, const char *uuid)
6250Sstevel@tonic-gate {
6260Sstevel@tonic-gate 	fmd_log_t *lp = fmd_log_tryopen(ahp->ah_dirpath, uuid, FMD_LOG_ASRU);
6270Sstevel@tonic-gate 	uint_t n;
6280Sstevel@tonic-gate 
6290Sstevel@tonic-gate 	if (lp == NULL) {
6300Sstevel@tonic-gate 		fmd_asru_hash_discard(ahp, uuid, errno);
6310Sstevel@tonic-gate 		return;
6320Sstevel@tonic-gate 	}
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 	ahp->ah_error = 0;
6356228Sstephh 	n = ahp->ah_al_count;
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	fmd_log_replay(lp, (fmd_log_f *)fmd_asru_hash_recreate, ahp);
6380Sstevel@tonic-gate 	fmd_log_rele(lp);
6390Sstevel@tonic-gate 
6406228Sstephh 	if (ahp->ah_al_count == n)
6410Sstevel@tonic-gate 		fmd_asru_hash_discard(ahp, uuid, ahp->ah_error);
6420Sstevel@tonic-gate }
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate void
fmd_asru_hash_refresh(fmd_asru_hash_t * ahp)6450Sstevel@tonic-gate fmd_asru_hash_refresh(fmd_asru_hash_t *ahp)
6460Sstevel@tonic-gate {
647871Scasper 	struct dirent *dp;
6480Sstevel@tonic-gate 	DIR *dirp;
6490Sstevel@tonic-gate 	int zero;
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate 	if ((dirp = opendir(ahp->ah_dirpath)) == NULL) {
6520Sstevel@tonic-gate 		fmd_error(EFMD_ASRU_NODIR,
6530Sstevel@tonic-gate 		    "failed to open asru cache directory %s", ahp->ah_dirpath);
6540Sstevel@tonic-gate 		return;
6550Sstevel@tonic-gate 	}
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	(void) fmd_conf_getprop(fmd.d_conf, "rsrc.zero", &zero);
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	(void) pthread_rwlock_wrlock(&ahp->ah_lock);
6600Sstevel@tonic-gate 
661871Scasper 	while ((dp = readdir(dirp)) != NULL) {
6620Sstevel@tonic-gate 		if (dp->d_name[0] == '.')
6630Sstevel@tonic-gate 			continue; /* skip "." and ".." */
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 		if (zero)
6660Sstevel@tonic-gate 			fmd_asru_hash_discard(ahp, dp->d_name, 0);
6670Sstevel@tonic-gate 		else if (!fmd_strmatch(dp->d_name, "*-"))
6680Sstevel@tonic-gate 			fmd_asru_hash_logopen(ahp, dp->d_name);
6690Sstevel@tonic-gate 	}
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	(void) pthread_rwlock_unlock(&ahp->ah_lock);
6720Sstevel@tonic-gate 	(void) closedir(dirp);
6730Sstevel@tonic-gate }
6740Sstevel@tonic-gate 
6751552Smws /*
6761552Smws  * If the resource is present and faulty but not unusable, replay the fault
6771552Smws  * event that caused it be marked faulty.  This will cause the agent
6781552Smws  * subscribing to this fault class to again disable the resource.
6791552Smws  */
6801552Smws /*ARGSUSED*/
6811552Smws static void
fmd_asru_hash_replay_asru(fmd_asru_t * ap,void * data)6821552Smws fmd_asru_hash_replay_asru(fmd_asru_t *ap, void *data)
6831552Smws {
6841552Smws 	fmd_event_t *e;
6851552Smws 	nvlist_t *nvl;
6861552Smws 	char *class;
6871552Smws 
6881552Smws 	if (ap->asru_event != NULL && (ap->asru_flags & (FMD_ASRU_STATE |
6891552Smws 	    FMD_ASRU_PRESENT)) == (FMD_ASRU_FAULTY | FMD_ASRU_PRESENT)) {
6901552Smws 
6911552Smws 		fmd_dprintf(FMD_DBG_ASRU,
6921552Smws 		    "replaying fault event for %s", ap->asru_name);
6931552Smws 
6941552Smws 		(void) nvlist_xdup(ap->asru_event, &nvl, &fmd.d_nva);
6951552Smws 		(void) nvlist_lookup_string(nvl, FM_CLASS, &class);
6961552Smws 
6971552Smws 		(void) nvlist_add_string(nvl, FMD_EVN_UUID,
6981552Smws 		    ((fmd_case_impl_t *)ap->asru_case)->ci_uuid);
6991552Smws 
7001552Smws 		e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class);
7011552Smws 		fmd_dispq_dispatch(fmd.d_disp, e, class);
7021552Smws 	}
7031552Smws }
7041552Smws 
7051552Smws void
fmd_asru_hash_replay(fmd_asru_hash_t * ahp)7061552Smws fmd_asru_hash_replay(fmd_asru_hash_t *ahp)
7071552Smws {
7081552Smws 	fmd_asru_hash_apply(ahp, fmd_asru_hash_replay_asru, NULL);
7091552Smws }
7101552Smws 
7116228Sstephh /*
7126228Sstephh  * Check if the resource is still present. If not, and if the rsrc.age time
7136228Sstephh  * has expired, then do an implicit repair on the resource.
7146228Sstephh  */
7157275Sstephh /*ARGSUSED*/
7166228Sstephh static void
fmd_asru_repair_if_aged(fmd_asru_link_t * alp,void * arg)7177275Sstephh fmd_asru_repair_if_aged(fmd_asru_link_t *alp, void *arg)
7186228Sstephh {
7196228Sstephh 	struct timeval tv;
7206228Sstephh 	fmd_log_t *lp;
7216228Sstephh 	hrtime_t hrt;
7227275Sstephh 	int ps;
7237275Sstephh 	int err;
7249120SStephen.Hanson@Sun.COM 	fmd_asru_rep_arg_t fara;
7256228Sstephh 
72610656SStephen.Hanson@Sun.COM 	if (!(alp->al_flags & FMD_ASRU_FAULTY))
72710656SStephen.Hanson@Sun.COM 		return;
72810656SStephen.Hanson@Sun.COM 
7299120SStephen.Hanson@Sun.COM 	/*
7309120SStephen.Hanson@Sun.COM 	 * Checking for aged resources only happens on the diagnosing side
7319120SStephen.Hanson@Sun.COM 	 * not on a proxy.
7329120SStephen.Hanson@Sun.COM 	 */
7339120SStephen.Hanson@Sun.COM 	if (alp->al_flags & FMD_ASRU_PROXY)
7349120SStephen.Hanson@Sun.COM 		return;
7359120SStephen.Hanson@Sun.COM 
7369120SStephen.Hanson@Sun.COM 	ps = fmd_asru_replacement_state(alp->al_event, HC_ONLY_FALSE);
7377275Sstephh 	if (ps == FMD_OBJ_STATE_REPLACED) {
7389120SStephen.Hanson@Sun.COM 		fara.fara_reason = FMD_ASRU_REPLACED;
7399120SStephen.Hanson@Sun.COM 		fara.fara_bywhat = FARA_ALL;
7409120SStephen.Hanson@Sun.COM 		fara.fara_rval = &err;
7419120SStephen.Hanson@Sun.COM 		fmd_asru_repaired(alp, &fara);
7427275Sstephh 	} else if (ps == FMD_OBJ_STATE_NOT_PRESENT) {
7437275Sstephh 		fmd_time_gettimeofday(&tv);
7447275Sstephh 		lp = fmd_log_open(alp->al_asru->asru_root, alp->al_uuid,
7457275Sstephh 		    FMD_LOG_ASRU);
74611202SStephen.Hanson@Sun.COM 		if (lp == NULL)
74711202SStephen.Hanson@Sun.COM 			return;
7487275Sstephh 		hrt = (hrtime_t)(tv.tv_sec - lp->log_stat.st_mtime);
7497275Sstephh 		fmd_log_rele(lp);
7509120SStephen.Hanson@Sun.COM 		if (hrt * NANOSEC >= fmd.d_asrus->ah_lifetime) {
7519120SStephen.Hanson@Sun.COM 			fara.fara_reason = FMD_ASRU_REMOVED;
7529120SStephen.Hanson@Sun.COM 			fara.fara_bywhat = FARA_ALL;
7539120SStephen.Hanson@Sun.COM 			fara.fara_rval = &err;
7549120SStephen.Hanson@Sun.COM 			fmd_asru_repaired(alp, &fara);
7559120SStephen.Hanson@Sun.COM 		}
7567275Sstephh 	}
7576228Sstephh }
7586228Sstephh 
75910656SStephen.Hanson@Sun.COM /*ARGSUSED*/
76010656SStephen.Hanson@Sun.COM void
fmd_asru_check_if_aged(fmd_asru_link_t * alp,void * arg)76110656SStephen.Hanson@Sun.COM fmd_asru_check_if_aged(fmd_asru_link_t *alp, void *arg)
76210656SStephen.Hanson@Sun.COM {
76310656SStephen.Hanson@Sun.COM 	struct timeval tv;
76410656SStephen.Hanson@Sun.COM 	fmd_log_t *lp;
76510656SStephen.Hanson@Sun.COM 	hrtime_t hrt;
76610656SStephen.Hanson@Sun.COM 
76710656SStephen.Hanson@Sun.COM 	/*
76810656SStephen.Hanson@Sun.COM 	 * Case must be in resolved state for this to be called. So modified
76910656SStephen.Hanson@Sun.COM 	 * time on resource cache entry should be the time the resolve occurred.
77010656SStephen.Hanson@Sun.COM 	 * Return 0 if not yet hit rsrc.aged.
77110656SStephen.Hanson@Sun.COM 	 */
77210656SStephen.Hanson@Sun.COM 	fmd_time_gettimeofday(&tv);
77310656SStephen.Hanson@Sun.COM 	lp = fmd_log_open(alp->al_asru->asru_root, alp->al_uuid, FMD_LOG_ASRU);
77410656SStephen.Hanson@Sun.COM 	if (lp == NULL)
77510656SStephen.Hanson@Sun.COM 		return;
77610656SStephen.Hanson@Sun.COM 	hrt = (hrtime_t)(tv.tv_sec - lp->log_stat.st_mtime);
77710656SStephen.Hanson@Sun.COM 	fmd_log_rele(lp);
77810656SStephen.Hanson@Sun.COM 	if (hrt * NANOSEC < fmd.d_asrus->ah_lifetime)
77910656SStephen.Hanson@Sun.COM 		*(int *)arg = 0;
78010656SStephen.Hanson@Sun.COM }
78110656SStephen.Hanson@Sun.COM 
78210656SStephen.Hanson@Sun.COM /*ARGSUSED*/
78310656SStephen.Hanson@Sun.COM void
fmd_asru_most_recent(fmd_asru_link_t * alp,void * arg)78410656SStephen.Hanson@Sun.COM fmd_asru_most_recent(fmd_asru_link_t *alp, void *arg)
78510656SStephen.Hanson@Sun.COM {
78610656SStephen.Hanson@Sun.COM 	fmd_log_t *lp;
78710656SStephen.Hanson@Sun.COM 	uint64_t hrt;
78810656SStephen.Hanson@Sun.COM 
78910656SStephen.Hanson@Sun.COM 	/*
79010656SStephen.Hanson@Sun.COM 	 * Find most recent modified time of a set of resource cache entries.
79110656SStephen.Hanson@Sun.COM 	 */
79210656SStephen.Hanson@Sun.COM 	lp = fmd_log_open(alp->al_asru->asru_root, alp->al_uuid, FMD_LOG_ASRU);
79310656SStephen.Hanson@Sun.COM 	if (lp == NULL)
79410656SStephen.Hanson@Sun.COM 		return;
79510656SStephen.Hanson@Sun.COM 	hrt = lp->log_stat.st_mtime;
79610656SStephen.Hanson@Sun.COM 	fmd_log_rele(lp);
79710656SStephen.Hanson@Sun.COM 	if (*(uint64_t *)arg < hrt)
79810656SStephen.Hanson@Sun.COM 		*(uint64_t *)arg = hrt;
79910656SStephen.Hanson@Sun.COM }
80010656SStephen.Hanson@Sun.COM 
8016228Sstephh void
fmd_asru_clear_aged_rsrcs()8026228Sstephh fmd_asru_clear_aged_rsrcs()
8036228Sstephh {
80410656SStephen.Hanson@Sun.COM 	int check_if_aged = 1;
8057275Sstephh 	fmd_asru_al_hash_apply(fmd.d_asrus, fmd_asru_repair_if_aged, NULL);
80610656SStephen.Hanson@Sun.COM 	fmd_case_hash_apply(fmd.d_cases, fmd_case_discard_resolved,
80710656SStephen.Hanson@Sun.COM 	    &check_if_aged);
8086228Sstephh }
8096228Sstephh 
8100Sstevel@tonic-gate fmd_asru_hash_t *
fmd_asru_hash_create(const char * root,const char * dir)8110Sstevel@tonic-gate fmd_asru_hash_create(const char *root, const char *dir)
8120Sstevel@tonic-gate {
8130Sstevel@tonic-gate 	fmd_asru_hash_t *ahp;
8140Sstevel@tonic-gate 	char path[PATH_MAX];
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 	ahp = fmd_alloc(sizeof (fmd_asru_hash_t), FMD_SLEEP);
8170Sstevel@tonic-gate 	(void) pthread_rwlock_init(&ahp->ah_lock, NULL);
8180Sstevel@tonic-gate 	ahp->ah_hashlen = fmd.d_str_buckets;
8190Sstevel@tonic-gate 	ahp->ah_hash = fmd_zalloc(sizeof (void *) * ahp->ah_hashlen, FMD_SLEEP);
8206228Sstephh 	ahp->ah_asru_hash = fmd_zalloc(sizeof (void *) * ahp->ah_hashlen,
8216228Sstephh 	    FMD_SLEEP);
8226228Sstephh 	ahp->ah_case_hash = fmd_zalloc(sizeof (void *) * ahp->ah_hashlen,
8236228Sstephh 	    FMD_SLEEP);
8246228Sstephh 	ahp->ah_fru_hash = fmd_zalloc(sizeof (void *) * ahp->ah_hashlen,
8256228Sstephh 	    FMD_SLEEP);
8266228Sstephh 	ahp->ah_label_hash = fmd_zalloc(sizeof (void *) * ahp->ah_hashlen,
8276228Sstephh 	    FMD_SLEEP);
8286228Sstephh 	ahp->ah_rsrc_hash = fmd_zalloc(sizeof (void *) * ahp->ah_hashlen,
8296228Sstephh 	    FMD_SLEEP);
8300Sstevel@tonic-gate 	(void) snprintf(path, sizeof (path), "%s/%s", root, dir);
8310Sstevel@tonic-gate 	ahp->ah_dirpath = fmd_strdup(path, FMD_SLEEP);
8320Sstevel@tonic-gate 	(void) fmd_conf_getprop(fmd.d_conf, "rsrc.age", &ahp->ah_lifetime);
8335255Sstephh 	(void) fmd_conf_getprop(fmd.d_conf, "fakenotpresent",
8345255Sstephh 	    (uint32_t *)&fmd_asru_fake_not_present);
8356228Sstephh 	ahp->ah_al_count = 0;
8360Sstevel@tonic-gate 	ahp->ah_count = 0;
8370Sstevel@tonic-gate 	ahp->ah_error = 0;
8386869Seschrock 	ahp->ah_topo = fmd_topo_hold();
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 	return (ahp);
8410Sstevel@tonic-gate }
8420Sstevel@tonic-gate 
8430Sstevel@tonic-gate void
fmd_asru_hash_destroy(fmd_asru_hash_t * ahp)8440Sstevel@tonic-gate fmd_asru_hash_destroy(fmd_asru_hash_t *ahp)
8450Sstevel@tonic-gate {
8466228Sstephh 	fmd_asru_link_t *alp, *np;
8470Sstevel@tonic-gate 	uint_t i;
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 	for (i = 0; i < ahp->ah_hashlen; i++) {
8506228Sstephh 		for (alp = ahp->ah_case_hash[i]; alp != NULL; alp = np) {
8516228Sstephh 			np = alp->al_case_next;
8526228Sstephh 			alp->al_case_next = NULL;
8536228Sstephh 			fmd_case_rele(alp->al_case);
8546228Sstephh 			alp->al_case = NULL;
8556228Sstephh 			fmd_asru_al_hash_release(ahp, alp);
8560Sstevel@tonic-gate 		}
8570Sstevel@tonic-gate 	}
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 	fmd_strfree(ahp->ah_dirpath);
8600Sstevel@tonic-gate 	fmd_free(ahp->ah_hash, sizeof (void *) * ahp->ah_hashlen);
8616228Sstephh 	fmd_free(ahp->ah_asru_hash, sizeof (void *) * ahp->ah_hashlen);
8626228Sstephh 	fmd_free(ahp->ah_case_hash, sizeof (void *) * ahp->ah_hashlen);
8636228Sstephh 	fmd_free(ahp->ah_fru_hash, sizeof (void *) * ahp->ah_hashlen);
8646228Sstephh 	fmd_free(ahp->ah_label_hash, sizeof (void *) * ahp->ah_hashlen);
8656228Sstephh 	fmd_free(ahp->ah_rsrc_hash, sizeof (void *) * ahp->ah_hashlen);
8666869Seschrock 	fmd_topo_rele(ahp->ah_topo);
8670Sstevel@tonic-gate 	fmd_free(ahp, sizeof (fmd_asru_hash_t));
8680Sstevel@tonic-gate }
8690Sstevel@tonic-gate 
8700Sstevel@tonic-gate /*
8710Sstevel@tonic-gate  * Take a snapshot of the ASRU database by placing an additional hold on each
8720Sstevel@tonic-gate  * member in an auxiliary array, and then call 'func' for each ASRU.
8730Sstevel@tonic-gate  */
8740Sstevel@tonic-gate void
fmd_asru_hash_apply(fmd_asru_hash_t * ahp,void (* func)(fmd_asru_t *,void *),void * arg)8750Sstevel@tonic-gate fmd_asru_hash_apply(fmd_asru_hash_t *ahp,
8760Sstevel@tonic-gate     void (*func)(fmd_asru_t *, void *), void *arg)
8770Sstevel@tonic-gate {
8780Sstevel@tonic-gate 	fmd_asru_t *ap, **aps, **app;
8790Sstevel@tonic-gate 	uint_t apc, i;
8800Sstevel@tonic-gate 
8810Sstevel@tonic-gate 	(void) pthread_rwlock_rdlock(&ahp->ah_lock);
8820Sstevel@tonic-gate 
8830Sstevel@tonic-gate 	aps = app = fmd_alloc(ahp->ah_count * sizeof (fmd_asru_t *), FMD_SLEEP);
8840Sstevel@tonic-gate 	apc = ahp->ah_count;
8850Sstevel@tonic-gate 
8860Sstevel@tonic-gate 	for (i = 0; i < ahp->ah_hashlen; i++) {
8870Sstevel@tonic-gate 		for (ap = ahp->ah_hash[i]; ap != NULL; ap = ap->asru_next)
8880Sstevel@tonic-gate 			*app++ = fmd_asru_hold(ap);
8890Sstevel@tonic-gate 	}
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	ASSERT(app == aps + apc);
8920Sstevel@tonic-gate 	(void) pthread_rwlock_unlock(&ahp->ah_lock);
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	for (i = 0; i < apc; i++) {
8956228Sstephh 		if (aps[i]->asru_fmri != NULL)
8966228Sstephh 			func(aps[i], arg);
8970Sstevel@tonic-gate 		fmd_asru_hash_release(ahp, aps[i]);
8980Sstevel@tonic-gate 	}
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	fmd_free(aps, apc * sizeof (fmd_asru_t *));
9010Sstevel@tonic-gate }
9020Sstevel@tonic-gate 
9036228Sstephh void
fmd_asru_al_hash_apply(fmd_asru_hash_t * ahp,void (* func)(fmd_asru_link_t *,void *),void * arg)9046228Sstephh fmd_asru_al_hash_apply(fmd_asru_hash_t *ahp,
9056228Sstephh     void (*func)(fmd_asru_link_t *, void *), void *arg)
9066228Sstephh {
9076228Sstephh 	fmd_asru_link_t *alp, **alps, **alpp;
9086228Sstephh 	uint_t alpc, i;
9096228Sstephh 
9106228Sstephh 	(void) pthread_rwlock_rdlock(&ahp->ah_lock);
9116228Sstephh 
9126228Sstephh 	alps = alpp = fmd_alloc(ahp->ah_al_count * sizeof (fmd_asru_link_t *),
9136228Sstephh 	    FMD_SLEEP);
9146228Sstephh 	alpc = ahp->ah_al_count;
9156228Sstephh 
9166228Sstephh 	for (i = 0; i < ahp->ah_hashlen; i++) {
9176228Sstephh 		for (alp = ahp->ah_case_hash[i]; alp != NULL;
9186228Sstephh 		    alp = alp->al_case_next)
9196228Sstephh 			*alpp++ = fmd_asru_al_hold(alp);
9206228Sstephh 	}
9216228Sstephh 
9226228Sstephh 	ASSERT(alpp == alps + alpc);
9236228Sstephh 	(void) pthread_rwlock_unlock(&ahp->ah_lock);
9246228Sstephh 
9256228Sstephh 	for (i = 0; i < alpc; i++) {
9266228Sstephh 		func(alps[i], arg);
9276228Sstephh 		fmd_asru_al_hash_release(ahp, alps[i]);
9286228Sstephh 	}
9296228Sstephh 
9306228Sstephh 	fmd_free(alps, alpc * sizeof (fmd_asru_link_t *));
9316228Sstephh }
9326228Sstephh 
9336228Sstephh 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)9349728SEric.Schrock@Sun.COM fmd_asru_do_hash_apply(fmd_asru_hash_t *ahp, const char *name,
9356228Sstephh     void (*func)(fmd_asru_link_t *, void *), void *arg,
9366228Sstephh     fmd_asru_link_t **hash, size_t match_offset, size_t next_offset)
9376228Sstephh {
9386228Sstephh 	fmd_asru_link_t *alp, **alps, **alpp;
9396228Sstephh 	uint_t alpc = 0, i;
9406228Sstephh 	uint_t h;
9416228Sstephh 
9426228Sstephh 	(void) pthread_rwlock_rdlock(&ahp->ah_lock);
9436228Sstephh 
9446869Seschrock 	h = fmd_asru_strhash(ahp, name);
9456228Sstephh 
9466228Sstephh 	for (alp = hash[h]; alp != NULL; alp =
9476228Sstephh 	    /* LINTED pointer alignment */
9486228Sstephh 	    FMD_ASRU_AL_HASH_NEXT(alp, next_offset))
9496869Seschrock 		if (fmd_asru_strcmp(ahp,
9506869Seschrock 		    /* LINTED pointer alignment */
9516869Seschrock 		    FMD_ASRU_AL_HASH_NAME(alp, match_offset), name))
9526228Sstephh 			alpc++;
9536228Sstephh 
9546228Sstephh 	alps = alpp = fmd_alloc(alpc * sizeof (fmd_asru_link_t *), FMD_SLEEP);
9556228Sstephh 
9566228Sstephh 	for (alp = hash[h]; alp != NULL; alp =
9576228Sstephh 	    /* LINTED pointer alignment */
9586228Sstephh 	    FMD_ASRU_AL_HASH_NEXT(alp, next_offset))
9596869Seschrock 		if (fmd_asru_strcmp(ahp,
9606869Seschrock 		    /* LINTED pointer alignment */
9616869Seschrock 		    FMD_ASRU_AL_HASH_NAME(alp, match_offset), name))
9626228Sstephh 			*alpp++ = fmd_asru_al_hold(alp);
9636228Sstephh 
9646228Sstephh 	ASSERT(alpp == alps + alpc);
9656228Sstephh 	(void) pthread_rwlock_unlock(&ahp->ah_lock);
9666228Sstephh 
9676228Sstephh 	for (i = 0; i < alpc; i++) {
9686228Sstephh 		func(alps[i], arg);
9696228Sstephh 		fmd_asru_al_hash_release(ahp, alps[i]);
9706228Sstephh 	}
9716228Sstephh 
9726228Sstephh 	fmd_free(alps, alpc * sizeof (fmd_asru_link_t *));
9736228Sstephh }
9746228Sstephh 
9756228Sstephh void
fmd_asru_hash_apply_by_asru(fmd_asru_hash_t * ahp,const char * name,void (* func)(fmd_asru_link_t *,void *),void * arg)9769728SEric.Schrock@Sun.COM fmd_asru_hash_apply_by_asru(fmd_asru_hash_t *ahp, const char *name,
9776228Sstephh     void (*func)(fmd_asru_link_t *, void *), void *arg)
9786228Sstephh {
9796228Sstephh 	fmd_asru_do_hash_apply(ahp, name, func, arg, ahp->ah_asru_hash,
9806228Sstephh 	    offsetof(fmd_asru_link_t, al_asru_name),
9816228Sstephh 	    offsetof(fmd_asru_link_t, al_asru_next));
9826228Sstephh }
9836228Sstephh 
9846228Sstephh 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)9856228Sstephh fmd_asru_hash_apply_by_case(fmd_asru_hash_t *ahp, fmd_case_t *cp,
9866228Sstephh 	void (*func)(fmd_asru_link_t *, void *), void *arg)
9876228Sstephh {
9886228Sstephh 	fmd_asru_do_hash_apply(ahp, ((fmd_case_impl_t *)cp)->ci_uuid, func, arg,
9896228Sstephh 	    ahp->ah_case_hash, offsetof(fmd_asru_link_t, al_case_uuid),
9906228Sstephh 	    offsetof(fmd_asru_link_t, al_case_next));
9916228Sstephh }
9926228Sstephh 
9936228Sstephh void
fmd_asru_hash_apply_by_fru(fmd_asru_hash_t * ahp,const char * name,void (* func)(fmd_asru_link_t *,void *),void * arg)9949728SEric.Schrock@Sun.COM fmd_asru_hash_apply_by_fru(fmd_asru_hash_t *ahp, const char *name,
9956228Sstephh     void (*func)(fmd_asru_link_t *, void *), void *arg)
9966228Sstephh {
9976228Sstephh 	fmd_asru_do_hash_apply(ahp, name, func, arg, ahp->ah_fru_hash,
9986228Sstephh 	    offsetof(fmd_asru_link_t, al_fru_name),
9996228Sstephh 	    offsetof(fmd_asru_link_t, al_fru_next));
10006228Sstephh }
10016228Sstephh 
10026228Sstephh void
fmd_asru_hash_apply_by_rsrc(fmd_asru_hash_t * ahp,const char * name,void (* func)(fmd_asru_link_t *,void *),void * arg)10039728SEric.Schrock@Sun.COM fmd_asru_hash_apply_by_rsrc(fmd_asru_hash_t *ahp, const char *name,
10046228Sstephh     void (*func)(fmd_asru_link_t *, void *), void *arg)
10056228Sstephh {
10066228Sstephh 	fmd_asru_do_hash_apply(ahp, name, func, arg, ahp->ah_rsrc_hash,
10076228Sstephh 	    offsetof(fmd_asru_link_t, al_rsrc_name),
10086228Sstephh 	    offsetof(fmd_asru_link_t, al_rsrc_next));
10096228Sstephh }
10106228Sstephh 
10116228Sstephh void
fmd_asru_hash_apply_by_label(fmd_asru_hash_t * ahp,const char * name,void (* func)(fmd_asru_link_t *,void *),void * arg)10129728SEric.Schrock@Sun.COM fmd_asru_hash_apply_by_label(fmd_asru_hash_t *ahp, const char *name,
10136228Sstephh     void (*func)(fmd_asru_link_t *, void *), void *arg)
10146228Sstephh {
10156228Sstephh 	fmd_asru_do_hash_apply(ahp, name, func, arg, ahp->ah_label_hash,
10166228Sstephh 	    offsetof(fmd_asru_link_t, al_label),
10176228Sstephh 	    offsetof(fmd_asru_link_t, al_label_next));
10186228Sstephh }
10196228Sstephh 
10200Sstevel@tonic-gate /*
10210Sstevel@tonic-gate  * Lookup an asru in the hash by name and place a hold on it.  If the asru is
10220Sstevel@tonic-gate  * not found, no entry is created and NULL is returned.
10230Sstevel@tonic-gate  */
10240Sstevel@tonic-gate fmd_asru_t *
fmd_asru_hash_lookup_name(fmd_asru_hash_t * ahp,const char * name)10250Sstevel@tonic-gate fmd_asru_hash_lookup_name(fmd_asru_hash_t *ahp, const char *name)
10260Sstevel@tonic-gate {
10270Sstevel@tonic-gate 	fmd_asru_t *ap;
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 	(void) pthread_rwlock_rdlock(&ahp->ah_lock);
10300Sstevel@tonic-gate 	ap = fmd_asru_hash_lookup(ahp, name);
10310Sstevel@tonic-gate 	(void) pthread_rwlock_unlock(&ahp->ah_lock);
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate 	return (ap);
10340Sstevel@tonic-gate }
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate /*
10376228Sstephh  * Create a resource cache entry using the fault event "nvl" for one of the
10386228Sstephh  * suspects from the case "cp".
10396228Sstephh  *
10406228Sstephh  * The fault event can have the following components :  FM_FAULT_ASRU,
10416228Sstephh  * FM_FAULT_FRU, FM_FAULT_RESOURCE. These should be set by the Diagnosis Engine
10426228Sstephh  * when calling fmd_nvl_create_fault(). In the general case, these are all
10436228Sstephh  * optional and an entry will always be added into the cache even if one or all
10446228Sstephh  * of these fields is missing.
10456228Sstephh  *
10466228Sstephh  * However, for hardware faults the recommended practice is that the fault
10476228Sstephh  * event should always have the FM_FAULT_RESOURCE field present and that this
10486228Sstephh  * should be represented in hc-scheme.
10496228Sstephh  *
10506228Sstephh  * Currently the DE should also add the FM_FAULT_ASRU and FM_FAULT_FRU fields
10516228Sstephh  * where known, though at some future stage fmd might be able to fill these
10526228Sstephh  * in automatically from the topology.
10536228Sstephh  */
10546228Sstephh fmd_asru_link_t *
fmd_asru_hash_create_entry(fmd_asru_hash_t * ahp,fmd_case_t * cp,nvlist_t * nvl)10556228Sstephh fmd_asru_hash_create_entry(fmd_asru_hash_t *ahp, fmd_case_t *cp, nvlist_t *nvl)
10566228Sstephh {
10576228Sstephh 	char *parsed_uuid;
10586228Sstephh 	uuid_t uuid;
10596228Sstephh 	int uuidlen;
10606228Sstephh 	fmd_asru_link_t *alp;
10610Sstevel@tonic-gate 
10620Sstevel@tonic-gate 	/*
10636228Sstephh 	 * Generate a UUID for the ASRU.  libuuid cleverly gives us no
10646228Sstephh 	 * interface for specifying or learning the buffer size.  Sigh.
10656228Sstephh 	 * The spec says 36 bytes but we use a tunable just to be safe.
10660Sstevel@tonic-gate 	 */
10676228Sstephh 	(void) fmd_conf_getprop(fmd.d_conf, "uuidlen", &uuidlen);
10686228Sstephh 	parsed_uuid = fmd_zalloc(uuidlen + 1, FMD_SLEEP);
10696228Sstephh 	uuid_generate(uuid);
10706228Sstephh 	uuid_unparse(uuid, parsed_uuid);
10710Sstevel@tonic-gate 
10726228Sstephh 	/*
10736228Sstephh 	 * Now create the resource cache entries.
10746228Sstephh 	 */
10756228Sstephh 	fmd_case_hold_locked(cp);
10766228Sstephh 	alp = fmd_asru_al_create(ahp, nvl, cp, parsed_uuid);
10776228Sstephh 	TRACE((FMD_DBG_ASRU, "asru %s created as %p",
10786228Sstephh 	    alp->al_uuid, (void *)alp->al_asru));
10790Sstevel@tonic-gate 
10806228Sstephh 	fmd_free(parsed_uuid, uuidlen + 1);
10816228Sstephh 	return (alp);
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate }
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate /*
10860Sstevel@tonic-gate  * Release the reference count on an asru obtained using fmd_asru_hash_lookup.
10870Sstevel@tonic-gate  * We take 'ahp' for symmetry and in case we need to use it in future work.
10880Sstevel@tonic-gate  */
10890Sstevel@tonic-gate /*ARGSUSED*/
10900Sstevel@tonic-gate void
fmd_asru_hash_release(fmd_asru_hash_t * ahp,fmd_asru_t * ap)10910Sstevel@tonic-gate fmd_asru_hash_release(fmd_asru_hash_t *ahp, fmd_asru_t *ap)
10920Sstevel@tonic-gate {
10930Sstevel@tonic-gate 	(void) pthread_mutex_lock(&ap->asru_lock);
10940Sstevel@tonic-gate 
10950Sstevel@tonic-gate 	ASSERT(ap->asru_refs != 0);
10960Sstevel@tonic-gate 	if (--ap->asru_refs == 0)
10970Sstevel@tonic-gate 		fmd_asru_destroy(ap);
10980Sstevel@tonic-gate 	else
10990Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&ap->asru_lock);
11000Sstevel@tonic-gate }
11010Sstevel@tonic-gate 
11026228Sstephh 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)11036228Sstephh fmd_asru_do_delete_entry(fmd_asru_hash_t *ahp, fmd_case_t *cp,
11046228Sstephh     fmd_asru_link_t **hash, size_t next_offset, char *name)
11050Sstevel@tonic-gate {
11060Sstevel@tonic-gate 	uint_t h;
11076228Sstephh 	fmd_asru_link_t *alp, **pp, *alpnext, **alpnextp;
11080Sstevel@tonic-gate 
11090Sstevel@tonic-gate 	(void) pthread_rwlock_wrlock(&ahp->ah_lock);
11106869Seschrock 	h = fmd_asru_strhash(ahp, name);
11116228Sstephh 	pp = &hash[h];
11126228Sstephh 	for (alp = *pp; alp != NULL; alp = alpnext) {
11136228Sstephh 		/* LINTED pointer alignment */
11146228Sstephh 		alpnextp = FMD_ASRU_AL_HASH_NEXTP(alp, next_offset);
11156228Sstephh 		alpnext = *alpnextp;
11166228Sstephh 		if (alp->al_case == cp) {
11176228Sstephh 			*pp = *alpnextp;
11186228Sstephh 			*alpnextp = NULL;
11196228Sstephh 		} else
11206228Sstephh 			pp = alpnextp;
11210Sstevel@tonic-gate 	}
11220Sstevel@tonic-gate 	(void) pthread_rwlock_unlock(&ahp->ah_lock);
11230Sstevel@tonic-gate }
11240Sstevel@tonic-gate 
11250Sstevel@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)11266228Sstephh fmd_asru_do_hash_delete(fmd_asru_hash_t *ahp, fmd_case_susp_t *cis,
11276228Sstephh     fmd_case_t *cp, fmd_asru_link_t **hash, size_t next_offset, char *nvname)
11286228Sstephh {
11296228Sstephh 	nvlist_t *nvl;
11306228Sstephh 	char *name = NULL;
11316228Sstephh 	ssize_t namelen;
11326228Sstephh 
11336228Sstephh 	if (nvlist_lookup_nvlist(cis->cis_nvl, nvname, &nvl) == 0 &&
11346228Sstephh 	    (namelen = fmd_fmri_nvl2str(nvl, NULL, 0)) != -1 &&
11356228Sstephh 	    (name = fmd_alloc(namelen + 1, FMD_SLEEP)) != NULL) {
11366228Sstephh 		if (fmd_fmri_nvl2str(nvl, name, namelen + 1) != -1)
11376228Sstephh 			fmd_asru_do_delete_entry(ahp, cp, hash, next_offset,
11386228Sstephh 			    name);
11396228Sstephh 		fmd_free(name, namelen + 1);
11406228Sstephh 	} else
11416228Sstephh 		fmd_asru_do_delete_entry(ahp, cp, hash, next_offset, "");
11426228Sstephh }
11436228Sstephh 
11446228Sstephh void
fmd_asru_hash_delete_case(fmd_asru_hash_t * ahp,fmd_case_t * cp)11456228Sstephh fmd_asru_hash_delete_case(fmd_asru_hash_t *ahp, fmd_case_t *cp)
11460Sstevel@tonic-gate {
11476228Sstephh 	fmd_case_impl_t *cip = (fmd_case_impl_t *)cp;
11486228Sstephh 	fmd_case_susp_t *cis;
11496228Sstephh 	fmd_asru_link_t *alp, **plp, *alpnext;
11506228Sstephh 	fmd_asru_t *ap;
11516228Sstephh 	char path[PATH_MAX];
11526228Sstephh 	char *label;
11536228Sstephh 	uint_t h;
11546228Sstephh 
11556228Sstephh 	/*
11566228Sstephh 	 * first delete hash entries for each suspect
11576228Sstephh 	 */
11586228Sstephh 	for (cis = cip->ci_suspects; cis != NULL; cis = cis->cis_next) {
11596228Sstephh 		fmd_asru_do_hash_delete(ahp, cis, cp, ahp->ah_fru_hash,
11606228Sstephh 		    offsetof(fmd_asru_link_t, al_fru_next), FM_FAULT_FRU);
11616228Sstephh 		fmd_asru_do_hash_delete(ahp, cis, cp, ahp->ah_rsrc_hash,
11626228Sstephh 		    offsetof(fmd_asru_link_t, al_rsrc_next), FM_FAULT_RESOURCE);
11636228Sstephh 		if (nvlist_lookup_string(cis->cis_nvl, FM_FAULT_LOCATION,
11646228Sstephh 		    &label) != 0)
11656228Sstephh 			label = "";
11666228Sstephh 		fmd_asru_do_delete_entry(ahp, cp, ahp->ah_label_hash,
11676228Sstephh 		    offsetof(fmd_asru_link_t, al_label_next), label);
11686228Sstephh 		fmd_asru_do_hash_delete(ahp, cis, cp, ahp->ah_asru_hash,
11696228Sstephh 		    offsetof(fmd_asru_link_t, al_asru_next), FM_FAULT_ASRU);
11706228Sstephh 	}
11716228Sstephh 
11726228Sstephh 	/*
11736228Sstephh 	 * then delete associated case hash entries
11746228Sstephh 	 */
11756228Sstephh 	(void) pthread_rwlock_wrlock(&ahp->ah_lock);
11766869Seschrock 	h = fmd_asru_strhash(ahp, cip->ci_uuid);
11776228Sstephh 	plp = &ahp->ah_case_hash[h];
11786228Sstephh 	for (alp = *plp; alp != NULL; alp = alpnext) {
11796228Sstephh 		alpnext = alp->al_case_next;
11806228Sstephh 		if (alp->al_case == cp) {
11816228Sstephh 			*plp = alp->al_case_next;
11826228Sstephh 			alp->al_case_next = NULL;
11836228Sstephh 			ASSERT(ahp->ah_al_count != 0);
11846228Sstephh 			ahp->ah_al_count--;
11856228Sstephh 
11866228Sstephh 			/*
11876228Sstephh 			 * decrement case ref.
11886228Sstephh 			 */
11896228Sstephh 			fmd_case_rele_locked(cp);
11906228Sstephh 			alp->al_case = NULL;
11916228Sstephh 
11926228Sstephh 			/*
11936228Sstephh 			 * If we found a matching ASRU, unlink its log file and
11946228Sstephh 			 * then release the hash entry. Note that it may still
11956228Sstephh 			 * be referenced if another thread is manipulating it;
11966228Sstephh 			 * this is ok because once we unlink, the log file will
11976228Sstephh 			 * not be restored, and the log data will be freed when
11986228Sstephh 			 * all of the referencing threads release their
11996228Sstephh 			 * respective references.
12006228Sstephh 			 */
12016228Sstephh 			(void) snprintf(path, sizeof (path), "%s/%s",
12026228Sstephh 			    ahp->ah_dirpath, alp->al_uuid);
12039120SStephen.Hanson@Sun.COM 			if (cip->ci_xprt == NULL && unlink(path) != 0)
12046228Sstephh 				fmd_error(EFMD_ASRU_UNLINK,
12056228Sstephh 				    "failed to unlink asru %s", path);
12066228Sstephh 
12076228Sstephh 			/*
12086228Sstephh 			 * Now unlink from the global per-resource cache
12096228Sstephh 			 * and if this is the last link then remove that from
12106228Sstephh 			 * it's own hash too.
12116228Sstephh 			 */
12126228Sstephh 			ap = alp->al_asru;
12136228Sstephh 			(void) pthread_mutex_lock(&ap->asru_lock);
12146228Sstephh 			fmd_list_delete(&ap->asru_list, alp);
12156228Sstephh 			if (ap->asru_list.l_next == NULL) {
12166228Sstephh 				uint_t h;
12176228Sstephh 				fmd_asru_t *ap2, **pp;
12186228Sstephh 				fmd_asru_t *apnext, **apnextp;
12196228Sstephh 
12206228Sstephh 				ASSERT(ahp->ah_count != 0);
12216228Sstephh 				ahp->ah_count--;
12226869Seschrock 				h = fmd_asru_strhash(ahp, ap->asru_name);
12236869Seschrock 				pp = &ahp->ah_hash[h];
12246228Sstephh 				for (ap2 = *pp; ap2 != NULL; ap2 = apnext) {
12256228Sstephh 					apnextp = &ap2->asru_next;
12266228Sstephh 					apnext = *apnextp;
12276228Sstephh 					if (ap2 == ap) {
12286228Sstephh 						*pp = *apnextp;
12296228Sstephh 						*apnextp = NULL;
12306228Sstephh 					} else
12316228Sstephh 						pp = apnextp;
12326228Sstephh 				}
12336228Sstephh 			}
12346228Sstephh 			(void) pthread_mutex_unlock(&ap->asru_lock);
12356228Sstephh 			fmd_asru_al_hash_release(ahp, alp);
12366228Sstephh 		} else
12376228Sstephh 			plp = &alp->al_case_next;
12386228Sstephh 	}
12396228Sstephh 	(void) pthread_rwlock_unlock(&ahp->ah_lock);
12406228Sstephh }
12416228Sstephh 
12429120SStephen.Hanson@Sun.COM typedef struct {
12439120SStephen.Hanson@Sun.COM 	nvlist_t *farc_parent_fmri;
12449120SStephen.Hanson@Sun.COM 	uint8_t farc_reason;
12459120SStephen.Hanson@Sun.COM } fmd_asru_farc_t;
12466228Sstephh 
12479120SStephen.Hanson@Sun.COM static void
fmd_asru_repair_containee(fmd_asru_link_t * alp,void * arg)12489120SStephen.Hanson@Sun.COM fmd_asru_repair_containee(fmd_asru_link_t *alp, void *arg)
12496228Sstephh {
12509120SStephen.Hanson@Sun.COM 	fmd_asru_farc_t *farcp = (fmd_asru_farc_t *)arg;
12516228Sstephh 
12529120SStephen.Hanson@Sun.COM 	if ((alp->al_asru->asru_flags & FMD_ASRU_INVISIBLE) &&
12539120SStephen.Hanson@Sun.COM 	    alp->al_asru_fmri &&
12549120SStephen.Hanson@Sun.COM 	    fmd_fmri_contains(farcp->farc_parent_fmri, alp->al_asru_fmri) > 0) {
12559120SStephen.Hanson@Sun.COM 		if (fmd_asru_clrflags(alp, FMD_ASRU_FAULTY,
12569120SStephen.Hanson@Sun.COM 		    farcp->farc_reason)) {
12579120SStephen.Hanson@Sun.COM 			if (alp->al_flags & FMD_ASRU_PROXY)
12589120SStephen.Hanson@Sun.COM 				fmd_case_xprt_updated(alp->al_case);
12599120SStephen.Hanson@Sun.COM 			else
12609120SStephen.Hanson@Sun.COM 				fmd_case_update(alp->al_case);
12619120SStephen.Hanson@Sun.COM 		}
12626228Sstephh 	}
12636228Sstephh }
12646228Sstephh 
12656228Sstephh static void
fmd_asru_do_repair_containees(fmd_asru_link_t * alp,uint8_t reason)12669120SStephen.Hanson@Sun.COM fmd_asru_do_repair_containees(fmd_asru_link_t *alp, uint8_t reason)
12677275Sstephh {
12687275Sstephh 	int flags;
12697275Sstephh 
12707275Sstephh 	/*
12719120SStephen.Hanson@Sun.COM 	 * Check if all entries associated with this asru are acquitted and
12729120SStephen.Hanson@Sun.COM 	 * if so acquit containees. Don't try to repair containees on proxy
12739120SStephen.Hanson@Sun.COM 	 * side unless we have local asru.
12747275Sstephh 	 */
12759120SStephen.Hanson@Sun.COM 	if (alp->al_asru_fmri != NULL && (!(alp->al_flags & FMD_ASRU_PROXY) ||
12769120SStephen.Hanson@Sun.COM 	    (alp->al_flags & FMD_ASRU_PROXY_WITH_ASRU))) {
12779120SStephen.Hanson@Sun.COM 		(void) pthread_mutex_lock(&alp->al_asru->asru_lock);
12789120SStephen.Hanson@Sun.COM 		flags = alp->al_asru->asru_flags;
12799120SStephen.Hanson@Sun.COM 		(void) pthread_mutex_unlock(&alp->al_asru->asru_lock);
12809120SStephen.Hanson@Sun.COM 		if (!(flags & (FMD_ASRU_FAULTY | FMD_ASRU_INVISIBLE))) {
12819120SStephen.Hanson@Sun.COM 			fmd_asru_farc_t farc;
12827275Sstephh 
12839120SStephen.Hanson@Sun.COM 			farc.farc_parent_fmri = alp->al_asru_fmri;
12849120SStephen.Hanson@Sun.COM 			farc.farc_reason = reason;
12859120SStephen.Hanson@Sun.COM 			fmd_asru_al_hash_apply(fmd.d_asrus,
12869120SStephen.Hanson@Sun.COM 			    fmd_asru_repair_containee, &farc);
12879120SStephen.Hanson@Sun.COM 		}
12889120SStephen.Hanson@Sun.COM 	}
12897275Sstephh }
12907275Sstephh 
12917275Sstephh void
fmd_asru_repaired(fmd_asru_link_t * alp,void * arg)12929120SStephen.Hanson@Sun.COM fmd_asru_repaired(fmd_asru_link_t *alp, void *arg)
12937275Sstephh {
12949120SStephen.Hanson@Sun.COM 	int cleared;
12959120SStephen.Hanson@Sun.COM 	fmd_asru_rep_arg_t *farap = (fmd_asru_rep_arg_t *)arg;
12969120SStephen.Hanson@Sun.COM 
12979120SStephen.Hanson@Sun.COM 	/*
12989120SStephen.Hanson@Sun.COM 	 * don't allow remote repair over readonly transport
12999120SStephen.Hanson@Sun.COM 	 */
13009120SStephen.Hanson@Sun.COM 	if (alp->al_flags & FMD_ASRU_PROXY_RDONLY)
13019120SStephen.Hanson@Sun.COM 		return;
13029120SStephen.Hanson@Sun.COM 
13039120SStephen.Hanson@Sun.COM 	/*
13049120SStephen.Hanson@Sun.COM 	 * don't allow repair etc by asru on proxy unless asru is local
13059120SStephen.Hanson@Sun.COM 	 */
13069120SStephen.Hanson@Sun.COM 	if (farap->fara_bywhat == FARA_BY_ASRU &&
13079120SStephen.Hanson@Sun.COM 	    (alp->al_flags & FMD_ASRU_PROXY) &&
13089120SStephen.Hanson@Sun.COM 	    !(alp->al_flags & FMD_ASRU_PROXY_WITH_ASRU))
13099120SStephen.Hanson@Sun.COM 		return;
13109120SStephen.Hanson@Sun.COM 	/*
13119120SStephen.Hanson@Sun.COM 	 * For acquit, need to check both name and uuid if specified
13129120SStephen.Hanson@Sun.COM 	 */
13139120SStephen.Hanson@Sun.COM 	if (farap->fara_reason == FMD_ASRU_ACQUITTED &&
13149120SStephen.Hanson@Sun.COM 	    farap->fara_rval != NULL && strcmp(farap->fara_uuid, "") != 0 &&
13159120SStephen.Hanson@Sun.COM 	    strcmp(farap->fara_uuid, alp->al_case_uuid) != 0)
13169120SStephen.Hanson@Sun.COM 		return;
13177275Sstephh 
13189120SStephen.Hanson@Sun.COM 	/*
13199874SStephen.Hanson@Sun.COM 	 * For replaced, verify it has been replaced if we have serial number.
13209874SStephen.Hanson@Sun.COM 	 * If not set *farap->fara_rval to FARA_ERR_RSRCNOTR.
13219120SStephen.Hanson@Sun.COM 	 */
13229120SStephen.Hanson@Sun.COM 	if (farap->fara_reason == FMD_ASRU_REPLACED &&
13239120SStephen.Hanson@Sun.COM 	    !(alp->al_flags & FMD_ASRU_PROXY_EXTERNAL) &&
13249120SStephen.Hanson@Sun.COM 	    fmd_asru_replacement_state(alp->al_event,
13259120SStephen.Hanson@Sun.COM 	    (alp->al_flags & FMD_ASRU_PROXY) ? HC_ONLY_TRUE : HC_ONLY_FALSE) ==
13269120SStephen.Hanson@Sun.COM 	    FMD_OBJ_STATE_STILL_PRESENT) {
13279874SStephen.Hanson@Sun.COM 		if (farap->fara_rval)
13289874SStephen.Hanson@Sun.COM 			*farap->fara_rval = FARA_ERR_RSRCNOTR;
13299120SStephen.Hanson@Sun.COM 		return;
13309120SStephen.Hanson@Sun.COM 	}
13319120SStephen.Hanson@Sun.COM 
13329120SStephen.Hanson@Sun.COM 	cleared = fmd_asru_clrflags(alp, FMD_ASRU_FAULTY, farap->fara_reason);
13339120SStephen.Hanson@Sun.COM 	fmd_asru_do_repair_containees(alp, farap->fara_reason);
13349120SStephen.Hanson@Sun.COM 
13359120SStephen.Hanson@Sun.COM 	/*
13369120SStephen.Hanson@Sun.COM 	 * if called from fmd_adm_*() and we really did clear the bit then
13379120SStephen.Hanson@Sun.COM 	 * we need to do a case update to see if the associated case can be
13389120SStephen.Hanson@Sun.COM 	 * repaired. No need to do this if called from fmd_case_*() (ie
13399120SStephen.Hanson@Sun.COM 	 * when arg is NULL) as the case will be explicitly repaired anyway.
13409120SStephen.Hanson@Sun.COM 	 */
13419120SStephen.Hanson@Sun.COM 	if (farap->fara_rval) {
13429874SStephen.Hanson@Sun.COM 		/*
13439874SStephen.Hanson@Sun.COM 		 * *farap->fara_rval defaults to FARA_ERR_RSRCNOTF (not found).
13449874SStephen.Hanson@Sun.COM 		 * If we find a valid cache entry which we repair then we
13459874SStephen.Hanson@Sun.COM 		 * set it to FARA_OK. However we don't want to do this if
13469874SStephen.Hanson@Sun.COM 		 * we have already set it to FARA_ERR_RSRCNOTR (not replaced)
13479874SStephen.Hanson@Sun.COM 		 * in a previous iteration (see above). So only set it to
13489874SStephen.Hanson@Sun.COM 		 * FARA_OK if the current value is still FARA_ERR_RSRCNOTF.
13499874SStephen.Hanson@Sun.COM 		 */
13509874SStephen.Hanson@Sun.COM 		if (*farap->fara_rval == FARA_ERR_RSRCNOTF)
13519874SStephen.Hanson@Sun.COM 			*farap->fara_rval = FARA_OK;
13529120SStephen.Hanson@Sun.COM 		if (cleared) {
13539120SStephen.Hanson@Sun.COM 			if (alp->al_flags & FMD_ASRU_PROXY)
13549120SStephen.Hanson@Sun.COM 				fmd_case_xprt_updated(alp->al_case);
13559120SStephen.Hanson@Sun.COM 			else
13569120SStephen.Hanson@Sun.COM 				fmd_case_update(alp->al_case);
13579120SStephen.Hanson@Sun.COM 		}
13589120SStephen.Hanson@Sun.COM 	}
13599120SStephen.Hanson@Sun.COM }
13609120SStephen.Hanson@Sun.COM 
13619120SStephen.Hanson@Sun.COM /*
136210656SStephen.Hanson@Sun.COM  * Discard the case associated with this alp if it is in resolved state.
136310656SStephen.Hanson@Sun.COM  * Called on "fmadm flush".
136410656SStephen.Hanson@Sun.COM  */
136510656SStephen.Hanson@Sun.COM /*ARGSUSED*/
136610656SStephen.Hanson@Sun.COM void
fmd_asru_flush(fmd_asru_link_t * alp,void * arg)136710656SStephen.Hanson@Sun.COM fmd_asru_flush(fmd_asru_link_t *alp, void *arg)
136810656SStephen.Hanson@Sun.COM {
136910656SStephen.Hanson@Sun.COM 	int check_if_aged = 0;
137010656SStephen.Hanson@Sun.COM 	int *rval = (int *)arg;
137110656SStephen.Hanson@Sun.COM 
137210656SStephen.Hanson@Sun.COM 	if (alp->al_case)
137310656SStephen.Hanson@Sun.COM 		fmd_case_discard_resolved(alp->al_case, &check_if_aged);
137410656SStephen.Hanson@Sun.COM 	*rval = 0;
137510656SStephen.Hanson@Sun.COM }
137610656SStephen.Hanson@Sun.COM 
137710656SStephen.Hanson@Sun.COM /*
13789120SStephen.Hanson@Sun.COM  * This is only called for proxied faults. Set various flags so we can
13799120SStephen.Hanson@Sun.COM  * find the nature of the transport from the resource cache code.
13809120SStephen.Hanson@Sun.COM  */
13819120SStephen.Hanson@Sun.COM /*ARGSUSED*/
13829120SStephen.Hanson@Sun.COM void
fmd_asru_set_on_proxy(fmd_asru_link_t * alp,void * arg)13839120SStephen.Hanson@Sun.COM fmd_asru_set_on_proxy(fmd_asru_link_t *alp, void *arg)
13849120SStephen.Hanson@Sun.COM {
13859120SStephen.Hanson@Sun.COM 	fmd_asru_set_on_proxy_t *entryp = (fmd_asru_set_on_proxy_t *)arg;
13869120SStephen.Hanson@Sun.COM 
13879120SStephen.Hanson@Sun.COM 	if (*entryp->fasp_countp >= entryp->fasp_maxcount)
13887275Sstephh 		return;
13897275Sstephh 
13907275Sstephh 	/*
13919120SStephen.Hanson@Sun.COM 	 * Note that this is a proxy fault and save whetehr transport is
13929120SStephen.Hanson@Sun.COM 	 * RDONLY or EXTERNAL.
13937275Sstephh 	 */
13949120SStephen.Hanson@Sun.COM 	alp->al_flags |= FMD_ASRU_PROXY;
13959120SStephen.Hanson@Sun.COM 	alp->al_asru->asru_flags |= FMD_ASRU_PROXY;
13969120SStephen.Hanson@Sun.COM 
13979120SStephen.Hanson@Sun.COM 	if (entryp->fasp_proxy_external) {
13989120SStephen.Hanson@Sun.COM 		alp->al_flags |= FMD_ASRU_PROXY_EXTERNAL;
13999120SStephen.Hanson@Sun.COM 		alp->al_asru->asru_flags |= FMD_ASRU_PROXY_EXTERNAL;
14009120SStephen.Hanson@Sun.COM 	}
14019120SStephen.Hanson@Sun.COM 
14029120SStephen.Hanson@Sun.COM 	if (entryp->fasp_proxy_rdonly)
14039120SStephen.Hanson@Sun.COM 		alp->al_flags |= FMD_ASRU_PROXY_RDONLY;
14047275Sstephh 
14057275Sstephh 	/*
14069120SStephen.Hanson@Sun.COM 	 * Save whether asru is accessible in local domain
14077275Sstephh 	 */
14089120SStephen.Hanson@Sun.COM 	if (entryp->fasp_proxy_asru[*entryp->fasp_countp]) {
14099120SStephen.Hanson@Sun.COM 		alp->al_flags |= FMD_ASRU_PROXY_WITH_ASRU;
14109120SStephen.Hanson@Sun.COM 		alp->al_asru->asru_flags |= FMD_ASRU_PROXY_WITH_ASRU;
14119120SStephen.Hanson@Sun.COM 	}
14129120SStephen.Hanson@Sun.COM 	(*entryp->fasp_countp)++;
14139120SStephen.Hanson@Sun.COM }
14147275Sstephh 
14159120SStephen.Hanson@Sun.COM /*ARGSUSED*/
14169120SStephen.Hanson@Sun.COM void
fmd_asru_update_containees(fmd_asru_link_t * alp,void * arg)14179120SStephen.Hanson@Sun.COM fmd_asru_update_containees(fmd_asru_link_t *alp, void *arg)
14189120SStephen.Hanson@Sun.COM {
14199120SStephen.Hanson@Sun.COM 	fmd_asru_do_repair_containees(alp, alp->al_reason);
14207275Sstephh }
14217275Sstephh 
14229120SStephen.Hanson@Sun.COM /*
14239120SStephen.Hanson@Sun.COM  * This function is used for fault proxying. It updates the resource status in
14249120SStephen.Hanson@Sun.COM  * the resource cache based on information that has come from the other side of
14259120SStephen.Hanson@Sun.COM  * the transport. This can be called on either the proxy side or the
14269120SStephen.Hanson@Sun.COM  * diagnosing side.
14279120SStephen.Hanson@Sun.COM  */
14289120SStephen.Hanson@Sun.COM void
fmd_asru_update_status(fmd_asru_link_t * alp,void * arg)14299120SStephen.Hanson@Sun.COM fmd_asru_update_status(fmd_asru_link_t *alp, void *arg)
14307275Sstephh {
14319120SStephen.Hanson@Sun.COM 	fmd_asru_update_status_t *entryp = (fmd_asru_update_status_t *)arg;
14329120SStephen.Hanson@Sun.COM 	uint8_t status;
14339120SStephen.Hanson@Sun.COM 
14349120SStephen.Hanson@Sun.COM 	if (*entryp->faus_countp >= entryp->faus_maxcount)
14359120SStephen.Hanson@Sun.COM 		return;
14369120SStephen.Hanson@Sun.COM 
14379120SStephen.Hanson@Sun.COM 	status = entryp->faus_ba[*entryp->faus_countp];
14387275Sstephh 
14399120SStephen.Hanson@Sun.COM 	/*
14409120SStephen.Hanson@Sun.COM 	 * For proxy, if there is no asru on the proxy side, but there is on
14419120SStephen.Hanson@Sun.COM 	 * the diag side, then take the diag side asru status.
14429120SStephen.Hanson@Sun.COM 	 * For diag, if there is an asru on the proxy side, then take the proxy
14439120SStephen.Hanson@Sun.COM 	 * side asru status.
14449120SStephen.Hanson@Sun.COM 	 */
14459120SStephen.Hanson@Sun.COM 	if (entryp->faus_is_proxy ?
14469120SStephen.Hanson@Sun.COM 	    (entryp->faus_diag_asru[*entryp->faus_countp] &&
14479120SStephen.Hanson@Sun.COM 	    !entryp->faus_proxy_asru[*entryp->faus_countp]) :
14489120SStephen.Hanson@Sun.COM 	    entryp->faus_proxy_asru[*entryp->faus_countp]) {
14499120SStephen.Hanson@Sun.COM 		if (status & FM_SUSPECT_DEGRADED)
14509120SStephen.Hanson@Sun.COM 			alp->al_flags |= FMD_ASRU_DEGRADED;
14519120SStephen.Hanson@Sun.COM 		else
14529120SStephen.Hanson@Sun.COM 			alp->al_flags &= ~FMD_ASRU_DEGRADED;
14539120SStephen.Hanson@Sun.COM 		if (status & FM_SUSPECT_UNUSABLE)
14549120SStephen.Hanson@Sun.COM 			(void) fmd_asru_setflags(alp, FMD_ASRU_UNUSABLE);
14559120SStephen.Hanson@Sun.COM 		else
14569120SStephen.Hanson@Sun.COM 			(void) fmd_asru_clrflags(alp, FMD_ASRU_UNUSABLE, 0);
14579120SStephen.Hanson@Sun.COM 	}
14587275Sstephh 
14597275Sstephh 	/*
14609120SStephen.Hanson@Sun.COM 	 * Update the faulty status too.
14617275Sstephh 	 */
14629120SStephen.Hanson@Sun.COM 	if (!(status & FM_SUSPECT_FAULTY))
14639120SStephen.Hanson@Sun.COM 		(void) fmd_asru_clrflags(alp, FMD_ASRU_FAULTY,
14649120SStephen.Hanson@Sun.COM 		    (status & FM_SUSPECT_REPAIRED) ? FMD_ASRU_REPAIRED :
14659120SStephen.Hanson@Sun.COM 		    (status & FM_SUSPECT_REPLACED) ? FMD_ASRU_REPLACED :
14669120SStephen.Hanson@Sun.COM 		    (status & FM_SUSPECT_ACQUITTED) ? FMD_ASRU_ACQUITTED :
14679120SStephen.Hanson@Sun.COM 		    FMD_ASRU_REMOVED);
14689120SStephen.Hanson@Sun.COM 	else if (entryp->faus_is_proxy)
14699120SStephen.Hanson@Sun.COM 		(void) fmd_asru_setflags(alp, FMD_ASRU_FAULTY);
14707275Sstephh 
14717275Sstephh 	/*
14729120SStephen.Hanson@Sun.COM 	 * for proxy only, update the present status too.
14737275Sstephh 	 */
14749120SStephen.Hanson@Sun.COM 	if (entryp->faus_is_proxy) {
14759120SStephen.Hanson@Sun.COM 		if (!(status & FM_SUSPECT_NOT_PRESENT)) {
14769120SStephen.Hanson@Sun.COM 			alp->al_flags |= FMD_ASRU_PRESENT;
14779120SStephen.Hanson@Sun.COM 			alp->al_asru->asru_flags |= FMD_ASRU_PRESENT;
14789120SStephen.Hanson@Sun.COM 		} else {
14799120SStephen.Hanson@Sun.COM 			alp->al_flags &= ~FMD_ASRU_PRESENT;
14809120SStephen.Hanson@Sun.COM 			alp->al_asru->asru_flags &= ~FMD_ASRU_PRESENT;
14819120SStephen.Hanson@Sun.COM 		}
14829120SStephen.Hanson@Sun.COM 	}
14839120SStephen.Hanson@Sun.COM 	(*entryp->faus_countp)++;
14849120SStephen.Hanson@Sun.COM }
14859120SStephen.Hanson@Sun.COM 
14869120SStephen.Hanson@Sun.COM /*
14879120SStephen.Hanson@Sun.COM  * This function is called on the diagnosing side when fault proxying is
14889120SStephen.Hanson@Sun.COM  * in use and the proxy has sent a uuclose. It updates the status of the
14899120SStephen.Hanson@Sun.COM  * resource cache entries.
14909120SStephen.Hanson@Sun.COM  */
14919120SStephen.Hanson@Sun.COM void
fmd_asru_close_status(fmd_asru_link_t * alp,void * arg)14929120SStephen.Hanson@Sun.COM fmd_asru_close_status(fmd_asru_link_t *alp, void *arg)
14939120SStephen.Hanson@Sun.COM {
14949120SStephen.Hanson@Sun.COM 	fmd_asru_close_status_t *entryp = (fmd_asru_close_status_t *)arg;
14959120SStephen.Hanson@Sun.COM 
14969120SStephen.Hanson@Sun.COM 	if (*entryp->facs_countp >= entryp->facs_maxcount)
14979120SStephen.Hanson@Sun.COM 		return;
14989120SStephen.Hanson@Sun.COM 	alp->al_flags &= ~FMD_ASRU_DEGRADED;
14999120SStephen.Hanson@Sun.COM 	(void) fmd_asru_setflags(alp, FMD_ASRU_UNUSABLE);
15009120SStephen.Hanson@Sun.COM 	(*entryp->facs_countp)++;
15017275Sstephh }
15027275Sstephh 
15037275Sstephh static void
fmd_asru_logevent(fmd_asru_link_t * alp)15046228Sstephh fmd_asru_logevent(fmd_asru_link_t *alp)
15056228Sstephh {
15066228Sstephh 	fmd_asru_t *ap = alp->al_asru;
15077275Sstephh 	boolean_t faulty = (alp->al_flags & FMD_ASRU_FAULTY) != 0;
15087275Sstephh 	boolean_t unusable = (alp->al_flags & FMD_ASRU_UNUSABLE) != 0;
15097275Sstephh 	boolean_t message = (ap->asru_flags & FMD_ASRU_INVISIBLE) == 0;
15107275Sstephh 	boolean_t repaired = (alp->al_reason == FMD_ASRU_REPAIRED);
15117275Sstephh 	boolean_t replaced = (alp->al_reason == FMD_ASRU_REPLACED);
15127275Sstephh 	boolean_t acquitted = (alp->al_reason == FMD_ASRU_ACQUITTED);
15130Sstevel@tonic-gate 
15141193Smws 	fmd_case_impl_t *cip;
15150Sstevel@tonic-gate 	fmd_event_t *e;
15160Sstevel@tonic-gate 	fmd_log_t *lp;
15170Sstevel@tonic-gate 	nvlist_t *nvl;
15180Sstevel@tonic-gate 	char *class;
15190Sstevel@tonic-gate 
15200Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ap->asru_lock));
15216228Sstephh 	cip = (fmd_case_impl_t *)alp->al_case;
15225255Sstephh 	ASSERT(cip != NULL);
15230Sstevel@tonic-gate 
15249120SStephen.Hanson@Sun.COM 	/*
15259120SStephen.Hanson@Sun.COM 	 * Don't log to disk on proxy side
15269120SStephen.Hanson@Sun.COM 	 */
15279120SStephen.Hanson@Sun.COM 	if (cip->ci_xprt != NULL)
15289120SStephen.Hanson@Sun.COM 		return;
15299120SStephen.Hanson@Sun.COM 
15306228Sstephh 	if ((lp = alp->al_log) == NULL)
15316228Sstephh 		lp = fmd_log_open(ap->asru_root, alp->al_uuid, FMD_LOG_ASRU);
15320Sstevel@tonic-gate 
15330Sstevel@tonic-gate 	if (lp == NULL)
15340Sstevel@tonic-gate 		return; /* can't log events if we can't open the log */
15350Sstevel@tonic-gate 
15367275Sstephh 	nvl = fmd_protocol_rsrc_asru(_fmd_asru_events[faulty | (unusable << 1)],
15377275Sstephh 	    alp->al_asru_fmri, cip->ci_uuid, cip->ci_code, faulty, unusable,
15389120SStephen.Hanson@Sun.COM 	    message, alp->al_event, &cip->ci_tv, repaired, replaced, acquitted,
153910656SStephen.Hanson@Sun.COM 	    cip->ci_state == FMD_CASE_RESOLVED, cip->ci_diag_de == NULL ?
154010928SStephen.Hanson@Sun.COM 	    cip->ci_mod->mod_fmri : cip->ci_diag_de, cip->ci_injected == 1);
15410Sstevel@tonic-gate 
15420Sstevel@tonic-gate 	(void) nvlist_lookup_string(nvl, FM_CLASS, &class);
15430Sstevel@tonic-gate 	e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class);
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 	fmd_event_hold(e);
15460Sstevel@tonic-gate 	fmd_log_append(lp, e, NULL);
15470Sstevel@tonic-gate 	fmd_event_rele(e);
15480Sstevel@tonic-gate 
15490Sstevel@tonic-gate 	/*
15500Sstevel@tonic-gate 	 * For now, we close the log file after every update to conserve file
15510Sstevel@tonic-gate 	 * descriptors and daemon overhead.  If this becomes a performance
15520Sstevel@tonic-gate 	 * issue this code can change to keep a fixed-size LRU cache of logs.
15530Sstevel@tonic-gate 	 */
15540Sstevel@tonic-gate 	fmd_log_rele(lp);
15556228Sstephh 	alp->al_log = NULL;
15560Sstevel@tonic-gate }
15570Sstevel@tonic-gate 
15580Sstevel@tonic-gate int
fmd_asru_setflags(fmd_asru_link_t * alp,uint_t sflag)15596228Sstephh fmd_asru_setflags(fmd_asru_link_t *alp, uint_t sflag)
15600Sstevel@tonic-gate {
15616228Sstephh 	fmd_asru_t *ap = alp->al_asru;
15620Sstevel@tonic-gate 	uint_t nstate, ostate;
15630Sstevel@tonic-gate 
15640Sstevel@tonic-gate 	ASSERT(!(sflag & ~FMD_ASRU_STATE));
15650Sstevel@tonic-gate 	ASSERT(sflag != FMD_ASRU_STATE);
15660Sstevel@tonic-gate 
15670Sstevel@tonic-gate 	(void) pthread_mutex_lock(&ap->asru_lock);
15680Sstevel@tonic-gate 
15696228Sstephh 	ostate = alp->al_flags & FMD_ASRU_STATE;
15706228Sstephh 	alp->al_flags |= sflag;
15716228Sstephh 	nstate = alp->al_flags & FMD_ASRU_STATE;
15726228Sstephh 
15736228Sstephh 	if (nstate == ostate) {
15746228Sstephh 		(void) pthread_mutex_unlock(&ap->asru_lock);
15756228Sstephh 		return (0);
15766228Sstephh 	}
15776228Sstephh 
15786228Sstephh 	ap->asru_flags |= sflag;
15796228Sstephh 	TRACE((FMD_DBG_ASRU, "asru %s %s->%s", alp->al_uuid,
15806228Sstephh 	    _fmd_asru_snames[ostate], _fmd_asru_snames[nstate]));
15816228Sstephh 
15826228Sstephh 	fmd_asru_logevent(alp);
15836228Sstephh 
15846228Sstephh 	(void) pthread_cond_broadcast(&ap->asru_cv);
15856228Sstephh 	(void) pthread_mutex_unlock(&ap->asru_lock);
15866228Sstephh 	return (1);
15876228Sstephh }
15886228Sstephh 
15896228Sstephh int
fmd_asru_clrflags(fmd_asru_link_t * alp,uint_t sflag,uint8_t reason)15907275Sstephh fmd_asru_clrflags(fmd_asru_link_t *alp, uint_t sflag, uint8_t reason)
15916228Sstephh {
15926228Sstephh 	fmd_asru_t *ap = alp->al_asru;
15936228Sstephh 	fmd_asru_link_t *nalp;
15946228Sstephh 	uint_t nstate, ostate, flags = 0;
15956228Sstephh 
15966228Sstephh 	ASSERT(!(sflag & ~FMD_ASRU_STATE));
15976228Sstephh 	ASSERT(sflag != FMD_ASRU_STATE);
15986228Sstephh 
15996228Sstephh 	(void) pthread_mutex_lock(&ap->asru_lock);
16006228Sstephh 
16016228Sstephh 	ostate = alp->al_flags & FMD_ASRU_STATE;
16026228Sstephh 	alp->al_flags &= ~sflag;
16036228Sstephh 	nstate = alp->al_flags & FMD_ASRU_STATE;
16040Sstevel@tonic-gate 
16051193Smws 	if (nstate == ostate) {
160610656SStephen.Hanson@Sun.COM 		if (reason > alp->al_reason &&
160710656SStephen.Hanson@Sun.COM 		    ((fmd_case_impl_t *)alp->al_case)->ci_state <
160810656SStephen.Hanson@Sun.COM 		    FMD_CASE_REPAIRED) {
16097275Sstephh 			alp->al_reason = reason;
16107275Sstephh 			fmd_asru_logevent(alp);
16117275Sstephh 			(void) pthread_cond_broadcast(&ap->asru_cv);
16127275Sstephh 		}
16131193Smws 		(void) pthread_mutex_unlock(&ap->asru_lock);
16141193Smws 		return (0);
16151193Smws 	}
16167275Sstephh 	if (reason > alp->al_reason)
16177275Sstephh 		alp->al_reason = reason;
16181193Smws 
16196228Sstephh 	if (sflag == FMD_ASRU_UNUSABLE)
16206228Sstephh 		ap->asru_flags &= ~sflag;
16216228Sstephh 	else if (sflag == FMD_ASRU_FAULTY) {
16226228Sstephh 		/*
16236228Sstephh 		 * only clear the faulty bit if all links are clear
16246228Sstephh 		 */
16256228Sstephh 		for (nalp = fmd_list_next(&ap->asru_list); nalp != NULL;
16266228Sstephh 		    nalp = fmd_list_next(nalp))
16276228Sstephh 			flags |= nalp->al_flags;
16286228Sstephh 		if (!(flags & FMD_ASRU_FAULTY))
16296228Sstephh 			ap->asru_flags &= ~sflag;
16300Sstevel@tonic-gate 	}
16310Sstevel@tonic-gate 
16326228Sstephh 	TRACE((FMD_DBG_ASRU, "asru %s %s->%s", alp->al_uuid,
16331193Smws 	    _fmd_asru_snames[ostate], _fmd_asru_snames[nstate]));
16341193Smws 
16356228Sstephh 	fmd_asru_logevent(alp);
16360Sstevel@tonic-gate 
16371193Smws 	(void) pthread_cond_broadcast(&ap->asru_cv);
16380Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&ap->asru_lock);
16391193Smws 
16406228Sstephh 	return (1);
16416228Sstephh }
16426228Sstephh 
164310656SStephen.Hanson@Sun.COM /*ARGSUSED*/
164410656SStephen.Hanson@Sun.COM void
fmd_asru_log_resolved(fmd_asru_link_t * alp,void * unused)164510656SStephen.Hanson@Sun.COM fmd_asru_log_resolved(fmd_asru_link_t *alp, void *unused)
164610656SStephen.Hanson@Sun.COM {
164710656SStephen.Hanson@Sun.COM 	fmd_asru_t *ap = alp->al_asru;
164810656SStephen.Hanson@Sun.COM 
164910656SStephen.Hanson@Sun.COM 	(void) pthread_mutex_lock(&ap->asru_lock);
165010656SStephen.Hanson@Sun.COM 	fmd_asru_logevent(alp);
165110656SStephen.Hanson@Sun.COM 	(void) pthread_cond_broadcast(&ap->asru_cv);
165210656SStephen.Hanson@Sun.COM 	(void) pthread_mutex_unlock(&ap->asru_lock);
165310656SStephen.Hanson@Sun.COM }
165410656SStephen.Hanson@Sun.COM 
16556228Sstephh /*
16566228Sstephh  * Report the current known state of the link entry (ie this particular fault
16576228Sstephh  * affecting this particular ASRU).
16586228Sstephh  */
16596228Sstephh int
fmd_asru_al_getstate(fmd_asru_link_t * alp)16606228Sstephh fmd_asru_al_getstate(fmd_asru_link_t *alp)
16616228Sstephh {
16629120SStephen.Hanson@Sun.COM 	int us, st = (alp->al_flags & (FMD_ASRU_FAULTY | FMD_ASRU_UNUSABLE));
16636228Sstephh 	nvlist_t *asru;
16649120SStephen.Hanson@Sun.COM 	int ps = FMD_OBJ_STATE_UNKNOWN;
16651193Smws 
16669120SStephen.Hanson@Sun.COM 	/*
16679120SStephen.Hanson@Sun.COM 	 * For fault proxying with an EXTERNAL transport, believe the presence
16689120SStephen.Hanson@Sun.COM 	 * state as sent by the diagnosing side. Otherwise find the presence
16699120SStephen.Hanson@Sun.COM 	 * state here. Note that if fault proxying with an INTERNAL transport
16709120SStephen.Hanson@Sun.COM 	 * we can only trust the presence state where we are using hc-scheme
16719120SStephen.Hanson@Sun.COM 	 * fmris which should be consistant across domains in the same system -
16729120SStephen.Hanson@Sun.COM 	 * other schemes can refer to different devices in different domains.
16739120SStephen.Hanson@Sun.COM 	 */
16749120SStephen.Hanson@Sun.COM 	if (!(alp->al_flags & FMD_ASRU_PROXY_EXTERNAL)) {
16759120SStephen.Hanson@Sun.COM 		ps = fmd_asru_replacement_state(alp->al_event, (alp->al_flags &
16769120SStephen.Hanson@Sun.COM 		    FMD_ASRU_PROXY)? HC_ONLY_TRUE : HC_ONLY_FALSE);
16779120SStephen.Hanson@Sun.COM 		if (ps == FMD_OBJ_STATE_NOT_PRESENT)
16789120SStephen.Hanson@Sun.COM 			return (st | FMD_ASRU_UNUSABLE);
16799120SStephen.Hanson@Sun.COM 		if (ps == FMD_OBJ_STATE_REPLACED) {
16809120SStephen.Hanson@Sun.COM 			if (alp->al_reason < FMD_ASRU_REPLACED)
16819120SStephen.Hanson@Sun.COM 				alp->al_reason = FMD_ASRU_REPLACED;
16829120SStephen.Hanson@Sun.COM 			return (st | FMD_ASRU_UNUSABLE);
16839120SStephen.Hanson@Sun.COM 		}
16847275Sstephh 	}
16859120SStephen.Hanson@Sun.COM 	if (ps == FMD_OBJ_STATE_UNKNOWN && (alp->al_flags & FMD_ASRU_PROXY))
16869120SStephen.Hanson@Sun.COM 		st |= (alp->al_flags & (FMD_ASRU_DEGRADED | FMD_ASRU_PRESENT));
16879120SStephen.Hanson@Sun.COM 	else
16889120SStephen.Hanson@Sun.COM 		st |= (alp->al_flags & (FMD_ASRU_DEGRADED)) | FMD_ASRU_PRESENT;
16891552Smws 
16909120SStephen.Hanson@Sun.COM 	/*
16919120SStephen.Hanson@Sun.COM 	 * For fault proxying, unless we have a local ASRU, then believe the
16929120SStephen.Hanson@Sun.COM 	 * service state sent by the diagnosing side. Otherwise find the service
16939120SStephen.Hanson@Sun.COM 	 * state here. Try fmd_fmri_service_state() first, but if that's not
16949120SStephen.Hanson@Sun.COM 	 * supported by the scheme then fall back to fmd_fmri_unusable().
16959120SStephen.Hanson@Sun.COM 	 */
16969120SStephen.Hanson@Sun.COM 	if ((!(alp->al_flags & FMD_ASRU_PROXY) ||
16979120SStephen.Hanson@Sun.COM 	    (alp->al_flags & FMD_ASRU_PROXY_WITH_ASRU)) &&
16989120SStephen.Hanson@Sun.COM 	    nvlist_lookup_nvlist(alp->al_event, FM_FAULT_ASRU, &asru) == 0) {
16997275Sstephh 		us = fmd_fmri_service_state(asru);
17007275Sstephh 		if (us == -1 || us == FMD_SERVICE_STATE_UNKNOWN) {
17017275Sstephh 			/* not supported by scheme - try fmd_fmri_unusable */
17027275Sstephh 			us = fmd_fmri_unusable(asru);
17039120SStephen.Hanson@Sun.COM 			if (us > 0)
17049120SStephen.Hanson@Sun.COM 				st |= FMD_ASRU_UNUSABLE;
17059120SStephen.Hanson@Sun.COM 			else if (us == 0)
17069120SStephen.Hanson@Sun.COM 				st &= ~FMD_ASRU_UNUSABLE;
17079120SStephen.Hanson@Sun.COM 		} else {
17089120SStephen.Hanson@Sun.COM 			if (us == FMD_SERVICE_STATE_UNUSABLE) {
17099120SStephen.Hanson@Sun.COM 				st &= ~FMD_ASRU_DEGRADED;
17109120SStephen.Hanson@Sun.COM 				st |= FMD_ASRU_UNUSABLE;
17119120SStephen.Hanson@Sun.COM 			} else if (us == FMD_SERVICE_STATE_OK) {
17129120SStephen.Hanson@Sun.COM 				st &= ~(FMD_ASRU_DEGRADED | FMD_ASRU_UNUSABLE);
17139120SStephen.Hanson@Sun.COM 			} else if (us == FMD_SERVICE_STATE_ISOLATE_PENDING) {
17149120SStephen.Hanson@Sun.COM 				st &= ~(FMD_ASRU_DEGRADED | FMD_ASRU_UNUSABLE);
17159120SStephen.Hanson@Sun.COM 			} else if (us == FMD_SERVICE_STATE_DEGRADED) {
17169120SStephen.Hanson@Sun.COM 				st &= ~FMD_ASRU_UNUSABLE;
17179120SStephen.Hanson@Sun.COM 				st |= FMD_ASRU_DEGRADED;
17189120SStephen.Hanson@Sun.COM 			}
17197275Sstephh 		}
17209120SStephen.Hanson@Sun.COM 	}
17216228Sstephh 	return (st);
17220Sstevel@tonic-gate }
17230Sstevel@tonic-gate 
17240Sstevel@tonic-gate /*
17250Sstevel@tonic-gate  * Report the current known state of the ASRU by refreshing its unusable status
17260Sstevel@tonic-gate  * based upon the routines provided by the scheme module.  If the unusable bit
17270Sstevel@tonic-gate  * is different, we do *not* generate a state change here because that change
17280Sstevel@tonic-gate  * may be unrelated to fmd activities and therefore we have no case or event.
17290Sstevel@tonic-gate  * The absence of the transition is harmless as this function is only provided
17300Sstevel@tonic-gate  * for RPC observability and fmd's clients are only concerned with ASRU_FAULTY.
17310Sstevel@tonic-gate  */
17320Sstevel@tonic-gate int
fmd_asru_getstate(fmd_asru_t * ap)17330Sstevel@tonic-gate fmd_asru_getstate(fmd_asru_t *ap)
17340Sstevel@tonic-gate {
17359120SStephen.Hanson@Sun.COM 	int us, st, p = -1;
17369120SStephen.Hanson@Sun.COM 	char *s;
17370Sstevel@tonic-gate 
17389120SStephen.Hanson@Sun.COM 	/* do not report non-fmd non-present resources */
17399120SStephen.Hanson@Sun.COM 	if (!(ap->asru_flags & FMD_ASRU_INTERNAL)) {
17409120SStephen.Hanson@Sun.COM 		/*
17419120SStephen.Hanson@Sun.COM 		 * As with fmd_asru_al_getstate(), we can only trust the
17429120SStephen.Hanson@Sun.COM 		 * local presence state on a proxy if the transport is
17439120SStephen.Hanson@Sun.COM 		 * internal and the scheme is hc. Otherwise we believe the
17449120SStephen.Hanson@Sun.COM 		 * state as sent by the diagnosing side.
17459120SStephen.Hanson@Sun.COM 		 */
17469120SStephen.Hanson@Sun.COM 		if (!(ap->asru_flags & FMD_ASRU_PROXY) ||
17479120SStephen.Hanson@Sun.COM 		    (!(ap->asru_flags & FMD_ASRU_PROXY_EXTERNAL) &&
17489120SStephen.Hanson@Sun.COM 		    (nvlist_lookup_string(ap->asru_fmri, FM_FMRI_SCHEME,
17499120SStephen.Hanson@Sun.COM 		    &s) == 0 && strcmp(s, FM_FMRI_SCHEME_HC) == 0))) {
17509120SStephen.Hanson@Sun.COM 			if (fmd_asru_fake_not_present >=
17519120SStephen.Hanson@Sun.COM 			    FMD_OBJ_STATE_REPLACED)
17529120SStephen.Hanson@Sun.COM 				return (0);
17539120SStephen.Hanson@Sun.COM 			p = fmd_fmri_present(ap->asru_fmri);
17549120SStephen.Hanson@Sun.COM 		}
17559120SStephen.Hanson@Sun.COM 		if (p == 0 || (p < 0 && !(ap->asru_flags & FMD_ASRU_PROXY) ||
17569120SStephen.Hanson@Sun.COM 		    !(ap->asru_flags & FMD_ASRU_PRESENT)))
17579120SStephen.Hanson@Sun.COM 			return (0);
17589120SStephen.Hanson@Sun.COM 	}
17590Sstevel@tonic-gate 
17609120SStephen.Hanson@Sun.COM 	/*
17619120SStephen.Hanson@Sun.COM 	 * As with fmd_asru_al_getstate(), we can only trust the local unusable
17629120SStephen.Hanson@Sun.COM 	 * state on a proxy if there is a local ASRU.
17639120SStephen.Hanson@Sun.COM 	 */
17649120SStephen.Hanson@Sun.COM 	st = ap->asru_flags & (FMD_ASRU_FAULTY | FMD_ASRU_UNUSABLE);
17659120SStephen.Hanson@Sun.COM 	if (!(ap->asru_flags & FMD_ASRU_PROXY) ||
17669120SStephen.Hanson@Sun.COM 	    (ap->asru_flags & FMD_ASRU_PROXY_WITH_ASRU)) {
17679120SStephen.Hanson@Sun.COM 		us = fmd_fmri_unusable(ap->asru_fmri);
17689120SStephen.Hanson@Sun.COM 		if (us > 0)
17699120SStephen.Hanson@Sun.COM 			st |= FMD_ASRU_UNUSABLE;
17709120SStephen.Hanson@Sun.COM 		else if (us == 0)
17719120SStephen.Hanson@Sun.COM 			st &= ~FMD_ASRU_UNUSABLE;
17729120SStephen.Hanson@Sun.COM 	}
17730Sstevel@tonic-gate 	return (st);
17740Sstevel@tonic-gate }
1775