/*
 * Copyright (c) 1999-2001 by Sun Microsystems, Inc.
 * All rights reserved.
 */

#ifndef	_SYS_RSM_RSMKA_PATH_INT_H
#define	_SYS_RSM_RSMKA_PATH_INT_H

#pragma ident	"@(#)rsmka_path_int.h	1.2	01/11/01 SMI"

#ifdef	__cplusplus
extern "C" {
#endif

#include <sys/rsm/rsm_common.h>
#include <sys/rsm/rsm.h>
#include <sys/rsm/rsmpi.h>

/*
 * Taskq setup
 * Only one taskq thread is created and only one task is executed
 * the task is executed as an infinite loop
 */
#define	RSMKA_ONE_THREAD	1
#define	RSMKA_ONE_TASK		1

/* Path (path_t) States */
#define	RSMKA_PATH_DOWN	1
#define	RSMKA_PATH_UP	2
#define	RSMKA_PATH_ACTIVE	3
#define	RSMKA_PATH_GOING_DOWN	4

#define	RSMKA_OPCODE_TYPES	2

/*
 * Deferred Work Token Index
 */
#define	RSMKA_IPC_DOWN_INDEX	0
#define	RSMKA_IPC_UP_INDEX	1

/* Deferred Work Opcodes */
#define	RSMKA_IPC_DOWN	1
#define	RSMKA_IPC_UP	2

/* Flags */
#define	RSMKA_NO_SLEEP			1
#define	RSMKA_USE_COOKIE		2
#define	RSMKA_NOHOLD			4


/*
 * A work token is enqueued on the workqueue (singly linked list)
 * when pathup or pathdown processing is to be done by the deferred work
 * thread.  Token are enqueued at the end of the queue and processed
 * from the front of the queue.
 */
typedef struct work_token {
	struct work_token	*next;		/* pointer to next token */
	int			opcode;		/* opcode for work to do */
} work_token_t;

typedef struct workqueue {
	work_token_t	*head;		/* start of work queue		*/
	work_token_t	*tail;		/* end of work queue		*/
	kmutex_t	work_mutex;	/* protects queue add/delete    */
	kcondvar_t	work_cv;	/* synchronize deferred thread  */
} work_queue_t;

/*
 * a pointer to srv_handler_arg is registered along with the handler
 * and is passed to the rsm_srv_func - the service handler when it
 * is invoked.
 */
typedef struct srv_handler_arg {
	char		adapter_name[MAXNAMELEN];
	int		adapter_instance;
	rsm_addr_t	adapter_hwaddr;
} srv_handler_arg_t;

typedef struct msgbuf_elem {
	boolean_t		active;
	rsmipc_request_t	msg;
} msgbuf_elem_t;

/*
 * receive buffer object
 * procmsg_cnt - receivers count of messages processed since sending credits
 * msgbuf_queue - an array-based circular queue of messages received
 * msgbuf_head - index pointing to the head of msgbuf_queue
 * msgbuf_head - index pointing to the tail of msgbuf_queue
 * msgbuf_cnt - number of valid entries in msgbuf_queue
 */
typedef struct recv_info {
	int				procmsg_cnt;
	int				rem_sendq_ready;
	taskq_t				*recv_taskq;
	msgbuf_elem_t			*msgbuf_queue;
	int				msgbuf_head;
	int				msgbuf_tail;
	int				msgbuf_cnt;
} recv_info_t;

/*
 * sendq_tokens are inserted in a circular list of the ipc_info descriptor
 * when a path is added for a remote node.  When the path is active the
 * rsmpi_sendq_handle will be valid and the sendq token can be used for
 * ipc.  The sendq_tokens are used in a round robin fashion.
 *
 * msgbuf_avail - used by sender, number of avail slots in recvrs msgbuf_queue
 */
typedef struct sendq_token {
	struct sendq_token		*next;
	rsm_send_q_handle_t		rsmpi_sendq_handle;
	int				ref_cnt;
	int				msgbuf_avail;
	kcondvar_t			sendq_cv;
}sendq_token_t;




typedef struct path {
	struct path		*next_path;
	rsm_node_id_t		remote_node;
	int			remote_devinst;
	rsm_addr_t		remote_hwaddr;
	int			state;
	int			flags;
#define	RSMKA_WAIT_FOR_SQACK	0x0001	/* waiting for SQREADY_ACK	*/
#define	RSMKA_SQCREATE_PENDING	0x0002	/* sendq_create is pending	*/
	kmutex_t		mutex;
	struct adapter		*local_adapter;
	sendq_token_t		sendq_token;
	work_token_t		work_token[RSMKA_OPCODE_TYPES];
	recv_info_t		recv_buffer;
#define	procmsg_cnt	recv_buffer.procmsg_cnt
#define	rem_sendq_ready	recv_buffer.rem_sendq_ready
#define	msgbuf_queue	recv_buffer.msgbuf_queue
#define	msgbuf_head	recv_buffer.msgbuf_head
#define	msgbuf_tail	recv_buffer.msgbuf_tail
#define	msgbuf_cnt	recv_buffer.msgbuf_cnt
#define	recv_taskq	recv_buffer.recv_taskq
	int64_t			local_incn;
	int64_t			remote_incn;
#define	RSM_UNKNOWN_INCN	0
	int			ref_cnt;
	kcondvar_t 		hold_cv;
} path_t;


typedef struct adapter {
	struct adapter		*next;
	struct adapter_listhead *listhead;
	int			ref_cnt;
	kmutex_t		mutex;
	int			instance;
	dev_info_t		*dip;
	rsm_addr_t		hwaddr;
	path_t			*next_path;
	rsm_controller_handle_t rsmpi_handle;
	rsm_controller_attr_t	rsm_attr;
	rsm_ops_t		*rsmpi_ops;
	srv_handler_arg_t	*hdlr_argp;
} adapter_t;


/*
typedef struct {
	adapter_t		*next_chunk;
	int			base;
	int			next_index;
	int			used_count;
	adapter_t		*phys_adapters[MAX_CHUNK_INDEX];
} adapter_map_chunks_t;
*/


/*
 * There is one adapter_listhead for each adapter devname. This
 * adapter_listhead stores the number of adapters belonging to
 * it. It also stores the number of paths for all the adapters
 * belonging to it.
 */
typedef struct adapter_listhead {
	struct adapter_listhead	*next_listhead;
	char			adapter_devname[MAXNAMELEN];
	adapter_t		*next_adapter;
	int			ref_cnt;
	kmutex_t		mutex;
	int			adapter_count;
	int			path_count;
} adapter_listhead_t;


struct adapter_listhead_list {
	adapter_listhead_t	*next;
	kmutex_t		listlock;
};


/*
 * One ipc_info descriptor for each remote node
 */
typedef struct ipc_info {
	struct ipc_info			*next;
	rsm_node_id_t			remote_node;
	boolean_t			node_is_alive;
	sendq_token_t			*token_list;
	sendq_token_t			*current_token;
	kmutex_t			token_list_mutex;
	int				ref_cnt;
} ipc_info_t;


#define	SQ_TOKEN_TO_PATH(token) 	\
	((path_t *)((char *)(token) - ((char *)(&((path_t *)0)->sendq_token))))



#define	WORK_TOKEN_TO_PATH(token, index) \
	((path_t *)((char *)(token) - 	\
		((char *)(&((path_t *)0)->work_token[(index)]))))




/*
 * Descriptor Reference Count macros
 */

#define	ADAPTER_HOLD(adapter)	{	\
		mutex_enter(&((adapter)->mutex)); 	\
		(adapter)->ref_cnt++;		\
		ASSERT((adapter)->ref_cnt != 0);	\
		mutex_exit(&((adapter)->mutex));	\
}

