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