1d9638e54Smws /* 2d9638e54Smws * CDDL HEADER START 3d9638e54Smws * 4d9638e54Smws * The contents of this file are subject to the terms of the 5724365f7Ssethg * Common Development and Distribution License (the "License"). 6724365f7Ssethg * You may not use this file except in compliance with the License. 7d9638e54Smws * 8d9638e54Smws * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9d9638e54Smws * or http://www.opensolaris.org/os/licensing. 10d9638e54Smws * See the License for the specific language governing permissions 11d9638e54Smws * and limitations under the License. 12d9638e54Smws * 13d9638e54Smws * When distributing Covered Code, include this CDDL HEADER in each 14d9638e54Smws * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15d9638e54Smws * If applicable, add the following below this CDDL HEADER, with the 16d9638e54Smws * fields enclosed by brackets "[]" replaced with your own identifying 17d9638e54Smws * information: Portions Copyright [yyyy] [name of copyright owner] 18d9638e54Smws * 19d9638e54Smws * CDDL HEADER END 20d9638e54Smws */ 21d9638e54Smws 22d9638e54Smws /* 23084b846fSStephen Hanson * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24d9638e54Smws */ 25d9638e54Smws 26d9638e54Smws /* 27d9638e54Smws * FMD Transport Subsystem 28d9638e54Smws * 29d9638e54Smws * A transport module uses some underlying mechanism to transport events. 30d9638e54Smws * This mechanism may use any underlying link-layer protocol and may support 31d9638e54Smws * additional link-layer packets unrelated to FMA. Some appropriate link- 32d9638e54Smws * layer mechanism to create the underlying connection is expected to be 33d9638e54Smws * called prior to calling fmd_xprt_open() itself. Alternatively, a transport 34d9638e54Smws * may be created in the suspended state by specifying the FMD_XPRT_SUSPENDED 35d9638e54Smws * flag as part of the call to fmd_xprt_open(), and then may be resumed later. 36d9638e54Smws * The underlying transport mechanism is *required* to provide ordering: that 37d9638e54Smws * is, the sequences of bytes written across the transport must be read by 38d9638e54Smws * the remote peer in the order that they are written, even across separate 39d9638e54Smws * calls to fmdo_send(). As an example, the Internet TCP protocol would be 40d9638e54Smws * a valid transport as it guarantees ordering, whereas the Internet UDP 41d9638e54Smws * protocol would not because UDP datagrams may be delivered in any order 42d9638e54Smws * as a result of delays introduced when datagrams pass through routers. 43d9638e54Smws * 44d9638e54Smws * Similar to sending events, a transport module receives events that are from 45d9638e54Smws * its peer remote endpoint using some transport-specific mechanism that is 46d9638e54Smws * unknown to FMD. As each event is received, the transport module is 47d9638e54Smws * responsible for constructing a valid nvlist_t object from the data and then 48d9638e54Smws * calling fmd_xprt_post() to post the event to the containing FMD's dispatch 49d9638e54Smws * queue, making it available to all local modules that are not transport 50d9638e54Smws * modules that have subscribed to the event. 51d9638e54Smws * 52d9638e54Smws * The following state machine is used for each transport. The initial state 53d9638e54Smws * is either SYN, ACK, or RUN, depending on the flags specified to xprt_create. 54d9638e54Smws * 55d9638e54Smws * FMD_XPRT_ACCEPT !FMD_XPRT_ACCEPT 56d9638e54Smws * | | 57d9638e54Smws * waiting +--v--+ +--v--+ waiting 58d9638e54Smws * for syn | SYN |--+ --+| ACK | for ack 59d9638e54Smws * event +-----+ \ / +-----+ event 60d9638e54Smws * | \ / | 61d9638e54Smws * drop all +--v--+ X +--v--+ send subscriptions, 62d9638e54Smws * events | ERR |<---+ +--->| SUB | recv subscriptions, 63d9638e54Smws * +-----+ +-----+ wait for run event 64d9638e54Smws * ^ | 65d9638e54Smws * | +-----+ | 66d9638e54Smws * +-----| RUN |<----+ 67d9638e54Smws * +--^--+ 68d9638e54Smws * | 69d9638e54Smws * FMD_XPRT_RDONLY 70d9638e54Smws * 71d9638e54Smws * When fmd_xprt_open() is called without FMD_XPRT_ACCEPT, the Common Transport 72d9638e54Smws * Layer enqueues a "syn" event for the module in its event queue and sets the 73d9638e54Smws * state to ACK. In state ACK, we are waiting for the transport to get an 74d9638e54Smws * "ack" event and call fmd_xprt_post() on this event. Other events will be 75d9638e54Smws * discarded. If an "ack" is received, we transition to state SUB. If a 76d9638e54Smws * configurable timeout occurs or if the "ack" is invalid (e.g. invalid version 77d9638e54Smws * exchange), we transition to state ERR. Once in state ERR, no further 78d9638e54Smws * operations are valid except fmd_xprt_close() and fmd_xprt_error() will 79d9638e54Smws * return a non-zero value to the caller indicating the transport has failed. 80d9638e54Smws * 81d9638e54Smws * When fmd_xprt_open() is called with FMD_XPRT_ACCEPT, the Common Transport 82d9638e54Smws * Layer assumes this transport is being used to accept a virtual connection 83d9638e54Smws * from a remote peer that is sending a "syn", and sets the initial state to 84d9638e54Smws * SYN. In this state, the transport waits for a "syn" event, validates it, 85d9638e54Smws * and then transitions to state SUB if it is valid or state ERR if it is not. 86d9638e54Smws * 87d9638e54Smws * Once in state SUB, the transport module is expected to receive a sequence of 88d9638e54Smws * zero or more "subscribe" events from the remote peer, followed by a "run" 89d9638e54Smws * event. Once in state RUN, the transport is active and any events can be 90d9638e54Smws * sent or received. The transport module is free to call fmd_xprt_close() 91d9638e54Smws * from any state. The fmd_xprt_error() function will return zero if the 92d9638e54Smws * transport is not in the ERR state, or non-zero if it is in the ERR state. 93d9638e54Smws * 94d9638e54Smws * Once the state machine reaches RUN, other FMA protocol events can be sent 95d9638e54Smws * and received across the transport in addition to the various control events. 96d9638e54Smws * 97d9638e54Smws * Table of Common Transport Layer Control Events 98d9638e54Smws * ============================================== 99d9638e54Smws * 100d9638e54Smws * FMA Class Payload 101d9638e54Smws * --------- ------- 102d9638e54Smws * resource.fm.xprt.uuclose string (uuid of case) 103cbf75e67SStephen Hanson * resource.fm.xprt.uuresolved string (uuid of case) 104cbf75e67SStephen Hanson * resource.fm.xprt.updated string (uuid of case) 105d9638e54Smws * resource.fm.xprt.subscribe string (class pattern) 106d9638e54Smws * resource.fm.xprt.unsubscribe string (class pattern) 107d9638e54Smws * resource.fm.xprt.unsuback string (class pattern) 108d9638e54Smws * resource.fm.xprt.syn version information 109d9638e54Smws * resource.fm.xprt.ack version information 110d9638e54Smws * resource.fm.xprt.run version information 111d9638e54Smws * 112d9638e54Smws * Control events are used to add and delete proxy subscriptions on the remote 113d9638e54Smws * transport peer module, and to set up connections. When a "syn" event is 114d9638e54Smws * sent, FMD will include in the payload the highest version of the FMA event 115d9638e54Smws * protocol that is supported by the sender. When a "syn" event is received, 116d9638e54Smws * the receiving FMD will use the minimum of this version and its version of 117d9638e54Smws * the protocol, and reply with this new minimum version in the "ack" event. 118d9638e54Smws * The receiver will then use this new minimum for subsequent event semantics. 119d9638e54Smws */ 120d9638e54Smws 121d9638e54Smws #include <sys/fm/protocol.h> 122d9638e54Smws #include <strings.h> 123d9638e54Smws #include <limits.h> 124d9638e54Smws 125d9638e54Smws #include <fmd_alloc.h> 126d9638e54Smws #include <fmd_error.h> 127d9638e54Smws #include <fmd_conf.h> 128d9638e54Smws #include <fmd_subr.h> 129d9638e54Smws #include <fmd_string.h> 130d9638e54Smws #include <fmd_protocol.h> 131d9638e54Smws #include <fmd_thread.h> 132d9638e54Smws #include <fmd_eventq.h> 133d9638e54Smws #include <fmd_dispq.h> 134d9638e54Smws #include <fmd_ctl.h> 135d9638e54Smws #include <fmd_log.h> 136d9638e54Smws #include <fmd_ustat.h> 137d9638e54Smws #include <fmd_case.h> 138d9638e54Smws #include <fmd_api.h> 139d9638e54Smws #include <fmd_fmri.h> 140d9638e54Smws #include <fmd_asru.h> 141d9638e54Smws #include <fmd_xprt.h> 142d9638e54Smws 143d9638e54Smws #include <fmd.h> 144d9638e54Smws 145d9638e54Smws /* 146d9638e54Smws * The states shown above in the transport state machine diagram are encoded 147d9638e54Smws * using arrays of class patterns and a corresponding action function. These 148d9638e54Smws * arrays are then passed to fmd_xprt_transition() to change transport states. 149d9638e54Smws */ 150d9638e54Smws 151d9638e54Smws const fmd_xprt_rule_t _fmd_xprt_state_syn[] = { 152d9638e54Smws { "resource.fm.xprt.syn", fmd_xprt_event_syn }, 153d9638e54Smws { "*", fmd_xprt_event_error }, 154d9638e54Smws { NULL, NULL } 155d9638e54Smws }; 156d9638e54Smws 157d9638e54Smws const fmd_xprt_rule_t _fmd_xprt_state_ack[] = { 158d9638e54Smws { "resource.fm.xprt.ack", fmd_xprt_event_ack }, 159d9638e54Smws { "*", fmd_xprt_event_error }, 160d9638e54Smws }; 161d9638e54Smws 162d9638e54Smws const fmd_xprt_rule_t _fmd_xprt_state_err[] = { 163d9638e54Smws { "*", fmd_xprt_event_drop }, 164d9638e54Smws { NULL, NULL } 165d9638e54Smws }; 166d9638e54Smws 167d9638e54Smws const fmd_xprt_rule_t _fmd_xprt_state_sub[] = { 168d9638e54Smws { "resource.fm.xprt.subscribe", fmd_xprt_event_sub }, 169d9638e54Smws { "resource.fm.xprt.run", fmd_xprt_event_run }, 170d9638e54Smws { "resource.fm.xprt.*", fmd_xprt_event_error }, 171d9638e54Smws { "*", fmd_xprt_event_drop }, 172d9638e54Smws { NULL, NULL } 173d9638e54Smws }; 174d9638e54Smws 175d9638e54Smws const fmd_xprt_rule_t _fmd_xprt_state_run[] = { 176d9638e54Smws { "resource.fm.xprt.subscribe", fmd_xprt_event_sub }, 177d9638e54Smws { "resource.fm.xprt.unsubscribe", fmd_xprt_event_unsub }, 178d9638e54Smws { "resource.fm.xprt.unsuback", fmd_xprt_event_unsuback }, 179d9638e54Smws { "resource.fm.xprt.uuclose", fmd_xprt_event_uuclose }, 180cbf75e67SStephen Hanson { "resource.fm.xprt.uuresolved", fmd_xprt_event_uuresolved }, 181cbf75e67SStephen Hanson { "resource.fm.xprt.updated", fmd_xprt_event_updated }, 182d9638e54Smws { "resource.fm.xprt.*", fmd_xprt_event_error }, 183d9638e54Smws { NULL, NULL } 184d9638e54Smws }; 185d9638e54Smws 186d9638e54Smws /* 187d9638e54Smws * Template for per-transport statistics installed by fmd on behalf of each 188d9638e54Smws * transport. These are used to initialize the per-transport xi_stats. For 189d9638e54Smws * each statistic, the name is prepended with "fmd.xprt.%u", where %u is the 190d9638e54Smws * transport ID (xi_id) and then are inserted into the per-module stats hash. 191d9638e54Smws * The values in this array must match fmd_xprt_stat_t from <fmd_xprt.h>. 192d9638e54Smws */ 193d9638e54Smws static const fmd_xprt_stat_t _fmd_xprt_stat_tmpl = { 194d9638e54Smws { 195d9638e54Smws { "dispatched", FMD_TYPE_UINT64, "total events dispatched to transport" }, 196d9638e54Smws { "dequeued", FMD_TYPE_UINT64, "total events dequeued by transport" }, 197d9638e54Smws { "prdequeued", FMD_TYPE_UINT64, "protocol events dequeued by transport" }, 198d9638e54Smws { "dropped", FMD_TYPE_UINT64, "total events dropped on queue overflow" }, 199d9638e54Smws { "wcnt", FMD_TYPE_UINT32, "count of events waiting on queue" }, 200d9638e54Smws { "wtime", FMD_TYPE_TIME, "total wait time on queue" }, 201d9638e54Smws { "wlentime", FMD_TYPE_TIME, "total wait length * time product" }, 202d9638e54Smws { "wlastupdate", FMD_TYPE_TIME, "hrtime of last wait queue update" }, 203d9638e54Smws { "dtime", FMD_TYPE_TIME, "total processing time after dequeue" }, 204d9638e54Smws { "dlastupdate", FMD_TYPE_TIME, "hrtime of last event dequeue completion" }, 205d9638e54Smws }, 206d9638e54Smws { "module", FMD_TYPE_STRING, "module that owns this transport" }, 207d9638e54Smws { "authority", FMD_TYPE_STRING, "authority associated with this transport" }, 208d9638e54Smws { "state", FMD_TYPE_STRING, "current transport state" }, 209d9638e54Smws { "received", FMD_TYPE_UINT64, "events received by transport" }, 210d9638e54Smws { "discarded", FMD_TYPE_UINT64, "bad events discarded by transport" }, 211d9638e54Smws { "retried", FMD_TYPE_UINT64, "retries requested of transport" }, 212d9638e54Smws { "replayed", FMD_TYPE_UINT64, "events replayed by transport" }, 213d9638e54Smws { "lost", FMD_TYPE_UINT64, "events lost by transport" }, 214d9638e54Smws { "timeouts", FMD_TYPE_UINT64, "events received by transport with ttl=0" }, 215d9638e54Smws { "subscriptions", FMD_TYPE_UINT64, "subscriptions registered to transport" }, 216d9638e54Smws }; 217d9638e54Smws 218d9638e54Smws static void 219d9638e54Smws fmd_xprt_class_hash_create(fmd_xprt_class_hash_t *xch, fmd_eventq_t *eq) 220d9638e54Smws { 221d9638e54Smws uint_t hashlen = fmd.d_str_buckets; 222d9638e54Smws 223d9638e54Smws xch->xch_queue = eq; 224d9638e54Smws xch->xch_hashlen = hashlen; 225d9638e54Smws xch->xch_hash = fmd_zalloc(sizeof (void *) * hashlen, FMD_SLEEP); 226d9638e54Smws } 227d9638e54Smws 228d9638e54Smws static void 229d9638e54Smws fmd_xprt_class_hash_destroy(fmd_xprt_class_hash_t *xch) 230d9638e54Smws { 231d9638e54Smws fmd_eventq_t *eq = xch->xch_queue; 232d9638e54Smws fmd_xprt_class_t *xcp, *ncp; 233d9638e54Smws uint_t i; 234d9638e54Smws 235d9638e54Smws for (i = 0; i < xch->xch_hashlen; i++) { 236d9638e54Smws for (xcp = xch->xch_hash[i]; xcp != NULL; xcp = ncp) { 237d9638e54Smws ncp = xcp->xc_next; 238d9638e54Smws 239d9638e54Smws if (eq != NULL) 240d9638e54Smws fmd_dispq_delete(fmd.d_disp, eq, xcp->xc_class); 241d9638e54Smws 242d9638e54Smws fmd_strfree(xcp->xc_class); 243d9638e54Smws fmd_free(xcp, sizeof (fmd_xprt_class_t)); 244d9638e54Smws } 245d9638e54Smws } 246d9638e54Smws 247d9638e54Smws fmd_free(xch->xch_hash, sizeof (void *) * xch->xch_hashlen); 248d9638e54Smws } 249d9638e54Smws 250d9638e54Smws /* 251d9638e54Smws * Insert the specified class into the specified class hash, and return the 252d9638e54Smws * reference count. A return value of one indicates this is the first insert. 253d9638e54Smws * If an eventq is associated with the hash, insert a dispq subscription for it. 254d9638e54Smws */ 255d9638e54Smws static uint_t 256d9638e54Smws fmd_xprt_class_hash_insert(fmd_xprt_impl_t *xip, 257d9638e54Smws fmd_xprt_class_hash_t *xch, const char *class) 258d9638e54Smws { 259d9638e54Smws uint_t h = fmd_strhash(class) % xch->xch_hashlen; 260d9638e54Smws fmd_xprt_class_t *xcp; 261d9638e54Smws 262d9638e54Smws ASSERT(MUTEX_HELD(&xip->xi_lock)); 263d9638e54Smws 264d9638e54Smws for (xcp = xch->xch_hash[h]; xcp != NULL; xcp = xcp->xc_next) { 265d9638e54Smws if (strcmp(class, xcp->xc_class) == 0) 266d9638e54Smws return (++xcp->xc_refs); 267d9638e54Smws } 268d9638e54Smws 269d9638e54Smws xcp = fmd_alloc(sizeof (fmd_xprt_class_t), FMD_SLEEP); 270d9638e54Smws xcp->xc_class = fmd_strdup(class, FMD_SLEEP); 271d9638e54Smws xcp->xc_next = xch->xch_hash[h]; 272d9638e54Smws xcp->xc_refs = 1; 273d9638e54Smws xch->xch_hash[h] = xcp; 274d9638e54Smws 275d9638e54Smws if (xch->xch_queue != NULL) 276d9638e54Smws fmd_dispq_insert(fmd.d_disp, xch->xch_queue, class); 277d9638e54Smws 278d9638e54Smws return (xcp->xc_refs); 279d9638e54Smws } 280d9638e54Smws 281d9638e54Smws /* 282d9638e54Smws * Delete the specified class from the specified class hash, and return the 283d9638e54Smws * reference count. A return value of zero indicates the class was deleted. 284d9638e54Smws * If an eventq is associated with the hash, delete the dispq subscription. 285d9638e54Smws */ 286d9638e54Smws static uint_t 287d9638e54Smws fmd_xprt_class_hash_delete(fmd_xprt_impl_t *xip, 288d9638e54Smws fmd_xprt_class_hash_t *xch, const char *class) 289d9638e54Smws { 290d9638e54Smws uint_t h = fmd_strhash(class) % xch->xch_hashlen; 291d9638e54Smws fmd_xprt_class_t *xcp, **pp; 292d9638e54Smws 293d9638e54Smws ASSERT(MUTEX_HELD(&xip->xi_lock)); 294d9638e54Smws pp = &xch->xch_hash[h]; 295d9638e54Smws 296d9638e54Smws for (xcp = *pp; xcp != NULL; xcp = xcp->xc_next) { 297d9638e54Smws if (strcmp(class, xcp->xc_class) == 0) 298d9638e54Smws break; 299d9638e54Smws else 300d9638e54Smws pp = &xcp->xc_next; 301d9638e54Smws } 302d9638e54Smws 303d9638e54Smws if (xcp == NULL) 304d9638e54Smws return (-1U); /* explicitly permit an invalid delete */ 305d9638e54Smws 306d9638e54Smws if (--xcp->xc_refs != 0) 307d9638e54Smws return (xcp->xc_refs); 308d9638e54Smws 309d9638e54Smws ASSERT(xcp->xc_refs == 0); 310d9638e54Smws *pp = xcp->xc_next; 311d9638e54Smws 312d9638e54Smws fmd_strfree(xcp->xc_class); 313d9638e54Smws fmd_free(xcp, sizeof (fmd_xprt_class_t)); 314d9638e54Smws 315d9638e54Smws if (xch->xch_queue != NULL) 316d9638e54Smws fmd_dispq_delete(fmd.d_disp, xch->xch_queue, class); 317d9638e54Smws 318d9638e54Smws return (0); 319d9638e54Smws } 320d9638e54Smws 321d9638e54Smws /* 322d9638e54Smws * Queue subscribe events for the specified transport corresponding to all of 323d9638e54Smws * the active module subscriptions. This is an extremely heavyweight operation 324d9638e54Smws * that we expect to take place rarely (i.e. when loading a transport module 325d9638e54Smws * or when it establishes a connection). We lock all of the known modules to 326d9638e54Smws * prevent them from adding or deleting subscriptions, then snapshot their 327d9638e54Smws * subscriptions, and then unlock all of the modules. We hold the modhash 328d9638e54Smws * lock for the duration of this operation to prevent new modules from loading. 329d9638e54Smws */ 330d9638e54Smws static void 331d9638e54Smws fmd_xprt_subscribe_modhash(fmd_xprt_impl_t *xip, fmd_modhash_t *mhp) 332d9638e54Smws { 333d9638e54Smws fmd_xprt_t *xp = (fmd_xprt_t *)xip; 334d9638e54Smws const fmd_conf_path_t *pap; 335d9638e54Smws fmd_module_t *mp; 336d9638e54Smws uint_t i, j; 337d9638e54Smws 338d9638e54Smws (void) pthread_rwlock_rdlock(&mhp->mh_lock); 339d9638e54Smws 340d9638e54Smws for (i = 0; i < mhp->mh_hashlen; i++) { 341d9638e54Smws for (mp = mhp->mh_hash[i]; mp != NULL; mp = mp->mod_next) 342d9638e54Smws fmd_module_lock(mp); 343d9638e54Smws } 344d9638e54Smws 345d9638e54Smws (void) pthread_mutex_lock(&xip->xi_lock); 346d9638e54Smws ASSERT(!(xip->xi_flags & FMD_XPRT_SUBSCRIBER)); 347d9638e54Smws xip->xi_flags |= FMD_XPRT_SUBSCRIBER; 348d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_lock); 349d9638e54Smws 350d9638e54Smws for (i = 0; i < mhp->mh_hashlen; i++) { 351d9638e54Smws for (mp = mhp->mh_hash[i]; mp != NULL; mp = mp->mod_next) { 352d9638e54Smws (void) fmd_conf_getprop(mp->mod_conf, 353d9638e54Smws FMD_PROP_SUBSCRIPTIONS, &pap); 354d9638e54Smws for (j = 0; j < pap->cpa_argc; j++) 355d9638e54Smws fmd_xprt_subscribe(xp, pap->cpa_argv[j]); 356d9638e54Smws } 357d9638e54Smws } 358d9638e54Smws 359d9638e54Smws for (i = 0; i < mhp->mh_hashlen; i++) { 360d9638e54Smws for (mp = mhp->mh_hash[i]; mp != NULL; mp = mp->mod_next) 361d9638e54Smws fmd_module_unlock(mp); 362d9638e54Smws } 363d9638e54Smws 364d9638e54Smws (void) pthread_rwlock_unlock(&mhp->mh_lock); 365d9638e54Smws } 366d9638e54Smws 367d9638e54Smws static void 368d9638e54Smws fmd_xprt_transition(fmd_xprt_impl_t *xip, 369d9638e54Smws const fmd_xprt_rule_t *state, const char *tag) 370d9638e54Smws { 371b6955755SRobert Johnston fmd_xprt_t *xp = (fmd_xprt_t *)xip; 372d9638e54Smws fmd_event_t *e; 373d9638e54Smws nvlist_t *nvl; 374d9638e54Smws char *s; 375d9638e54Smws 376d9638e54Smws TRACE((FMD_DBG_XPRT, "xprt %u -> %s\n", xip->xi_id, tag)); 377d9638e54Smws 378d9638e54Smws xip->xi_state = state; 379d9638e54Smws s = fmd_strdup(tag, FMD_SLEEP); 380d9638e54Smws 381d9638e54Smws (void) pthread_mutex_lock(&xip->xi_stats_lock); 382d9638e54Smws fmd_strfree(xip->xi_stats->xs_state.fmds_value.str); 383d9638e54Smws xip->xi_stats->xs_state.fmds_value.str = s; 384d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_stats_lock); 385d9638e54Smws 386d9638e54Smws /* 387d9638e54Smws * If we've reached the SUB state, take out the big hammer and snapshot 388d9638e54Smws * all of the subscriptions of all of the loaded modules. Then queue a 389d9638e54Smws * run event for our remote peer indicating that it can enter RUN. 390d9638e54Smws */ 391d9638e54Smws if (state == _fmd_xprt_state_sub) { 392d9638e54Smws fmd_xprt_subscribe_modhash(xip, fmd.d_mod_hash); 393d9638e54Smws 394b6955755SRobert Johnston /* 395b6955755SRobert Johnston * For read-write transports, we always want to set up remote 396b6955755SRobert Johnston * subscriptions to the bultin list.* events, regardless of 397b6955755SRobert Johnston * whether any agents have subscribed to them. 398b6955755SRobert Johnston */ 399b6955755SRobert Johnston if (xip->xi_flags & FMD_XPRT_RDWR) { 400b6955755SRobert Johnston fmd_xprt_subscribe(xp, FM_LIST_SUSPECT_CLASS); 401b6955755SRobert Johnston fmd_xprt_subscribe(xp, FM_LIST_ISOLATED_CLASS); 402b6955755SRobert Johnston fmd_xprt_subscribe(xp, FM_LIST_UPDATED_CLASS); 403b6955755SRobert Johnston fmd_xprt_subscribe(xp, FM_LIST_RESOLVED_CLASS); 404b6955755SRobert Johnston fmd_xprt_subscribe(xp, FM_LIST_REPAIRED_CLASS); 405b6955755SRobert Johnston } 406b6955755SRobert Johnston 407d9638e54Smws nvl = fmd_protocol_xprt_ctl(xip->xi_queue->eq_mod, 408d9638e54Smws "resource.fm.xprt.run", xip->xi_version); 409d9638e54Smws 410d9638e54Smws (void) nvlist_lookup_string(nvl, FM_CLASS, &s); 411d9638e54Smws e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s); 412d9638e54Smws fmd_eventq_insert_at_time(xip->xi_queue, e); 413d9638e54Smws } 414d9638e54Smws } 415d9638e54Smws 416d9638e54Smws static void 417d9638e54Smws fmd_xprt_authupdate(fmd_xprt_impl_t *xip) 418d9638e54Smws { 419d9638e54Smws char *s = fmd_fmri_auth2str(xip->xi_auth); 420d9638e54Smws 421d9638e54Smws (void) pthread_mutex_lock(&xip->xi_stats_lock); 422d9638e54Smws fmd_strfree(xip->xi_stats->xs_authority.fmds_value.str); 423d9638e54Smws xip->xi_stats->xs_authority.fmds_value.str = s; 424d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_stats_lock); 425d9638e54Smws } 426d9638e54Smws 427d9638e54Smws static int 428d9638e54Smws fmd_xprt_vmismatch(fmd_xprt_impl_t *xip, nvlist_t *nvl, uint_t *rversionp) 429d9638e54Smws { 430d9638e54Smws uint8_t rversion; 431d9638e54Smws 432d9638e54Smws if (nvlist_lookup_uint8(nvl, FM_VERSION, &rversion) != 0) { 433d9638e54Smws (void) pthread_mutex_lock(&xip->xi_stats_lock); 434d9638e54Smws xip->xi_stats->xs_discarded.fmds_value.ui64++; 435d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_stats_lock); 436d9638e54Smws 437d9638e54Smws fmd_xprt_transition(xip, _fmd_xprt_state_err, "ERR"); 438d9638e54Smws return (1); 439d9638e54Smws } 440d9638e54Smws 441d9638e54Smws if (rversion > xip->xi_version) { 442d9638e54Smws fmd_dprintf(FMD_DBG_XPRT, "xprt %u protocol mismatch: %u>%u\n", 443d9638e54Smws xip->xi_id, rversion, xip->xi_version); 444d9638e54Smws 445d9638e54Smws (void) pthread_mutex_lock(&xip->xi_stats_lock); 446d9638e54Smws xip->xi_stats->xs_discarded.fmds_value.ui64++; 447d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_stats_lock); 448d9638e54Smws 449d9638e54Smws fmd_xprt_transition(xip, _fmd_xprt_state_err, "ERR"); 450d9638e54Smws return (1); 451d9638e54Smws } 452d9638e54Smws 453d9638e54Smws if (rversionp != NULL) 454d9638e54Smws *rversionp = rversion; 455d9638e54Smws 456d9638e54Smws return (0); 457d9638e54Smws } 458d9638e54Smws 459d9638e54Smws void 460d9638e54Smws fmd_xprt_event_syn(fmd_xprt_impl_t *xip, nvlist_t *nvl) 461d9638e54Smws { 462d9638e54Smws fmd_event_t *e; 463d9638e54Smws uint_t vers; 464d9638e54Smws char *class; 465d9638e54Smws 466d9638e54Smws if (fmd_xprt_vmismatch(xip, nvl, &vers)) 467d9638e54Smws return; /* transitioned to error state */ 468d9638e54Smws 469d9638e54Smws /* 470d9638e54Smws * If the transport module didn't specify an authority, extract the 471d9638e54Smws * one that is passed along with the xprt.syn event and use that. 472d9638e54Smws */ 473d9638e54Smws if (xip->xi_auth == NULL && 474d9638e54Smws nvlist_lookup_nvlist(nvl, FM_RSRC_RESOURCE, &nvl) == 0 && 475d9638e54Smws nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &nvl) == 0) { 476d9638e54Smws (void) nvlist_xdup(nvl, &xip->xi_auth, &fmd.d_nva); 477d9638e54Smws fmd_xprt_authupdate(xip); 478d9638e54Smws } 479d9638e54Smws 480d9638e54Smws nvl = fmd_protocol_xprt_ctl(xip->xi_queue->eq_mod, 481d9638e54Smws "resource.fm.xprt.ack", xip->xi_version); 482d9638e54Smws 483d9638e54Smws (void) nvlist_lookup_string(nvl, FM_CLASS, &class); 484d9638e54Smws e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class); 485d9638e54Smws fmd_eventq_insert_at_time(xip->xi_queue, e); 486d9638e54Smws 487d9638e54Smws xip->xi_version = MIN(FM_RSRC_XPRT_VERSION, vers); 488d9638e54Smws fmd_xprt_transition(xip, _fmd_xprt_state_sub, "SUB"); 489d9638e54Smws } 490d9638e54Smws 491d9638e54Smws void 492d9638e54Smws fmd_xprt_event_ack(fmd_xprt_impl_t *xip, nvlist_t *nvl) 493d9638e54Smws { 494d9638e54Smws uint_t vers; 495d9638e54Smws 496d9638e54Smws if (fmd_xprt_vmismatch(xip, nvl, &vers)) 497d9638e54Smws return; /* transitioned to error state */ 498d9638e54Smws 499d9638e54Smws /* 500d9638e54Smws * If the transport module didn't specify an authority, extract the 501d9638e54Smws * one that is passed along with the xprt.syn event and use that. 502d9638e54Smws */ 503d9638e54Smws if (xip->xi_auth == NULL && 504d9638e54Smws nvlist_lookup_nvlist(nvl, FM_RSRC_RESOURCE, &nvl) == 0 && 505d9638e54Smws nvlist_lookup_nvlist(nvl, FM_FMRI_AUTHORITY, &nvl) == 0) { 506d9638e54Smws (void) nvlist_xdup(nvl, &xip->xi_auth, &fmd.d_nva); 507d9638e54Smws fmd_xprt_authupdate(xip); 508d9638e54Smws } 509d9638e54Smws 510d9638e54Smws xip->xi_version = MIN(FM_RSRC_XPRT_VERSION, vers); 511d9638e54Smws fmd_xprt_transition(xip, _fmd_xprt_state_sub, "SUB"); 512d9638e54Smws } 513d9638e54Smws 514d9638e54Smws /* 515d9638e54Smws * Upon transition to RUN, we take every solved case and resend a list.suspect 516d9638e54Smws * event for it to our remote peer. If a case transitions from solved to a 517d9638e54Smws * future state (CLOSE_WAIT, CLOSED, or REPAIRED) while we are iterating over 518d9638e54Smws * the case hash, we will get it as part of examining the resource cache, next. 519d9638e54Smws */ 520d9638e54Smws static void 521d9638e54Smws fmd_xprt_send_case(fmd_case_t *cp, void *arg) 522d9638e54Smws { 523d9638e54Smws fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 524d9638e54Smws fmd_xprt_impl_t *xip = arg; 525d9638e54Smws 526d9638e54Smws fmd_event_t *e; 527d9638e54Smws nvlist_t *nvl; 528d9638e54Smws char *class; 529d9638e54Smws 530*107c18c1SLauri Tirkkonen if (cip->ci_state != FMD_CASE_SOLVED) 531cbf75e67SStephen Hanson return; 532d9638e54Smws 533d9638e54Smws nvl = fmd_case_mkevent(cp, FM_LIST_SUSPECT_CLASS); 534d9638e54Smws (void) nvlist_lookup_string(nvl, FM_CLASS, &class); 535d9638e54Smws e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class); 536d9638e54Smws 537d9638e54Smws fmd_dprintf(FMD_DBG_XPRT, "re-send %s for %s to transport %u\n", 538d9638e54Smws FM_LIST_SUSPECT_CLASS, cip->ci_uuid, xip->xi_id); 539d9638e54Smws 540d9638e54Smws fmd_dispq_dispatch_gid(fmd.d_disp, e, class, xip->xi_queue->eq_sgid); 541d9638e54Smws } 542d9638e54Smws 543084b846fSStephen Hanson /* 544084b846fSStephen Hanson * Similar to the above function, but for use with readonly transport. Puts 545084b846fSStephen Hanson * the event on the module's queue such that it's fmdo_recv function can pick 546084b846fSStephen Hanson * it up and send it if appropriate. 547084b846fSStephen Hanson */ 548084b846fSStephen Hanson static void 549084b846fSStephen Hanson fmd_xprt_send_case_ro(fmd_case_t *cp, void *arg) 550084b846fSStephen Hanson { 551084b846fSStephen Hanson fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 552084b846fSStephen Hanson fmd_module_t *mp = arg; 553084b846fSStephen Hanson 554084b846fSStephen Hanson fmd_event_t *e; 555084b846fSStephen Hanson nvlist_t *nvl; 556084b846fSStephen Hanson char *class; 557084b846fSStephen Hanson 558*107c18c1SLauri Tirkkonen if (cip->ci_state != FMD_CASE_SOLVED) 559084b846fSStephen Hanson return; 560084b846fSStephen Hanson 561084b846fSStephen Hanson nvl = fmd_case_mkevent(cp, FM_LIST_SUSPECT_CLASS); 562084b846fSStephen Hanson (void) nvlist_lookup_string(nvl, FM_CLASS, &class); 563084b846fSStephen Hanson e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class); 564084b846fSStephen Hanson 565084b846fSStephen Hanson fmd_dprintf(FMD_DBG_XPRT, "re-send %s for %s to rdonly transport %s\n", 566084b846fSStephen Hanson FM_LIST_SUSPECT_CLASS, cip->ci_uuid, mp->mod_name); 567084b846fSStephen Hanson 568084b846fSStephen Hanson fmd_dispq_dispatch_gid(fmd.d_disp, e, class, mp->mod_queue->eq_sgid); 569084b846fSStephen Hanson } 570084b846fSStephen Hanson 571d9638e54Smws void 572d9638e54Smws fmd_xprt_event_run(fmd_xprt_impl_t *xip, nvlist_t *nvl) 573d9638e54Smws { 574d9638e54Smws if (!fmd_xprt_vmismatch(xip, nvl, NULL)) { 575d9638e54Smws fmd_xprt_transition(xip, _fmd_xprt_state_run, "RUN"); 576d9638e54Smws fmd_case_hash_apply(fmd.d_cases, fmd_xprt_send_case, xip); 577d9638e54Smws } 578d9638e54Smws } 579d9638e54Smws 580d9638e54Smws void 581d9638e54Smws fmd_xprt_event_sub(fmd_xprt_impl_t *xip, nvlist_t *nvl) 582d9638e54Smws { 583d9638e54Smws char *class; 584d9638e54Smws 585d9638e54Smws if (fmd_xprt_vmismatch(xip, nvl, NULL)) 586d9638e54Smws return; /* transitioned to error state */ 587d9638e54Smws 588d9638e54Smws if (nvlist_lookup_string(nvl, FM_RSRC_XPRT_SUBCLASS, &class) != 0) 589d9638e54Smws return; /* malformed protocol event */ 590d9638e54Smws 591d9638e54Smws (void) pthread_mutex_lock(&xip->xi_lock); 592d9638e54Smws (void) fmd_xprt_class_hash_insert(xip, &xip->xi_lsub, class); 593d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_lock); 594d9638e54Smws 595d9638e54Smws (void) pthread_mutex_lock(&xip->xi_stats_lock); 596d9638e54Smws xip->xi_stats->xs_subscriptions.fmds_value.ui64++; 597d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_stats_lock); 598d9638e54Smws } 599d9638e54Smws 600d9638e54Smws void 601d9638e54Smws fmd_xprt_event_unsub(fmd_xprt_impl_t *xip, nvlist_t *nvl) 602d9638e54Smws { 603d9638e54Smws fmd_event_t *e; 604d9638e54Smws char *class; 605d9638e54Smws 606d9638e54Smws if (fmd_xprt_vmismatch(xip, nvl, NULL)) 607d9638e54Smws return; /* transitioned to error state */ 608d9638e54Smws 609d9638e54Smws if (nvlist_lookup_string(nvl, FM_RSRC_XPRT_SUBCLASS, &class) != 0) 610d9638e54Smws return; /* malformed protocol event */ 611d9638e54Smws 612d9638e54Smws (void) pthread_mutex_lock(&xip->xi_lock); 613d9638e54Smws (void) fmd_xprt_class_hash_delete(xip, &xip->xi_lsub, class); 614d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_lock); 615d9638e54Smws 616d9638e54Smws (void) pthread_mutex_lock(&xip->xi_stats_lock); 617d9638e54Smws xip->xi_stats->xs_subscriptions.fmds_value.ui64--; 618d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_stats_lock); 619d9638e54Smws 620d9638e54Smws nvl = fmd_protocol_xprt_sub(xip->xi_queue->eq_mod, 621d9638e54Smws "resource.fm.xprt.unsuback", xip->xi_version, class); 622d9638e54Smws 623d9638e54Smws (void) nvlist_lookup_string(nvl, FM_CLASS, &class); 624d9638e54Smws e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class); 625d9638e54Smws fmd_eventq_insert_at_time(xip->xi_queue, e); 626d9638e54Smws } 627d9638e54Smws 628d9638e54Smws void 629d9638e54Smws fmd_xprt_event_unsuback(fmd_xprt_impl_t *xip, nvlist_t *nvl) 630d9638e54Smws { 631d9638e54Smws char *class; 632d9638e54Smws 633d9638e54Smws if (fmd_xprt_vmismatch(xip, nvl, NULL)) 634d9638e54Smws return; /* transitioned to error state */ 635d9638e54Smws 636d9638e54Smws if (nvlist_lookup_string(nvl, FM_RSRC_XPRT_SUBCLASS, &class) != 0) 637d9638e54Smws return; /* malformed protocol event */ 638d9638e54Smws 639d9638e54Smws (void) pthread_mutex_lock(&xip->xi_lock); 640d9638e54Smws (void) fmd_xprt_class_hash_delete(xip, &xip->xi_usub, class); 641d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_lock); 642d9638e54Smws } 643d9638e54Smws 644cbf75e67SStephen Hanson /* 645cbf75e67SStephen Hanson * on diagnosing side, receive a uuclose from the proxy. 646cbf75e67SStephen Hanson */ 647d9638e54Smws void 648d9638e54Smws fmd_xprt_event_uuclose(fmd_xprt_impl_t *xip, nvlist_t *nvl) 649d9638e54Smws { 650d9638e54Smws fmd_case_t *cp; 651d9638e54Smws char *uuid; 652d9638e54Smws 653d9638e54Smws if (fmd_xprt_vmismatch(xip, nvl, NULL)) 654d9638e54Smws return; /* transitioned to error state */ 655d9638e54Smws 656d9638e54Smws if (nvlist_lookup_string(nvl, FM_RSRC_XPRT_UUID, &uuid) == 0 && 657d9638e54Smws (cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) != NULL) { 658cbf75e67SStephen Hanson /* 659cbf75e67SStephen Hanson * update resource cache status and transition case 660cbf75e67SStephen Hanson */ 661cbf75e67SStephen Hanson fmd_case_close_status(cp); 662d9638e54Smws fmd_case_transition(cp, FMD_CASE_CLOSE_WAIT, FMD_CF_ISOLATED); 663d9638e54Smws fmd_case_rele(cp); 664d9638e54Smws } 665d9638e54Smws } 666d9638e54Smws 667cbf75e67SStephen Hanson /* 668cbf75e67SStephen Hanson * on diagnosing side, receive a uuresolved from the proxy. 669cbf75e67SStephen Hanson */ 670cbf75e67SStephen Hanson void 671cbf75e67SStephen Hanson fmd_xprt_event_uuresolved(fmd_xprt_impl_t *xip, nvlist_t *nvl) 672cbf75e67SStephen Hanson { 673cbf75e67SStephen Hanson fmd_case_t *cp; 674cbf75e67SStephen Hanson char *uuid; 675cbf75e67SStephen Hanson 676cbf75e67SStephen Hanson if (fmd_xprt_vmismatch(xip, nvl, NULL)) 677cbf75e67SStephen Hanson return; /* transitioned to error state */ 678cbf75e67SStephen Hanson 679cbf75e67SStephen Hanson if (nvlist_lookup_string(nvl, FM_RSRC_XPRT_UUID, &uuid) == 0 && 680cbf75e67SStephen Hanson (cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) != NULL) { 681cbf75e67SStephen Hanson fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 682cbf75e67SStephen Hanson 683cbf75e67SStephen Hanson fmd_case_transition(cp, (cip->ci_state == FMD_CASE_REPAIRED) ? 684cbf75e67SStephen Hanson FMD_CASE_RESOLVED : (cip->ci_state == FMD_CASE_CLOSED) ? 685cbf75e67SStephen Hanson FMD_CASE_REPAIRED : FMD_CASE_CLOSE_WAIT, FMD_CF_RESOLVED); 686cbf75e67SStephen Hanson fmd_case_rele(cp); 687cbf75e67SStephen Hanson } 688cbf75e67SStephen Hanson } 689cbf75e67SStephen Hanson 690cbf75e67SStephen Hanson /* 691cbf75e67SStephen Hanson * on diagnosing side, receive a repair/acquit from the proxy. 692cbf75e67SStephen Hanson */ 693cbf75e67SStephen Hanson void 694cbf75e67SStephen Hanson fmd_xprt_event_updated(fmd_xprt_impl_t *xip, nvlist_t *nvl) 695cbf75e67SStephen Hanson { 696cbf75e67SStephen Hanson fmd_case_t *cp; 697cbf75e67SStephen Hanson char *uuid; 698cbf75e67SStephen Hanson 699cbf75e67SStephen Hanson if (fmd_xprt_vmismatch(xip, nvl, NULL)) 700cbf75e67SStephen Hanson return; /* transitioned to error state */ 701cbf75e67SStephen Hanson 702cbf75e67SStephen Hanson if (nvlist_lookup_string(nvl, FM_RSRC_XPRT_UUID, &uuid) == 0 && 703cbf75e67SStephen Hanson (cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) != NULL) { 704cbf75e67SStephen Hanson uint8_t *statusp, *proxy_asrup = NULL; 705cbf75e67SStephen Hanson uint_t nelem = 0; 706cbf75e67SStephen Hanson 707cbf75e67SStephen Hanson /* 708cbf75e67SStephen Hanson * Only update status with new repairs if "no remote repair" 709cbf75e67SStephen Hanson * is not set. Do the case_update anyway though (as this will 710cbf75e67SStephen Hanson * refresh the status on the proxy side). 711cbf75e67SStephen Hanson */ 712cbf75e67SStephen Hanson if (!(xip->xi_flags & FMD_XPRT_NO_REMOTE_REPAIR)) { 713cbf75e67SStephen Hanson if (nvlist_lookup_uint8_array(nvl, 714cbf75e67SStephen Hanson FM_RSRC_XPRT_FAULT_STATUS, &statusp, &nelem) == 0 && 715cbf75e67SStephen Hanson nelem != 0) { 716cbf75e67SStephen Hanson (void) nvlist_lookup_uint8_array(nvl, 717cbf75e67SStephen Hanson FM_RSRC_XPRT_FAULT_HAS_ASRU, &proxy_asrup, 718cbf75e67SStephen Hanson &nelem); 719cbf75e67SStephen Hanson fmd_case_update_status(cp, statusp, 720cbf75e67SStephen Hanson proxy_asrup, NULL); 721cbf75e67SStephen Hanson } 722cbf75e67SStephen Hanson fmd_case_update_containees(cp); 723cbf75e67SStephen Hanson } 724cbf75e67SStephen Hanson fmd_case_update(cp); 725cbf75e67SStephen Hanson fmd_case_rele(cp); 726cbf75e67SStephen Hanson } 727cbf75e67SStephen Hanson } 728cbf75e67SStephen Hanson 729d9638e54Smws void 730d9638e54Smws fmd_xprt_event_error(fmd_xprt_impl_t *xip, nvlist_t *nvl) 731d9638e54Smws { 732d9638e54Smws char *class = "<unknown>"; 733d9638e54Smws 734d9638e54Smws (void) pthread_mutex_lock(&xip->xi_stats_lock); 735d9638e54Smws xip->xi_stats->xs_discarded.fmds_value.ui64++; 736d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_stats_lock); 737d9638e54Smws 738d9638e54Smws (void) nvlist_lookup_string(nvl, FM_CLASS, &class); 739d9638e54Smws TRACE((FMD_DBG_XPRT, "xprt %u bad event %s\n", xip->xi_id, class)); 740d9638e54Smws 741d9638e54Smws fmd_xprt_transition(xip, _fmd_xprt_state_err, "ERR"); 742d9638e54Smws } 743d9638e54Smws 744d9638e54Smws void 745d9638e54Smws fmd_xprt_event_drop(fmd_xprt_impl_t *xip, nvlist_t *nvl) 746d9638e54Smws { 747d9638e54Smws char *class = "<unknown>"; 748d9638e54Smws 749d9638e54Smws (void) pthread_mutex_lock(&xip->xi_stats_lock); 750d9638e54Smws xip->xi_stats->xs_discarded.fmds_value.ui64++; 751d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_stats_lock); 752d9638e54Smws 753d9638e54Smws (void) nvlist_lookup_string(nvl, FM_CLASS, &class); 754d9638e54Smws TRACE((FMD_DBG_XPRT, "xprt %u drop event %s\n", xip->xi_id, class)); 755d9638e54Smws 756d9638e54Smws } 757d9638e54Smws 758d9638e54Smws fmd_xprt_t * 759d9638e54Smws fmd_xprt_create(fmd_module_t *mp, uint_t flags, nvlist_t *auth, void *data) 760d9638e54Smws { 761d9638e54Smws fmd_xprt_impl_t *xip = fmd_zalloc(sizeof (fmd_xprt_impl_t), FMD_SLEEP); 762d9638e54Smws fmd_stat_t *statv; 763d9638e54Smws uint_t i, statc; 764d9638e54Smws 765d9638e54Smws char buf[PATH_MAX]; 766d9638e54Smws fmd_event_t *e; 767d9638e54Smws nvlist_t *nvl; 768d9638e54Smws char *s; 769d9638e54Smws 770d9638e54Smws (void) pthread_mutex_init(&xip->xi_lock, NULL); 771d9638e54Smws (void) pthread_cond_init(&xip->xi_cv, NULL); 772d9638e54Smws (void) pthread_mutex_init(&xip->xi_stats_lock, NULL); 773d9638e54Smws 774d9638e54Smws xip->xi_auth = auth; 775d9638e54Smws xip->xi_data = data; 776d9638e54Smws xip->xi_version = FM_RSRC_XPRT_VERSION; 777d9638e54Smws xip->xi_flags = flags; 778d9638e54Smws 779d9638e54Smws /* 780d9638e54Smws * Grab fmd.d_xprt_lock to block fmd_xprt_suspend_all() and then create 781d9638e54Smws * a transport ID and make it visible in fmd.d_xprt_ids. If transports 782d9638e54Smws * were previously suspended, set the FMD_XPRT_DSUSPENDED flag on us to 783d9638e54Smws * ensure that this transport will not run until fmd_xprt_resume_all(). 784d9638e54Smws */ 785d9638e54Smws (void) pthread_mutex_lock(&fmd.d_xprt_lock); 786d9638e54Smws xip->xi_id = fmd_idspace_alloc(fmd.d_xprt_ids, xip); 787d9638e54Smws 788d9638e54Smws if (fmd.d_xprt_suspend != 0) 789d9638e54Smws xip->xi_flags |= FMD_XPRT_DSUSPENDED; 790d9638e54Smws 791d9638e54Smws (void) pthread_mutex_unlock(&fmd.d_xprt_lock); 792d9638e54Smws 793d9638e54Smws /* 794d9638e54Smws * If the module has not yet finished _fmd_init(), set the ISUSPENDED 795d9638e54Smws * bit so that fmdo_send() is not called until _fmd_init() completes. 796d9638e54Smws */ 797d9638e54Smws if (!(mp->mod_flags & FMD_MOD_INIT)) 798d9638e54Smws xip->xi_flags |= FMD_XPRT_ISUSPENDED; 799d9638e54Smws 800d9638e54Smws /* 801d9638e54Smws * Initialize the transport statistics that we keep on behalf of fmd. 802d9638e54Smws * These are set up using a template defined at the top of this file. 803d9638e54Smws * We rename each statistic with a prefix ensuring its uniqueness. 804d9638e54Smws */ 805d9638e54Smws statc = sizeof (_fmd_xprt_stat_tmpl) / sizeof (fmd_stat_t); 806d9638e54Smws statv = fmd_alloc(sizeof (_fmd_xprt_stat_tmpl), FMD_SLEEP); 807d9638e54Smws bcopy(&_fmd_xprt_stat_tmpl, statv, sizeof (_fmd_xprt_stat_tmpl)); 808d9638e54Smws 809d9638e54Smws for (i = 0; i < statc; i++) { 810d9638e54Smws (void) snprintf(statv[i].fmds_name, 811d9638e54Smws sizeof (statv[i].fmds_name), "fmd.xprt.%u.%s", xip->xi_id, 812d9638e54Smws ((fmd_stat_t *)&_fmd_xprt_stat_tmpl + i)->fmds_name); 813d9638e54Smws } 814d9638e54Smws 815d9638e54Smws xip->xi_stats = (fmd_xprt_stat_t *)fmd_ustat_insert( 816d9638e54Smws mp->mod_ustat, FMD_USTAT_NOALLOC, statc, statv, NULL); 817d9638e54Smws 818d9638e54Smws if (xip->xi_stats == NULL) 819d9638e54Smws fmd_panic("failed to create xi_stats (%p)\n", (void *)statv); 820d9638e54Smws 821d9638e54Smws xip->xi_stats->xs_module.fmds_value.str = 822d9638e54Smws fmd_strdup(mp->mod_name, FMD_SLEEP); 823d9638e54Smws 824d9638e54Smws if (xip->xi_auth != NULL) 825d9638e54Smws fmd_xprt_authupdate(xip); 826d9638e54Smws 827d9638e54Smws /* 828d9638e54Smws * Create the outbound eventq for this transport and link to its stats. 829d9638e54Smws * If any suspend bits were set above, suspend the eventq immediately. 830d9638e54Smws */ 831d9638e54Smws xip->xi_queue = fmd_eventq_create(mp, &xip->xi_stats->xs_evqstat, 832d9638e54Smws &xip->xi_stats_lock, mp->mod_stats->ms_xprtqlimit.fmds_value.ui32); 833d9638e54Smws 834d9638e54Smws if (xip->xi_flags & FMD_XPRT_SMASK) 835d9638e54Smws fmd_eventq_suspend(xip->xi_queue); 836d9638e54Smws 837d9638e54Smws /* 838d9638e54Smws * Create our subscription hashes: local subscriptions go to xi_queue, 839d9638e54Smws * remote subscriptions are tracked only for protocol requests, and 840d9638e54Smws * pending unsubscriptions are associated with the /dev/null eventq. 841d9638e54Smws */ 842d9638e54Smws fmd_xprt_class_hash_create(&xip->xi_lsub, xip->xi_queue); 843d9638e54Smws fmd_xprt_class_hash_create(&xip->xi_rsub, NULL); 844d9638e54Smws fmd_xprt_class_hash_create(&xip->xi_usub, fmd.d_rmod->mod_queue); 845d9638e54Smws 846d9638e54Smws /* 847d9638e54Smws * Determine our initial state based upon the creation flags. If we're 848d9638e54Smws * read-only, go directly to RUN. If we're accepting a new connection, 849d9638e54Smws * wait for a SYN. Otherwise send a SYN and wait for an ACK. 850d9638e54Smws */ 851084b846fSStephen Hanson if ((flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY) { 852084b846fSStephen Hanson /* 853084b846fSStephen Hanson * Send the list.suspects across here for readonly transports. 854084b846fSStephen Hanson * For read-write transport they will be sent on transition to 855084b846fSStephen Hanson * RUN state in fmd_xprt_event_run(). 856084b846fSStephen Hanson */ 857084b846fSStephen Hanson fmd_case_hash_apply(fmd.d_cases, fmd_xprt_send_case_ro, mp); 858d9638e54Smws fmd_xprt_transition(xip, _fmd_xprt_state_run, "RUN"); 859084b846fSStephen Hanson } else if (flags & FMD_XPRT_ACCEPT) 860d9638e54Smws fmd_xprt_transition(xip, _fmd_xprt_state_syn, "SYN"); 861d9638e54Smws else 862d9638e54Smws fmd_xprt_transition(xip, _fmd_xprt_state_ack, "ACK"); 863d9638e54Smws 864d9638e54Smws /* 865d9638e54Smws * If client.xprtlog is set to TRUE, create a debugging log for the 866d9638e54Smws * events received by the transport in var/fm/fmd/xprt/. 867d9638e54Smws */ 868d9638e54Smws (void) fmd_conf_getprop(fmd.d_conf, "client.xprtlog", &i); 869d9638e54Smws (void) fmd_conf_getprop(fmd.d_conf, "log.xprt", &s); 870d9638e54Smws 871d9638e54Smws if (i) { 872d9638e54Smws (void) snprintf(buf, sizeof (buf), "%s/%u.log", s, xip->xi_id); 873d9638e54Smws xip->xi_log = fmd_log_open(fmd.d_rootdir, buf, FMD_LOG_XPRT); 874d9638e54Smws } 875d9638e54Smws 876d9638e54Smws ASSERT(fmd_module_locked(mp)); 877d9638e54Smws fmd_list_append(&mp->mod_transports, xip); 878d9638e54Smws 879d9638e54Smws (void) pthread_mutex_lock(&mp->mod_stats_lock); 880d9638e54Smws mp->mod_stats->ms_xprtopen.fmds_value.ui32++; 881d9638e54Smws (void) pthread_mutex_unlock(&mp->mod_stats_lock); 882d9638e54Smws 883d9638e54Smws /* 884d9638e54Smws * If this is a read-only transport, return without creating a send 885d9638e54Smws * queue thread and setting up any connection events in our queue. 886d9638e54Smws */ 887d9638e54Smws if ((flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY) 888d9638e54Smws goto out; 889d9638e54Smws 890d9638e54Smws /* 891d9638e54Smws * Once the transport is fully initialized, create a send queue thread 892d9638e54Smws * and start any connect events flowing to complete our initialization. 893d9638e54Smws */ 894d9638e54Smws if ((xip->xi_thread = fmd_thread_create(mp, 895d9638e54Smws (fmd_thread_f *)fmd_xprt_send, xip)) == NULL) { 896d9638e54Smws 897d9638e54Smws fmd_error(EFMD_XPRT_THR, 898d9638e54Smws "failed to create thread for transport %u", xip->xi_id); 899d9638e54Smws 900d9638e54Smws fmd_xprt_destroy((fmd_xprt_t *)xip); 901d9638e54Smws (void) fmd_set_errno(EFMD_XPRT_THR); 902d9638e54Smws return (NULL); 903d9638e54Smws } 904d9638e54Smws 905d9638e54Smws /* 906d9638e54Smws * If the transport is not being opened to accept an inbound connect, 907d9638e54Smws * start an outbound connection by enqueuing a SYN event for our peer. 908d9638e54Smws */ 909d9638e54Smws if (!(flags & FMD_XPRT_ACCEPT)) { 910d9638e54Smws nvl = fmd_protocol_xprt_ctl(mp, 911d9638e54Smws "resource.fm.xprt.syn", FM_RSRC_XPRT_VERSION); 912d9638e54Smws 913d9638e54Smws (void) nvlist_lookup_string(nvl, FM_CLASS, &s); 914d9638e54Smws e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s); 915d9638e54Smws fmd_eventq_insert_at_time(xip->xi_queue, e); 916d9638e54Smws } 917d9638e54Smws out: 918d9638e54Smws fmd_dprintf(FMD_DBG_XPRT, "opened transport %u\n", xip->xi_id); 919d9638e54Smws return ((fmd_xprt_t *)xip); 920d9638e54Smws } 921d9638e54Smws 922d9638e54Smws void 923d9638e54Smws fmd_xprt_destroy(fmd_xprt_t *xp) 924d9638e54Smws { 925d9638e54Smws fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 926d9638e54Smws fmd_module_t *mp = xip->xi_queue->eq_mod; 927d9638e54Smws uint_t id = xip->xi_id; 928d9638e54Smws 929d9638e54Smws fmd_case_impl_t *cip, *nip; 930d9638e54Smws fmd_stat_t *sp; 931d9638e54Smws uint_t i, n; 932d9638e54Smws 933d9638e54Smws ASSERT(fmd_module_locked(mp)); 934d9638e54Smws fmd_list_delete(&mp->mod_transports, xip); 935d9638e54Smws 936d9638e54Smws (void) pthread_mutex_lock(&mp->mod_stats_lock); 937d9638e54Smws mp->mod_stats->ms_xprtopen.fmds_value.ui32--; 938d9638e54Smws (void) pthread_mutex_unlock(&mp->mod_stats_lock); 939d9638e54Smws 940d9638e54Smws (void) pthread_mutex_lock(&xip->xi_lock); 941d9638e54Smws 942d9638e54Smws while (xip->xi_busy != 0) 943d9638e54Smws (void) pthread_cond_wait(&xip->xi_cv, &xip->xi_lock); 944d9638e54Smws 945d9638e54Smws /* 946d9638e54Smws * Remove the transport from global visibility, cancel its send-side 947d9638e54Smws * thread, join with it, and then remove the transport from module 948d9638e54Smws * visibility. Once all this is done, destroy and free the transport. 949d9638e54Smws */ 950d9638e54Smws (void) fmd_idspace_free(fmd.d_xprt_ids, xip->xi_id); 951d9638e54Smws 952d9638e54Smws if (xip->xi_thread != NULL) { 953d9638e54Smws fmd_eventq_abort(xip->xi_queue); 9548e7248e5SStephen Hanson fmd_module_unlock(mp); 955d9638e54Smws fmd_thread_destroy(xip->xi_thread, FMD_THREAD_JOIN); 9568e7248e5SStephen Hanson fmd_module_lock(mp); 957d9638e54Smws } 958d9638e54Smws 959d9638e54Smws if (xip->xi_log != NULL) 960d9638e54Smws fmd_log_rele(xip->xi_log); 961d9638e54Smws 962d9638e54Smws /* 963d9638e54Smws * Release every case handle in the module that was cached by this 964d9638e54Smws * transport. This will result in these cases disappearing from the 965cbf75e67SStephen Hanson * local case hash so that fmd_case_uuclose() and fmd_case_repaired() 966cbf75e67SStephen Hanson * etc can no longer be used. 967d9638e54Smws */ 968d9638e54Smws for (cip = fmd_list_next(&mp->mod_cases); cip != NULL; cip = nip) { 969d9638e54Smws nip = fmd_list_next(cip); 970d9638e54Smws if (cip->ci_xprt == xp) 971cbf75e67SStephen Hanson fmd_case_discard((fmd_case_t *)cip, B_TRUE); 972d9638e54Smws } 973d9638e54Smws 974d9638e54Smws /* 975d9638e54Smws * Destroy every class in the various subscription hashes and remove 976d9638e54Smws * any corresponding subscriptions from the event dispatch queue. 977d9638e54Smws */ 978d9638e54Smws fmd_xprt_class_hash_destroy(&xip->xi_lsub); 979d9638e54Smws fmd_xprt_class_hash_destroy(&xip->xi_rsub); 980d9638e54Smws fmd_xprt_class_hash_destroy(&xip->xi_usub); 981d9638e54Smws 982d9638e54Smws /* 9838f4d6bb2Sstephh * Uniquify the stat names exactly as was done in fmd_xprt_create() 9848f4d6bb2Sstephh * before calling fmd_ustat_insert(), otherwise fmd_ustat_delete() 9858f4d6bb2Sstephh * won't find the entries in the hash table. 986d9638e54Smws */ 9878f4d6bb2Sstephh n = sizeof (_fmd_xprt_stat_tmpl) / sizeof (fmd_stat_t); 9888f4d6bb2Sstephh sp = fmd_alloc(sizeof (_fmd_xprt_stat_tmpl), FMD_SLEEP); 9898f4d6bb2Sstephh bcopy(&_fmd_xprt_stat_tmpl, sp, sizeof (_fmd_xprt_stat_tmpl)); 9908f4d6bb2Sstephh for (i = 0; i < n; i++) { 9918f4d6bb2Sstephh (void) snprintf(sp[i].fmds_name, 9928f4d6bb2Sstephh sizeof (sp[i].fmds_name), "fmd.xprt.%u.%s", xip->xi_id, 9938f4d6bb2Sstephh ((fmd_stat_t *)&_fmd_xprt_stat_tmpl + i)->fmds_name); 994d9638e54Smws } 9958f4d6bb2Sstephh fmd_ustat_delete(mp->mod_ustat, n, sp); 9968f4d6bb2Sstephh fmd_free(sp, sizeof (_fmd_xprt_stat_tmpl)); 997d9638e54Smws 998d9638e54Smws fmd_free(xip->xi_stats, sizeof (fmd_xprt_stat_t)); 999d9638e54Smws fmd_eventq_destroy(xip->xi_queue); 1000d9638e54Smws nvlist_free(xip->xi_auth); 1001d9638e54Smws fmd_free(xip, sizeof (fmd_xprt_impl_t)); 1002d9638e54Smws 1003d9638e54Smws fmd_dprintf(FMD_DBG_XPRT, "closed transport %u\n", id); 1004d9638e54Smws } 1005d9638e54Smws 1006d9638e54Smws void 1007d9638e54Smws fmd_xprt_xsuspend(fmd_xprt_t *xp, uint_t flags) 1008d9638e54Smws { 1009d9638e54Smws fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1010d9638e54Smws uint_t oflags; 1011d9638e54Smws 1012d9638e54Smws ASSERT((flags & ~FMD_XPRT_SMASK) == 0); 1013d9638e54Smws (void) pthread_mutex_lock(&xip->xi_lock); 1014d9638e54Smws 1015d9638e54Smws oflags = xip->xi_flags; 1016d9638e54Smws xip->xi_flags |= flags; 1017d9638e54Smws 1018d9638e54Smws if (!(oflags & FMD_XPRT_SMASK) && (xip->xi_flags & FMD_XPRT_SMASK) != 0) 1019d9638e54Smws fmd_eventq_suspend(xip->xi_queue); 1020d9638e54Smws 1021d9638e54Smws (void) pthread_cond_broadcast(&xip->xi_cv); 1022d9638e54Smws 1023d9638e54Smws while (xip->xi_busy != 0) 1024d9638e54Smws (void) pthread_cond_wait(&xip->xi_cv, &xip->xi_lock); 1025d9638e54Smws 1026d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_lock); 1027d9638e54Smws } 1028d9638e54Smws 1029d9638e54Smws void 1030d9638e54Smws fmd_xprt_xresume(fmd_xprt_t *xp, uint_t flags) 1031d9638e54Smws { 1032d9638e54Smws fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1033d9638e54Smws uint_t oflags; 1034d9638e54Smws 1035d9638e54Smws ASSERT((flags & ~FMD_XPRT_SMASK) == 0); 1036d9638e54Smws (void) pthread_mutex_lock(&xip->xi_lock); 1037d9638e54Smws 1038d9638e54Smws oflags = xip->xi_flags; 1039d9638e54Smws xip->xi_flags &= ~flags; 1040d9638e54Smws 1041d9638e54Smws if ((oflags & FMD_XPRT_SMASK) != 0 && !(xip->xi_flags & FMD_XPRT_SMASK)) 1042d9638e54Smws fmd_eventq_resume(xip->xi_queue); 1043d9638e54Smws 1044d9638e54Smws (void) pthread_cond_broadcast(&xip->xi_cv); 1045d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_lock); 1046d9638e54Smws } 1047d9638e54Smws 1048d9638e54Smws void 1049d9638e54Smws fmd_xprt_send(fmd_xprt_t *xp) 1050d9638e54Smws { 1051d9638e54Smws fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1052d9638e54Smws fmd_module_t *mp = xip->xi_queue->eq_mod; 1053d9638e54Smws fmd_event_t *ep; 1054d9638e54Smws int err; 1055d9638e54Smws 1056d9638e54Smws while ((ep = fmd_eventq_delete(xip->xi_queue)) != NULL) { 1057d9638e54Smws if (FMD_EVENT_TTL(ep) == 0) { 1058d9638e54Smws fmd_event_rele(ep); 1059d9638e54Smws continue; 1060d9638e54Smws } 1061d9638e54Smws 1062d9638e54Smws fmd_dprintf(FMD_DBG_XPRT, "xprt %u sending %s\n", 1063d9638e54Smws xip->xi_id, (char *)FMD_EVENT_DATA(ep)); 1064d9638e54Smws 1065d9638e54Smws err = mp->mod_ops->mop_transport(mp, xp, ep); 1066d9638e54Smws fmd_eventq_done(xip->xi_queue); 1067d9638e54Smws 1068d9638e54Smws if (err == FMD_SEND_RETRY) { 1069d9638e54Smws fmd_eventq_insert_at_time(xip->xi_queue, ep); 1070d9638e54Smws (void) pthread_mutex_lock(&xip->xi_stats_lock); 1071d9638e54Smws xip->xi_stats->xs_retried.fmds_value.ui64++; 1072d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_stats_lock); 1073d9638e54Smws } 1074d9638e54Smws 1075d9638e54Smws if (err != FMD_SEND_SUCCESS && err != FMD_SEND_RETRY) { 1076d9638e54Smws (void) pthread_mutex_lock(&xip->xi_stats_lock); 1077d9638e54Smws xip->xi_stats->xs_lost.fmds_value.ui64++; 1078d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_stats_lock); 1079d9638e54Smws } 1080d9638e54Smws 1081d9638e54Smws fmd_event_rele(ep); 1082d9638e54Smws } 1083d9638e54Smws } 1084d9638e54Smws 1085cbf75e67SStephen Hanson /* 1086cbf75e67SStephen Hanson * This function creates a local suspect list. This is used when a suspect list 1087cbf75e67SStephen Hanson * is created directly by an external source like fminject. 1088cbf75e67SStephen Hanson */ 1089cbf75e67SStephen Hanson static void 1090cbf75e67SStephen Hanson fmd_xprt_list_suspect_local(fmd_xprt_t *xp, nvlist_t *nvl) 1091cbf75e67SStephen Hanson { 1092cbf75e67SStephen Hanson nvlist_t **nvlp; 1093cbf75e67SStephen Hanson nvlist_t *de_fmri, *de_fmri_dup = NULL; 1094cbf75e67SStephen Hanson int64_t *diag_time; 1095cbf75e67SStephen Hanson char *code = NULL; 1096cbf75e67SStephen Hanson fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1097cbf75e67SStephen Hanson fmd_case_t *cp; 1098cbf75e67SStephen Hanson uint_t nelem = 0, nelem2 = 0, i; 1099540db9a9SStephen Hanson boolean_t injected; 1100cbf75e67SStephen Hanson 1101cbf75e67SStephen Hanson fmd_module_lock(xip->xi_queue->eq_mod); 1102f6e214c7SGavin Maltby cp = fmd_case_create(xip->xi_queue->eq_mod, NULL, NULL); 1103cbf75e67SStephen Hanson if (cp == NULL) { 1104cbf75e67SStephen Hanson fmd_module_unlock(xip->xi_queue->eq_mod); 1105cbf75e67SStephen Hanson return; 1106cbf75e67SStephen Hanson } 1107cbf75e67SStephen Hanson 1108cbf75e67SStephen Hanson /* 1109cbf75e67SStephen Hanson * copy diag_code if present 1110cbf75e67SStephen Hanson */ 1111cbf75e67SStephen Hanson (void) nvlist_lookup_string(nvl, FM_SUSPECT_DIAG_CODE, &code); 1112cbf75e67SStephen Hanson if (code != NULL) { 1113cbf75e67SStephen Hanson fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 1114cbf75e67SStephen Hanson 1115cbf75e67SStephen Hanson cip->ci_precanned = 1; 1116cbf75e67SStephen Hanson fmd_case_setcode(cp, code); 1117cbf75e67SStephen Hanson } 1118cbf75e67SStephen Hanson 1119cbf75e67SStephen Hanson /* 1120cbf75e67SStephen Hanson * copy suspects 1121cbf75e67SStephen Hanson */ 1122cbf75e67SStephen Hanson (void) nvlist_lookup_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST, &nvlp, 1123cbf75e67SStephen Hanson &nelem); 1124cbf75e67SStephen Hanson for (i = 0; i < nelem; i++) { 1125cbf75e67SStephen Hanson nvlist_t *flt_copy, *asru = NULL, *fru = NULL, *rsrc = NULL; 1126cbf75e67SStephen Hanson topo_hdl_t *thp; 1127cbf75e67SStephen Hanson char *loc = NULL; 1128cbf75e67SStephen Hanson int err; 1129cbf75e67SStephen Hanson 1130cbf75e67SStephen Hanson thp = fmd_fmri_topo_hold(TOPO_VERSION); 1131cbf75e67SStephen Hanson (void) nvlist_xdup(nvlp[i], &flt_copy, &fmd.d_nva); 1132cbf75e67SStephen Hanson (void) nvlist_lookup_nvlist(nvlp[i], FM_FAULT_RESOURCE, &rsrc); 1133cbf75e67SStephen Hanson 1134cbf75e67SStephen Hanson /* 1135cbf75e67SStephen Hanson * If no fru specified, get it from topo 1136cbf75e67SStephen Hanson */ 1137cbf75e67SStephen Hanson if (nvlist_lookup_nvlist(nvlp[i], FM_FAULT_FRU, &fru) != 0 && 1138cbf75e67SStephen Hanson rsrc && topo_fmri_fru(thp, rsrc, &fru, &err) == 0) 1139cbf75e67SStephen Hanson (void) nvlist_add_nvlist(flt_copy, FM_FAULT_FRU, fru); 1140cbf75e67SStephen Hanson /* 1141cbf75e67SStephen Hanson * If no asru specified, get it from topo 1142cbf75e67SStephen Hanson */ 1143cbf75e67SStephen Hanson if (nvlist_lookup_nvlist(nvlp[i], FM_FAULT_ASRU, &asru) != 0 && 1144cbf75e67SStephen Hanson rsrc && topo_fmri_asru(thp, rsrc, &asru, &err) == 0) 1145cbf75e67SStephen Hanson (void) nvlist_add_nvlist(flt_copy, FM_FAULT_ASRU, asru); 1146cbf75e67SStephen Hanson /* 1147cbf75e67SStephen Hanson * If no location specified, get it from topo 1148cbf75e67SStephen Hanson */ 1149cbf75e67SStephen Hanson if (nvlist_lookup_string(nvlp[i], FM_FAULT_LOCATION, 1150cbf75e67SStephen Hanson &loc) != 0) { 1151cbf75e67SStephen Hanson if (fru && topo_fmri_label(thp, fru, &loc, &err) == 0) 1152cbf75e67SStephen Hanson (void) nvlist_add_string(flt_copy, 1153cbf75e67SStephen Hanson FM_FAULT_LOCATION, loc); 1154cbf75e67SStephen Hanson else if (rsrc && topo_fmri_label(thp, rsrc, &loc, 1155cbf75e67SStephen Hanson &err) == 0) 1156cbf75e67SStephen Hanson (void) nvlist_add_string(flt_copy, 1157cbf75e67SStephen Hanson FM_FAULT_LOCATION, loc); 1158cbf75e67SStephen Hanson if (loc) 1159cbf75e67SStephen Hanson topo_hdl_strfree(thp, loc); 1160cbf75e67SStephen Hanson } 1161cbf75e67SStephen Hanson nvlist_free(fru); 1162cbf75e67SStephen Hanson nvlist_free(asru); 1163cbf75e67SStephen Hanson nvlist_free(rsrc); 1164cbf75e67SStephen Hanson fmd_fmri_topo_rele(thp); 1165cbf75e67SStephen Hanson fmd_case_insert_suspect(cp, flt_copy); 1166cbf75e67SStephen Hanson } 1167cbf75e67SStephen Hanson 1168cbf75e67SStephen Hanson /* 1169cbf75e67SStephen Hanson * copy diag_time if present 1170cbf75e67SStephen Hanson */ 1171cbf75e67SStephen Hanson if (nvlist_lookup_int64_array(nvl, FM_SUSPECT_DIAG_TIME, &diag_time, 1172cbf75e67SStephen Hanson &nelem2) == 0 && nelem2 >= 2) 1173cbf75e67SStephen Hanson fmd_case_settime(cp, diag_time[0], diag_time[1]); 1174cbf75e67SStephen Hanson 1175cbf75e67SStephen Hanson /* 1176cbf75e67SStephen Hanson * copy DE fmri if present 1177cbf75e67SStephen Hanson */ 1178cbf75e67SStephen Hanson if (nvlist_lookup_nvlist(nvl, FM_SUSPECT_DE, &de_fmri) == 0) { 1179cbf75e67SStephen Hanson (void) nvlist_xdup(de_fmri, &de_fmri_dup, &fmd.d_nva); 1180cbf75e67SStephen Hanson fmd_case_set_de_fmri(cp, de_fmri_dup); 1181cbf75e67SStephen Hanson } 1182cbf75e67SStephen Hanson 1183540db9a9SStephen Hanson /* 1184540db9a9SStephen Hanson * copy injected if present 1185540db9a9SStephen Hanson */ 1186540db9a9SStephen Hanson if (nvlist_lookup_boolean_value(nvl, FM_SUSPECT_INJECTED, 1187540db9a9SStephen Hanson &injected) == 0 && injected) 1188540db9a9SStephen Hanson fmd_case_set_injected(cp); 1189540db9a9SStephen Hanson 1190cbf75e67SStephen Hanson fmd_case_transition(cp, FMD_CASE_SOLVED, FMD_CF_SOLVED); 1191cbf75e67SStephen Hanson fmd_module_unlock(xip->xi_queue->eq_mod); 1192cbf75e67SStephen Hanson } 1193cbf75e67SStephen Hanson 1194cbf75e67SStephen Hanson /* 1195cbf75e67SStephen Hanson * This function is called to create a proxy case on receipt of a list.suspect 1196cbf75e67SStephen Hanson * from the diagnosing side of the transport. 1197cbf75e67SStephen Hanson */ 1198cbf75e67SStephen Hanson static void 1199cbf75e67SStephen Hanson fmd_xprt_list_suspect(fmd_xprt_t *xp, nvlist_t *nvl) 1200cbf75e67SStephen Hanson { 1201cbf75e67SStephen Hanson fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1202cbf75e67SStephen Hanson nvlist_t **nvlp; 1203cbf75e67SStephen Hanson uint_t nelem = 0, nelem2 = 0, i; 1204cbf75e67SStephen Hanson int64_t *diag_time; 1205cbf75e67SStephen Hanson topo_hdl_t *thp; 1206cbf75e67SStephen Hanson char *class; 1207cbf75e67SStephen Hanson nvlist_t *rsrc, *asru, *de_fmri, *de_fmri_dup = NULL; 1208cbf75e67SStephen Hanson nvlist_t *flt_copy; 1209cbf75e67SStephen Hanson int err; 1210cbf75e67SStephen Hanson nvlist_t **asrua; 1211cbf75e67SStephen Hanson uint8_t *proxy_asru = NULL; 1212cbf75e67SStephen Hanson int got_proxy_asru = 0; 1213cbf75e67SStephen Hanson int got_hc_rsrc = 0; 1214ac83d604SStephen Hanson int got_hc_asru = 0; 1215cbf75e67SStephen Hanson int got_present_rsrc = 0; 1216cbf75e67SStephen Hanson uint8_t *diag_asru = NULL; 1217cbf75e67SStephen Hanson char *scheme; 1218cbf75e67SStephen Hanson uint8_t *statusp; 1219cbf75e67SStephen Hanson char *uuid, *code; 1220cbf75e67SStephen Hanson fmd_case_t *cp; 1221cbf75e67SStephen Hanson fmd_case_impl_t *cip; 1222cbf75e67SStephen Hanson int need_update = 0; 1223540db9a9SStephen Hanson boolean_t injected; 1224cbf75e67SStephen Hanson 1225cbf75e67SStephen Hanson if (nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid) != 0) 1226cbf75e67SStephen Hanson return; 1227cbf75e67SStephen Hanson if (nvlist_lookup_string(nvl, FM_SUSPECT_DIAG_CODE, &code) != 0) 1228cbf75e67SStephen Hanson return; 1229cbf75e67SStephen Hanson (void) nvlist_lookup_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST, &nvlp, 1230cbf75e67SStephen Hanson &nelem); 1231cbf75e67SStephen Hanson 1232cbf75e67SStephen Hanson /* 1233cbf75e67SStephen Hanson * In order to implement FMD_XPRT_HCONLY and FMD_XPRT_HC_PRESENT_ONLY 1234cbf75e67SStephen Hanson * etc we first scan the suspects to see if 1235cbf75e67SStephen Hanson * - there was an asru in the received fault 1236cbf75e67SStephen Hanson * - there was an hc-scheme resource in the received fault 1237cbf75e67SStephen Hanson * - any hc-scheme resource in the received fault is present in the 1238cbf75e67SStephen Hanson * local topology 1239cbf75e67SStephen Hanson * - any hc-scheme resource in the received fault has an asru in the 1240cbf75e67SStephen Hanson * local topology 1241cbf75e67SStephen Hanson */ 1242cbf75e67SStephen Hanson if (nelem > 0) { 1243cbf75e67SStephen Hanson asrua = fmd_zalloc(sizeof (nvlist_t *) * nelem, FMD_SLEEP); 1244cbf75e67SStephen Hanson proxy_asru = fmd_zalloc(sizeof (uint8_t) * nelem, FMD_SLEEP); 1245cbf75e67SStephen Hanson diag_asru = fmd_zalloc(sizeof (uint8_t) * nelem, FMD_SLEEP); 1246cbf75e67SStephen Hanson thp = fmd_fmri_topo_hold(TOPO_VERSION); 1247cbf75e67SStephen Hanson for (i = 0; i < nelem; i++) { 1248cbf75e67SStephen Hanson if (nvlist_lookup_nvlist(nvlp[i], FM_FAULT_ASRU, 1249cbf75e67SStephen Hanson &asru) == 0 && asru != NULL) 1250cbf75e67SStephen Hanson diag_asru[i] = 1; 1251cbf75e67SStephen Hanson if (nvlist_lookup_string(nvlp[i], FM_CLASS, 1252cbf75e67SStephen Hanson &class) != 0 || strncmp(class, "fault", 5) != 0) 1253cbf75e67SStephen Hanson continue; 1254cbf75e67SStephen Hanson /* 1255cbf75e67SStephen Hanson * If there is an hc-scheme asru, use that to find the 1256cbf75e67SStephen Hanson * real asru. Otherwise if there is an hc-scheme 1257cbf75e67SStephen Hanson * resource, work out the old asru from that. 1258cbf75e67SStephen Hanson * This order is to allow a two stage evaluation 1259cbf75e67SStephen Hanson * of the asru where a fault in the diagnosing side 1260cbf75e67SStephen Hanson * is in a component not visible to the proxy side, 1261cbf75e67SStephen Hanson * but prevents a component that is visible from 1262cbf75e67SStephen Hanson * working. So the diagnosing side sets the asru to 1263cbf75e67SStephen Hanson * the latter component (in hc-scheme as the diagnosing 1264cbf75e67SStephen Hanson * side doesn't know about the proxy side's virtual 1265cbf75e67SStephen Hanson * schemes), and then the proxy side can convert that 1266cbf75e67SStephen Hanson * to a suitable virtual scheme asru. 1267cbf75e67SStephen Hanson */ 1268cbf75e67SStephen Hanson if (nvlist_lookup_nvlist(nvlp[i], FM_FAULT_ASRU, 1269cbf75e67SStephen Hanson &asru) == 0 && asru != NULL && 1270cbf75e67SStephen Hanson nvlist_lookup_string(asru, FM_FMRI_SCHEME, 1271cbf75e67SStephen Hanson &scheme) == 0 && 1272cbf75e67SStephen Hanson strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) { 1273ac83d604SStephen Hanson got_hc_asru = 1; 1274cbf75e67SStephen Hanson if (xip->xi_flags & FMD_XPRT_EXTERNAL) 1275cbf75e67SStephen Hanson continue; 12766e1fa242SStephen Hanson if (topo_fmri_present(thp, asru, &err) != 0) 1277cbf75e67SStephen Hanson got_present_rsrc = 1; 1278cbf75e67SStephen Hanson if (topo_fmri_asru(thp, asru, &asrua[i], 1279cbf75e67SStephen Hanson &err) == 0) { 1280cbf75e67SStephen Hanson proxy_asru[i] = 1281cbf75e67SStephen Hanson FMD_PROXY_ASRU_FROM_ASRU; 1282cbf75e67SStephen Hanson got_proxy_asru = 1; 1283cbf75e67SStephen Hanson } 1284cbf75e67SStephen Hanson } else if (nvlist_lookup_nvlist(nvlp[i], 1285cbf75e67SStephen Hanson FM_FAULT_RESOURCE, &rsrc) == 0 && rsrc != NULL && 1286cbf75e67SStephen Hanson nvlist_lookup_string(rsrc, FM_FMRI_SCHEME, 1287cbf75e67SStephen Hanson &scheme) == 0 && 1288cbf75e67SStephen Hanson strcmp(scheme, FM_FMRI_SCHEME_HC) == 0) { 1289cbf75e67SStephen Hanson got_hc_rsrc = 1; 1290cbf75e67SStephen Hanson if (xip->xi_flags & FMD_XPRT_EXTERNAL) 1291cbf75e67SStephen Hanson continue; 12926e1fa242SStephen Hanson if (topo_fmri_present(thp, rsrc, &err) != 0) 1293cbf75e67SStephen Hanson got_present_rsrc = 1; 1294cbf75e67SStephen Hanson if (topo_fmri_asru(thp, rsrc, &asrua[i], 1295cbf75e67SStephen Hanson &err) == 0) { 1296cbf75e67SStephen Hanson proxy_asru[i] = 1297cbf75e67SStephen Hanson FMD_PROXY_ASRU_FROM_RSRC; 1298cbf75e67SStephen Hanson got_proxy_asru = 1; 1299cbf75e67SStephen Hanson } 1300cbf75e67SStephen Hanson } 1301cbf75e67SStephen Hanson } 1302cbf75e67SStephen Hanson fmd_fmri_topo_rele(thp); 1303cbf75e67SStephen Hanson } 1304cbf75e67SStephen Hanson 1305cbf75e67SStephen Hanson /* 1306cbf75e67SStephen Hanson * If we're set up only to report hc-scheme faults, and 1307cbf75e67SStephen Hanson * there aren't any, then just drop the event. 1308cbf75e67SStephen Hanson */ 1309ac83d604SStephen Hanson if (got_hc_rsrc == 0 && got_hc_asru == 0 && 1310ac83d604SStephen Hanson (xip->xi_flags & FMD_XPRT_HCONLY)) { 1311cbf75e67SStephen Hanson if (nelem > 0) { 1312cbf75e67SStephen Hanson fmd_free(proxy_asru, sizeof (uint8_t) * nelem); 1313cbf75e67SStephen Hanson fmd_free(diag_asru, sizeof (uint8_t) * nelem); 1314cbf75e67SStephen Hanson fmd_free(asrua, sizeof (nvlist_t *) * nelem); 1315cbf75e67SStephen Hanson } 1316cbf75e67SStephen Hanson return; 1317cbf75e67SStephen Hanson } 1318cbf75e67SStephen Hanson 1319cbf75e67SStephen Hanson /* 1320cbf75e67SStephen Hanson * If we're set up only to report locally present hc-scheme 1321cbf75e67SStephen Hanson * faults, and there aren't any, then just drop the event. 1322cbf75e67SStephen Hanson */ 1323cbf75e67SStephen Hanson if (got_present_rsrc == 0 && 1324cbf75e67SStephen Hanson (xip->xi_flags & FMD_XPRT_HC_PRESENT_ONLY)) { 1325cbf75e67SStephen Hanson if (nelem > 0) { 1326cbf75e67SStephen Hanson for (i = 0; i < nelem; i++) 1327cbf75e67SStephen Hanson nvlist_free(asrua[i]); 1328cbf75e67SStephen Hanson fmd_free(proxy_asru, sizeof (uint8_t) * nelem); 1329cbf75e67SStephen Hanson fmd_free(diag_asru, sizeof (uint8_t) * nelem); 1330cbf75e67SStephen Hanson fmd_free(asrua, sizeof (nvlist_t *) * nelem); 1331cbf75e67SStephen Hanson } 1332cbf75e67SStephen Hanson return; 1333cbf75e67SStephen Hanson } 1334cbf75e67SStephen Hanson 1335cbf75e67SStephen Hanson /* 1336cbf75e67SStephen Hanson * If fmd_case_recreate() returns NULL, UUID is already known. 1337cbf75e67SStephen Hanson */ 1338cbf75e67SStephen Hanson fmd_module_lock(xip->xi_queue->eq_mod); 1339cbf75e67SStephen Hanson if ((cp = fmd_case_recreate(xip->xi_queue->eq_mod, xp, 1340cbf75e67SStephen Hanson FMD_CASE_UNSOLVED, uuid, code)) == NULL) { 1341cbf75e67SStephen Hanson if (nelem > 0) { 1342cbf75e67SStephen Hanson for (i = 0; i < nelem; i++) 1343cbf75e67SStephen Hanson nvlist_free(asrua[i]); 1344cbf75e67SStephen Hanson fmd_free(proxy_asru, sizeof (uint8_t) * nelem); 1345cbf75e67SStephen Hanson fmd_free(diag_asru, sizeof (uint8_t) * nelem); 1346cbf75e67SStephen Hanson fmd_free(asrua, sizeof (nvlist_t *) * nelem); 1347cbf75e67SStephen Hanson } 1348cbf75e67SStephen Hanson fmd_module_unlock(xip->xi_queue->eq_mod); 1349cbf75e67SStephen Hanson return; 1350cbf75e67SStephen Hanson } 1351cbf75e67SStephen Hanson 1352cbf75e67SStephen Hanson cip = (fmd_case_impl_t *)cp; 1353cbf75e67SStephen Hanson cip->ci_diag_asru = diag_asru; 1354cbf75e67SStephen Hanson cip->ci_proxy_asru = proxy_asru; 1355cbf75e67SStephen Hanson for (i = 0; i < nelem; i++) { 1356cbf75e67SStephen Hanson (void) nvlist_xdup(nvlp[i], &flt_copy, &fmd.d_nva); 1357cbf75e67SStephen Hanson if (proxy_asru[i] != FMD_PROXY_ASRU_NOT_NEEDED) { 1358cbf75e67SStephen Hanson /* 1359cbf75e67SStephen Hanson * Copy suspects, but remove/replace asru first. Also if 1360cbf75e67SStephen Hanson * the original asru was hc-scheme use that as resource. 1361cbf75e67SStephen Hanson */ 1362cbf75e67SStephen Hanson if (proxy_asru[i] == FMD_PROXY_ASRU_FROM_ASRU) { 1363cbf75e67SStephen Hanson (void) nvlist_remove(flt_copy, 1364cbf75e67SStephen Hanson FM_FAULT_RESOURCE, DATA_TYPE_NVLIST); 1365cbf75e67SStephen Hanson (void) nvlist_lookup_nvlist(flt_copy, 1366cbf75e67SStephen Hanson FM_FAULT_ASRU, &asru); 1367cbf75e67SStephen Hanson (void) nvlist_add_nvlist(flt_copy, 1368cbf75e67SStephen Hanson FM_FAULT_RESOURCE, asru); 1369cbf75e67SStephen Hanson } 1370cbf75e67SStephen Hanson (void) nvlist_remove(flt_copy, FM_FAULT_ASRU, 1371cbf75e67SStephen Hanson DATA_TYPE_NVLIST); 1372cbf75e67SStephen Hanson (void) nvlist_add_nvlist(flt_copy, FM_FAULT_ASRU, 1373cbf75e67SStephen Hanson asrua[i]); 1374cbf75e67SStephen Hanson nvlist_free(asrua[i]); 1375ac83d604SStephen Hanson } else if (got_hc_asru == 0 && 1376ac83d604SStephen Hanson nvlist_lookup_nvlist(flt_copy, FM_FAULT_ASRU, 1377cbf75e67SStephen Hanson &asru) == 0 && asru != NULL) { 1378cbf75e67SStephen Hanson /* 1379ac83d604SStephen Hanson * If we have an asru from diag side, but it's not 1380ac83d604SStephen Hanson * in hc scheme, then we can't be sure what it 1381ac83d604SStephen Hanson * represents, so mark as no retire. 1382cbf75e67SStephen Hanson */ 1383cbf75e67SStephen Hanson (void) nvlist_add_boolean_value(flt_copy, 1384cbf75e67SStephen Hanson FM_SUSPECT_RETIRE, B_FALSE); 1385cbf75e67SStephen Hanson } 1386cbf75e67SStephen Hanson fmd_case_insert_suspect(cp, flt_copy); 1387cbf75e67SStephen Hanson } 1388cbf75e67SStephen Hanson /* 1389cbf75e67SStephen Hanson * copy diag_time 1390cbf75e67SStephen Hanson */ 1391cbf75e67SStephen Hanson if (nvlist_lookup_int64_array(nvl, FM_SUSPECT_DIAG_TIME, &diag_time, 1392cbf75e67SStephen Hanson &nelem2) == 0 && nelem2 >= 2) 1393cbf75e67SStephen Hanson fmd_case_settime(cp, diag_time[0], diag_time[1]); 1394cbf75e67SStephen Hanson /* 1395cbf75e67SStephen Hanson * copy DE fmri 1396cbf75e67SStephen Hanson */ 1397cbf75e67SStephen Hanson if (nvlist_lookup_nvlist(nvl, FM_SUSPECT_DE, &de_fmri) == 0) { 1398cbf75e67SStephen Hanson (void) nvlist_xdup(de_fmri, &de_fmri_dup, &fmd.d_nva); 1399cbf75e67SStephen Hanson fmd_case_set_de_fmri(cp, de_fmri_dup); 1400cbf75e67SStephen Hanson } 1401cbf75e67SStephen Hanson 1402cbf75e67SStephen Hanson /* 1403540db9a9SStephen Hanson * copy injected if present 1404540db9a9SStephen Hanson */ 1405540db9a9SStephen Hanson if (nvlist_lookup_boolean_value(nvl, FM_SUSPECT_INJECTED, 1406540db9a9SStephen Hanson &injected) == 0 && injected) 1407540db9a9SStephen Hanson fmd_case_set_injected(cp); 1408540db9a9SStephen Hanson 1409540db9a9SStephen Hanson /* 1410cbf75e67SStephen Hanson * Transition to solved. This will log the suspect list and create 1411cbf75e67SStephen Hanson * the resource cache entries. 1412cbf75e67SStephen Hanson */ 1413cbf75e67SStephen Hanson fmd_case_transition(cp, FMD_CASE_SOLVED, FMD_CF_SOLVED); 1414cbf75e67SStephen Hanson 1415cbf75e67SStephen Hanson /* 1416cbf75e67SStephen Hanson * Update status if it is not simply "all faulty" (can happen if 1417cbf75e67SStephen Hanson * list.suspects are being re-sent when the transport has reconnected). 1418cbf75e67SStephen Hanson */ 1419cbf75e67SStephen Hanson (void) nvlist_lookup_uint8_array(nvl, FM_SUSPECT_FAULT_STATUS, &statusp, 1420cbf75e67SStephen Hanson &nelem); 1421cbf75e67SStephen Hanson for (i = 0; i < nelem; i++) { 1422cbf75e67SStephen Hanson if ((statusp[i] & (FM_SUSPECT_FAULTY | FM_SUSPECT_UNUSABLE | 1423cbf75e67SStephen Hanson FM_SUSPECT_NOT_PRESENT | FM_SUSPECT_DEGRADED)) != 1424cbf75e67SStephen Hanson FM_SUSPECT_FAULTY) 1425cbf75e67SStephen Hanson need_update = 1; 1426cbf75e67SStephen Hanson } 1427cbf75e67SStephen Hanson if (need_update) { 1428cbf75e67SStephen Hanson fmd_case_update_status(cp, statusp, cip->ci_proxy_asru, 1429cbf75e67SStephen Hanson cip->ci_diag_asru); 1430cbf75e67SStephen Hanson fmd_case_update_containees(cp); 1431cbf75e67SStephen Hanson fmd_case_update(cp); 1432cbf75e67SStephen Hanson } 1433cbf75e67SStephen Hanson 1434cbf75e67SStephen Hanson /* 1435cbf75e67SStephen Hanson * if asru on proxy side, send an update back to the diagnosing side to 1436cbf75e67SStephen Hanson * update UNUSABLE/DEGRADED. 1437cbf75e67SStephen Hanson */ 1438cbf75e67SStephen Hanson if (got_proxy_asru) 1439cbf75e67SStephen Hanson fmd_case_xprt_updated(cp); 1440cbf75e67SStephen Hanson 1441cbf75e67SStephen Hanson if (nelem > 0) 1442cbf75e67SStephen Hanson fmd_free(asrua, sizeof (nvlist_t *) * nelem); 1443cbf75e67SStephen Hanson fmd_module_unlock(xip->xi_queue->eq_mod); 1444cbf75e67SStephen Hanson } 1445cbf75e67SStephen Hanson 1446d9638e54Smws void 144725351652SVuong Nguyen fmd_xprt_recv(fmd_xprt_t *xp, nvlist_t *nvl, hrtime_t hrt, boolean_t logonly) 1448d9638e54Smws { 1449d9638e54Smws fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1450d9638e54Smws const fmd_xprt_rule_t *xrp; 1451d9638e54Smws fmd_t *dp = &fmd; 1452d9638e54Smws 1453d9638e54Smws fmd_event_t *e; 1454cbf75e67SStephen Hanson char *class, *uuid; 1455f6e214c7SGavin Maltby boolean_t isproto, isereport, isireport, ishvireport, issysevent; 1456d9638e54Smws 1457d9638e54Smws uint64_t *tod; 1458d9638e54Smws uint8_t ttl; 1459d9638e54Smws uint_t n; 1460cbf75e67SStephen Hanson fmd_case_t *cp; 1461d9638e54Smws 1462d9638e54Smws /* 1463d9638e54Smws * Grab the transport lock and set the busy flag to indicate we are 1464d9638e54Smws * busy receiving an event. If [DI]SUSPEND is pending, wait until fmd 1465d9638e54Smws * resumes the transport before continuing on with the receive. 1466d9638e54Smws */ 1467d9638e54Smws (void) pthread_mutex_lock(&xip->xi_lock); 1468d9638e54Smws 1469724365f7Ssethg while (xip->xi_flags & (FMD_XPRT_DSUSPENDED | FMD_XPRT_ISUSPENDED)) { 1470724365f7Ssethg 1471724365f7Ssethg if (fmd.d_signal != 0) { 1472724365f7Ssethg (void) pthread_mutex_unlock(&xip->xi_lock); 1473724365f7Ssethg return; /* fmd_destroy() is in progress */ 1474724365f7Ssethg } 1475724365f7Ssethg 1476d9638e54Smws (void) pthread_cond_wait(&xip->xi_cv, &xip->xi_lock); 1477724365f7Ssethg } 1478d9638e54Smws 1479d9638e54Smws xip->xi_busy++; 1480d9638e54Smws ASSERT(xip->xi_busy != 0); 1481d9638e54Smws 1482d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_lock); 1483d9638e54Smws 1484d9638e54Smws (void) pthread_mutex_lock(&xip->xi_stats_lock); 1485d9638e54Smws xip->xi_stats->xs_received.fmds_value.ui64++; 1486d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_stats_lock); 1487d9638e54Smws 1488d9638e54Smws if (nvlist_lookup_string(nvl, FM_CLASS, &class) != 0) { 1489d9638e54Smws fmd_error(EFMD_XPRT_PAYLOAD, "discarding nvlist %p: missing " 1490d9638e54Smws "required \"%s\" payload element", (void *)nvl, FM_CLASS); 1491d9638e54Smws 1492d9638e54Smws (void) pthread_mutex_lock(&xip->xi_stats_lock); 1493d9638e54Smws xip->xi_stats->xs_discarded.fmds_value.ui64++; 1494d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_stats_lock); 1495d9638e54Smws 1496d9638e54Smws nvlist_free(nvl); 1497d9638e54Smws goto done; 1498d9638e54Smws } 1499d9638e54Smws 150025351652SVuong Nguyen fmd_dprintf(FMD_DBG_XPRT, "xprt %u %s %s\n", xip->xi_id, 150125351652SVuong Nguyen ((logonly == FMD_B_TRUE) ? "logging" : "posting"), class); 150225351652SVuong Nguyen 1503f6e214c7SGavin Maltby isereport = (strncmp(class, FM_EREPORT_CLASS ".", 1504f6e214c7SGavin Maltby sizeof (FM_EREPORT_CLASS)) == 0) ? FMD_B_TRUE : FMD_B_FALSE; 1505f6e214c7SGavin Maltby 1506f6e214c7SGavin Maltby isireport = (strncmp(class, FM_IREPORT_CLASS ".", 1507f6e214c7SGavin Maltby sizeof (FM_IREPORT_CLASS)) == 0) ? FMD_B_TRUE : FMD_B_FALSE; 1508f6e214c7SGavin Maltby 1509f6e214c7SGavin Maltby issysevent = (strncmp(class, SYSEVENT_RSRC_CLASS, 1510f6e214c7SGavin Maltby sizeof (SYSEVENT_RSRC_CLASS) - 1)) == 0 ? FMD_B_TRUE : FMD_B_FALSE; 1511f6e214c7SGavin Maltby 1512f6e214c7SGavin Maltby if (isireport) { 1513f6e214c7SGavin Maltby char *pri; 1514f6e214c7SGavin Maltby 1515f6e214c7SGavin Maltby if (nvlist_lookup_string(nvl, FM_IREPORT_PRIORITY, &pri) == 0 && 1516f6e214c7SGavin Maltby strncmp(pri, "high", 5) == 0) { 1517f6e214c7SGavin Maltby ishvireport = 1; 1518f6e214c7SGavin Maltby } else { 1519f6e214c7SGavin Maltby ishvireport = 0; 1520f6e214c7SGavin Maltby } 1521f6e214c7SGavin Maltby } 152225351652SVuong Nguyen 152325351652SVuong Nguyen /* 152425351652SVuong Nguyen * The logonly flag should only be set for ereports. 152525351652SVuong Nguyen */ 1526f6e214c7SGavin Maltby if (logonly == FMD_B_TRUE && isereport == FMD_B_FALSE) { 152725351652SVuong Nguyen fmd_error(EFMD_XPRT_INVAL, "discarding nvlist %p: " 152825351652SVuong Nguyen "logonly flag is not valid for class %s", 152925351652SVuong Nguyen (void *)nvl, class); 153025351652SVuong Nguyen 153125351652SVuong Nguyen (void) pthread_mutex_lock(&xip->xi_stats_lock); 153225351652SVuong Nguyen xip->xi_stats->xs_discarded.fmds_value.ui64++; 153325351652SVuong Nguyen (void) pthread_mutex_unlock(&xip->xi_stats_lock); 153425351652SVuong Nguyen 153525351652SVuong Nguyen nvlist_free(nvl); 153625351652SVuong Nguyen goto done; 153725351652SVuong Nguyen } 1538d9638e54Smws 1539d9638e54Smws /* 1540d9638e54Smws * If a time-to-live value is present in the event and is zero, drop 1541d9638e54Smws * the event and bump xs_timeouts. Otherwise decrement the TTL value. 1542d9638e54Smws */ 1543d9638e54Smws if (nvlist_lookup_uint8(nvl, FMD_EVN_TTL, &ttl) == 0) { 1544d9638e54Smws if (ttl == 0) { 1545d9638e54Smws fmd_dprintf(FMD_DBG_XPRT, "xprt %u nvlist %p (%s) " 1546d9638e54Smws "timeout: event received with ttl=0\n", 1547d9638e54Smws xip->xi_id, (void *)nvl, class); 1548d9638e54Smws 1549d9638e54Smws (void) pthread_mutex_lock(&xip->xi_stats_lock); 1550d9638e54Smws xip->xi_stats->xs_timeouts.fmds_value.ui64++; 1551d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_stats_lock); 1552d9638e54Smws 1553d9638e54Smws nvlist_free(nvl); 1554d9638e54Smws goto done; 1555d9638e54Smws } 1556d9638e54Smws (void) nvlist_remove(nvl, FMD_EVN_TTL, DATA_TYPE_UINT8); 1557d9638e54Smws (void) nvlist_add_uint8(nvl, FMD_EVN_TTL, ttl - 1); 1558d9638e54Smws } 1559d9638e54Smws 1560d9638e54Smws /* 1561d9638e54Smws * If we are using the native system clock, the underlying transport 1562d9638e54Smws * code can provide a tighter event time bound by telling us when the 1563d9638e54Smws * event was enqueued. If we're using simulated clocks, this time 1564d9638e54Smws * has no meaning to us, so just reset the value to use HRT_NOW. 1565d9638e54Smws */ 1566d9638e54Smws if (dp->d_clockops != &fmd_timeops_native) 1567d9638e54Smws hrt = FMD_HRT_NOW; 1568d9638e54Smws 1569d9638e54Smws /* 1570d9638e54Smws * If an event's class is in the FMD_CTL_CLASS family, then create a 1571d9638e54Smws * control event. If a FMD_EVN_TOD member is found, create a protocol 1572d9638e54Smws * event using this time. Otherwise create a protocol event using hrt. 1573d9638e54Smws */ 157425351652SVuong Nguyen isproto = (strncmp(class, FMD_CTL_CLASS, FMD_CTL_CLASS_LEN) == 0) ? 157525351652SVuong Nguyen FMD_B_FALSE : FMD_B_TRUE; 157625351652SVuong Nguyen if (isproto == FMD_B_FALSE) 1577d9638e54Smws e = fmd_event_create(FMD_EVT_CTL, hrt, nvl, fmd_ctl_init(nvl)); 1578d9638e54Smws else if (nvlist_lookup_uint64_array(nvl, FMD_EVN_TOD, &tod, &n) != 0) 1579d9638e54Smws e = fmd_event_create(FMD_EVT_PROTOCOL, hrt, nvl, class); 1580d9638e54Smws else { 1581d9638e54Smws e = fmd_event_recreate(FMD_EVT_PROTOCOL, 1582d9638e54Smws NULL, nvl, class, NULL, 0, 0); 1583d9638e54Smws } 1584d9638e54Smws 1585d9638e54Smws /* 1586d9638e54Smws * If the debug log is enabled, create a temporary event, log it to the 1587d9638e54Smws * debug log, and then reset the underlying state of the event. 1588d9638e54Smws */ 1589d9638e54Smws if (xip->xi_log != NULL) { 1590d9638e54Smws fmd_event_impl_t *ep = (fmd_event_impl_t *)e; 1591d9638e54Smws 1592d9638e54Smws fmd_log_append(xip->xi_log, e, NULL); 1593d9638e54Smws 1594d9638e54Smws ep->ev_flags |= FMD_EVF_VOLATILE; 1595d9638e54Smws ep->ev_off = 0; 1596d9638e54Smws ep->ev_len = 0; 1597d9638e54Smws 1598d9638e54Smws if (ep->ev_log != NULL) { 1599d9638e54Smws fmd_log_rele(ep->ev_log); 1600d9638e54Smws ep->ev_log = NULL; 1601d9638e54Smws } 1602d9638e54Smws } 1603d9638e54Smws 1604d9638e54Smws /* 1605d9638e54Smws * Iterate over the rules for the current state trying to match the 1606d9638e54Smws * event class to one of our special rules. If a rule is matched, the 1607d9638e54Smws * event is consumed and not dispatched to other modules. If the rule 1608d9638e54Smws * set ends without matching an event, we fall through to dispatching. 1609d9638e54Smws */ 1610d9638e54Smws for (xrp = xip->xi_state; xrp->xr_class != NULL; xrp++) { 1611d9638e54Smws if (fmd_event_match(e, FMD_EVT_PROTOCOL, xrp->xr_class)) { 1612d9638e54Smws fmd_event_hold(e); 1613d9638e54Smws xrp->xr_func(xip, nvl); 1614d9638e54Smws fmd_event_rele(e); 1615d9638e54Smws goto done; 1616d9638e54Smws } 1617d9638e54Smws } 1618d9638e54Smws 1619d9638e54Smws /* 1620f6e214c7SGavin Maltby * Record ereports and ireports in the log. This code will 1621d9638e54Smws * be replaced later with a per-transport intent log instead. 1622d9638e54Smws */ 1623f6e214c7SGavin Maltby if (isereport == FMD_B_TRUE || isireport == FMD_B_TRUE || 1624f6e214c7SGavin Maltby issysevent == B_TRUE) { 1625f6e214c7SGavin Maltby pthread_rwlock_t *lockp; 1626f6e214c7SGavin Maltby fmd_log_t *lp; 1627f6e214c7SGavin Maltby 162825351652SVuong Nguyen if (isereport == FMD_B_TRUE) { 1629f6e214c7SGavin Maltby lp = fmd.d_errlog; 1630f6e214c7SGavin Maltby lockp = &fmd.d_log_lock; 1631f6e214c7SGavin Maltby } else { 1632f6e214c7SGavin Maltby if (ishvireport || issysevent) { 1633f6e214c7SGavin Maltby lp = fmd.d_hvilog; 1634f6e214c7SGavin Maltby lockp = &fmd.d_hvilog_lock; 1635f6e214c7SGavin Maltby } else { 1636f6e214c7SGavin Maltby lp = fmd.d_ilog; 1637f6e214c7SGavin Maltby lockp = &fmd.d_ilog_lock; 1638f6e214c7SGavin Maltby } 1639f6e214c7SGavin Maltby } 1640f6e214c7SGavin Maltby 1641f6e214c7SGavin Maltby (void) pthread_rwlock_rdlock(lockp); 1642f6e214c7SGavin Maltby fmd_log_append(lp, e, NULL); 1643f6e214c7SGavin Maltby (void) pthread_rwlock_unlock(lockp); 1644d9638e54Smws } 1645d9638e54Smws 1646d9638e54Smws /* 1647d9638e54Smws * If a list.suspect event is received, create a case for the specified 1648cbf75e67SStephen Hanson * UUID in the case hash, with the transport module as its owner. 1649d9638e54Smws */ 1650cbf75e67SStephen Hanson if (fmd_event_match(e, FMD_EVT_PROTOCOL, FM_LIST_SUSPECT_CLASS)) { 1651cbf75e67SStephen Hanson if (xip->xi_flags & FMD_XPRT_CACHE_AS_LOCAL) 1652cbf75e67SStephen Hanson fmd_xprt_list_suspect_local(xp, nvl); 1653cbf75e67SStephen Hanson else 1654cbf75e67SStephen Hanson fmd_xprt_list_suspect(xp, nvl); 1655cbf75e67SStephen Hanson fmd_event_hold(e); 1656cbf75e67SStephen Hanson fmd_event_rele(e); 1657cbf75e67SStephen Hanson goto done; 1658d9638e54Smws } 1659d9638e54Smws 1660cbf75e67SStephen Hanson /* 1661cbf75e67SStephen Hanson * If a list.updated or list.repaired event is received, update the 1662cbf75e67SStephen Hanson * resource cache status and the local case. 1663cbf75e67SStephen Hanson */ 1664cbf75e67SStephen Hanson if (fmd_event_match(e, FMD_EVT_PROTOCOL, FM_LIST_REPAIRED_CLASS) || 1665cbf75e67SStephen Hanson fmd_event_match(e, FMD_EVT_PROTOCOL, FM_LIST_UPDATED_CLASS)) { 1666cbf75e67SStephen Hanson uint8_t *statusp; 1667cbf75e67SStephen Hanson uint_t nelem = 0; 1668cbf75e67SStephen Hanson 1669cbf75e67SStephen Hanson (void) nvlist_lookup_uint8_array(nvl, FM_SUSPECT_FAULT_STATUS, 1670cbf75e67SStephen Hanson &statusp, &nelem); 1671cbf75e67SStephen Hanson fmd_module_lock(xip->xi_queue->eq_mod); 1672cbf75e67SStephen Hanson if (nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid) == 0 && 1673cbf75e67SStephen Hanson (cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) != NULL) { 1674cbf75e67SStephen Hanson fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 1675cbf75e67SStephen Hanson if (cip->ci_xprt != NULL) { 1676cbf75e67SStephen Hanson fmd_case_update_status(cp, statusp, 1677cbf75e67SStephen Hanson cip->ci_proxy_asru, cip->ci_diag_asru); 1678cbf75e67SStephen Hanson fmd_case_update_containees(cp); 1679cbf75e67SStephen Hanson fmd_case_update(cp); 1680cbf75e67SStephen Hanson } 1681cbf75e67SStephen Hanson fmd_case_rele(cp); 1682cbf75e67SStephen Hanson } 1683cbf75e67SStephen Hanson fmd_module_unlock(xip->xi_queue->eq_mod); 1684cbf75e67SStephen Hanson fmd_event_hold(e); 1685cbf75e67SStephen Hanson fmd_event_rele(e); 1686cbf75e67SStephen Hanson goto done; 1687cbf75e67SStephen Hanson } 1688cbf75e67SStephen Hanson 1689cbf75e67SStephen Hanson /* 1690cbf75e67SStephen Hanson * If a list.isolated event is received, update resource cache status 1691cbf75e67SStephen Hanson */ 1692cbf75e67SStephen Hanson if (fmd_event_match(e, FMD_EVT_PROTOCOL, FM_LIST_ISOLATED_CLASS)) { 1693cbf75e67SStephen Hanson uint8_t *statusp; 1694cbf75e67SStephen Hanson uint_t nelem = 0; 1695cbf75e67SStephen Hanson 1696cbf75e67SStephen Hanson (void) nvlist_lookup_uint8_array(nvl, FM_SUSPECT_FAULT_STATUS, 1697cbf75e67SStephen Hanson &statusp, &nelem); 1698cbf75e67SStephen Hanson fmd_module_lock(xip->xi_queue->eq_mod); 1699cbf75e67SStephen Hanson if (nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid) == 0 && 1700cbf75e67SStephen Hanson (cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) != NULL) { 1701cbf75e67SStephen Hanson fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 1702cbf75e67SStephen Hanson if (cip->ci_xprt != NULL) 1703cbf75e67SStephen Hanson fmd_case_update_status(cp, statusp, 1704cbf75e67SStephen Hanson cip->ci_proxy_asru, cip->ci_diag_asru); 1705cbf75e67SStephen Hanson fmd_case_rele(cp); 1706cbf75e67SStephen Hanson } 1707cbf75e67SStephen Hanson fmd_module_unlock(xip->xi_queue->eq_mod); 1708cbf75e67SStephen Hanson fmd_event_hold(e); 1709cbf75e67SStephen Hanson fmd_event_rele(e); 1710cbf75e67SStephen Hanson goto done; 1711cbf75e67SStephen Hanson } 1712cbf75e67SStephen Hanson 1713cbf75e67SStephen Hanson /* 1714cbf75e67SStephen Hanson * If a list.resolved event is received, resolve the local case. 1715cbf75e67SStephen Hanson */ 1716cbf75e67SStephen Hanson if (fmd_event_match(e, FMD_EVT_PROTOCOL, FM_LIST_RESOLVED_CLASS)) { 1717cbf75e67SStephen Hanson fmd_module_lock(xip->xi_queue->eq_mod); 1718cbf75e67SStephen Hanson if (nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid) == 0 && 1719cbf75e67SStephen Hanson (cp = fmd_case_hash_lookup(fmd.d_cases, uuid)) != NULL) { 1720cbf75e67SStephen Hanson fmd_case_impl_t *cip = (fmd_case_impl_t *)cp; 1721cbf75e67SStephen Hanson if (cip->ci_xprt != NULL) 1722cbf75e67SStephen Hanson fmd_case_transition(cp, (cip->ci_state == 1723cbf75e67SStephen Hanson FMD_CASE_REPAIRED) ? FMD_CASE_RESOLVED : 1724cbf75e67SStephen Hanson (cip->ci_state == FMD_CASE_CLOSED) ? 1725cbf75e67SStephen Hanson FMD_CASE_REPAIRED : FMD_CASE_CLOSE_WAIT, 1726cbf75e67SStephen Hanson FMD_CF_RESOLVED); 1727cbf75e67SStephen Hanson fmd_case_rele(cp); 1728cbf75e67SStephen Hanson } 1729cbf75e67SStephen Hanson fmd_module_unlock(xip->xi_queue->eq_mod); 1730cbf75e67SStephen Hanson fmd_event_hold(e); 1731cbf75e67SStephen Hanson fmd_event_rele(e); 1732cbf75e67SStephen Hanson goto done; 1733cbf75e67SStephen Hanson } 1734cbf75e67SStephen Hanson 1735cbf75e67SStephen Hanson if (logonly == FMD_B_TRUE || (xip->xi_flags & FMD_XPRT_EXTERNAL)) { 1736cbf75e67SStephen Hanson /* 1737cbf75e67SStephen Hanson * Don't proxy ereports on an EXTERNAL transport - we won't 1738cbf75e67SStephen Hanson * know how to diagnose them with the wrong topology. Note 1739cbf75e67SStephen Hanson * that here (and above) we have to hold/release the event in 1740cbf75e67SStephen Hanson * order for it to be freed. 1741cbf75e67SStephen Hanson */ 174225351652SVuong Nguyen fmd_event_hold(e); 174325351652SVuong Nguyen fmd_event_rele(e); 174425351652SVuong Nguyen } else if (isproto == FMD_B_TRUE) 1745d9638e54Smws fmd_dispq_dispatch(dp->d_disp, e, class); 1746d9638e54Smws else 1747d9638e54Smws fmd_modhash_dispatch(dp->d_mod_hash, e); 1748d9638e54Smws done: 1749d9638e54Smws (void) pthread_mutex_lock(&xip->xi_lock); 1750d9638e54Smws 1751d9638e54Smws ASSERT(xip->xi_busy != 0); 1752d9638e54Smws xip->xi_busy--; 1753d9638e54Smws 1754d9638e54Smws (void) pthread_cond_broadcast(&xip->xi_cv); 1755d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_lock); 1756d9638e54Smws } 1757d9638e54Smws 1758d9638e54Smws void 1759d9638e54Smws fmd_xprt_uuclose(fmd_xprt_t *xp, const char *uuid) 1760d9638e54Smws { 1761d9638e54Smws fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1762d9638e54Smws 1763d9638e54Smws fmd_event_t *e; 1764d9638e54Smws nvlist_t *nvl; 1765d9638e54Smws char *s; 1766d9638e54Smws 1767cbf75e67SStephen Hanson if ((xip->xi_flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY) 1768cbf75e67SStephen Hanson return; /* read-only transports do not proxy uuclose */ 1769cbf75e67SStephen Hanson 1770cbf75e67SStephen Hanson TRACE((FMD_DBG_XPRT, "xprt %u closing case %s\n", xip->xi_id, uuid)); 1771d9638e54Smws 1772d9638e54Smws nvl = fmd_protocol_xprt_uuclose(xip->xi_queue->eq_mod, 1773d9638e54Smws "resource.fm.xprt.uuclose", xip->xi_version, uuid); 1774d9638e54Smws 1775d9638e54Smws (void) nvlist_lookup_string(nvl, FM_CLASS, &s); 1776d9638e54Smws e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s); 1777d9638e54Smws fmd_eventq_insert_at_time(xip->xi_queue, e); 1778d9638e54Smws } 1779d9638e54Smws 1780d9638e54Smws /* 1781cbf75e67SStephen Hanson * On proxy side, send back uuresolved request to diagnosing side 1782cbf75e67SStephen Hanson */ 1783cbf75e67SStephen Hanson void 1784cbf75e67SStephen Hanson fmd_xprt_uuresolved(fmd_xprt_t *xp, const char *uuid) 1785cbf75e67SStephen Hanson { 1786cbf75e67SStephen Hanson fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1787cbf75e67SStephen Hanson 1788cbf75e67SStephen Hanson fmd_event_t *e; 1789cbf75e67SStephen Hanson nvlist_t *nvl; 1790cbf75e67SStephen Hanson char *s; 1791cbf75e67SStephen Hanson 1792cbf75e67SStephen Hanson if ((xip->xi_flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY) 1793cbf75e67SStephen Hanson return; /* read-only transports do not proxy uuresolved */ 1794cbf75e67SStephen Hanson 1795cbf75e67SStephen Hanson TRACE((FMD_DBG_XPRT, "xprt %u resolving case %s\n", xip->xi_id, uuid)); 1796cbf75e67SStephen Hanson 1797cbf75e67SStephen Hanson nvl = fmd_protocol_xprt_uuresolved(xip->xi_queue->eq_mod, 1798cbf75e67SStephen Hanson "resource.fm.xprt.uuresolved", xip->xi_version, uuid); 1799cbf75e67SStephen Hanson 1800cbf75e67SStephen Hanson (void) nvlist_lookup_string(nvl, FM_CLASS, &s); 1801cbf75e67SStephen Hanson e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s); 1802cbf75e67SStephen Hanson fmd_eventq_insert_at_time(xip->xi_queue, e); 1803cbf75e67SStephen Hanson } 1804cbf75e67SStephen Hanson 1805cbf75e67SStephen Hanson /* 1806cbf75e67SStephen Hanson * On proxy side, send back repair/acquit/etc request to diagnosing side 1807cbf75e67SStephen Hanson */ 1808cbf75e67SStephen Hanson void 1809cbf75e67SStephen Hanson fmd_xprt_updated(fmd_xprt_t *xp, const char *uuid, uint8_t *statusp, 1810cbf75e67SStephen Hanson uint8_t *has_asrup, uint_t nelem) 1811cbf75e67SStephen Hanson { 1812cbf75e67SStephen Hanson fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1813cbf75e67SStephen Hanson 1814cbf75e67SStephen Hanson fmd_event_t *e; 1815cbf75e67SStephen Hanson nvlist_t *nvl; 1816cbf75e67SStephen Hanson char *s; 1817cbf75e67SStephen Hanson 1818cbf75e67SStephen Hanson if ((xip->xi_flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY) 1819cbf75e67SStephen Hanson return; /* read-only transports do not support remote repairs */ 1820cbf75e67SStephen Hanson 1821cbf75e67SStephen Hanson TRACE((FMD_DBG_XPRT, "xprt %u updating case %s\n", xip->xi_id, uuid)); 1822cbf75e67SStephen Hanson 1823cbf75e67SStephen Hanson nvl = fmd_protocol_xprt_updated(xip->xi_queue->eq_mod, 1824cbf75e67SStephen Hanson "resource.fm.xprt.updated", xip->xi_version, uuid, statusp, 1825cbf75e67SStephen Hanson has_asrup, nelem); 1826cbf75e67SStephen Hanson 1827cbf75e67SStephen Hanson (void) nvlist_lookup_string(nvl, FM_CLASS, &s); 1828cbf75e67SStephen Hanson e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s); 1829cbf75e67SStephen Hanson fmd_eventq_insert_at_time(xip->xi_queue, e); 1830cbf75e67SStephen Hanson } 1831cbf75e67SStephen Hanson 1832cbf75e67SStephen Hanson /* 1833d9638e54Smws * Insert the specified class into our remote subscription hash. If the class 1834d9638e54Smws * is already present, bump the reference count; otherwise add it to the hash 1835d9638e54Smws * and then enqueue an event for our remote peer to proxy our subscription. 1836d9638e54Smws */ 1837d9638e54Smws void 1838d9638e54Smws fmd_xprt_subscribe(fmd_xprt_t *xp, const char *class) 1839d9638e54Smws { 1840d9638e54Smws fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1841d9638e54Smws 1842d9638e54Smws uint_t refs; 1843d9638e54Smws nvlist_t *nvl; 1844d9638e54Smws fmd_event_t *e; 1845d9638e54Smws char *s; 1846d9638e54Smws 1847d9638e54Smws if ((xip->xi_flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY) 1848d9638e54Smws return; /* read-only transports do not proxy subscriptions */ 1849d9638e54Smws 1850d9638e54Smws if (!(xip->xi_flags & FMD_XPRT_SUBSCRIBER)) 1851d9638e54Smws return; /* transport is not yet an active subscriber */ 1852d9638e54Smws 1853d9638e54Smws (void) pthread_mutex_lock(&xip->xi_lock); 1854d9638e54Smws refs = fmd_xprt_class_hash_insert(xip, &xip->xi_rsub, class); 1855d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_lock); 1856d9638e54Smws 1857d9638e54Smws if (refs > 1) 1858d9638e54Smws return; /* we've already asked our peer for this subscription */ 1859d9638e54Smws 1860d9638e54Smws fmd_dprintf(FMD_DBG_XPRT, 1861d9638e54Smws "xprt %u subscribing to %s\n", xip->xi_id, class); 1862d9638e54Smws 1863d9638e54Smws nvl = fmd_protocol_xprt_sub(xip->xi_queue->eq_mod, 1864d9638e54Smws "resource.fm.xprt.subscribe", xip->xi_version, class); 1865d9638e54Smws 1866d9638e54Smws (void) nvlist_lookup_string(nvl, FM_CLASS, &s); 1867d9638e54Smws e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s); 1868d9638e54Smws fmd_eventq_insert_at_time(xip->xi_queue, e); 1869d9638e54Smws } 1870d9638e54Smws 1871d9638e54Smws /* 1872d9638e54Smws * Delete the specified class from the remote subscription hash. If the 1873d9638e54Smws * reference count drops to zero, ask our remote peer to unsubscribe by proxy. 1874d9638e54Smws */ 1875d9638e54Smws void 1876d9638e54Smws fmd_xprt_unsubscribe(fmd_xprt_t *xp, const char *class) 1877d9638e54Smws { 1878d9638e54Smws fmd_xprt_impl_t *xip = (fmd_xprt_impl_t *)xp; 1879d9638e54Smws 1880d9638e54Smws uint_t refs; 1881d9638e54Smws nvlist_t *nvl; 1882d9638e54Smws fmd_event_t *e; 1883d9638e54Smws char *s; 1884d9638e54Smws 1885d9638e54Smws if ((xip->xi_flags & FMD_XPRT_RDWR) == FMD_XPRT_RDONLY) 1886d9638e54Smws return; /* read-only transports do not proxy subscriptions */ 1887d9638e54Smws 1888d9638e54Smws if (!(xip->xi_flags & FMD_XPRT_SUBSCRIBER)) 1889d9638e54Smws return; /* transport is not yet an active subscriber */ 1890d9638e54Smws 1891d9638e54Smws /* 1892d9638e54Smws * If the subscription reference count drops to zero in xi_rsub, insert 1893d9638e54Smws * an entry into the xi_usub hash indicating we await an unsuback event. 1894d9638e54Smws */ 1895d9638e54Smws (void) pthread_mutex_lock(&xip->xi_lock); 1896d9638e54Smws 1897d9638e54Smws if ((refs = fmd_xprt_class_hash_delete(xip, &xip->xi_rsub, class)) == 0) 1898d9638e54Smws (void) fmd_xprt_class_hash_insert(xip, &xip->xi_usub, class); 1899d9638e54Smws 1900d9638e54Smws (void) pthread_mutex_unlock(&xip->xi_lock); 1901d9638e54Smws 1902d9638e54Smws if (refs != 0) 1903d9638e54Smws return; /* other subscriptions for this class still active */ 1904d9638e54Smws 1905d9638e54Smws fmd_dprintf(FMD_DBG_XPRT, 1906d9638e54Smws "xprt %u unsubscribing from %s\n", xip->xi_id, class); 1907d9638e54Smws 1908d9638e54Smws nvl = fmd_protocol_xprt_sub(xip->xi_queue->eq_mod, 1909d9638e54Smws "resource.fm.xprt.unsubscribe", xip->xi_version, class); 1910d9638e54Smws 1911d9638e54Smws (void) nvlist_lookup_string(nvl, FM_CLASS, &s); 1912d9638e54Smws e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, s); 1913d9638e54Smws fmd_eventq_insert_at_time(xip->xi_queue, e); 1914d9638e54Smws } 1915d9638e54Smws 1916d9638e54Smws static void 1917d9638e54Smws fmd_xprt_subscribe_xid(fmd_idspace_t *ids, id_t id, void *class) 1918d9638e54Smws { 1919d9638e54Smws fmd_xprt_t *xp; 1920d9638e54Smws 1921d9638e54Smws if ((xp = fmd_idspace_hold(ids, id)) != NULL) { 1922d9638e54Smws fmd_xprt_subscribe(xp, class); 1923d9638e54Smws fmd_idspace_rele(ids, id); 1924d9638e54Smws } 1925d9638e54Smws } 1926d9638e54Smws 1927d9638e54Smws void 1928d9638e54Smws fmd_xprt_subscribe_all(const char *class) 1929d9638e54Smws { 1930d9638e54Smws fmd_idspace_t *ids = fmd.d_xprt_ids; 1931d9638e54Smws 1932d9638e54Smws if (ids->ids_count != 0) 1933d9638e54Smws fmd_idspace_apply(ids, fmd_xprt_subscribe_xid, (void *)class); 1934d9638e54Smws } 1935d9638e54Smws 1936d9638e54Smws static void 1937d9638e54Smws fmd_xprt_unsubscribe_xid(fmd_idspace_t *ids, id_t id, void *class) 1938d9638e54Smws { 1939d9638e54Smws fmd_xprt_t *xp; 1940d9638e54Smws 1941d9638e54Smws if ((xp = fmd_idspace_hold(ids, id)) != NULL) { 1942d9638e54Smws fmd_xprt_unsubscribe(xp, class); 1943d9638e54Smws fmd_idspace_rele(ids, id); 1944d9638e54Smws } 1945d9638e54Smws } 1946d9638e54Smws 1947d9638e54Smws void 1948d9638e54Smws fmd_xprt_unsubscribe_all(const char *class) 1949d9638e54Smws { 1950d9638e54Smws fmd_idspace_t *ids = fmd.d_xprt_ids; 1951d9638e54Smws 1952d9638e54Smws if (ids->ids_count != 0) 1953d9638e54Smws fmd_idspace_apply(ids, fmd_xprt_unsubscribe_xid, (void *)class); 1954d9638e54Smws } 1955d9638e54Smws 1956d9638e54Smws /*ARGSUSED*/ 1957d9638e54Smws static void 1958d9638e54Smws fmd_xprt_suspend_xid(fmd_idspace_t *ids, id_t id, void *arg) 1959d9638e54Smws { 1960d9638e54Smws fmd_xprt_t *xp; 1961d9638e54Smws 1962d9638e54Smws if ((xp = fmd_idspace_hold(ids, id)) != NULL) { 1963d9638e54Smws fmd_xprt_xsuspend(xp, FMD_XPRT_DSUSPENDED); 1964d9638e54Smws fmd_idspace_rele(ids, id); 1965d9638e54Smws } 1966d9638e54Smws } 1967d9638e54Smws 1968d9638e54Smws void 1969d9638e54Smws fmd_xprt_suspend_all(void) 1970d9638e54Smws { 1971d9638e54Smws fmd_idspace_t *ids = fmd.d_xprt_ids; 1972d9638e54Smws 1973d9638e54Smws (void) pthread_mutex_lock(&fmd.d_xprt_lock); 1974d9638e54Smws 1975d9638e54Smws if (fmd.d_xprt_suspend++ != 0) { 1976d9638e54Smws (void) pthread_mutex_unlock(&fmd.d_xprt_lock); 1977d9638e54Smws return; /* already suspended */ 1978d9638e54Smws } 1979d9638e54Smws 1980d9638e54Smws if (ids->ids_count != 0) 1981d9638e54Smws fmd_idspace_apply(ids, fmd_xprt_suspend_xid, NULL); 1982d9638e54Smws 1983d9638e54Smws (void) pthread_mutex_unlock(&fmd.d_xprt_lock); 1984d9638e54Smws } 1985d9638e54Smws 1986d9638e54Smws /*ARGSUSED*/ 1987d9638e54Smws static void 1988d9638e54Smws fmd_xprt_resume_xid(fmd_idspace_t *ids, id_t id, void *arg) 1989d9638e54Smws { 1990d9638e54Smws fmd_xprt_t *xp; 1991d9638e54Smws 1992d9638e54Smws if ((xp = fmd_idspace_hold(ids, id)) != NULL) { 1993d9638e54Smws fmd_xprt_xresume(xp, FMD_XPRT_DSUSPENDED); 1994d9638e54Smws fmd_idspace_rele(ids, id); 1995d9638e54Smws } 1996d9638e54Smws } 1997d9638e54Smws 1998d9638e54Smws void 1999d9638e54Smws fmd_xprt_resume_all(void) 2000d9638e54Smws { 2001d9638e54Smws fmd_idspace_t *ids = fmd.d_xprt_ids; 2002d9638e54Smws 2003d9638e54Smws (void) pthread_mutex_lock(&fmd.d_xprt_lock); 2004d9638e54Smws 2005d9638e54Smws if (fmd.d_xprt_suspend == 0) 2006d9638e54Smws fmd_panic("fmd_xprt_suspend/resume_all mismatch\n"); 2007d9638e54Smws 2008d9638e54Smws if (--fmd.d_xprt_suspend != 0) { 2009d9638e54Smws (void) pthread_mutex_unlock(&fmd.d_xprt_lock); 2010d9638e54Smws return; /* not ready to be resumed */ 2011d9638e54Smws } 2012d9638e54Smws 2013d9638e54Smws if (ids->ids_count != 0) 2014d9638e54Smws fmd_idspace_apply(ids, fmd_xprt_resume_xid, NULL); 2015d9638e54Smws 2016d9638e54Smws (void) pthread_mutex_unlock(&fmd.d_xprt_lock); 2017d9638e54Smws } 2018