#define	ADAPTER_RELE(adapter)	{			\
		mutex_enter(&((adapter)->mutex)); 	\
		(adapter)->ref_cnt--;			\
		ASSERT((adapter)->ref_cnt >= 0);	\
		mutex_exit(&((adapter)->mutex));	\
}

#define	ADAPTER_RELE_NOLOCK(adapter)	{		\
		ASSERT(MUTEX_HELD(&(adapter)->mutex));	\
		(adapter)->ref_cnt--;			\
		ASSERT((adapter)->ref_cnt >= 0);	\
}

#define	PATH_HOLD(path)	{			\
		mutex_enter(&(path)->mutex); 	\
		(path)->ref_cnt++;		\
		ASSERT((path)->ref_cnt != 0);	\
		mutex_exit(&(path)->mutex);	\
}

#define	PATH_HOLD_NOLOCK(path)	{			\
		ASSERT(MUTEX_HELD(&(path)->mutex));	\
		(path)->ref_cnt++;			\
		ASSERT((path)->ref_cnt != 0);		\
}

#define	PATH_RELE(path)	{				\
		mutex_enter(&(path)->mutex); 		\
		(path)->ref_cnt--;			\
		ASSERT((path)->ref_cnt >= 0);		\
		if ((path)->ref_cnt == 0)		\
			cv_signal(&(path)->hold_cv);	\
		mutex_exit(&(path)->mutex);		\
}

