1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <sys/fm/protocol.h> 28 #include <uuid/uuid.h> 29 30 #include <dirent.h> 31 #include <limits.h> 32 #include <unistd.h> 33 #include <alloca.h> 34 #include <stddef.h> 35 #include <fm/libtopo.h> 36 37 #include <fmd_alloc.h> 38 #include <fmd_string.h> 39 #include <fmd_error.h> 40 #include <fmd_subr.h> 41 #include <fmd_protocol.h> 42 #include <fmd_event.h> 43 #include <fmd_conf.h> 44 #include <fmd_fmri.h> 45 #include <fmd_dispq.h> 46 #include <fmd_case.h> 47 #include <fmd_module.h> 48 #include <fmd_asru.h> 49 50 #include <fmd.h> 51 52 static const char *const _fmd_asru_events[] = { 53 FMD_RSRC_CLASS "asru.ok", /* UNUSABLE=0 FAULTED=0 */ 54 FMD_RSRC_CLASS "asru.degraded", /* UNUSABLE=0 FAULTED=1 */ 55 FMD_RSRC_CLASS "asru.unknown", /* UNUSABLE=1 FAULTED=0 */ 56 FMD_RSRC_CLASS "asru.faulted" /* UNUSABLE=1 FAULTED=1 */ 57 }; 58 59 static const char *const _fmd_asru_snames[] = { 60 "uf", "uF", "Uf", "UF" /* same order as above */ 61 }; 62 63 volatile uint32_t fmd_asru_fake_not_present = 0; 64 65 static uint_t 66 fmd_asru_strhash(fmd_asru_hash_t *ahp, const char *val) 67 { 68 return (topo_fmri_strhash(ahp->ah_topo->ft_hdl, val) % ahp->ah_hashlen); 69 } 70 71 static boolean_t 72 fmd_asru_strcmp(fmd_asru_hash_t *ahp, const char *a, const char *b) 73 { 74 return (topo_fmri_strcmp(ahp->ah_topo->ft_hdl, a, b)); 75 } 76 77 static fmd_asru_t * 78 fmd_asru_create(fmd_asru_hash_t *ahp, const char *uuid, 79 const char *name, nvlist_t *fmri) 80 { 81 fmd_asru_t *ap = fmd_zalloc(sizeof (fmd_asru_t), FMD_SLEEP); 82 char *s; 83 84 (void) pthread_mutex_init(&ap->asru_lock, NULL); 85 (void) pthread_cond_init(&ap->asru_cv, NULL); 86 87 ap->asru_name = fmd_strdup(name, FMD_SLEEP); 88 if (fmri) 89 (void) nvlist_xdup(fmri, &ap->asru_fmri, &fmd.d_nva); 90 ap->asru_root = fmd_strdup(ahp->ah_dirpath, FMD_SLEEP); 91 ap->asru_uuid = fmd_strdup(uuid, FMD_SLEEP); 92 ap->asru_uuidlen = ap->asru_uuid ? strlen(ap->asru_uuid) : 0; 93 ap->asru_refs = 1; 94 95 if (fmri && nvlist_lookup_string(fmri, FM_FMRI_SCHEME, &s) == 0 && 96 strcmp(s, FM_FMRI_SCHEME_FMD) == 0) 97 ap->asru_flags |= FMD_ASRU_INTERNAL; 98 99 return (ap); 100 } 101 102 static void 103 fmd_asru_destroy(fmd_asru_t *ap) 104 { 105 ASSERT(MUTEX_HELD(&ap->asru_lock)); 106 ASSERT(ap->asru_refs == 0); 107 108 nvlist_free(ap->asru_event); 109 fmd_strfree(ap->asru_name); 110 nvlist_free(ap->asru_fmri); 111 fmd_strfree(ap->asru_root); 112 fmd_free(ap->asru_uuid, ap->asru_uuidlen + 1); 113 fmd_free(ap, sizeof (fmd_asru_t)); 114 } 115 116 static void 117 fmd_asru_hash_insert(fmd_asru_hash_t *ahp, fmd_asru_t *ap) 118 { 119 uint_t h = fmd_asru_strhash(ahp, ap->asru_name); 120 121 ASSERT(RW_WRITE_HELD(&ahp->ah_lock)); 122 ap->asru_next = ahp->ah_hash[h]; 123 ahp->ah_hash[h] = ap; 124 ahp->ah_count++; 125 } 126 127 static fmd_asru_t * 128 fmd_asru_hold(fmd_asru_t *ap) 129 { 130 (void) pthread_mutex_lock(&ap->asru_lock); 131 ap->asru_refs++; 132 ASSERT(ap->asru_refs != 0); 133 (void) pthread_mutex_unlock(&ap->asru_lock); 134 return (ap); 135 } 136 137 /* 138 * Lookup an asru in the hash by name and place a hold on it. If the asru is 139 * not found, no entry is created and NULL is returned. This internal function 140 * is for callers who have the ah_lock held and is used by lookup_name below. 141 */ 142 fmd_asru_t * 143 fmd_asru_hash_lookup(fmd_asru_hash_t *ahp, const char *name) 144 { 145 fmd_asru_t *ap; 146 uint_t h; 147 148 ASSERT(RW_LOCK_HELD(&ahp->ah_lock)); 149 h = fmd_asru_strhash(ahp, name); 150 151 for (ap = ahp->ah_hash[h]; ap != NULL; ap = ap->asru_next) { 152 if (fmd_asru_strcmp(ahp, ap->asru_name, name)) 153 break; 154 } 155 156 if (ap != NULL) 157 (void) fmd_asru_hold(ap); 158 else 159 (void) fmd_set_errno(EFMD_ASRU_NOENT); 160 161 return (ap); 162 } 163 164 #define HC_ONLY_FALSE 0 165 #define HC_ONLY_TRUE 1 166 167 static int 168 fmd_asru_replacement_state(nvlist_t *event, int hc_only) 169 { 170 int ps = -1; 171 nvlist_t *asru, *fru, *rsrc; 172 char *s; 173 174 /* 175 * Check if there is evidence that this object is no longer present. 176 * In general fmd_fmri_present() should be supported on resources and/or 177 * frus, as those are the things that are physically present or not 178 * present - an asru can be spread over a number of frus some of which 179 * are present and some not, so fmd_fmri_present() is not generally 180 * meaningful. However retain a check for asru first for compatibility. 181 * If we have checked all three and we still get -1 then nothing knows 182 * whether it's present or not, so err on the safe side and treat it 183 * as still present. 184 * 185 * Note that if hc_only is set, then we only check status using fmris 186 * that are in hc-scheme. 187 */ 188 if (fmd_asru_fake_not_present) 189 return (fmd_asru_fake_not_present); 190 if (nvlist_lookup_nvlist(event, FM_FAULT_ASRU, &asru) == 0 && 191 (hc_only == HC_ONLY_FALSE || (nvlist_lookup_string(asru, 192 FM_FMRI_SCHEME, &s) == 0 && strcmp(s, FM_FMRI_SCHEME_HC) == 0))) 193 ps = fmd_fmri_replaced(asru); 194 if (ps == -1 || ps == FMD_OBJ_STATE_UNKNOWN) { 195 if (nvlist_lookup_nvlist(event, FM_FAULT_RESOURCE, 196 &rsrc) == 0 && (hc_only == HC_ONLY_FALSE || 197 (nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, &s) == 0 && 198 strcmp(s, FM_FMRI_SCHEME_HC) == 0))) { 199 if (ps == -1) { 200 ps = fmd_fmri_replaced(rsrc); 201 } else { 202 /* see if we can improve on UNKNOWN */ 203 int ps2 = fmd_fmri_replaced(rsrc); 204 if (ps2 == FMD_OBJ_STATE_STILL_PRESENT || 205 ps2 == FMD_OBJ_STATE_REPLACED) 206 ps = ps2; 207 } 208 } 209 } 210 if (ps == -1 || ps == FMD_OBJ_STATE_UNKNOWN) { 211 if (nvlist_lookup_nvlist(event, FM_FAULT_FRU, &fru) == 0 && 212 (hc_only == HC_ONLY_FALSE || (nvlist_lookup_string(fru, 213 FM_FMRI_SCHEME, &s) == 0 && 214 strcmp(s, FM_FMRI_SCHEME_HC) == 0))) { 215 if (ps == -1) { 216 ps = fmd_fmri_replaced(fru); 217 } else { 218 /* see if we can improve on UNKNOWN */ 219 int ps2 = fmd_fmri_replaced(fru); 220 if (ps2 == FMD_OBJ_STATE_STILL_PRESENT || 221 ps2 == FMD_OBJ_STATE_REPLACED) 222 ps = ps2; 223 } 224 } 225 } 226 if (ps == -1) 227 ps = FMD_OBJ_STATE_UNKNOWN; 228 return (ps); 229 } 230 231 static void 232 fmd_asru_asru_hash_insert(fmd_asru_hash_t *ahp, fmd_asru_link_t *alp, 233 char *name) 234 { 235 uint_t h = fmd_asru_strhash(ahp, name); 236 237 ASSERT(RW_WRITE_HELD(&ahp->ah_lock)); 238 alp->al_asru_next = ahp->ah_asru_hash[h]; 239 ahp->ah_asru_hash[h] = alp; 240 ahp->ah_al_count++; 241 } 242 243 static void 244 fmd_asru_case_hash_insert(fmd_asru_hash_t *ahp, fmd_asru_link_t *alp, 245 char *name) 246 { 247 uint_t h = fmd_asru_strhash(ahp, name); 248 249 ASSERT(RW_WRITE_HELD(&ahp->ah_lock)); 250 alp->al_case_next = ahp->ah_case_hash[h]; 251 ahp->ah_case_hash[h] = alp; 252 } 253 254 static void 255 fmd_asru_fru_hash_insert(fmd_asru_hash_t *ahp, fmd_asru_link_t *alp, char *name) 256 { 257 uint_t h = fmd_asru_strhash(ahp, name); 258 259 ASSERT(RW_WRITE_HELD(&ahp->ah_lock)); 260 alp->al_fru_next = ahp->ah_fru_hash[h]; 261 ahp->ah_fru_hash[h] = alp; 262 } 263 264 static void 265 fmd_asru_label_hash_insert(fmd_asru_hash_t *ahp, fmd_asru_link_t *alp, 266 char *name) 267 { 268 uint_t h = fmd_asru_strhash(ahp, name); 269 270 ASSERT(RW_WRITE_HELD(&ahp->ah_lock)); 271 alp->al_label_next = ahp->ah_label_hash[h]; 272 ahp->ah_label_hash[h] = alp; 273 } 274 275 static void 276 fmd_asru_rsrc_hash_insert(fmd_asru_hash_t *ahp, fmd_asru_link_t *alp, 277 char *name) 278 { 279 uint_t h = fmd_asru_strhash(ahp, name); 280 281 ASSERT(RW_WRITE_HELD(&ahp->ah_lock)); 282 alp->al_rsrc_next = ahp->ah_rsrc_hash[h]; 283 ahp->ah_rsrc_hash[h] = alp; 284 } 285 286 static void 287 fmd_asru_al_destroy(fmd_asru_link_t *alp) 288 { 289 ASSERT(alp->al_refs == 0); 290 ASSERT(MUTEX_HELD(&alp->al_asru->asru_lock)); 291 292 if (alp->al_log != NULL) 293 fmd_log_rele(alp->al_log); 294 295 fmd_free(alp->al_uuid, alp->al_uuidlen + 1); 296 nvlist_free(alp->al_event); 297 fmd_strfree(alp->al_rsrc_name); 298 fmd_strfree(alp->al_case_uuid); 299 fmd_strfree(alp->al_fru_name); 300 fmd_strfree(alp->al_asru_name); 301 fmd_strfree(alp->al_label); 302 nvlist_free(alp->al_asru_fmri); 303 fmd_free(alp, sizeof (fmd_asru_link_t)); 304 } 305 306 static fmd_asru_link_t * 307 fmd_asru_al_hold(fmd_asru_link_t *alp) 308 { 309 fmd_asru_t *ap = alp->al_asru; 310 311 (void) pthread_mutex_lock(&ap->asru_lock); 312 ap->asru_refs++; 313 alp->al_refs++; 314 ASSERT(alp->al_refs != 0); 315 (void) pthread_mutex_unlock(&ap->asru_lock); 316 return (alp); 317 } 318 319 static void fmd_asru_destroy(fmd_asru_t *ap); 320 321 /*ARGSUSED*/ 322 static void 323 fmd_asru_al_hash_release(fmd_asru_hash_t *ahp, fmd_asru_link_t *alp) 324 { 325 fmd_asru_t *ap = alp->al_asru; 326 327 (void) pthread_mutex_lock(&ap->asru_lock); 328 ASSERT(alp->al_refs != 0); 329 if (--alp->al_refs == 0) 330 fmd_asru_al_destroy(alp); 331 ASSERT(ap->asru_refs != 0); 332 if (--ap->asru_refs == 0) 333 fmd_asru_destroy(ap); 334 else 335 (void) pthread_mutex_unlock(&ap->asru_lock); 336 } 337 338 static int 339 fmd_asru_get_namestr(nvlist_t *nvl, char **name, ssize_t *namelen) 340 { 341 if ((*namelen = fmd_fmri_nvl2str(nvl, NULL, 0)) == -1) 342 return (EFMD_ASRU_FMRI); 343 *name = fmd_alloc(*namelen + 1, FMD_SLEEP); 344 if (fmd_fmri_nvl2str(nvl, *name, *namelen + 1) == -1) { 345 if (*name != NULL) 346 fmd_free(*name, *namelen + 1); 347 return (EFMD_ASRU_FMRI); 348 } 349 return (0); 350 } 351 352 static fmd_asru_link_t * 353 fmd_asru_al_create(fmd_asru_hash_t *ahp, nvlist_t *nvl, fmd_case_t *cp, 354 const char *al_uuid) 355 { 356 nvlist_t *asru = NULL, *fru, *rsrc; 357 int got_rsrc = 0, got_asru = 0, got_fru = 0; 358 ssize_t fru_namelen, rsrc_namelen, asru_namelen; 359 char *asru_name, *rsrc_name, *fru_name, *name, *label; 360 fmd_asru_link_t *alp; 361 fmd_asru_t *ap; 362 boolean_t msg; 363 fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 364 365 if (nvlist_lookup_nvlist(nvl, FM_FAULT_ASRU, &asru) == 0 && 366 fmd_asru_get_namestr(asru, &asru_name, &asru_namelen) == 0) 367 got_asru = 1; 368 if (nvlist_lookup_nvlist(nvl, FM_FAULT_FRU, &fru) == 0 && 369 fmd_asru_get_namestr(fru, &fru_name, &fru_namelen) == 0) 370 got_fru = 1; 371 if (nvlist_lookup_nvlist(nvl, FM_FAULT_RESOURCE, &rsrc) == 0 && 372 fmd_asru_get_namestr(rsrc, &rsrc_name, &rsrc_namelen) == 0) 373 got_rsrc = 1; 374 if (nvlist_lookup_string(nvl, FM_FAULT_LOCATION, &label) != 0) 375 label = ""; 376 377 /* 378 * Grab the rwlock as a writer; Then create and insert the asru with 379 * ahp->ah_lock held and hash it in. We'll then drop the rwlock and 380 * proceed to initializing the asru. 381 */ 382 (void) pthread_rwlock_wrlock(&ahp->ah_lock); 383 384 /* 385 * Create and initialise the per-fault "link" structure. 386 */ 387 alp = fmd_zalloc(sizeof (fmd_asru_link_t), FMD_SLEEP); 388 if (got_asru) 389 (void) nvlist_xdup(asru, &alp->al_asru_fmri, &fmd.d_nva); 390 alp->al_uuid = fmd_strdup(al_uuid, FMD_SLEEP); 391 alp->al_uuidlen = strlen(alp->al_uuid); 392 alp->al_refs = 1; 393 394 /* 395 * If this is the first fault for this asru, then create the per-asru 396 * structure and link into the hash. 397 */ 398 name = got_asru ? asru_name : ""; 399 if ((ap = fmd_asru_hash_lookup(ahp, name)) == NULL) { 400 ap = fmd_asru_create(ahp, al_uuid, name, got_asru ? asru : 401 NULL); 402 fmd_asru_hash_insert(ahp, ap); 403 } else 404 nvlist_free(ap->asru_event); 405 (void) nvlist_xdup(nvl, &ap->asru_event, &fmd.d_nva); 406 407 /* 408 * Put the link structure on the list associated with the per-asru 409 * structure. Then put the link structure on the various hashes. 410 */ 411 fmd_list_append(&ap->asru_list, (fmd_list_t *)alp); 412 alp->al_asru = ap; 413 alp->al_asru_name = got_asru ? asru_name : fmd_strdup("", FMD_SLEEP); 414 fmd_asru_asru_hash_insert(ahp, alp, alp->al_asru_name); 415 alp->al_fru_name = got_fru ? fru_name : fmd_strdup("", FMD_SLEEP); 416 fmd_asru_fru_hash_insert(ahp, alp, alp->al_fru_name); 417 alp->al_rsrc_name = got_rsrc ? rsrc_name : fmd_strdup("", FMD_SLEEP); 418 fmd_asru_rsrc_hash_insert(ahp, alp, alp->al_rsrc_name); 419 alp->al_label = fmd_strdup(label, FMD_SLEEP); 420 fmd_asru_label_hash_insert(ahp, alp, label); 421 alp->al_case_uuid = fmd_strdup(cip->ci_uuid, FMD_SLEEP); 422 fmd_asru_case_hash_insert(ahp, alp, cip->ci_uuid); 423 (void) pthread_mutex_lock(&ap->asru_lock); 424 (void) pthread_rwlock_unlock(&ahp->ah_lock); 425 426 ap->asru_case = alp->al_case = cp; 427 if (nvlist_lookup_boolean_value(nvl, FM_SUSPECT_MESSAGE, &msg) == 0 && 428 msg == B_FALSE) 429 ap->asru_flags |= FMD_ASRU_INVISIBLE; 430 (void) nvlist_xdup(nvl, &alp->al_event, &fmd.d_nva); 431 ap->asru_flags |= FMD_ASRU_VALID; 432 (void) pthread_cond_broadcast(&ap->asru_cv); 433 (void) pthread_mutex_unlock(&ap->asru_lock); 434 return (alp); 435 } 436 437 static void 438 fmd_asru_hash_recreate(fmd_log_t *lp, fmd_event_t *ep, fmd_asru_hash_t *ahp) 439 { 440 nvlist_t *nvl = FMD_EVENT_NVL(ep); 441 boolean_t faulty = FMD_B_FALSE, unusable = FMD_B_FALSE; 442 int ps; 443 boolean_t repaired = FMD_B_FALSE, replaced = FMD_B_FALSE; 444 boolean_t acquitted = FMD_B_FALSE; 445 nvlist_t *flt, *flt_copy, *asru; 446 char *case_uuid = NULL, *case_code = NULL; 447 fmd_asru_t *ap; 448 fmd_asru_link_t *alp; 449 fmd_case_t *cp; 450 int64_t *diag_time; 451 nvlist_t *de_fmri, *de_fmri_dup; 452 uint_t nelem; 453 topo_hdl_t *thp; 454 char *class; 455 nvlist_t *rsrc; 456 int err; 457 458 /* 459 * Extract the most recent values of 'faulty' from the event log. 460 */ 461 if (nvlist_lookup_boolean_value(nvl, FM_RSRC_ASRU_FAULTY, 462 &faulty) != 0) { 463 fmd_error(EFMD_ASRU_EVENT, "failed to reload asru %s: " 464 "invalid event log record\n", lp->log_name); 465 ahp->ah_error = EFMD_ASRU_EVENT; 466 return; 467 } 468 if (nvlist_lookup_nvlist(nvl, FM_RSRC_ASRU_EVENT, &flt) != 0) { 469 fmd_error(EFMD_ASRU_EVENT, "failed to reload asru %s: " 470 "invalid event log record\n", lp->log_name); 471 ahp->ah_error = EFMD_ASRU_EVENT; 472 return; 473 } 474 (void) nvlist_lookup_string(nvl, FM_RSRC_ASRU_UUID, &case_uuid); 475 (void) nvlist_lookup_string(nvl, FM_RSRC_ASRU_CODE, &case_code); 476 (void) nvlist_lookup_boolean_value(nvl, FM_RSRC_ASRU_UNUSABLE, 477 &unusable); 478 (void) nvlist_lookup_boolean_value(nvl, FM_RSRC_ASRU_REPAIRED, 479 &repaired); 480 (void) nvlist_lookup_boolean_value(nvl, FM_RSRC_ASRU_REPLACED, 481 &replaced); 482 (void) nvlist_lookup_boolean_value(nvl, FM_RSRC_ASRU_ACQUITTED, 483 &acquitted); 484 485 /* 486 * Attempt to recreate the case in either the CLOSED or REPAIRED state 487 * (depending on whether the faulty bit is still set). 488 * If the case is already present, fmd_case_recreate() will return it. 489 * If not, we'll create a new orphaned case. Either way, we use the 490 * ASRU event to insert a suspect into the partially-restored case. 491 */ 492 fmd_module_lock(fmd.d_rmod); 493 cp = fmd_case_recreate(fmd.d_rmod, NULL, faulty ? FMD_CASE_CLOSED : 494 FMD_CASE_REPAIRED, case_uuid, case_code); 495 fmd_case_hold(cp); 496 fmd_module_unlock(fmd.d_rmod); 497 if (nvlist_lookup_int64_array(nvl, FM_SUSPECT_DIAG_TIME, &diag_time, 498 &nelem) == 0 && nelem >= 2) 499 fmd_case_settime(cp, diag_time[0], diag_time[1]); 500 else 501 fmd_case_settime(cp, lp->log_stat.st_ctime, 0); 502 if (nvlist_lookup_nvlist(nvl, FM_SUSPECT_DE, &de_fmri) == 0) { 503 (void) nvlist_xdup(de_fmri, &de_fmri_dup, &fmd.d_nva); 504 fmd_case_set_de_fmri(cp, de_fmri_dup); 505 } 506 (void) nvlist_xdup(flt, &flt_copy, &fmd.d_nva); 507 508 /* 509 * For faults with a resource, re-evaluate the asru from the resource. 510 */ 511 thp = fmd_fmri_topo_hold(TOPO_VERSION); 512 if (nvlist_lookup_string(flt_copy, FM_CLASS, &class) == 0 && 513 strncmp(class, "fault", 5) == 0 && 514 nvlist_lookup_nvlist(flt_copy, FM_FAULT_RESOURCE, &rsrc) == 0 && 515 rsrc != NULL && topo_fmri_asru(thp, rsrc, &asru, &err) == 0) { 516 (void) nvlist_remove(flt_copy, FM_FAULT_ASRU, DATA_TYPE_NVLIST); 517 (void) nvlist_add_nvlist(flt_copy, FM_FAULT_ASRU, asru); 518 nvlist_free(asru); 519 } 520 fmd_fmri_topo_rele(thp); 521 522 (void) nvlist_xdup(flt_copy, &flt, &fmd.d_nva); 523 524 fmd_case_recreate_suspect(cp, flt_copy); 525 526 /* 527 * Now create the resource cache entries. 528 */ 529 alp = fmd_asru_al_create(ahp, flt, cp, fmd_strbasename(lp->log_name)); 530 ap = alp->al_asru; 531 532 /* 533 * Check to see if the resource is still present in the system. 534 */ 535 ps = fmd_asru_replacement_state(flt, HC_ONLY_FALSE); 536 if (ps == FMD_OBJ_STATE_REPLACED) { 537 replaced = FMD_B_TRUE; 538 } else if (ps == FMD_OBJ_STATE_STILL_PRESENT || 539 ps == FMD_OBJ_STATE_UNKNOWN) { 540 ap->asru_flags |= FMD_ASRU_PRESENT; 541 if (nvlist_lookup_nvlist(alp->al_event, FM_FAULT_ASRU, 542 &asru) == 0) { 543 int us; 544 545 switch (fmd_fmri_service_state(asru)) { 546 case FMD_SERVICE_STATE_UNUSABLE: 547 unusable = FMD_B_TRUE; 548 break; 549 case FMD_SERVICE_STATE_OK: 550 case FMD_SERVICE_STATE_ISOLATE_PENDING: 551 case FMD_SERVICE_STATE_DEGRADED: 552 unusable = FMD_B_FALSE; 553 break; 554 case FMD_SERVICE_STATE_UNKNOWN: 555 case -1: 556 /* not supported by scheme */ 557 us = fmd_fmri_unusable(asru); 558 if (us > 0) 559 unusable = FMD_B_TRUE; 560 else if (us == 0) 561 unusable = FMD_B_FALSE; 562 break; 563 } 564 } 565 } 566 567 nvlist_free(flt); 568 569 ap->asru_flags |= FMD_ASRU_RECREATED; 570 if (faulty) { 571 alp->al_flags |= FMD_ASRU_FAULTY; 572 ap->asru_flags |= FMD_ASRU_FAULTY; 573 } 574 if (unusable) { 575 alp->al_flags |= FMD_ASRU_UNUSABLE; 576 ap->asru_flags |= FMD_ASRU_UNUSABLE; 577 } 578 if (replaced) 579 alp->al_reason = FMD_ASRU_REPLACED; 580 else if (repaired) 581 alp->al_reason = FMD_ASRU_REPAIRED; 582 else if (acquitted) 583 alp->al_reason = FMD_ASRU_ACQUITTED; 584 585 TRACE((FMD_DBG_ASRU, "asru %s recreated as %p (%s)", alp->al_uuid, 586 (void *)ap, _fmd_asru_snames[ap->asru_flags & FMD_ASRU_STATE])); 587 } 588 589 static void 590 fmd_asru_hash_discard(fmd_asru_hash_t *ahp, const char *uuid, int err) 591 { 592 char src[PATH_MAX], dst[PATH_MAX]; 593 594 (void) snprintf(src, PATH_MAX, "%s/%s", ahp->ah_dirpath, uuid); 595 (void) snprintf(dst, PATH_MAX, "%s/%s-", ahp->ah_dirpath, uuid); 596 597 if (err != 0) 598 err = rename(src, dst); 599 else 600 err = unlink(src); 601 602 if (err != 0 && errno != ENOENT) 603 fmd_error(EFMD_ASRU_EVENT, "failed to rename log %s", src); 604 } 605 606 /* 607 * Open a saved log file and restore it into the ASRU hash. If we can't even 608 * open the log, rename the log file to <uuid>- to indicate it is corrupt. If 609 * fmd_log_replay() fails, we either delete the file (if it has reached the 610 * upper limit on cache age) or rename it for debugging if it was corrupted. 611 */ 612 static void 613 fmd_asru_hash_logopen(fmd_asru_hash_t *ahp, const char *uuid) 614 { 615 fmd_log_t *lp = fmd_log_tryopen(ahp->ah_dirpath, uuid, FMD_LOG_ASRU); 616 uint_t n; 617 618 if (lp == NULL) { 619 fmd_asru_hash_discard(ahp, uuid, errno); 620 return; 621 } 622 623 ahp->ah_error = 0; 624 n = ahp->ah_al_count; 625 626 fmd_log_replay(lp, (fmd_log_f *)fmd_asru_hash_recreate, ahp); 627 fmd_log_rele(lp); 628 629 if (ahp->ah_al_count == n) 630 fmd_asru_hash_discard(ahp, uuid, ahp->ah_error); 631 } 632 633 void 634 fmd_asru_hash_refresh(fmd_asru_hash_t *ahp) 635 { 636 struct dirent *dp; 637 DIR *dirp; 638 int zero; 639 640 if ((dirp = opendir(ahp->ah_dirpath)) == NULL) { 641 fmd_error(EFMD_ASRU_NODIR, 642 "failed to open asru cache directory %s", ahp->ah_dirpath); 643 return; 644 } 645 646 (void) fmd_conf_getprop(fmd.d_conf, "rsrc.zero", &zero); 647 648 (void) pthread_rwlock_wrlock(&ahp->ah_lock); 649 650 while ((dp = readdir(dirp)) != NULL) { 651 if (dp->d_name[0] == '.') 652 continue; /* skip "." and ".." */ 653 654 if (zero) 655 fmd_asru_hash_discard(ahp, dp->d_name, 0); 656 else if (!fmd_strmatch(dp->d_name, "*-")) 657 fmd_asru_hash_logopen(ahp, dp->d_name); 658 } 659 660 (void) pthread_rwlock_unlock(&ahp->ah_lock); 661 (void) closedir(dirp); 662 } 663 664 /* 665 * If the resource is present and faulty but not unusable, replay the fault 666 * event that caused it be marked faulty. This will cause the agent 667 * subscribing to this fault class to again disable the resource. 668 */ 669 /*ARGSUSED*/ 670 static void 671 fmd_asru_hash_replay_asru(fmd_asru_t *ap, void *data) 672 { 673 fmd_event_t *e; 674 nvlist_t *nvl; 675 char *class; 676 677 if (ap->asru_event != NULL && (ap->asru_flags & (FMD_ASRU_STATE | 678 FMD_ASRU_PRESENT)) == (FMD_ASRU_FAULTY | FMD_ASRU_PRESENT)) { 679 680 fmd_dprintf(FMD_DBG_ASRU, 681 "replaying fault event for %s", ap->asru_name); 682 683 (void) nvlist_xdup(ap->asru_event, &nvl, &fmd.d_nva); 684 (void) nvlist_lookup_string(nvl, FM_CLASS, &class); 685 686 (void) nvlist_add_string(nvl, FMD_EVN_UUID, 687 ((fmd_case_impl_t *)ap->asru_case)->ci_uuid); 688 689 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class); 690 fmd_dispq_dispatch(fmd.d_disp, e, class); 691 } 692 } 693 694 void 695 fmd_asru_hash_replay(fmd_asru_hash_t *ahp) 696 { 697 fmd_asru_hash_apply(ahp, fmd_asru_hash_replay_asru, NULL); 698 } 699 700 /* 701 * Check if the resource is still present. If not, and if the rsrc.age time 702 * has expired, then do an implicit repair on the resource. 703 */ 704 /*ARGSUSED*/ 705 static void 706 fmd_asru_repair_if_aged(fmd_asru_link_t *alp, void *arg) 707 { 708 struct timeval tv; 709 fmd_log_t *lp; 710 hrtime_t hrt; 711 int ps; 712 int err; 713 fmd_asru_rep_arg_t fara; 714 715 /* 716 * Checking for aged resources only happens on the diagnosing side 717 * not on a proxy. 718 */ 719 if (alp->al_flags & FMD_ASRU_PROXY) 720 return; 721 722 ps = fmd_asru_replacement_state(alp->al_event, HC_ONLY_FALSE); 723 if (ps == FMD_OBJ_STATE_REPLACED) { 724 fara.fara_reason = FMD_ASRU_REPLACED; 725 fara.fara_bywhat = FARA_ALL; 726 fara.fara_rval = &err; 727 fmd_asru_repaired(alp, &fara); 728 } else if (ps == FMD_OBJ_STATE_NOT_PRESENT) { 729 fmd_time_gettimeofday(&tv); 730 lp = fmd_log_open(alp->al_asru->asru_root, alp->al_uuid, 731 FMD_LOG_ASRU); 732 hrt = (hrtime_t)(tv.tv_sec - lp->log_stat.st_mtime); 733 fmd_log_rele(lp); 734 if (hrt * NANOSEC >= fmd.d_asrus->ah_lifetime) { 735 fara.fara_reason = FMD_ASRU_REMOVED; 736 fara.fara_bywhat = FARA_ALL; 737 fara.fara_rval = &err; 738 fmd_asru_repaired(alp, &fara); 739 } 740 } 741 } 742 743 void 744 fmd_asru_clear_aged_rsrcs() 745 { 746 fmd_asru_al_hash_apply(fmd.d_asrus, fmd_asru_repair_if_aged, NULL); 747 } 748 749 fmd_asru_hash_t * 750 fmd_asru_hash_create(const char *root, const char *dir) 751 { 752 fmd_asru_hash_t *ahp; 753 char path[PATH_MAX]; 754 755 ahp = fmd_alloc(sizeof (fmd_asru_hash_t), FMD_SLEEP); 756 (void) pthread_rwlock_init(&ahp->ah_lock, NULL); 757 ahp->ah_hashlen = fmd.d_str_buckets; 758 ahp->ah_hash = fmd_zalloc(sizeof (void *) * ahp->ah_hashlen, FMD_SLEEP); 759 ahp->ah_asru_hash = fmd_zalloc(sizeof (void *) * ahp->ah_hashlen, 760 FMD_SLEEP); 761 ahp->ah_case_hash = fmd_zalloc(sizeof (void *) * ahp->ah_hashlen, 762 FMD_SLEEP); 763 ahp->ah_fru_hash = fmd_zalloc(sizeof (void *) * ahp->ah_hashlen, 764 FMD_SLEEP); 765 ahp->ah_label_hash = fmd_zalloc(sizeof (void *) * ahp->ah_hashlen, 766 FMD_SLEEP); 767 ahp->ah_rsrc_hash = fmd_zalloc(sizeof (void *) * ahp->ah_hashlen, 768 FMD_SLEEP); 769 (void) snprintf(path, sizeof (path), "%s/%s", root, dir); 770 ahp->ah_dirpath = fmd_strdup(path, FMD_SLEEP); 771 (void) fmd_conf_getprop(fmd.d_conf, "rsrc.age", &ahp->ah_lifetime); 772 (void) fmd_conf_getprop(fmd.d_conf, "fakenotpresent", 773 (uint32_t *)&fmd_asru_fake_not_present); 774 ahp->ah_al_count = 0; 775 ahp->ah_count = 0; 776 ahp->ah_error = 0; 777 ahp->ah_topo = fmd_topo_hold(); 778 779 return (ahp); 780 } 781 782 void 783 fmd_asru_hash_destroy(fmd_asru_hash_t *ahp) 784 { 785 fmd_asru_link_t *alp, *np; 786 uint_t i; 787 788 for (i = 0; i < ahp->ah_hashlen; i++) { 789 for (alp = ahp->ah_case_hash[i]; alp != NULL; alp = np) { 790 np = alp->al_case_next; 791 alp->al_case_next = NULL; 792 fmd_case_rele(alp->al_case); 793 alp->al_case = NULL; 794 fmd_asru_al_hash_release(ahp, alp); 795 } 796 } 797 798 fmd_strfree(ahp->ah_dirpath); 799 fmd_free(ahp->ah_hash, sizeof (void *) * ahp->ah_hashlen); 800 fmd_free(ahp->ah_asru_hash, sizeof (void *) * ahp->ah_hashlen); 801 fmd_free(ahp->ah_case_hash, sizeof (void *) * ahp->ah_hashlen); 802 fmd_free(ahp->ah_fru_hash, sizeof (void *) * ahp->ah_hashlen); 803 fmd_free(ahp->ah_label_hash, sizeof (void *) * ahp->ah_hashlen); 804 fmd_free(ahp->ah_rsrc_hash, sizeof (void *) * ahp->ah_hashlen); 805 fmd_topo_rele(ahp->ah_topo); 806 fmd_free(ahp, sizeof (fmd_asru_hash_t)); 807 } 808 809 /* 810 * Take a snapshot of the ASRU database by placing an additional hold on each 811 * member in an auxiliary array, and then call 'func' for each ASRU. 812 */ 813 void 814 fmd_asru_hash_apply(fmd_asru_hash_t *ahp, 815 void (*func)(fmd_asru_t *, void *), void *arg) 816 { 817 fmd_asru_t *ap, **aps, **app; 818 uint_t apc, i; 819 820 (void) pthread_rwlock_rdlock(&ahp->ah_lock); 821 822 aps = app = fmd_alloc(ahp->ah_count * sizeof (fmd_asru_t *), FMD_SLEEP); 823 apc = ahp->ah_count; 824 825 for (i = 0; i < ahp->ah_hashlen; i++) { 826 for (ap = ahp->ah_hash[i]; ap != NULL; ap = ap->asru_next) 827 *app++ = fmd_asru_hold(ap); 828 } 829 830 ASSERT(app == aps + apc); 831 (void) pthread_rwlock_unlock(&ahp->ah_lock); 832 833 for (i = 0; i < apc; i++) { 834 if (aps[i]->asru_fmri != NULL) 835 func(aps[i], arg); 836 fmd_asru_hash_release(ahp, aps[i]); 837 } 838 839 fmd_free(aps, apc * sizeof (fmd_asru_t *)); 840 } 841 842 void 843 fmd_asru_al_hash_apply(fmd_asru_hash_t *ahp, 844 void (*func)(fmd_asru_link_t *, void *), void *arg) 845 { 846 fmd_asru_link_t *alp, **alps, **alpp; 847 uint_t alpc, i; 848 849 (void) pthread_rwlock_rdlock(&ahp->ah_lock); 850 851 alps = alpp = fmd_alloc(ahp->ah_al_count * sizeof (fmd_asru_link_t *), 852 FMD_SLEEP); 853 alpc = ahp->ah_al_count; 854 855 for (i = 0; i < ahp->ah_hashlen; i++) { 856 for (alp = ahp->ah_case_hash[i]; alp != NULL; 857 alp = alp->al_case_next) 858 *alpp++ = fmd_asru_al_hold(alp); 859 } 860 861 ASSERT(alpp == alps + alpc); 862 (void) pthread_rwlock_unlock(&ahp->ah_lock); 863 864 for (i = 0; i < alpc; i++) { 865 func(alps[i], arg); 866 fmd_asru_al_hash_release(ahp, alps[i]); 867 } 868 869 fmd_free(alps, alpc * sizeof (fmd_asru_link_t *)); 870 } 871 872 static void 873 fmd_asru_do_hash_apply(fmd_asru_hash_t *ahp, char *name, 874 void (*func)(fmd_asru_link_t *, void *), void *arg, 875 fmd_asru_link_t **hash, size_t match_offset, size_t next_offset) 876 { 877 fmd_asru_link_t *alp, **alps, **alpp; 878 uint_t alpc = 0, i; 879 uint_t h; 880 881 (void) pthread_rwlock_rdlock(&ahp->ah_lock); 882 883 h = fmd_asru_strhash(ahp, name); 884 885 for (alp = hash[h]; alp != NULL; alp = 886 /* LINTED pointer alignment */ 887 FMD_ASRU_AL_HASH_NEXT(alp, next_offset)) 888 if (fmd_asru_strcmp(ahp, 889 /* LINTED pointer alignment */ 890 FMD_ASRU_AL_HASH_NAME(alp, match_offset), name)) 891 alpc++; 892 893 alps = alpp = fmd_alloc(alpc * sizeof (fmd_asru_link_t *), FMD_SLEEP); 894 895 for (alp = hash[h]; alp != NULL; alp = 896 /* LINTED pointer alignment */ 897 FMD_ASRU_AL_HASH_NEXT(alp, next_offset)) 898 if (fmd_asru_strcmp(ahp, 899 /* LINTED pointer alignment */ 900 FMD_ASRU_AL_HASH_NAME(alp, match_offset), name)) 901 *alpp++ = fmd_asru_al_hold(alp); 902 903 ASSERT(alpp == alps + alpc); 904 (void) pthread_rwlock_unlock(&ahp->ah_lock); 905 906 for (i = 0; i < alpc; i++) { 907 func(alps[i], arg); 908 fmd_asru_al_hash_release(ahp, alps[i]); 909 } 910 911 fmd_free(alps, alpc * sizeof (fmd_asru_link_t *)); 912 } 913 914 void 915 fmd_asru_hash_apply_by_asru(fmd_asru_hash_t *ahp, char *name, 916 void (*func)(fmd_asru_link_t *, void *), void *arg) 917 { 918 fmd_asru_do_hash_apply(ahp, name, func, arg, ahp->ah_asru_hash, 919 offsetof(fmd_asru_link_t, al_asru_name), 920 offsetof(fmd_asru_link_t, al_asru_next)); 921 } 922 923 void 924 fmd_asru_hash_apply_by_case(fmd_asru_hash_t *ahp, fmd_case_t *cp, 925 void (*func)(fmd_asru_link_t *, void *), void *arg) 926 { 927 fmd_asru_do_hash_apply(ahp, ((fmd_case_impl_t *)cp)->ci_uuid, func, arg, 928 ahp->ah_case_hash, offsetof(fmd_asru_link_t, al_case_uuid), 929 offsetof(fmd_asru_link_t, al_case_next)); 930 } 931 932 void 933 fmd_asru_hash_apply_by_fru(fmd_asru_hash_t *ahp, char *name, 934 void (*func)(fmd_asru_link_t *, void *), void *arg) 935 { 936 fmd_asru_do_hash_apply(ahp, name, func, arg, ahp->ah_fru_hash, 937 offsetof(fmd_asru_link_t, al_fru_name), 938 offsetof(fmd_asru_link_t, al_fru_next)); 939 } 940 941 void 942 fmd_asru_hash_apply_by_rsrc(fmd_asru_hash_t *ahp, char *name, 943 void (*func)(fmd_asru_link_t *, void *), void *arg) 944 { 945 fmd_asru_do_hash_apply(ahp, name, func, arg, ahp->ah_rsrc_hash, 946 offsetof(fmd_asru_link_t, al_rsrc_name), 947 offsetof(fmd_asru_link_t, al_rsrc_next)); 948 } 949 950 void 951 fmd_asru_hash_apply_by_label(fmd_asru_hash_t *ahp, char *name, 952 void (*func)(fmd_asru_link_t *, void *), void *arg) 953 { 954 fmd_asru_do_hash_apply(ahp, name, func, arg, ahp->ah_label_hash, 955 offsetof(fmd_asru_link_t, al_label), 956 offsetof(fmd_asru_link_t, al_label_next)); 957 } 958 959 /* 960 * Lookup an asru in the hash by name and place a hold on it. If the asru is 961 * not found, no entry is created and NULL is returned. 962 */ 963 fmd_asru_t * 964 fmd_asru_hash_lookup_name(fmd_asru_hash_t *ahp, const char *name) 965 { 966 fmd_asru_t *ap; 967 968 (void) pthread_rwlock_rdlock(&ahp->ah_lock); 969 ap = fmd_asru_hash_lookup(ahp, name); 970 (void) pthread_rwlock_unlock(&ahp->ah_lock); 971 972 return (ap); 973 } 974 975 /* 976 * Create a resource cache entry using the fault event "nvl" for one of the 977 * suspects from the case "cp". 978 * 979 * The fault event can have the following components : FM_FAULT_ASRU, 980 * FM_FAULT_FRU, FM_FAULT_RESOURCE. These should be set by the Diagnosis Engine 981 * when calling fmd_nvl_create_fault(). In the general case, these are all 982 * optional and an entry will always be added into the cache even if one or all 983 * of these fields is missing. 984 * 985 * However, for hardware faults the recommended practice is that the fault 986 * event should always have the FM_FAULT_RESOURCE field present and that this 987 * should be represented in hc-scheme. 988 * 989 * Currently the DE should also add the FM_FAULT_ASRU and FM_FAULT_FRU fields 990 * where known, though at some future stage fmd might be able to fill these 991 * in automatically from the topology. 992 */ 993 fmd_asru_link_t * 994 fmd_asru_hash_create_entry(fmd_asru_hash_t *ahp, fmd_case_t *cp, nvlist_t *nvl) 995 { 996 char *parsed_uuid; 997 uuid_t uuid; 998 int uuidlen; 999 fmd_asru_link_t *alp; 1000 1001 /* 1002 * Generate a UUID for the ASRU. libuuid cleverly gives us no 1003 * interface for specifying or learning the buffer size. Sigh. 1004 * The spec says 36 bytes but we use a tunable just to be safe. 1005 */ 1006 (void) fmd_conf_getprop(fmd.d_conf, "uuidlen", &uuidlen); 1007 parsed_uuid = fmd_zalloc(uuidlen + 1, FMD_SLEEP); 1008 uuid_generate(uuid); 1009 uuid_unparse(uuid, parsed_uuid); 1010 1011 /* 1012 * Now create the resource cache entries. 1013 */ 1014 fmd_case_hold_locked(cp); 1015 alp = fmd_asru_al_create(ahp, nvl, cp, parsed_uuid); 1016 TRACE((FMD_DBG_ASRU, "asru %s created as %p", 1017 alp->al_uuid, (void *)alp->al_asru)); 1018 1019 fmd_free(parsed_uuid, uuidlen + 1); 1020 return (alp); 1021 1022 } 1023 1024 /* 1025 * Release the reference count on an asru obtained using fmd_asru_hash_lookup. 1026 * We take 'ahp' for symmetry and in case we need to use it in future work. 1027 */ 1028 /*ARGSUSED*/ 1029 void 1030 fmd_asru_hash_release(fmd_asru_hash_t *ahp, fmd_asru_t *ap) 1031 { 1032 (void) pthread_mutex_lock(&ap->asru_lock); 1033 1034 ASSERT(ap->asru_refs != 0); 1035 if (--ap->asru_refs == 0) 1036 fmd_asru_destroy(ap); 1037 else 1038 (void) pthread_mutex_unlock(&ap->asru_lock); 1039 } 1040 1041 static void 1042 fmd_asru_do_delete_entry(fmd_asru_hash_t *ahp, fmd_case_t *cp, 1043 fmd_asru_link_t **hash, size_t next_offset, char *name) 1044 { 1045 uint_t h; 1046 fmd_asru_link_t *alp, **pp, *alpnext, **alpnextp; 1047 1048 (void) pthread_rwlock_wrlock(&ahp->ah_lock); 1049 h = fmd_asru_strhash(ahp, name); 1050 pp = &hash[h]; 1051 for (alp = *pp; alp != NULL; alp = alpnext) { 1052 /* LINTED pointer alignment */ 1053 alpnextp = FMD_ASRU_AL_HASH_NEXTP(alp, next_offset); 1054 alpnext = *alpnextp; 1055 if (alp->al_case == cp) { 1056 *pp = *alpnextp; 1057 *alpnextp = NULL; 1058 } else 1059 pp = alpnextp; 1060 } 1061 (void) pthread_rwlock_unlock(&ahp->ah_lock); 1062 } 1063 1064 static void 1065 fmd_asru_do_hash_delete(fmd_asru_hash_t *ahp, fmd_case_susp_t *cis, 1066 fmd_case_t *cp, fmd_asru_link_t **hash, size_t next_offset, char *nvname) 1067 { 1068 nvlist_t *nvl; 1069 char *name = NULL; 1070 ssize_t namelen; 1071 1072 if (nvlist_lookup_nvlist(cis->cis_nvl, nvname, &nvl) == 0 && 1073 (namelen = fmd_fmri_nvl2str(nvl, NULL, 0)) != -1 && 1074 (name = fmd_alloc(namelen + 1, FMD_SLEEP)) != NULL) { 1075 if (fmd_fmri_nvl2str(nvl, name, namelen + 1) != -1) 1076 fmd_asru_do_delete_entry(ahp, cp, hash, next_offset, 1077 name); 1078 fmd_free(name, namelen + 1); 1079 } else 1080 fmd_asru_do_delete_entry(ahp, cp, hash, next_offset, ""); 1081 } 1082 1083 void 1084 fmd_asru_hash_delete_case(fmd_asru_hash_t *ahp, fmd_case_t *cp) 1085 { 1086 fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 1087 fmd_case_susp_t *cis; 1088 fmd_asru_link_t *alp, **plp, *alpnext; 1089 fmd_asru_t *ap; 1090 char path[PATH_MAX]; 1091 char *label; 1092 uint_t h; 1093 1094 /* 1095 * first delete hash entries for each suspect 1096 */ 1097 for (cis = cip->ci_suspects; cis != NULL; cis = cis->cis_next) { 1098 fmd_asru_do_hash_delete(ahp, cis, cp, ahp->ah_fru_hash, 1099 offsetof(fmd_asru_link_t, al_fru_next), FM_FAULT_FRU); 1100 fmd_asru_do_hash_delete(ahp, cis, cp, ahp->ah_rsrc_hash, 1101 offsetof(fmd_asru_link_t, al_rsrc_next), FM_FAULT_RESOURCE); 1102 if (nvlist_lookup_string(cis->cis_nvl, FM_FAULT_LOCATION, 1103 &label) != 0) 1104 label = ""; 1105 fmd_asru_do_delete_entry(ahp, cp, ahp->ah_label_hash, 1106 offsetof(fmd_asru_link_t, al_label_next), label); 1107 fmd_asru_do_hash_delete(ahp, cis, cp, ahp->ah_asru_hash, 1108 offsetof(fmd_asru_link_t, al_asru_next), FM_FAULT_ASRU); 1109 } 1110 1111 /* 1112 * then delete associated case hash entries 1113 */ 1114 (void) pthread_rwlock_wrlock(&ahp->ah_lock); 1115 h = fmd_asru_strhash(ahp, cip->ci_uuid); 1116 plp = &ahp->ah_case_hash[h]; 1117 for (alp = *plp; alp != NULL; alp = alpnext) { 1118 alpnext = alp->al_case_next; 1119 if (alp->al_case == cp) { 1120 *plp = alp->al_case_next; 1121 alp->al_case_next = NULL; 1122 ASSERT(ahp->ah_al_count != 0); 1123 ahp->ah_al_count--; 1124 1125 /* 1126 * decrement case ref. 1127 */ 1128 fmd_case_rele_locked(cp); 1129 alp->al_case = NULL; 1130 1131 /* 1132 * If we found a matching ASRU, unlink its log file and 1133 * then release the hash entry. Note that it may still 1134 * be referenced if another thread is manipulating it; 1135 * this is ok because once we unlink, the log file will 1136 * not be restored, and the log data will be freed when 1137 * all of the referencing threads release their 1138 * respective references. 1139 */ 1140 (void) snprintf(path, sizeof (path), "%s/%s", 1141 ahp->ah_dirpath, alp->al_uuid); 1142 if (cip->ci_xprt == NULL && unlink(path) != 0) 1143 fmd_error(EFMD_ASRU_UNLINK, 1144 "failed to unlink asru %s", path); 1145 1146 /* 1147 * Now unlink from the global per-resource cache 1148 * and if this is the last link then remove that from 1149 * it's own hash too. 1150 */ 1151 ap = alp->al_asru; 1152 (void) pthread_mutex_lock(&ap->asru_lock); 1153 fmd_list_delete(&ap->asru_list, alp); 1154 if (ap->asru_list.l_next == NULL) { 1155 uint_t h; 1156 fmd_asru_t *ap2, **pp; 1157 fmd_asru_t *apnext, **apnextp; 1158 1159 ASSERT(ahp->ah_count != 0); 1160 ahp->ah_count--; 1161 h = fmd_asru_strhash(ahp, ap->asru_name); 1162 pp = &ahp->ah_hash[h]; 1163 for (ap2 = *pp; ap2 != NULL; ap2 = apnext) { 1164 apnextp = &ap2->asru_next; 1165 apnext = *apnextp; 1166 if (ap2 == ap) { 1167 *pp = *apnextp; 1168 *apnextp = NULL; 1169 } else 1170 pp = apnextp; 1171 } 1172 } 1173 (void) pthread_mutex_unlock(&ap->asru_lock); 1174 fmd_asru_al_hash_release(ahp, alp); 1175 } else 1176 plp = &alp->al_case_next; 1177 } 1178 (void) pthread_rwlock_unlock(&ahp->ah_lock); 1179 } 1180 1181 typedef struct { 1182 nvlist_t *farc_parent_fmri; 1183 uint8_t farc_reason; 1184 } fmd_asru_farc_t; 1185 1186 static void 1187 fmd_asru_repair_containee(fmd_asru_link_t *alp, void *arg) 1188 { 1189 fmd_asru_farc_t *farcp = (fmd_asru_farc_t *)arg; 1190 1191 if ((alp->al_asru->asru_flags & FMD_ASRU_INVISIBLE) && 1192 alp->al_asru_fmri && 1193 fmd_fmri_contains(farcp->farc_parent_fmri, alp->al_asru_fmri) > 0) { 1194 if (fmd_asru_clrflags(alp, FMD_ASRU_FAULTY, 1195 farcp->farc_reason)) { 1196 if (alp->al_flags & FMD_ASRU_PROXY) 1197 fmd_case_xprt_updated(alp->al_case); 1198 else 1199 fmd_case_update(alp->al_case); 1200 } 1201 } 1202 } 1203 1204 static void 1205 fmd_asru_do_repair_containees(fmd_asru_link_t *alp, uint8_t reason) 1206 { 1207 int flags; 1208 1209 /* 1210 * Check if all entries associated with this asru are acquitted and 1211 * if so acquit containees. Don't try to repair containees on proxy 1212 * side unless we have local asru. 1213 */ 1214 if (alp->al_asru_fmri != NULL && (!(alp->al_flags & FMD_ASRU_PROXY) || 1215 (alp->al_flags & FMD_ASRU_PROXY_WITH_ASRU))) { 1216 (void) pthread_mutex_lock(&alp->al_asru->asru_lock); 1217 flags = alp->al_asru->asru_flags; 1218 (void) pthread_mutex_unlock(&alp->al_asru->asru_lock); 1219 if (!(flags & (FMD_ASRU_FAULTY | FMD_ASRU_INVISIBLE))) { 1220 fmd_asru_farc_t farc; 1221 1222 farc.farc_parent_fmri = alp->al_asru_fmri; 1223 farc.farc_reason = reason; 1224 fmd_asru_al_hash_apply(fmd.d_asrus, 1225 fmd_asru_repair_containee, &farc); 1226 } 1227 } 1228 } 1229 1230 void 1231 fmd_asru_repaired(fmd_asru_link_t *alp, void *arg) 1232 { 1233 int cleared; 1234 fmd_asru_rep_arg_t *farap = (fmd_asru_rep_arg_t *)arg; 1235 1236 /* 1237 * don't allow remote repair over readonly transport 1238 */ 1239 if (alp->al_flags & FMD_ASRU_PROXY_RDONLY) 1240 return; 1241 1242 /* 1243 * don't allow repair etc by asru on proxy unless asru is local 1244 */ 1245 if (farap->fara_bywhat == FARA_BY_ASRU && 1246 (alp->al_flags & FMD_ASRU_PROXY) && 1247 !(alp->al_flags & FMD_ASRU_PROXY_WITH_ASRU)) 1248 return; 1249 /* 1250 * For acquit, need to check both name and uuid if specified 1251 */ 1252 if (farap->fara_reason == FMD_ASRU_ACQUITTED && 1253 farap->fara_rval != NULL && strcmp(farap->fara_uuid, "") != 0 && 1254 strcmp(farap->fara_uuid, alp->al_case_uuid) != 0) 1255 return; 1256 1257 /* 1258 * For replaced, verify it has been replaced if we have serial number 1259 */ 1260 if (farap->fara_reason == FMD_ASRU_REPLACED && 1261 !(alp->al_flags & FMD_ASRU_PROXY_EXTERNAL) && 1262 fmd_asru_replacement_state(alp->al_event, 1263 (alp->al_flags & FMD_ASRU_PROXY) ? HC_ONLY_TRUE : HC_ONLY_FALSE) == 1264 FMD_OBJ_STATE_STILL_PRESENT) { 1265 return; 1266 } 1267 1268 cleared = fmd_asru_clrflags(alp, FMD_ASRU_FAULTY, farap->fara_reason); 1269 fmd_asru_do_repair_containees(alp, farap->fara_reason); 1270 1271 /* 1272 * if called from fmd_adm_*() and we really did clear the bit then 1273 * we need to do a case update to see if the associated case can be 1274 * repaired. No need to do this if called from fmd_case_*() (ie 1275 * when arg is NULL) as the case will be explicitly repaired anyway. 1276 */ 1277 if (farap->fara_rval) { 1278 *farap->fara_rval = 0; 1279 if (cleared) { 1280 if (alp->al_flags & FMD_ASRU_PROXY) 1281 fmd_case_xprt_updated(alp->al_case); 1282 else 1283 fmd_case_update(alp->al_case); 1284 } 1285 } 1286 } 1287 1288 /* 1289 * This is only called for proxied faults. Set various flags so we can 1290 * find the nature of the transport from the resource cache code. 1291 */ 1292 /*ARGSUSED*/ 1293 void 1294 fmd_asru_set_on_proxy(fmd_asru_link_t *alp, void *arg) 1295 { 1296 fmd_asru_set_on_proxy_t *entryp = (fmd_asru_set_on_proxy_t *)arg; 1297 1298 if (*entryp->fasp_countp >= entryp->fasp_maxcount) 1299 return; 1300 1301 /* 1302 * Note that this is a proxy fault and save whetehr transport is 1303 * RDONLY or EXTERNAL. 1304 */ 1305 alp->al_flags |= FMD_ASRU_PROXY; 1306 alp->al_asru->asru_flags |= FMD_ASRU_PROXY; 1307 1308 if (entryp->fasp_proxy_external) { 1309 alp->al_flags |= FMD_ASRU_PROXY_EXTERNAL; 1310 alp->al_asru->asru_flags |= FMD_ASRU_PROXY_EXTERNAL; 1311 } 1312 1313 if (entryp->fasp_proxy_rdonly) 1314 alp->al_flags |= FMD_ASRU_PROXY_RDONLY; 1315 1316 /* 1317 * Save whether asru is accessible in local domain 1318 */ 1319 if (entryp->fasp_proxy_asru[*entryp->fasp_countp]) { 1320 alp->al_flags |= FMD_ASRU_PROXY_WITH_ASRU; 1321 alp->al_asru->asru_flags |= FMD_ASRU_PROXY_WITH_ASRU; 1322 } 1323 (*entryp->fasp_countp)++; 1324 } 1325 1326 /*ARGSUSED*/ 1327 void 1328 fmd_asru_update_containees(fmd_asru_link_t *alp, void *arg) 1329 { 1330 fmd_asru_do_repair_containees(alp, alp->al_reason); 1331 } 1332 1333 /* 1334 * This function is used for fault proxying. It updates the resource status in 1335 * the resource cache based on information that has come from the other side of 1336 * the transport. This can be called on either the proxy side or the 1337 * diagnosing side. 1338 */ 1339 void 1340 fmd_asru_update_status(fmd_asru_link_t *alp, void *arg) 1341 { 1342 fmd_asru_update_status_t *entryp = (fmd_asru_update_status_t *)arg; 1343 uint8_t status; 1344 1345 if (*entryp->faus_countp >= entryp->faus_maxcount) 1346 return; 1347 1348 status = entryp->faus_ba[*entryp->faus_countp]; 1349 1350 /* 1351 * For proxy, if there is no asru on the proxy side, but there is on 1352 * the diag side, then take the diag side asru status. 1353 * For diag, if there is an asru on the proxy side, then take the proxy 1354 * side asru status. 1355 */ 1356 if (entryp->faus_is_proxy ? 1357 (entryp->faus_diag_asru[*entryp->faus_countp] && 1358 !entryp->faus_proxy_asru[*entryp->faus_countp]) : 1359 entryp->faus_proxy_asru[*entryp->faus_countp]) { 1360 if (status & FM_SUSPECT_DEGRADED) 1361 alp->al_flags |= FMD_ASRU_DEGRADED; 1362 else 1363 alp->al_flags &= ~FMD_ASRU_DEGRADED; 1364 if (status & FM_SUSPECT_UNUSABLE) 1365 (void) fmd_asru_setflags(alp, FMD_ASRU_UNUSABLE); 1366 else 1367 (void) fmd_asru_clrflags(alp, FMD_ASRU_UNUSABLE, 0); 1368 } 1369 1370 /* 1371 * Update the faulty status too. 1372 */ 1373 if (!(status & FM_SUSPECT_FAULTY)) 1374 (void) fmd_asru_clrflags(alp, FMD_ASRU_FAULTY, 1375 (status & FM_SUSPECT_REPAIRED) ? FMD_ASRU_REPAIRED : 1376 (status & FM_SUSPECT_REPLACED) ? FMD_ASRU_REPLACED : 1377 (status & FM_SUSPECT_ACQUITTED) ? FMD_ASRU_ACQUITTED : 1378 FMD_ASRU_REMOVED); 1379 else if (entryp->faus_is_proxy) 1380 (void) fmd_asru_setflags(alp, FMD_ASRU_FAULTY); 1381 1382 /* 1383 * for proxy only, update the present status too. 1384 */ 1385 if (entryp->faus_is_proxy) { 1386 if (!(status & FM_SUSPECT_NOT_PRESENT)) { 1387 alp->al_flags |= FMD_ASRU_PRESENT; 1388 alp->al_asru->asru_flags |= FMD_ASRU_PRESENT; 1389 } else { 1390 alp->al_flags &= ~FMD_ASRU_PRESENT; 1391 alp->al_asru->asru_flags &= ~FMD_ASRU_PRESENT; 1392 } 1393 } 1394 (*entryp->faus_countp)++; 1395 } 1396 1397 /* 1398 * This function is called on the diagnosing side when fault proxying is 1399 * in use and the proxy has sent a uuclose. It updates the status of the 1400 * resource cache entries. 1401 */ 1402 void 1403 fmd_asru_close_status(fmd_asru_link_t *alp, void *arg) 1404 { 1405 fmd_asru_close_status_t *entryp = (fmd_asru_close_status_t *)arg; 1406 1407 if (*entryp->facs_countp >= entryp->facs_maxcount) 1408 return; 1409 alp->al_flags &= ~FMD_ASRU_DEGRADED; 1410 (void) fmd_asru_setflags(alp, FMD_ASRU_UNUSABLE); 1411 (*entryp->facs_countp)++; 1412 } 1413 1414 static void 1415 fmd_asru_logevent(fmd_asru_link_t *alp) 1416 { 1417 fmd_asru_t *ap = alp->al_asru; 1418 boolean_t faulty = (alp->al_flags & FMD_ASRU_FAULTY) != 0; 1419 boolean_t unusable = (alp->al_flags & FMD_ASRU_UNUSABLE) != 0; 1420 boolean_t message = (ap->asru_flags & FMD_ASRU_INVISIBLE) == 0; 1421 boolean_t repaired = (alp->al_reason == FMD_ASRU_REPAIRED); 1422 boolean_t replaced = (alp->al_reason == FMD_ASRU_REPLACED); 1423 boolean_t acquitted = (alp->al_reason == FMD_ASRU_ACQUITTED); 1424 1425 fmd_case_impl_t *cip; 1426 fmd_event_t *e; 1427 fmd_log_t *lp; 1428 nvlist_t *nvl; 1429 char *class; 1430 1431 ASSERT(MUTEX_HELD(&ap->asru_lock)); 1432 cip = (fmd_case_impl_t *)alp->al_case; 1433 ASSERT(cip != NULL); 1434 1435 /* 1436 * Don't log to disk on proxy side 1437 */ 1438 if (cip->ci_xprt != NULL) 1439 return; 1440 1441 if ((lp = alp->al_log) == NULL) 1442 lp = fmd_log_open(ap->asru_root, alp->al_uuid, FMD_LOG_ASRU); 1443 1444 if (lp == NULL) 1445 return; /* can't log events if we can't open the log */ 1446 1447 nvl = fmd_protocol_rsrc_asru(_fmd_asru_events[faulty | (unusable << 1)], 1448 alp->al_asru_fmri, cip->ci_uuid, cip->ci_code, faulty, unusable, 1449 message, alp->al_event, &cip->ci_tv, repaired, replaced, acquitted, 1450 cip->ci_diag_de == NULL ? cip->ci_mod->mod_fmri : cip->ci_diag_de); 1451 1452 (void) nvlist_lookup_string(nvl, FM_CLASS, &class); 1453 e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class); 1454 1455 fmd_event_hold(e); 1456 fmd_log_append(lp, e, NULL); 1457 fmd_event_rele(e); 1458 1459 /* 1460 * For now, we close the log file after every update to conserve file 1461 * descriptors and daemon overhead. If this becomes a performance 1462 * issue this code can change to keep a fixed-size LRU cache of logs. 1463 */ 1464 fmd_log_rele(lp); 1465 alp->al_log = NULL; 1466 } 1467 1468 int 1469 fmd_asru_setflags(fmd_asru_link_t *alp, uint_t sflag) 1470 { 1471 fmd_asru_t *ap = alp->al_asru; 1472 uint_t nstate, ostate; 1473 1474 ASSERT(!(sflag & ~FMD_ASRU_STATE)); 1475 ASSERT(sflag != FMD_ASRU_STATE); 1476 1477 (void) pthread_mutex_lock(&ap->asru_lock); 1478 1479 ostate = alp->al_flags & FMD_ASRU_STATE; 1480 alp->al_flags |= sflag; 1481 nstate = alp->al_flags & FMD_ASRU_STATE; 1482 1483 if (nstate == ostate) { 1484 (void) pthread_mutex_unlock(&ap->asru_lock); 1485 return (0); 1486 } 1487 1488 ap->asru_flags |= sflag; 1489 TRACE((FMD_DBG_ASRU, "asru %s %s->%s", alp->al_uuid, 1490 _fmd_asru_snames[ostate], _fmd_asru_snames[nstate])); 1491 1492 fmd_asru_logevent(alp); 1493 1494 (void) pthread_cond_broadcast(&ap->asru_cv); 1495 (void) pthread_mutex_unlock(&ap->asru_lock); 1496 return (1); 1497 } 1498 1499 int 1500 fmd_asru_clrflags(fmd_asru_link_t *alp, uint_t sflag, uint8_t reason) 1501 { 1502 fmd_asru_t *ap = alp->al_asru; 1503 fmd_asru_link_t *nalp; 1504 uint_t nstate, ostate, flags = 0; 1505 1506 ASSERT(!(sflag & ~FMD_ASRU_STATE)); 1507 ASSERT(sflag != FMD_ASRU_STATE); 1508 1509 (void) pthread_mutex_lock(&ap->asru_lock); 1510 1511 ostate = alp->al_flags & FMD_ASRU_STATE; 1512 alp->al_flags &= ~sflag; 1513 nstate = alp->al_flags & FMD_ASRU_STATE; 1514 1515 if (nstate == ostate) { 1516 if (reason > alp->al_reason) { 1517 alp->al_reason = reason; 1518 fmd_asru_logevent(alp); 1519 (void) pthread_cond_broadcast(&ap->asru_cv); 1520 } 1521 (void) pthread_mutex_unlock(&ap->asru_lock); 1522 return (0); 1523 } 1524 if (reason > alp->al_reason) 1525 alp->al_reason = reason; 1526 1527 if (sflag == FMD_ASRU_UNUSABLE) 1528 ap->asru_flags &= ~sflag; 1529 else if (sflag == FMD_ASRU_FAULTY) { 1530 /* 1531 * only clear the faulty bit if all links are clear 1532 */ 1533 for (nalp = fmd_list_next(&ap->asru_list); nalp != NULL; 1534 nalp = fmd_list_next(nalp)) 1535 flags |= nalp->al_flags; 1536 if (!(flags & FMD_ASRU_FAULTY)) 1537 ap->asru_flags &= ~sflag; 1538 } 1539 1540 TRACE((FMD_DBG_ASRU, "asru %s %s->%s", alp->al_uuid, 1541 _fmd_asru_snames[ostate], _fmd_asru_snames[nstate])); 1542 1543 fmd_asru_logevent(alp); 1544 1545 (void) pthread_cond_broadcast(&ap->asru_cv); 1546 (void) pthread_mutex_unlock(&ap->asru_lock); 1547 1548 return (1); 1549 } 1550 1551 /* 1552 * Report the current known state of the link entry (ie this particular fault 1553 * affecting this particular ASRU). 1554 */ 1555 int 1556 fmd_asru_al_getstate(fmd_asru_link_t *alp) 1557 { 1558 int us, st = (alp->al_flags & (FMD_ASRU_FAULTY | FMD_ASRU_UNUSABLE)); 1559 nvlist_t *asru; 1560 int ps = FMD_OBJ_STATE_UNKNOWN; 1561 1562 /* 1563 * For fault proxying with an EXTERNAL transport, believe the presence 1564 * state as sent by the diagnosing side. Otherwise find the presence 1565 * state here. Note that if fault proxying with an INTERNAL transport 1566 * we can only trust the presence state where we are using hc-scheme 1567 * fmris which should be consistant across domains in the same system - 1568 * other schemes can refer to different devices in different domains. 1569 */ 1570 if (!(alp->al_flags & FMD_ASRU_PROXY_EXTERNAL)) { 1571 ps = fmd_asru_replacement_state(alp->al_event, (alp->al_flags & 1572 FMD_ASRU_PROXY)? HC_ONLY_TRUE : HC_ONLY_FALSE); 1573 if (ps == FMD_OBJ_STATE_NOT_PRESENT) 1574 return (st | FMD_ASRU_UNUSABLE); 1575 if (ps == FMD_OBJ_STATE_REPLACED) { 1576 if (alp->al_reason < FMD_ASRU_REPLACED) 1577 alp->al_reason = FMD_ASRU_REPLACED; 1578 return (st | FMD_ASRU_UNUSABLE); 1579 } 1580 } 1581 if (ps == FMD_OBJ_STATE_UNKNOWN && (alp->al_flags & FMD_ASRU_PROXY)) 1582 st |= (alp->al_flags & (FMD_ASRU_DEGRADED | FMD_ASRU_PRESENT)); 1583 else 1584 st |= (alp->al_flags & (FMD_ASRU_DEGRADED)) | FMD_ASRU_PRESENT; 1585 1586 /* 1587 * For fault proxying, unless we have a local ASRU, then believe the 1588 * service state sent by the diagnosing side. Otherwise find the service 1589 * state here. Try fmd_fmri_service_state() first, but if that's not 1590 * supported by the scheme then fall back to fmd_fmri_unusable(). 1591 */ 1592 if ((!(alp->al_flags & FMD_ASRU_PROXY) || 1593 (alp->al_flags & FMD_ASRU_PROXY_WITH_ASRU)) && 1594 nvlist_lookup_nvlist(alp->al_event, FM_FAULT_ASRU, &asru) == 0) { 1595 us = fmd_fmri_service_state(asru); 1596 if (us == -1 || us == FMD_SERVICE_STATE_UNKNOWN) { 1597 /* not supported by scheme - try fmd_fmri_unusable */ 1598 us = fmd_fmri_unusable(asru); 1599 if (us > 0) 1600 st |= FMD_ASRU_UNUSABLE; 1601 else if (us == 0) 1602 st &= ~FMD_ASRU_UNUSABLE; 1603 } else { 1604 if (us == FMD_SERVICE_STATE_UNUSABLE) { 1605 st &= ~FMD_ASRU_DEGRADED; 1606 st |= FMD_ASRU_UNUSABLE; 1607 } else if (us == FMD_SERVICE_STATE_OK) { 1608 st &= ~(FMD_ASRU_DEGRADED | FMD_ASRU_UNUSABLE); 1609 } else if (us == FMD_SERVICE_STATE_ISOLATE_PENDING) { 1610 st &= ~(FMD_ASRU_DEGRADED | FMD_ASRU_UNUSABLE); 1611 } else if (us == FMD_SERVICE_STATE_DEGRADED) { 1612 st &= ~FMD_ASRU_UNUSABLE; 1613 st |= FMD_ASRU_DEGRADED; 1614 } 1615 } 1616 } 1617 return (st); 1618 } 1619 1620 /* 1621 * Report the current known state of the ASRU by refreshing its unusable status 1622 * based upon the routines provided by the scheme module. If the unusable bit 1623 * is different, we do *not* generate a state change here because that change 1624 * may be unrelated to fmd activities and therefore we have no case or event. 1625 * The absence of the transition is harmless as this function is only provided 1626 * for RPC observability and fmd's clients are only concerned with ASRU_FAULTY. 1627 */ 1628 int 1629 fmd_asru_getstate(fmd_asru_t *ap) 1630 { 1631 int us, st, p = -1; 1632 char *s; 1633 1634 /* do not report non-fmd non-present resources */ 1635 if (!(ap->asru_flags & FMD_ASRU_INTERNAL)) { 1636 /* 1637 * As with fmd_asru_al_getstate(), we can only trust the 1638 * local presence state on a proxy if the transport is 1639 * internal and the scheme is hc. Otherwise we believe the 1640 * state as sent by the diagnosing side. 1641 */ 1642 if (!(ap->asru_flags & FMD_ASRU_PROXY) || 1643 (!(ap->asru_flags & FMD_ASRU_PROXY_EXTERNAL) && 1644 (nvlist_lookup_string(ap->asru_fmri, FM_FMRI_SCHEME, 1645 &s) == 0 && strcmp(s, FM_FMRI_SCHEME_HC) == 0))) { 1646 if (fmd_asru_fake_not_present >= 1647 FMD_OBJ_STATE_REPLACED) 1648 return (0); 1649 p = fmd_fmri_present(ap->asru_fmri); 1650 } 1651 if (p == 0 || (p < 0 && !(ap->asru_flags & FMD_ASRU_PROXY) || 1652 !(ap->asru_flags & FMD_ASRU_PRESENT))) 1653 return (0); 1654 } 1655 1656 /* 1657 * As with fmd_asru_al_getstate(), we can only trust the local unusable 1658 * state on a proxy if there is a local ASRU. 1659 */ 1660 st = ap->asru_flags & (FMD_ASRU_FAULTY | FMD_ASRU_UNUSABLE); 1661 if (!(ap->asru_flags & FMD_ASRU_PROXY) || 1662 (ap->asru_flags & FMD_ASRU_PROXY_WITH_ASRU)) { 1663 us = fmd_fmri_unusable(ap->asru_fmri); 1664 if (us > 0) 1665 st |= FMD_ASRU_UNUSABLE; 1666 else if (us == 0) 1667 st &= ~FMD_ASRU_UNUSABLE; 1668 } 1669 return (st); 1670 } 1671