/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License, Version 1.0 only
 * (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 2005 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#ifndef _SYS_IB_IBNEX_IBNEX_H
#define	_SYS_IB_IBNEX_IBNEX_H

#pragma ident	"%Z%%M%	%I%	%E% SMI"

/*
 * ibnex.h
 * This file contains defines and structures used within the IB Nexus
 */

#ifdef __cplusplus
extern "C" {
#endif

#include <sys/sunndi.h>

/* Defines for return codes within the IB nexus driver */
typedef enum {
	IBNEX_SUCCESS =	0,
	IBNEX_FAILURE = -1,
	IBNEX_OFFLINE_FAILED = -2,
	IBNEX_BUSY = -3,
	IBNEX_INVALID_NODE = -4
} ibnex_rval_t;


/* IOC device node specific data */
typedef struct ibnex_ioc_node_s {
	ib_guid_t		iou_guid;	/* GUID of the IOU */
	ib_guid_t		ioc_guid;	/* GUID of the IOC */
	char			ioc_id_string[IB_DM_IOC_ID_STRING_LEN];
	uint32_t		ioc_ngids;
	/* This field will be non NULL only for diconnected IOCs */
	ib_dm_ioc_ctrl_profile_t	*ioc_profile;
} ibnex_ioc_node_t;

/* DLPI device node specific data */
typedef struct ibnex_port_node_s {
	uint8_t			port_num;
	int			port_commsvc_idx;
	ib_guid_t		port_guid;
	ib_guid_t		port_hcaguid;
	ib_pkey_t		port_pkey;
} ibnex_port_node_t;

/* Pseudo device node specific data */
typedef struct ibnex_pseudo_node_s {
	char			*pseudo_node_addr;	/* node addr of drvr */
	char			*pseudo_unit_addr;	/* unit addr of drvr */
	int			pseudo_unit_addr_len;	/* unit addr len */
	char			*pseudo_devi_name;	/* name of driver */
	int			pseudo_new_node;	/* new node */
	int			pseudo_merge_node;	/* merge node */
} ibnex_pseudo_node_t;

/*
 * Defines for Child device node types. Note that these values are also
 * in use by usr/src/lib/cfgadm_plugins/ib/common/cfga_ib.h.
 * Any changes to these need to be reflected in that file as well.
 */
typedef enum {
	IBNEX_PORT_COMMSVC_NODE,
	IBNEX_VPPA_COMMSVC_NODE,
	IBNEX_HCASVC_COMMSVC_NODE,
	IBNEX_IOC_NODE,
	IBNEX_PSEUDO_NODE
} ibnex_node_type_t;


/*
 * Defines for Child device node state:
 *
 * By default the node is set to CONFIGURED state.
 *	CONFIGURED:---(bus_config/cfgadm configure)---->CONFIGURED
 *	CONFIGURED:----(cfgadm unconfigure:success)--->UNCONFIGURED
 *	CONFIGURED:----(cfgadm unconfigure:fail)--->still CONFIGURED
 *	UNCONFIGURED:----(cfgadm configure:success)--->CONFIGURED
 *
 * We maintain two additional states:
 *	CONFIGURING:---(bus_config/cfgadm configure in progress
 *	UNCONFIGURING:--(cfgadm unconfigure in progress)
 * This is maintained to avoid race conditions between multiple cfgadm
 * operations.
 */
typedef enum ibnex_node_state_e {
	IBNEX_CFGADM_CONFIGURED,	/* node is "configured" */
	IBNEX_CFGADM_UNCONFIGURED,	/* node is "unconfigured" */
	IBNEX_CFGADM_CONFIGURING,	/* node getting configured */
	IBNEX_CFGADM_UNCONFIGURING	/* node getting unconfigured */
} ibnex_node_state_t;

/*
 * Defines for reprobe_state:
 * 	IBNEX_NODE_REPROBE_NOTIFY_ON_UPDATE
 *		Reprobe and notify if there is a property update
 *	IBNEX_NODE_REPROBE_NOTIFY_ALWAYS
 *		Reprobe and notify always.
 *	IBNEX_NODE_REPROBE_IOC_WAIT
 *		Reprobe for IOC apid waiting
 *
 * Device reprobes triggered by ibt_reprobe_dev will result in an DDI
 * event, even though no prepoerties have changed.
 */
#define	IBNEX_NODE_REPROBE_NOTIFY_ON_UPDATE	0x01
#define	IBNEX_NODE_REPROBE_NOTIFY_ALWAYS	0x02
#define	IBNEX_NODE_REPROBE_IOC_WAIT			0x04

/* Node specific information, stored as dev_info_t private data */
typedef struct ibnex_node_data_s {
	dev_info_t		*node_dip;
	union {
		ibnex_ioc_node_t	ioc_node;
		ibnex_port_node_t	port_node;
		ibnex_pseudo_node_t	pseudo_node;
	} node_data;
	struct ibnex_node_data_s *node_next;
	struct ibnex_node_data_s *node_prev;
	ibnex_node_type_t	node_type;
	ibnex_node_state_t	node_state;
	int			node_reprobe_state;	/* Node reprobe flag */
} ibnex_node_data_t;

/*
 * The fields of IOC and Port node are initialized when the
 * device node is created. These are read only for the rest
 * of the IBnexus driver.
 */
_NOTE(SCHEME_PROTECTS_DATA("stable data", ibnex_ioc_node_s))
_NOTE(SCHEME_PROTECTS_DATA("stable data", ibnex_port_node_s))
_NOTE(SCHEME_PROTECTS_DATA("stable data", ibnex_pseudo_node_s))
_NOTE(SCHEME_PROTECTS_DATA("stable data", ibnex_node_data_s))

#define	IBNEX_VALID_NODE_TYPE(n)	\
	(((n)->node_type == IBNEX_PORT_COMMSVC_NODE) || \
	((n)->node_type == IBNEX_VPPA_COMMSVC_NODE) || \
	((n)->node_type == IBNEX_HCASVC_COMMSVC_NODE) || \
	((n)->node_type == IBNEX_IOC_NODE) || \
	((n)->node_type == IBNEX_PSEUDO_NODE))

#define	IBNEX_COMMSVC_NODE_TYPE(n)	\
	(((n)->node_type == IBNEX_PORT_COMMSVC_NODE) || \
	((n)->node_type == IBNEX_VPPA_COMMSVC_NODE) || \
	((n)->node_type == IBNEX_HCASVC_COMMSVC_NODE))

/*
 * Definition for the IB nexus global per-instance structure.
 * IB nexus supports only one instance.
 */
typedef struct ibnex_s {
	dev_info_t		*ibnex_dip;
	kmutex_t		ibnex_mutex;
	int			ibnex_num_comm_svcs;
	char			**ibnex_comm_svc_names;
	int			ibnex_nvppa_comm_svcs;
	char			**ibnex_vppa_comm_svc_names;
	int			ibnex_nhcasvc_comm_svcs;
	char			**ibnex_hcasvc_comm_svc_names;
	ibnex_node_data_t	*ibnex_port_node_head;
	ibnex_node_data_t	*ibnex_ioc_node_head;
	ibnex_node_data_t	*ibnex_pseudo_node_head;

	/*
	 * NDI Event handle for -all- ibnexus events
	 * Event Cookie for IB_PROP_UPDATE_EVENT event
	 */
	ndi_event_hdl_t		ibnex_ndi_event_hdl;
	ddi_eventcookie_t	ibnex_prop_update_evt_cookie;

	/* Flags & condition variables for reprobe handling */
	int					ibnex_reprobe_state;
	kcondvar_t			ibnex_reprobe_cv;

	/* Count of disconnected IOCs still configured */
	int					ibnex_num_disconnect_iocs;

	/* Pseudo nodes inited from ibnex_get_snapshot? */
	int			ibnex_pseudo_inited;
} ibnex_t;

/*
 * States for ibnex_reprobe_state
 *	0 to REPROBE_ALL_PROGRESS
 *		Reprobe all when no reprobes pending
 *	REPROBE_ALL_PROGRESS to REPROBE_ALL_WAIT
 *		Reprobe all request when another in progress
 *	0 to REPROBE_IOC_WAIT
 *		Waiting for One or more reprobe_ioc to complete
 *
 * Reprobe logic will ensure :
 *	1. A single reprobe all at any time.
 *	2. No individual IOC reprobe overlaps with reprobe all.
 *	3. Reprobe for multiple IOCs can be in parallel
 *	4. Single reprobe for each IOC.
 */
#define	IBNEX_REPROBE_ALL_PROGRESS	0x01
#define	IBNEX_REPROBE_ALL_WAIT		0x02
#define	IBNEX_REPROBE_IOC_WAIT		0x04

/* Defines for creating and binding device nodes.  */
#define	IBNEX_MAX_COMPAT_NAMES		6
#define	IBNEX_MAX_IBPORT_COMPAT_NAMES	3
#define	IBNEX_MAX_COMPAT_LEN		48
#define	IBNEX_MAX_COMPAT_PROP_SZ	\
	IBNEX_MAX_COMPAT_NAMES * IBNEX_MAX_COMPAT_LEN
#define	IBNEX_MAX_IBPORT_COMPAT_PROP_SZ	\
	IBNEX_MAX_IBPORT_COMPAT_NAMES * IBNEX_MAX_COMPAT_LEN
#define	IBNEX_DEVFS_ENUMERATE		0x1	/* enumerate via devfs(7fs) */
#define	IBNEX_CFGADM_ENUMERATE		0x2	/* enumerate via cfgadm */

#define	IBNEX_MAX_NODEADDR_SZ		35

/* Define for forming the unit address from GUID and class string */
#define	IBNEX_FORM_GUID(buf, size, guid) \
		(void) snprintf((buf), (size), "%llX", (longlong_t)guid);

#define	IBNEX_INVALID_PKEY(pkey)	\
		(((pkey) == IB_PKEY_INVALID_FULL) || \
		((pkey) == IB_PKEY_INVALID_LIMITED))

/*
 * Defines for the tags of IB DDI events
 */
typedef enum {
		IB_EVENT_TAG_PROP_UPDATE = 0
} ib_ddi_event_tag_t;

/* Definations for IB HW in device tree status */
#define	IBNEX_DEVTREE_NOT_CHECKED	-1
#define	IBNEX_HW_NOT_IN_DEVTREE		0
#define	IBNEX_HW_IN_DEVTREE		1

#ifdef __cplusplus
}
#endif

#endif	/* _SYS_IB_IBNEX_IBNEX_H */