#define	PATH_RELE_NOLOCK(path)	{			\
		ASSERT(MUTEX_HELD(&(path)->mutex));	\
		(path)->ref_cnt--;			\
		ASSERT((path)->ref_cnt >= 0);		\
		if ((path)->ref_cnt == 0)		\
			cv_signal(&(path)->hold_cv);	\
}

#define	SENDQ_TOKEN_HOLD(path)	{				\
		(path)->sendq_token.ref_cnt++;			\
		ASSERT((path)->sendq_token.ref_cnt != 0);	\
}

#define	SENDQ_TOKEN_RELE(path)	{					\
		(path)->sendq_token.ref_cnt--;				\
		ASSERT((path)->sendq_token.ref_cnt >= 0);		\
		if ((path)->sendq_token.ref_cnt == 0)			\
			cv_signal(&(path)->sendq_token.sendq_cv);	\
}

#define	IPCINFO_HOLD(ipc_info)	{			\
		mutex_enter(&ipc_info_lock); 		\
		(ipc_info)->ref_cnt++;			\
		ASSERT((ipc_info)->ref_cnt != 0); 	\
		mutex_exit(&ipc_info_lock);		\
}

#define	IPCINFO_HOLD_NOLOCK(ipc_info)	{		\
		ASSERT(MUTEX_HELD(&ipc_info_lock));	\
		(ipc_info)->ref_cnt++;			\
		ASSERT((ipc_info)->ref_cnt != 0); 	\
}

#define	IPCINFO_RELE(ipc_info)	{			\
		mutex_enter(&ipc_info_lock); 		\
		(ipc_info)->ref_cnt--;			\
		ASSERT((ipc_info)->ref_cnt >= 0); 	\
		mutex_exit(&ipc_info_lock);		\
}

#define	IPCINFO_RELE_NOLOCK(ipc_info)	{		\
		ASSERT(MUTEX_HELD(&ipc_info_lock));	\
		(ipc_info)->ref_cnt--;			\
		ASSERT((ipc_info)->ref_cnt >= 0); 	\
}
/*
 * Topology data structures - The primary structure is struct rsm_topology_t
 * The key interconnect data required for segment operations includes the
 * cluster nodeids and the controllers (name, hardware address); with
 * the fundamental constraint that the controller specified for a segment
 * import must have a physical connection with the contorller used in the
 * export of the segment. To facilitate applications in the establishment
 * of proper and efficient export and import policies, a delineation of the
 * interconnect topology is provided by these data structures.
 *
 * A pointer to an instance of this structure type is returned by a call
 * to rsm_get_interconnect_topology(). The application is responsible for
 * calling rsm_free_interconnect_topology() to free the allocated memory.
 *
 * Note: the rsmka_connections_t structure should be always double-word
 *	aligned.
 */


#define	RSM_CONNECTION_ACTIVE	3


typedef struct {
	rsm_node_id_t		local_nodeid;
	int			local_cntlr_count;
} rsmka_topology_hdr_t;

typedef struct {
	char		cntlr_name[MAXNAMELEN];
	rsm_addr_t	local_hwaddr;
	int		remote_cntlr_count;
} rsmka_connections_hdr_t;


/*
 * An application must not attempt to use a connection unless the
 * the connection_state element of struct remote_cntlr_t is equal to
 * RSM_CONNECTION_ACTIVE
 */
typedef struct {
	rsm_node_id_t		remote_nodeid;
	char			remote_cntlrname[MAXNAMELEN];
	rsm_addr_t		remote_hwaddr;
	uint_t			connection_state;
} rsmka_remote_cntlr_t;


/*
 * The actual size of the remote_cntlr array is equal to the remote_cntlr_count
 * of the connections_hdr_t struct.
 */
typedef struct {
	rsmka_connections_hdr_t	hdr;
	rsmka_remote_cntlr_t	remote_cntlr[1];
} rsmka_connections_t;

/*
 * A pointer to an instance of this structure type is returned by a call
 * to rsm_get_interconnect_topology().  The actual size of the connections
 * array is equal to the local_cntlr_count of the topology_hdr_t struct.
 */
typedef struct {
	rsmka_topology_hdr_t	topology_hdr;
	caddr_t			connections[1];
} rsmka_topology_t;

#ifdef _SYSCALL32
typedef struct {
	rsmka_topology_hdr_t	topology_hdr;
	caddr32_t		connections[1];
} rsmka_topology32_t;
#endif

#ifdef	__cplusplus
}
#endif

#endif	/* _SYS_RSM_RSMKA_PATH_INT_H */
