/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _DS_IMPL_H #define _DS_IMPL_H #ifdef __cplusplus extern "C" { #endif #include #include /* * The Domain Services Protocol * * The DS protocol is divided into two parts. The first is fixed and * must remain exactly the same for *all* versions of the DS protocol. * The only messages supported by the fixed portion of the protocol are * to negotiate a version to use for the rest of the protocol. */ /* * Domain Services Header */ typedef struct ds_hdr { uint32_t msg_type; /* message type */ uint32_t payload_len; /* payload length */ } ds_hdr_t; #define DS_HDR_SZ (sizeof (ds_hdr_t)) /* * DS Fixed Message Types */ #define DS_INIT_REQ 0x0 /* initiate DS connection */ #define DS_INIT_ACK 0x1 /* initiation acknowledgement */ #define DS_INIT_NACK 0x2 /* initiation negative acknowledgment */ /* * DS Fixed Initialization Messages */ typedef struct ds_init_req { uint16_t major_vers; /* requested major version */ uint16_t minor_vers; /* requested minor version */ } ds_init_req_t; typedef struct ds_init_ack { uint16_t minor_vers; /* highest supported minor version */ } ds_init_ack_t; typedef struct ds_init_nack { uint16_t major_vers; /* alternate supported major version */ } ds_init_nack_t; /* * DS Message Types for Version 1.0 */ #define DS_REG_REQ 0x3 /* register a service */ #define DS_REG_ACK 0x4 /* register acknowledgement */ #define DS_REG_NACK 0x5 /* register failed */ #define DS_UNREG 0x6 /* unregister a service */ #define DS_UNREG_ACK 0x7 /* unregister acknowledgement */ #define DS_UNREG_NACK 0x8 /* unregister failed */ #define DS_DATA 0x9 /* data message */ #define DS_NACK 0xa /* data error */ /* result codes */ #define DS_OK 0x0 /* success */ #define DS_REG_VER_NACK 0x1 /* unsupported major version */ #define DS_REG_DUP 0x2 /* duplicate registration attempted */ #define DS_INV_HDL 0x3 /* service handle not valid */ #define DS_TYPE_UNKNOWN 0x4 /* unknown message type received */ /* * Service Register Messages */ typedef struct ds_reg_req { uint64_t svc_handle; /* service handle to register */ uint16_t major_vers; /* requested major version */ uint16_t minor_vers; /* requested minor version */ char svc_id[1]; /* service identifier string */ } ds_reg_req_t; typedef struct ds_reg_ack { uint64_t svc_handle; /* service handle sent in register */ uint16_t minor_vers; /* highest supported minor version */ } ds_reg_ack_t; typedef struct ds_reg_nack { uint64_t svc_handle; /* service handle sent in register */ uint64_t result; /* reason for the failure */ uint16_t major_vers; /* alternate supported major version */ } ds_reg_nack_t; /* * Service Unregister Messages */ typedef struct ds_unreg_req { uint64_t svc_handle; /* service handle to unregister */ } ds_unreg_req_t; typedef struct ds_unreg_ack { uint64_t svc_handle; /* service handle sent in unregister */ } ds_unreg_ack_t; typedef struct ds_unreg_nack { uint64_t svc_handle; /* service handle sent in unregister */ } ds_unreg_nack_t; /* * Data Transfer Messages */ typedef struct ds_data_handle { uint64_t svc_handle; /* service handle for data */ } ds_data_handle_t; typedef struct ds_data_nack { uint64_t svc_handle; /* service handle sent in data msg */ uint64_t result; /* reason for failure */ } ds_data_nack_t; /* * Message Processing Utilities */ #define DS_MSG_TYPE_VALID(type) ((type) <= DS_NACK) #define DS_MSG_LEN(ds_type) (sizeof (ds_hdr_t) + sizeof (ds_type)) /* * Domain Service Port * * A DS port is a logical representation of an LDC dedicated to * communication between DS endpoints. The ds_port_t maintains state * associated with a connection to a remote endpoint. This includes * the state of the port, the LDC state, the current version of the * DS protocol in use on the port, and other port properties. * * Locking: The port is protected by a single mutex. It must be held * while the port structure is being accessed and also when data is * being read or written using the port */ typedef enum { DS_PORT_FREE, /* port structure not in use */ DS_PORT_INIT, /* port structure created */ DS_PORT_LDC_INIT, /* ldc successfully initialized */ DS_PORT_INIT_REQ, /* initialization handshake sent */ DS_PORT_READY /* init handshake completed */ } ds_port_state_t; typedef struct ds_ldc { uint64_t id; /* LDC id */ ldc_handle_t hdl; /* LDC handle */ ldc_status_t state; /* current LDC state */ } ds_ldc_t; typedef uint64_t ds_domain_hdl_t; #define DS_DHDL_INVALID ((ds_domain_hdl_t)0xffffffff) /* port flags */ #define DS_PORT_MUTEX_INITED 0x1 /* mutexes inited? */ typedef struct ds_port { uint32_t flags; /* port flags */ kmutex_t lock; /* port and service state lock */ kmutex_t tx_lock; /* tx port lock */ kmutex_t rcv_lock; /* rcv port lock */ uint64_t id; /* port id from MD */ ds_port_state_t state; /* state of the port */ ds_ver_t ver; /* DS protocol version in use */ uint32_t ver_idx; /* index of version during handshake */ ds_ldc_t ldc; /* LDC for this port */ ds_domain_hdl_t domain_hdl; /* LDOMs domain hdl assoc. with port */ char *domain_name; /* LDOMs domain name assoc. with port */ } ds_port_t; #define IS_DS_PORT(port) 1 /* VBSC code compatability */ #define PORTID(port) ((ulong_t)((port)->id)) #define PTR_TO_LONG(ptr) ((uint64_t)(ptr)) /* * A DS portset is a bitmap that represents a collection of DS * ports. Each bit represent a particular port id. We need * to allocate for the max. number of domains supported, * plus a small number (e.g. for the SP connection). */ #define DS_EXTRA_PORTS 16 #define DS_MAX_PORTS (LDOMS_MAX_DOMAINS + DS_EXTRA_PORTS) #define DS_PORTSET_SIZE BT_BITOUL(DS_MAX_PORTS) typedef ulong_t ds_portset_t[DS_PORTSET_SIZE]; extern ds_portset_t ds_nullport; #define DS_PORTID_INVALID ((uint64_t)-1) /* DS SP Port ID */ extern uint64_t ds_sp_port_id; #define DS_MAX_PORT_ID (DS_MAX_PORTS - 1) #define DS_PORT_IN_SET(set, port) BT_TEST((set), (port)) #define DS_PORTSET_ADD(set, port) BT_SET((set), (port)) #define DS_PORTSET_DEL(set, port) BT_CLEAR((set), (port)) #define DS_PORTSET_ISNULL(set) (memcmp((set), ds_nullport, \ sizeof (set)) == 0) #define DS_PORTSET_SETNULL(set) ((void)memset((set), 0, sizeof (set))) #define DS_PORTSET_DUP(set1, set2) ((void)memcpy((set1), (set2), \ sizeof (set1))) /* * A DS event consists of a buffer on a port. We explictly use a link to * enequeue/dequeue on non-Solaris environments. On Solaris we use taskq. */ typedef struct ds_event { ds_port_t *port; char *buf; size_t buflen; } ds_event_t; /* * LDC Information */ #define DS_STREAM_MTU 4096 /* * Machine Description Constants */ #define DS_MD_ROOT_NAME "domain-services" #define DS_MD_PORT_NAME "domain-services-port" #define DS_MD_CHAN_NAME "channel-endpoint" /* * DS Services * * A DS Service is a mapping between a DS capability and a client * of the DS framework that provides that capability. It includes * information on the state of the service, the currently negotiated * version of the capability specific protocol, the port that is * currently in use by the capability, etc. */ typedef enum { DS_SVC_INVAL, /* svc structure uninitialized */ DS_SVC_FREE, /* svc structure not in use */ DS_SVC_INACTIVE, /* svc not registered */ DS_SVC_REG_PENDING, /* register message sent */ DS_SVC_ACTIVE, /* register message acknowledged */ DS_SVC_UNREG_PENDING /* unregister is pending */ } ds_svc_state_t; /* ds_svc flags bits */ #define DSSF_ISCLIENT 0x0001 /* client service */ #define DSSF_ISUSER 0x0002 /* user land service */ #define DSSF_REGCB_VALID 0x0004 /* ops register callback is valid */ #define DSSF_UNREGCB_VALID 0x0008 /* ops unregister callback is valid */ #define DSSF_DATACB_VALID 0x0010 /* ops data callback is valid */ #define DSSF_LOOPBACK 0x0020 /* loopback */ #define DSSF_PEND_UNREG 0x0040 /* pending unregister */ #define DSSF_ANYCB_VALID (DSSF_REGCB_VALID | DSSF_UNREGCB_VALID | \ DSSF_DATACB_VALID) #define DSSF_USERFLAGS (DSSF_ISCLIENT | DSSF_ISUSER | DSSF_ANYCB_VALID) typedef struct ds_svc { ds_capability_t cap; /* capability information */ ds_clnt_ops_t ops; /* client ops vector */ ds_svc_hdl_t hdl; /* handle assigned by DS */ ds_svc_hdl_t svc_hdl; /* remote svc hdl if client svc */ ds_svc_state_t state; /* current service state */ ds_ver_t ver; /* svc protocol version in use */ uint_t ver_idx; /* index into client version array */ ds_port_t *port; /* port for this service */ ds_portset_t avail; /* ports available to this service */ ds_portset_t tried; /* ports tried by this service */ int fixed; /* is svc fixed to port */ uint_t flags; /* service flags */ ds_cb_arg_t uarg; /* user arg for user callbacks */ uint_t drvi; /* driver instance */ void *drv_psp; /* driver per svc ptr */ } ds_svc_t; typedef struct ds_svcs { ds_svc_t **tbl; /* ptr to table */ kmutex_t lock; uint_t maxsvcs; /* size of the table */ uint_t nsvcs; /* current number of items */ } ds_svcs_t; #define DS_SVC_ISFREE(svc) ((svc == NULL) || (svc->state == DS_SVC_FREE)) #ifndef DS_MAXSVCS_INIT #define DS_MAXSVCS_INIT 32 #endif /* * A service handle is a 64 bit value with three pieces of information * encoded in it. The upper 32 bits is the index into the table of * a particular service structure. Bit 31 indicates whether the handle * represents a service privider or service client. The lower 31 bits is * a counter that is incremented each time a service structure is reused. */ #define DS_IDX_SHIFT 32 #define DS_COUNT_MASK 0x7fffffffull #define DS_HDL_ISCLIENT_BIT 0x80000000ull #define DS_ALLOC_HDL(_idx, _count) (((uint64_t)_idx << DS_IDX_SHIFT) | \ ((uint64_t)(_count + 1) & \ DS_COUNT_MASK)) #define DS_HDL2IDX(hdl) (hdl >> DS_IDX_SHIFT) #define DS_HDL2COUNT(hdl) (hdl & DS_COUNT_MASK) #define DS_HDL_ISCLIENT(hdl) ((hdl) & DS_HDL_ISCLIENT_BIT) #define DS_HDL_SET_ISCLIENT(hdl) ((hdl) |= DS_HDL_ISCLIENT_BIT) #define DS_INVALID_INSTANCE (-1) /* enable/disable taskq processing */ extern boolean_t ds_enabled; /* * DS Message Logging * * The DS framework logs all incoming and outgoing messages to a * ring buffer. This provides the ability to reconstruct a trace * of DS activity for use in debugging. In addition to the message * data, each log entry contains a timestamp and the destination * of the message. The destination is based on the port number the * message passed through (port number + 1). The sign of the dest * field distinguishes incoming messages from outgoing messages. * Incoming messages have a negative destination field. */ typedef struct ds_log_entry { struct ds_log_entry *next; /* next in log or free list */ struct ds_log_entry *prev; /* previous in log */ time_t timestamp; /* time message added to log */ size_t datasz; /* size of the data */ void *data; /* the data itself */ int32_t dest; /* message destination */ } ds_log_entry_t; #define DS_LOG_IN(pid) (-(pid + 1)) #define DS_LOG_OUT(pid) (pid + 1) /* * DS Log Limits: * * The size of the log is controlled by two limits. The first is * a soft limit that is configurable by the user (via the global * variable ds_log_sz). When this limit is exceeded, each new * message that is added to the log replaces the oldest message. * * The second is a hard limit that is calculated based on the soft * limit (DS_LOG_LIMIT). It is defined to be ~3% above the soft limit. * Once this limit is exceeded, a thread is scheduled to delete old * messages until the size of the log is below the soft limit. */ #define DS_LOG_DEFAULT_SZ (4 * 1024 * 1024) /* 4 MB */ #define DS_LOG_LIMIT (ds_log_sz + (ds_log_sz >> 5)) #define DS_LOG_ENTRY_SZ(ep) (sizeof (ds_log_entry_t) + (ep)->datasz) /* * DS Log Memory Usage: * * The log free list is initialized from a pre-allocated pool of entry * structures (the global ds_log_entry_pool). The number of entries * in the pool (DS_LOG_NPOOL) is the number of entries that would * take up half the default size of the log. * * As messages are added to the log, entry structures are pulled from * the free list. If the free list is empty, memory is allocated for * the entry. When entries are removed from the log, they are placed * on the free list. Allocated memory is only deallocated when the * entire log is destroyed. */ #define DS_LOG_NPOOL ((DS_LOG_DEFAULT_SZ >> 1) / \ sizeof (ds_log_entry_t)) #define DS_LOG_POOL_END (ds_log_entry_pool + DS_LOG_NPOOL) #define DS_IS_POOL_ENTRY(ep) (((ep) >= ds_log_entry_pool) && \ ((ep) < &(ds_log_entry_pool[DS_LOG_NPOOL]))) /* VBSC code compatability related defines */ /* VBSC malloc/free are similar to user malloc/free */ #define DS_MALLOC(size) kmem_zalloc(size, KM_SLEEP) #define DS_FREE(ptr, size) kmem_free(ptr, size) /* VBSC debug print needs newline, Solaris cmn_err doesn't */ #define DS_EOL /* * Results of checking version array with ds_vers_isvalid() */ typedef enum { DS_VERS_OK, DS_VERS_INCREASING_MAJOR_ERR, DS_VERS_INCREASING_MINOR_ERR } ds_vers_check_t; /* System specific interfaces */ extern void ds_sys_port_init(ds_port_t *port); extern void ds_sys_port_fini(ds_port_t *port); extern void ds_sys_drain_events(ds_port_t *port); extern int ds_sys_dispatch_func(void (func)(void *), void *arg); extern void ds_sys_ldc_init(ds_port_t *port); /* vlds cb access to svc structure */ void ds_cbarg_get_hdl(ds_cb_arg_t arg, ds_svc_hdl_t *hdlp); void ds_cbarg_get_flags(ds_cb_arg_t arg, uint32_t *flagsp); void ds_cbarg_get_drv_info(ds_cb_arg_t arg, int *drvip); void ds_cbarg_get_drv_per_svc_ptr(ds_cb_arg_t arg, void **dpspp); void ds_cbarg_get_domain(ds_cb_arg_t arg, ds_domain_hdl_t *dhdlp); void ds_cbarg_get_service_id(ds_cb_arg_t arg, char **servicep); void ds_cbarg_set_drv_per_svc_ptr(ds_cb_arg_t arg, void *dpsp); int ds_hdl_get_cbarg(ds_svc_hdl_t hdl, ds_cb_arg_t *cbargp); void ds_cbarg_set_cookie(ds_svc_t *svc); int ds_is_my_hdl(ds_svc_hdl_t hdl, int instance); void ds_set_my_dom_hdl_name(ds_domain_hdl_t dhdl, char *name); /* initialization functions */ void ds_common_init(void); int ds_ldc_fini(ds_port_t *port); void ds_init_svcs_tbl(uint_t nentries); /* message sending functions */ void ds_send_init_req(ds_port_t *port); int ds_send_unreg_req(ds_svc_t *svc); /* walker functions */ typedef int (*svc_cb_t)(ds_svc_t *svc, void *arg); int ds_walk_svcs(svc_cb_t svc_cb, void *arg); int ds_svc_ismatch(ds_svc_t *svc, void *arg); int ds_svc_free(ds_svc_t *svc, void *arg); int ds_svc_register(ds_svc_t *svc, void *arg); /* service utilities */ ds_svc_t *ds_alloc_svc(void); ds_svc_t *ds_sys_find_svc_by_id_port(char *svc_id, ds_port_t *port, int is_client); ds_svc_t *ds_get_svc(ds_svc_hdl_t hdl); /* port utilities */ void ds_port_common_init(ds_port_t *port); void ds_port_common_fini(ds_port_t *port); /* misc utilities */ ds_vers_check_t ds_vers_isvalid(ds_ver_t *vers, int nvers); char *ds_errno_to_str(int ds_errno, char *ebuf); char *ds_strdup(char *str); boolean_t negotiate_version(int num_versions, ds_ver_t *sup_versionsp, uint16_t req_major, uint16_t *new_majorp, uint16_t *new_minorp); /* log functions */ int ds_log_add_msg(int32_t dest, uint8_t *msg, size_t sz); /* vlds driver interfaces to ds module */ int ds_ucap_init(ds_capability_t *cap, ds_clnt_ops_t *ops, uint_t flags, int instance, ds_svc_hdl_t *hdlp); int ds_unreg_hdl(ds_svc_hdl_t hdl); int ds_hdl_lookup(char *service, uint_t is_client, ds_svc_hdl_t *hdlp, uint_t maxhdls, uint_t *nhdlsp); int ds_service_lookup(ds_svc_hdl_t hdl, char **servicep, uint_t *is_client); int ds_domain_lookup(ds_svc_hdl_t hdl, ds_domain_hdl_t *dhdlp); int ds_hdl_isready(ds_svc_hdl_t hdl, uint_t *is_ready); void ds_unreg_all(int instance); int ds_dom_name_to_hdl(char *domain_name, ds_domain_hdl_t *dhdlp); int ds_dom_hdl_to_name(ds_domain_hdl_t dhdl, char **domain_namep); int ds_add_port(uint64_t port_id, uint64_t ldc_id, ds_domain_hdl_t dhdl, char *dom_name, int verbose); int ds_remove_port(uint64_t portid, int is_fini); /* ds_ucap_init flags */ #define DS_UCAP_CLNT 0x0 /* Service is Client */ #define DS_UCAP_SVC 0x1 /* Service is Server */ /* * Error buffer size for ds_errno_to_str */ #define DS_EBUFSIZE 80 /* * Debugging Features */ #ifdef DEBUG #define DS_DBG_BASIC 0x001 #define DS_DBG_FLAG_LDC 0x002 #define DS_DBG_FLAG_LOG 0x004 #define DS_DBG_DUMP_LDC_MSG 0x008 #define DS_DBG_FLAG_MD 0x010 #define DS_DBG_FLAG_USR 0x020 #define DS_DBG_FLAG_VLDS 0x040 #define DS_DBG_FLAG_PRCL 0x080 #define DS_DBG_FLAG_RCVQ 0x100 #define DS_DBG_FLAG_LOOP 0x200 #define DS_DBG if (ds_debug & DS_DBG_BASIC) cmn_err #define DS_DBG_LDC if (ds_debug & DS_DBG_FLAG_LDC) cmn_err #define DS_DBG_LOG if (ds_debug & DS_DBG_FLAG_LOG) cmn_err #define DS_DBG_MD if (ds_debug & DS_DBG_FLAG_MD) cmn_err #define DS_DBG_USR if (ds_debug & DS_DBG_FLAG_USR) cmn_err #define DS_DBG_VLDS if (ds_debug & DS_DBG_FLAG_VLDS) cmn_err #define DS_DBG_PRCL if (ds_debug & DS_DBG_FLAG_PRCL) cmn_err #define DS_DBG_RCVQ if (ds_debug & DS_DBG_FLAG_RCVQ) cmn_err #define DS_DBG_LOOP if (ds_debug & DS_DBG_FLAG_LOOP) cmn_err #define DS_DUMP_MSG(flags, buf, len) if (ds_debug & (flags)) \ ds_dump_msg(buf, len) extern uint_t ds_debug; void ds_dump_msg(void *buf, size_t len); #define DS_BADHDL1 (ds_svc_hdl_t)(0xdeadbed1deadbed1ull) #define DS_BADHDL2 (ds_svc_hdl_t)(0x2deadbed2deadbedull) #else /* DEBUG */ #define DS_DBG if (0) cmn_err #define DS_DBG_LDC DS_DBG #define DS_DBG_LOG DS_DBG #define DS_DBG_MD DS_DBG #define DS_DBG_USR DS_DBG #define DS_DBG_VLDS DS_DBG #define DS_DBG_PRCL DS_DBG #define DS_DBG_RCVQ DS_DBG #define DS_DBG_LOOP DS_DBG #define DS_DUMP_MSG(flags, buf, len) #define DS_DUMP_LDC_MSG(buf, len) #define DS_BADHDL1 (ds_svc_hdl_t)0 #define DS_BADHDL2 (ds_svc_hdl_t)0 #endif /* DEBUG */ #ifdef __cplusplus } #endif #endif /* _DS_IMPL_H */