etm_xport_api_dd.c revision 733a5356058ae0150a67d61f0ad8e5260d2acae3
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * CDDL HEADER START
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * The contents of this file are subject to the terms of the
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * Common Development and Distribution License, Version 1.0 only
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * (the "License"). You may not use this file except in compliance
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * with the License.
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * See the License for the specific language governing permissions
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * and limitations under the License.
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * When distributing Covered Code, include this CDDL HEADER in each
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * If applicable, add the following below this CDDL HEADER, with the
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * fields enclosed by brackets "[]" replaced with your own identifying
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * information: Portions Copyright [yyyy] [name of copyright owner]
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * CDDL HEADER END
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * Use is subject to license terms.
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_api_dd.c FMA ETM-to-Transport API implementation
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * library for establishing connections and transporting FMA events
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * between ETMs (event transport modules) in separate fault domain,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * ie, between domain and service processor in same chassis, using
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * a character device driver based transport
733a5356058ae0150a67d61f0ad8e5260d2acae3rb#pragma ident "%Z%%M% %I% %E% SMI"
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * --------------------------------- includes --------------------------------
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * ----------------------- private consts and defns --------------------------
733a5356058ae0150a67d61f0ad8e5260d2acae3rb/* magic numbers (32 bits) for transport address and connection handle */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb/* flags to use in opening transport device */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * transport address and connection handle structures overload fn and fd
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * fields to include state information:
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * fn file name NULL means unused or closed
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * fd file descriptor -1 means unused or closed
733a5356058ae0150a67d61f0ad8e5260d2acae3rbtypedef struct _etm_xport_addr {
733a5356058ae0150a67d61f0ad8e5260d2acae3rbtypedef struct _etm_xport_conn {
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * default filename of device node to reach SP from domain
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * filenames of device nodes to reach domains from SP
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * are NA because SP runs ALOM vs Solaris or Linux
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * and ETM is for Unix based OSes
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * -------------------------- global variables -------------------------------
733a5356058ae0150a67d61f0ad8e5260d2acae3rbstatic struct stats {
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* address handle failures */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* connection handle failures */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* internal read/peek failures */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* xport API failures */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* system and library failures */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* address handle failures */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb "invalid address handle magic number" },
733a5356058ae0150a67d61f0ad8e5260d2acae3rb "invalid address handle file name" },
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* connection handle failures */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb "invalid connection handle magic number" },
733a5356058ae0150a67d61f0ad8e5260d2acae3rb "invalid connection handle file descriptor" },
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* internal read/peek failures */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb "bad arguments in etm_xport_buffered_read" },
733a5356058ae0150a67d61f0ad8e5260d2acae3rb "bad arguments in etm_xport_raw_peek" },
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* xport API failures */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb "bad arguments in etm_xport_accept" },
733a5356058ae0150a67d61f0ad8e5260d2acae3rb "bad arguments in etm_xport_get_addr_conn" },
733a5356058ae0150a67d61f0ad8e5260d2acae3rb "bad arguments in etm_xport_free_addr" },
733a5356058ae0150a67d61f0ad8e5260d2acae3rb "bad arguments in etm_xport_free_addrv" },
733a5356058ae0150a67d61f0ad8e5260d2acae3rb "bad arguments in etm_xport_get_any_lcc" },
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* system and library failures */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb "open system call failures" },
733a5356058ae0150a67d61f0ad8e5260d2acae3rb "close system call failures" },
733a5356058ae0150a67d61f0ad8e5260d2acae3rb "read system call failures" },
733a5356058ae0150a67d61f0ad8e5260d2acae3rb "write system call failures" },
733a5356058ae0150a67d61f0ad8e5260d2acae3rb "peek (ioctl) failures" },
733a5356058ae0150a67d61f0ad8e5260d2acae3rb "ioctl system call failures" }
733a5356058ae0150a67d61f0ad8e5260d2acae3rb/* intermediate read buffer to [partially] emulate byte stream semantics */
733a5356058ae0150a67d61f0ad8e5260d2acae3rbstatic uint8_t *etm_xport_irb_area = NULL; /* buffered read area */
733a5356058ae0150a67d61f0ad8e5260d2acae3rbstatic uint8_t *etm_xport_irb_head = NULL; /* read head (dequeue) */
733a5356058ae0150a67d61f0ad8e5260d2acae3rbstatic uint8_t *etm_xport_irb_tail = NULL; /* read tail (enqueue) */
733a5356058ae0150a67d61f0ad8e5260d2acae3rbstatic size_t etm_xport_irb_mtu_sz = 0; /* MTU size (in bytes) */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * -------------------------- private variables ------------------------------
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * Design_Note:
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * Access to the transport for receiving is serialized so that if two threads
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * exist, one for accepting new connections and one for reading on an
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * accepted connection, they don't race with each other. A pingpong access
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * pattern is enforced/ensured using a mutex etm_xport_ser_lock. To avoid
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * deadlocks caused by locking the mutex inside accept() and open(), only
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * accept() is covered with an approrpriate unlock inside close() using
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_ser_conn to notice the proper connection and when to unlock.
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * This could've been done within ETM [inside the pertinent threads]
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * more easily; but because it's platform specific it's being done here
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * within the ETM-to-Transport API.
733a5356058ae0150a67d61f0ad8e5260d2acae3rbetm_xport_ser_conn = NULL; /* serialization connection handle */
733a5356058ae0150a67d61f0ad8e5260d2acae3rbetm_xport_debug_lvl = 0; /* debug level: 0 off, 1 on, 2 more, ... */
733a5356058ae0150a67d61f0ad8e5260d2acae3rbstatic char *
733a5356058ae0150a67d61f0ad8e5260d2acae3rbetm_xport_addrs = ""; /* spec str for transport addrs to use */
733a5356058ae0150a67d61f0ad8e5260d2acae3rbetm_xport_should_fake_dd = 0; /* bool for whether to fake device driver */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * -------------------------- private functions ------------------------------
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_fake_ioctl - fake/simulate transport driver's ioctl() behavior
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * [for unit testing with device driver absent or
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * for alternative directory entry based transports],
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * return 0 for success
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * or -1 and set errno
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * caveats:
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * simulation may be incomplete, especially wrt peek()
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * Design_Note: To avoid interfering with FMD's signal mask (SIGALRM)
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * do not use [Solaris] sleep(3C) and instead use
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * pthread_cond_wait() or nanosleep(), both of which
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * are POSIX spec-ed to leave signal masks alone.
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * This is needed for Solaris and Linux (domain and SP).
733a5356058ae0150a67d61f0ad8e5260d2acae3rb etm_xport_msg_peek_t *peek_ctl_ptr; /* ptr for peeking */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* sleep until some data avail, potentially forever */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb for (;;) {
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* return bogus data assuming content unused */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb } /* forever awaiting data */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* default near MTU_SZ gets and agree with everything else */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb } /* whether ioctl op is handled */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (rv);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_fake_ioctl() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_get_fn - return a cached read-only copy
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * of the device node name to use
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * for the given I/O operation
733a5356058ae0150a67d61f0ad8e5260d2acae3rbstatic char *
733a5356058ae0150a67d61f0ad8e5260d2acae3rb static char fn_rd[PATH_MAX] = {0}; /* fn for read/peek */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* use cached copies if avail */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb if (((io_op == ETM_IO_OP_RD) || (io_op == ETM_IO_OP_PK)) &&
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* create cached copies if empty "" property string */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb prop_str = fmd_prop_get_string(hdl, ETM_PROP_NM_XPORT_ADDRS);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb fmd_hdl_debug(hdl, "info: etm_xport_get_fn prop_str %s\n",
733a5356058ae0150a67d61f0ad8e5260d2acae3rb (void) strncpy(fn_wr, ETM_XPORT_DEV_FN_SP, PATH_MAX - 1);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb (void) strncpy(fn_rd, ETM_XPORT_DEV_FN_SP, PATH_MAX - 1);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb } /* if no/empty property set */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* create cached copies if "write[|read]" property string */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb } /* whether io op is write/read/peek */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb fmd_hdl_debug(hdl, "info: etm_xport_get_fn fn_wr %s fn_rd %s\n",
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (rv);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_get_fn() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_valid_addr - validate the given transport address,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * return 0 if valid
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * or -errno value if not
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (-EINVAL);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb etm_xport_stats.xport_addr_magicnum_bad.fmds_value.ui64++;
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (-EFAULT);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* errno assumed set by above call */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (-errno);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (0);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_valid_addr() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_valid_conn - validate the given connection handle,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * return 0 if valid
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * or -errno value if not
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (-EINVAL);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb etm_xport_stats.xport_conn_magicnum_bad.fmds_value.ui64++;
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (-EFAULT);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (-EBADF);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (0);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_valid_conn() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_free_addr - free the given transport address
733a5356058ae0150a67d61f0ad8e5260d2acae3rbstatic void
733a5356058ae0150a67d61f0ad8e5260d2acae3rbetm_xport_free_addr(fmd_hdl_t *hdl, etm_xport_addr_t addr)
733a5356058ae0150a67d61f0ad8e5260d2acae3rb etm_xport_stats.xport_free_addr_badargs.fmds_value.ui64++;
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_free_addr() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_dup_addr - duplicate the given transport address,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * which is to be freed separately,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * return the newly allocated transport address
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * pending until possible to do so
733a5356058ae0150a67d61f0ad8e5260d2acae3rb new_addr = fmd_hdl_zalloc(hdl, sizeof (_etm_xport_addr_t), FMD_SLEEP);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb (void) memcpy(new_addr, addr, sizeof (_etm_xport_addr_t));
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_dup_addr() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_raw_peek - try to peek N <= MTU bytes from the connection
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * into the caller's given buffer,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * return how many bytes actually peeked
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * or -errno value
733a5356058ae0150a67d61f0ad8e5260d2acae3rbetm_xport_raw_peek(fmd_hdl_t *hdl, _etm_xport_conn_t *_conn,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* sanity check args */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (-EINVAL);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb if ((etm_xport_irb_mtu_sz > 0) && (byte_cnt > etm_xport_irb_mtu_sz)) {
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (-EINVAL);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* try to peek requested amt of data */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb n = ioctl(_conn->fd, ETM_XPORT_IOCTL_DATA_PEEK, &peek_ctl);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb if (n < 0) {
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* errno assumed set by above call */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb fmd_hdl_debug(hdl, "info: [fake] ioctl(_PEEK) ~= %d bytes\n",
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (rv);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_raw_peek() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * Design_Note:
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * The transport device driver did not implement byte stream semantics
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * per the spec; its behavior is closer to that of a block device.
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * Consequently, ETM within its Transport API attempts to make the device
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * look like a byte stream by using an intermediate buffer in user space
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * and maintaining progress pointers within that buffer which is populated
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * in near-MTU sized reads. We think it's OK to leave the write side
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * implementation as it was originally written for byte stream semantics
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * because we were told subsequent write()s will pend until the earlier
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * content is read() at the remote end -- essentially each write() must be
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * paired with a single read() -- the device driver does not buffer any I/O.
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * The early driver bugs of returning more data than requested (thus
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * causing buffer overrun corruptions/crashes) and requiring user buffers
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * to be stack based vs heap based, have both been corrected.
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_buffered_read - try to read N <= MTU bytes from the connection
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * or from an privately maintained intermediate buffer,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * into the caller's given buffer,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * return how many bytes actually read
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * or -errno value
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * caveats:
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * simple buffer scheme consumes 2x MTU bytes of memory and
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * may do unnecesssary memory copies for ease of coding
733a5356058ae0150a67d61f0ad8e5260d2acae3rbetm_xport_buffered_read(fmd_hdl_t *hdl, _etm_xport_conn_t *_conn,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* perform one-time initializations */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * Design_Note:
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * These initializations are not done in etm_xport_init() because
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * the connection/device is not yet open and hence the MTU size
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * is not yet known. However, the corresponding cleanup is done
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * in etm_xport_fini(). The buffering for byte stream semantics
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * should be done on a per device vs per connection basis; the
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * MTU size is assumed to remain constant across all connections.
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* sanity check the byte count after have MTU */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb etm_xport_stats.xport_buffread_badargs.fmds_value.ui64++;
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (-EINVAL);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* if intermediate buffer can satisfy request do so w/out xport read */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb if (byte_cnt <= (etm_xport_irb_tail - etm_xport_irb_head)) {
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* slide buffer contents to front to make room for [MTU] more bytes */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb (void) memmove(etm_xport_irb_area, etm_xport_irb_head, n);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * peek to see how much data is avail and read all of it;
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * there is no race condition between peeking and reading
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * due to unbuffered design of the device driver
733a5356058ae0150a67d61f0ad8e5260d2acae3rb if ((i = etm_xport_raw_peek(hdl, _conn, etm_xport_irb_tail,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (i);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* errno assumed set by above call */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (-errno);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* satisfy request as best we can with what we now have */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb n = MIN(byte_cnt, (etm_xport_irb_tail - etm_xport_irb_head));
733a5356058ae0150a67d61f0ad8e5260d2acae3rb fmd_hdl_debug(hdl, "info: slow buffered read == %d\n", n);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (n);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_buffered_read() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * ------------------ connection establishment functions ---------------------
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_init - initialize/setup any transport infrastructure
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * before any connections are opened,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * return 0 or -errno value if initialization failed
733a5356058ae0150a67d61f0ad8e5260d2acae3rb int i; /* vector index */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* setup statistics and properties from FMD */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb etm_xport_debug_lvl = fmd_prop_get_int32(hdl, ETM_PROP_NM_DEBUG_LVL);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb etm_xport_addrs = fmd_prop_get_string(hdl, ETM_PROP_NM_XPORT_ADDRS);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb fmd_hdl_debug(hdl, "info: etm_xport_addrs %s\n", etm_xport_addrs);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* decide whether to fake [some of] the device driver behavior */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* errno assumed set by above call */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb fmd_hdl_error(hdl, "error: bad device node %s errno %d\n",
733a5356058ae0150a67d61f0ad8e5260d2acae3rb fmd_hdl_debug(hdl, "info: etm_xport_should_fake_dd %d\n",
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* validate each default dst transport address */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb if ((_addrv = (void *)etm_xport_get_ev_addrv(hdl, NULL)) == NULL) {
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* errno assumed set by above call */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb } /* foreach dst addr */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* create mutex for xport access serialization */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb if (rv >= 0) {
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (rv);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_init() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_open - open a connection with the given endpoint,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * return the connection handle,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * or NULL and set errno if open failed
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * Design_Note: The current transport device driver's open()
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * call will succeed even if the SP is down;
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * hence there's currently no need for a retry
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * mechanism.
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* allocate a connection handle and start populating it */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb _conn = fmd_hdl_zalloc(hdl, sizeof (_etm_xport_conn_t), FMD_SLEEP);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb if ((_conn->fd = open(_addr->fn, ETM_XPORT_OPEN_FLAGS, 0)) == -1) {
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* errno assumed set by above call */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* return the fully formed connection handle */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_open() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_accept - accept a request to open a connection,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * pending until a remote endpoint opens a
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * a new connection to us [and sends an ETM msg],
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * per non-NULL addrp optionally indicate the
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * remote address if known/avail (NULL if not),
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * return the connection handle,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * or NULL and set errno on failure
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * caveats:
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * any returned transport address is valid only for
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * as long as the associated connection remains open;
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * callers should not try to free the transport address
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * if new connections are rapid relative to how
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * frequently this function is called, fairness will
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * be provided among which connections are accepted
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * this function may maintain state to recognize [new]
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * connections and/or to provide fairness
733a5356058ae0150a67d61f0ad8e5260d2acae3rb int n; /* byte cnt */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * get the default dst transport address and open a connection to it;
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * there is only 1 default addr
733a5356058ae0150a67d61f0ad8e5260d2acae3rb if ((_addrv = (void*)etm_xport_get_ev_addrv(hdl, NULL)) == NULL) {
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* errno assumed set by above call */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* errno assumed set by above call */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * lock mutex to avoid race condition between handler for a new
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * connection and the top level connection acceptance server;
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * remember the connection handle for close
733a5356058ae0150a67d61f0ad8e5260d2acae3rb (void) ftruncate(_conn->fd, 0); /* act like socket/queue/pipe */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * peek from the connection to simulate an accept() system call
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * behavior; this will pend until some ETM message is written
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * from the other end
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* cleanup the connection if failed */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* free _addrv and all its transport addresses */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb fmd_hdl_debug(hdl, "info: accept conn %p w/ *addrp %p\n",
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (rv);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_accept() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_close - close a connection from either endpoint,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * return the original connection handle,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * or NULL and set errno if close failed
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* close the device node */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* errno assumed set by above call */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * unlock the mutex after the device node is closed
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * if this is the appropriate connection handle
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* cleanup the connection */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (rv);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_close() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_get_ev_addrv - indicate which transport addresses
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * are implied as destinations by the
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * given FMA event, if given no FMA event
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * (NULL) indicate default or policy
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * driven dst transport addresses,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * return an allocated NULL terminated
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * vector of allocated transport addresses,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * or NULL and set errno if none
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * caveats:
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * callers should never try to individually free an addr
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * within the returned vector
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * allocate address handles for default/policy destinations
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * in reality we have just 1 dst transport addr
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * allocate address handles per FMA event content
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * in reality we have just 1 dst transport addr
733a5356058ae0150a67d61f0ad8e5260d2acae3rb } /* whether caller passed in a FMA event */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* allocate vector with 1 non-NULL transport addr */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb _addrv = fmd_hdl_zalloc(hdl, 2 * sizeof (_etm_xport_addr_t *),
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return ((void *) _addrv);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_get_ev_addrv() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_free_addrv - free the given vector of transport addresses,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * including each transport address
733a5356058ae0150a67d61f0ad8e5260d2acae3rbetm_xport_free_addrv(fmd_hdl_t *hdl, etm_xport_addr_t *addrv)
733a5356058ae0150a67d61f0ad8e5260d2acae3rb int i; /* vector index */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb etm_xport_stats.xport_free_addrv_badargs.fmds_value.ui64++;
733a5356058ae0150a67d61f0ad8e5260d2acae3rb fmd_hdl_free(hdl, _addrv, (i + 1) * sizeof (_etm_xport_addr_t *));
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_free_addrv() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_get_addr_conn - indicate which connections in a NULL
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * terminated vector of connection
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * handles are associated with the
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * given transport address,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * return an allocated NULL terminated
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * vector of those connection handles,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * or NULL and set errno if none
733a5356058ae0150a67d61f0ad8e5260d2acae3rbetm_xport_get_addr_conn(fmd_hdl_t *hdl, etm_xport_conn_t *connv,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb _etm_xport_conn_t **_mcv; /* matching connections vector */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb int n; /* matching transport addr cnt */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb int i; /* vector index */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb etm_xport_stats.xport_get_addr_conn_badargs.fmds_value.ui64++;
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* count, allocate space for, and copy, all matching addrs */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb } /* for counting how many addresses match */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb _mcv = fmd_hdl_zalloc(hdl, (n + 1) * sizeof (_etm_xport_conn_t *),
733a5356058ae0150a67d61f0ad8e5260d2acae3rb } /* for copying matching address pointers */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return ((void *) _mcv);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_get_addr_conn() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_get_any_lcc - indicate which endpoint has undergone
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * a life cycle change and what that change
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * was (ex: came up), pending until a change
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * has occured for some/any endpoint,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * return the appropriate address handle,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * or NULL and set errno if problem
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * caveats:
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * this function maintains or accesses state/history
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * regarding life cycle changes of endpoints
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * if life cycle changes are rapid relative to how
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * frequently this function is called, fairness will
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * be provided among which endpoints are reported
733a5356058ae0150a67d61f0ad8e5260d2acae3rbetm_xport_get_any_lcc(fmd_hdl_t *hdl, etm_xport_lcc_t *lccp)
733a5356058ae0150a67d61f0ad8e5260d2acae3rb etm_xport_stats.xport_get_any_lcc_badargs.fmds_value.ui64++;
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * function not needed in FMA Phase 1 for sun4v/Ontario
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_get_any_lcc() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_fini - finish/teardown any transport infrastructure
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * after all connections are closed,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * return 0 or -errno value if teardown failed
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* destroy the xport access serialization lock */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* free any long standing properties from FMD */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* cleanup the intermediate read buffer */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb fmd_hdl_debug(hdl, "warning: xport %d bytes stale data\n",
733a5356058ae0150a67d61f0ad8e5260d2acae3rb fmd_hdl_free(hdl, etm_xport_irb_area, 2 * etm_xport_irb_mtu_sz);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (0);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_fini() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * ------------------------ input/output functions ---------------------------
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_read - try to read N bytes from the connection
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * into the given buffer,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * return how many bytes actually read
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * or -errno value
733a5356058ae0150a67d61f0ad8e5260d2acae3rbetm_xport_read(fmd_hdl_t *hdl, etm_xport_conn_t conn, void *buf,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (etm_xport_buffered_read(hdl, conn, buf, byte_cnt));
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_read() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_peek - same as etm_xport_read() but data is not dequeued
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * from the transport/connection; peeked data is
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * guaranteed by the transport to remain enqueued
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * if this process/thread crashes
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * caveats:
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * peeked data is NOT guaranteed by all platform transports
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * to remain enqueued if this process/thread crashes;
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * this casts some doubt on the utility of this func
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * transport does NOT support peek sizes > MTU
733a5356058ae0150a67d61f0ad8e5260d2acae3rbetm_xport_peek(fmd_hdl_t *hdl, etm_xport_conn_t conn, void *buf,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_peek() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_write - try to write N bytes to the connection
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * from the given buffer,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * return how many bytes actually written
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * or -errno value
733a5356058ae0150a67d61f0ad8e5260d2acae3rbetm_xport_write(fmd_hdl_t *hdl, etm_xport_conn_t conn, void *buf,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb int n; /* byte cnt */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (-EINVAL);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (n);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* write to the connection device's open file descriptor */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* errno assumed set by above call */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (n);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_write() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * ------------------------ miscellaneous functions --------------------------
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_get_opt - get a connection's transport option value,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * return the current value
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * or -errno value (ex: -ENOTSUP)
733a5356058ae0150a67d61f0ad8e5260d2acae3rbetm_xport_get_opt(fmd_hdl_t *hdl, etm_xport_conn_t conn, etm_xport_opt_t opt)
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (-EINVAL);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (n);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb if (n < 0) {
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* errno assumed set by above call */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (rv);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_get_opt() */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * etm_xport_set_opt - set a connection's transport option value,
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * return the value actually set
733a5356058ae0150a67d61f0ad8e5260d2acae3rb * or -errno value (ex: -ENOTSUP)
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (-EINVAL);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (n);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb if (n < 0) {
733a5356058ae0150a67d61f0ad8e5260d2acae3rb /* errno assumed set by above call */
733a5356058ae0150a67d61f0ad8e5260d2acae3rb return (-errno);
733a5356058ae0150a67d61f0ad8e5260d2acae3rb} /* etm_xport_set_opt() */