xref: /onnv-gate/usr/src/uts/common/io/ib/mgt/ibcm/ibcm_impl.c (revision 9913:b5cbbe12c671)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51495Shiremath  * Common Development and Distribution License (the "License").
61495Shiremath  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
228580SBill.Taylor@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * ibcm_impl.c
280Sstevel@tonic-gate  *
290Sstevel@tonic-gate  * contains internal functions of IB CM module.
300Sstevel@tonic-gate  *
310Sstevel@tonic-gate  * TBD:
320Sstevel@tonic-gate  * 1. HCA CATASTROPHIC/RECOVERED not handled yet
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include <sys/ib/mgt/ibcm/ibcm_impl.h>
360Sstevel@tonic-gate #include <sys/disp.h>
370Sstevel@tonic-gate 
380Sstevel@tonic-gate 
390Sstevel@tonic-gate /* function prototypes */
400Sstevel@tonic-gate static ibcm_status_t	ibcm_init(void);
410Sstevel@tonic-gate static ibcm_status_t	ibcm_fini(void);
420Sstevel@tonic-gate 
43*9913SShantkumar.Hiremath@Sun.COM /* Routines to initialize and destroy CM global locks and CVs */
440Sstevel@tonic-gate static void		ibcm_init_locks(void);
450Sstevel@tonic-gate static void		ibcm_fini_locks(void);
460Sstevel@tonic-gate 
470Sstevel@tonic-gate /* Routines that initialize/teardown CM's global hca structures */
480Sstevel@tonic-gate static void		ibcm_init_hcas();
490Sstevel@tonic-gate static ibcm_status_t	ibcm_fini_hcas();
500Sstevel@tonic-gate 
510Sstevel@tonic-gate static void		ibcm_init_classportinfo();
520Sstevel@tonic-gate static void		ibcm_stop_timeout_thread();
530Sstevel@tonic-gate 
540Sstevel@tonic-gate /* Routines that handle HCA attach/detach asyncs */
550Sstevel@tonic-gate static void		ibcm_hca_attach(ib_guid_t);
560Sstevel@tonic-gate static ibcm_status_t	ibcm_hca_detach(ibcm_hca_info_t *);
570Sstevel@tonic-gate 
580Sstevel@tonic-gate /* Routines that initialize the HCA's port related fields */
590Sstevel@tonic-gate static ibt_status_t	ibcm_hca_init_port(ibcm_hca_info_t *hcap,
600Sstevel@tonic-gate 			    uint8_t port_index);
610Sstevel@tonic-gate static ibcm_status_t	ibcm_hca_fini_port(ibcm_hca_info_t *hcap,
620Sstevel@tonic-gate 			    uint8_t port_index);
630Sstevel@tonic-gate 
64557Shiremath static void ibcm_rc_flow_control_init(void);
65557Shiremath static void ibcm_rc_flow_control_fini(void);
66557Shiremath 
670Sstevel@tonic-gate /*
680Sstevel@tonic-gate  * Routines that check if hca's avl trees and sidr lists are free of any
690Sstevel@tonic-gate  * active client resources ie., RC or UD state structures in certain states
700Sstevel@tonic-gate  */
710Sstevel@tonic-gate static ibcm_status_t	ibcm_check_avl_clean(ibcm_hca_info_t *hcap);
720Sstevel@tonic-gate static ibcm_status_t	ibcm_check_sidr_clean(ibcm_hca_info_t *hcap);
730Sstevel@tonic-gate 
740Sstevel@tonic-gate /* Add a new hca structure to CM's global hca list */
750Sstevel@tonic-gate static ibcm_hca_info_t	*ibcm_add_hca_entry(ib_guid_t hcaguid, uint_t nports);
760Sstevel@tonic-gate 
770Sstevel@tonic-gate static void		ibcm_comm_est_handler(ibt_async_event_t *);
780Sstevel@tonic-gate void			ibcm_async_handler(void *, ibt_hca_hdl_t,
790Sstevel@tonic-gate 			    ibt_async_code_t, ibt_async_event_t *);
800Sstevel@tonic-gate 
810Sstevel@tonic-gate /* Global variables */
820Sstevel@tonic-gate char			cmlog[] = "ibcm";	/* for debug log messages */
830Sstevel@tonic-gate ibt_clnt_hdl_t		ibcm_ibt_handle;	/* IBT handle */
840Sstevel@tonic-gate kmutex_t		ibcm_svc_info_lock;	/* list lock */
850Sstevel@tonic-gate kcondvar_t		ibcm_svc_info_cv;	/* cv for deregister */
860Sstevel@tonic-gate kmutex_t		ibcm_recv_mutex;
870Sstevel@tonic-gate avl_tree_t		ibcm_svc_avl_tree;
880Sstevel@tonic-gate taskq_t			*ibcm_taskq = NULL;
890Sstevel@tonic-gate int			taskq_dispatch_fail_cnt;
900Sstevel@tonic-gate 
91*9913SShantkumar.Hiremath@Sun.COM kmutex_t		ibcm_mcglist_lock;	/* MCG list lock */
920Sstevel@tonic-gate kmutex_t		ibcm_trace_mutex;	/* Trace mutex */
930Sstevel@tonic-gate kmutex_t		ibcm_trace_print_mutex;	/* Trace print mutex */
940Sstevel@tonic-gate int			ibcm_conn_max_trcnt = IBCM_MAX_CONN_TRCNT;
950Sstevel@tonic-gate 
961093Shiremath int			ibcm_enable_trace = 2;	/* Trace level 4 by default */
971093Shiremath int			ibcm_dtrace = 0; /* conditionally enable more dtrace */
980Sstevel@tonic-gate 
990Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(ibcm_svc_info_lock, ibcm_svc_info_s::{svc_bind_list
1000Sstevel@tonic-gate     svc_ref_cnt svc_to_delete}))
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(ibcm_svc_info_lock, ibcm_svc_bind_s::{sbind_link}))
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(ibcm_trace_mutex, ibcm_conn_trace_s))
1050Sstevel@tonic-gate 
1060Sstevel@tonic-gate _NOTE(DATA_READABLE_WITHOUT_LOCK(ibcm_conn_trace_s))
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(ibcm_trace_print_mutex, ibcm_debug_buf))
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate _NOTE(DATA_READABLE_WITHOUT_LOCK(ibcm_debug_buf))
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate /*
1130Sstevel@tonic-gate  * Initial state is INIT. All hca dr's return success immediately in this
1140Sstevel@tonic-gate  * state, without adding or deleting any hca's to CM.
1150Sstevel@tonic-gate  */
1160Sstevel@tonic-gate ibcm_finit_state_t	ibcm_finit_state = IBCM_FINIT_INIT;
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate /* mutex and cv to manage hca's reference and resource count(s) */
1190Sstevel@tonic-gate kmutex_t		ibcm_global_hca_lock;
1200Sstevel@tonic-gate kcondvar_t		ibcm_global_hca_cv;
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate /* mutex and cv to sa session open */
1230Sstevel@tonic-gate kmutex_t		ibcm_sa_open_lock;
1240Sstevel@tonic-gate kcondvar_t		ibcm_sa_open_cv;
1250Sstevel@tonic-gate int			ibcm_sa_timeout_delay = 1;		/* in ticks */
1260Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(ibcm_sa_open_lock,
1270Sstevel@tonic-gate     ibcm_port_info_s::{port_ibmf_saa_hdl port_saa_open_in_progress}))
1280Sstevel@tonic-gate 
1290Sstevel@tonic-gate _NOTE(DATA_READABLE_WITHOUT_LOCK(ibcm_port_info_s::{port_ibmf_saa_hdl}))
1300Sstevel@tonic-gate 
1310Sstevel@tonic-gate /* serialize sm notice callbacks */
1320Sstevel@tonic-gate kmutex_t		ibcm_sm_notice_serialize_lock;
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate _NOTE(LOCK_ORDER(ibcm_sm_notice_serialize_lock ibcm_global_hca_lock))
1350Sstevel@tonic-gate 
1360Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(ibcm_global_hca_lock, ibcm_hca_info_s::{hca_state
1370Sstevel@tonic-gate     hca_svc_cnt hca_acc_cnt hca_res_cnt hca_next}))
1380Sstevel@tonic-gate 
1390Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(ibcm_global_hca_lock,
1400Sstevel@tonic-gate     ibcm_port_info_s::{port_ibmf_hdl}))
1410Sstevel@tonic-gate 
1420Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(ibcm_sm_notice_serialize_lock,
1430Sstevel@tonic-gate     ibcm_port_info_s::{port_event_status}))
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate _NOTE(DATA_READABLE_WITHOUT_LOCK(ibcm_hca_info_s::{hca_state}))
1460Sstevel@tonic-gate _NOTE(DATA_READABLE_WITHOUT_LOCK(
1470Sstevel@tonic-gate     ibcm_hca_info_s::{hca_port_info.port_ibmf_hdl}))
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate /* mutex for CM's qp list management */
1500Sstevel@tonic-gate kmutex_t		ibcm_qp_list_lock;
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(ibcm_qp_list_lock, ibcm_port_info_s::{port_qplist}))
1530Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(ibcm_qp_list_lock, ibcm_qp_list_s))
1540Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(ibcm_qp_list_lock, ibcm_qp_list_s))
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate kcondvar_t		ibcm_timeout_list_cv;
1570Sstevel@tonic-gate kcondvar_t		ibcm_timeout_thread_done_cv;
1580Sstevel@tonic-gate kt_did_t		ibcm_timeout_thread_did;
1590Sstevel@tonic-gate ibcm_state_data_t	*ibcm_timeout_list_hdr, *ibcm_timeout_list_tail;
1600Sstevel@tonic-gate ibcm_ud_state_data_t	*ibcm_ud_timeout_list_hdr, *ibcm_ud_timeout_list_tail;
1610Sstevel@tonic-gate kmutex_t		ibcm_timeout_list_lock;
1620Sstevel@tonic-gate uint8_t			ibcm_timeout_list_flags = 0;
1630Sstevel@tonic-gate pri_t			ibcm_timeout_thread_pri = MINCLSYSPRI;
1640Sstevel@tonic-gate 
1650Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(ibcm_timeout_list_lock,
1660Sstevel@tonic-gate     ibcm_state_data_s::timeout_next))
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(ibcm_timeout_list_lock,
1690Sstevel@tonic-gate     ibcm_ud_state_data_s::ud_timeout_next))
1700Sstevel@tonic-gate 
1711093Shiremath /*
1721093Shiremath  * Flow control logic for open_rc_channel uses the following.
1731093Shiremath  */
1741093Shiremath 
1751093Shiremath struct ibcm_open_s {
1761093Shiremath 	kmutex_t		mutex;
1771093Shiremath 	kcondvar_t		cv;
1781093Shiremath 	uint8_t			task_running;
1791093Shiremath 	uint_t			queued;
1801093Shiremath 	uint_t			exit_deferred;
1811093Shiremath 	uint_t			in_progress;
1821093Shiremath 	uint_t			in_progress_max;
1831093Shiremath 	uint_t			sends;
1841093Shiremath 	uint_t			sends_max;
1851093Shiremath 	uint_t			sends_lowat;
1861093Shiremath 	uint_t			sends_hiwat;
1871093Shiremath 	ibcm_state_data_t	*tail;
1881093Shiremath 	ibcm_state_data_t	head;
1891093Shiremath } ibcm_open;
1901093Shiremath 
1911093Shiremath /*
1921093Shiremath  * Flow control logic for SA access and close_rc_channel calls follows.
1931093Shiremath  */
1941093Shiremath 
1951093Shiremath int ibcm_close_simul_max	= 12;
1961093Shiremath int ibcm_lapr_simul_max		= 12;
1971093Shiremath int ibcm_saa_simul_max		= 8;
1981093Shiremath 
1991093Shiremath typedef struct ibcm_flow1_s {
2001093Shiremath 	struct ibcm_flow1_s	*link;
2011093Shiremath 	kcondvar_t		cv;
2021093Shiremath 	uint8_t			waiters;	/* 1 to IBCM_FLOW_SIMUL_MAX */
2031093Shiremath } ibcm_flow1_t;
2041093Shiremath 
2051093Shiremath typedef struct ibcm_flow_s {
2061093Shiremath 	ibcm_flow1_t		*list;
2071093Shiremath 	uint_t			simul;	/* #requests currently outstanding */
2081093Shiremath 	uint_t			simul_max;
2091093Shiremath 	uint_t			waiters_per_chunk;
2101093Shiremath 	uint_t			lowat;
2111093Shiremath 	uint_t			lowat_default;
2121093Shiremath 	/* statistics */
2131093Shiremath 	uint_t			total;
2141093Shiremath } ibcm_flow_t;
2151093Shiremath 
2161093Shiremath ibcm_flow_t ibcm_saa_flow;
2171093Shiremath ibcm_flow_t ibcm_close_flow;
2181093Shiremath ibcm_flow_t ibcm_lapr_flow;
2191093Shiremath 
2203241Shiremath /* NONBLOCKING close requests are queued */
2213241Shiremath struct ibcm_close_s {
2223241Shiremath 	kmutex_t		mutex;
2233241Shiremath 	ibcm_state_data_t	*tail;
2243241Shiremath 	ibcm_state_data_t	head;
2253241Shiremath } ibcm_close;
2263241Shiremath 
2270Sstevel@tonic-gate static ibt_clnt_modinfo_t ibcm_ibt_modinfo = {	/* Client's modinfop */
2288580SBill.Taylor@Sun.COM 	IBTI_V_CURR,
2290Sstevel@tonic-gate 	IBT_CM,
2300Sstevel@tonic-gate 	ibcm_async_handler,
2310Sstevel@tonic-gate 	NULL,
2320Sstevel@tonic-gate 	"IBCM"
2330Sstevel@tonic-gate };
2340Sstevel@tonic-gate 
2350Sstevel@tonic-gate /* IBCM's list of HCAs registered with it */
2360Sstevel@tonic-gate static ibcm_hca_info_t	*ibcm_hca_listp = NULL;	/* CM's HCA list */
2370Sstevel@tonic-gate 
2380Sstevel@tonic-gate /* Array of CM state call table functions */
2390Sstevel@tonic-gate ibcm_state_handler_t	ibcm_sm_funcs_tbl[] = {
2400Sstevel@tonic-gate 	ibcm_process_req_msg,
2410Sstevel@tonic-gate 	ibcm_process_mra_msg,
2420Sstevel@tonic-gate 	ibcm_process_rej_msg,
2430Sstevel@tonic-gate 	ibcm_process_rep_msg,
2440Sstevel@tonic-gate 	ibcm_process_rtu_msg,
2450Sstevel@tonic-gate 	ibcm_process_dreq_msg,
2460Sstevel@tonic-gate 	ibcm_process_drep_msg,
2470Sstevel@tonic-gate 	ibcm_process_sidr_req_msg,
2480Sstevel@tonic-gate 	ibcm_process_sidr_rep_msg,
2490Sstevel@tonic-gate 	ibcm_process_lap_msg,
2500Sstevel@tonic-gate 	ibcm_process_apr_msg
2510Sstevel@tonic-gate };
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate /* the following globals are CM tunables */
2540Sstevel@tonic-gate ibt_rnr_nak_time_t	ibcm_default_rnr_nak_time = IBT_RNR_NAK_655ms;
2550Sstevel@tonic-gate 
256*9913SShantkumar.Hiremath@Sun.COM uint8_t		ibcm_max_retries = IBCM_MAX_RETRIES;
2570Sstevel@tonic-gate clock_t		ibcm_local_processing_time = IBCM_LOCAL_RESPONSE_TIME;
2580Sstevel@tonic-gate clock_t		ibcm_remote_response_time = IBCM_REMOTE_RESPONSE_TIME;
2590Sstevel@tonic-gate ib_time_t	ibcm_max_sidr_rep_proctime = IBCM_MAX_SIDR_PROCESS_TIME;
2600Sstevel@tonic-gate ib_time_t	ibcm_max_sidr_pktlife_time = IBCM_MAX_SIDR_PKT_LIFE_TIME;
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate ib_time_t	ibcm_max_sidr_rep_store_time = 18;
2638695SRajkumar.Sivaprakasam@Sun.COM uint32_t	ibcm_wait_for_acc_cnt_timeout = 2000000;	/* 2 sec */
2640Sstevel@tonic-gate 
2650Sstevel@tonic-gate ib_time_t	ibcm_max_ib_pkt_lt = IBCM_MAX_IB_PKT_LT;
2660Sstevel@tonic-gate ib_time_t	ibcm_max_ib_mad_pkt_lt = IBCM_MAX_IB_MAD_PKT_LT;
2670Sstevel@tonic-gate 
2680Sstevel@tonic-gate /*
2690Sstevel@tonic-gate  * This delay accounts for time involved in various activities as follows :
2700Sstevel@tonic-gate  *
2710Sstevel@tonic-gate  * IBMF delays for posting the MADs in non-blocking mode
2720Sstevel@tonic-gate  * IBMF delays for receiving the MADs and delivering to CM
2730Sstevel@tonic-gate  * CM delays in processing the MADs before invoking client handlers,
2740Sstevel@tonic-gate  * Any other delays associated with HCA driver in processing the MADs and
2750Sstevel@tonic-gate  * 	other subsystems that CM may invoke (ex : SA, HCA driver)
2760Sstevel@tonic-gate  */
2770Sstevel@tonic-gate uint32_t	ibcm_sw_delay	= 1000;	/* 1000us / 1ms */
2780Sstevel@tonic-gate uint32_t	ibcm_max_sa_retries = IBCM_MAX_SA_RETRIES + 1;
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate /*	approx boot time */
2810Sstevel@tonic-gate uint32_t	ibcm_adj_btime = 4;	/* 4 seconds */
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate /*
2840Sstevel@tonic-gate  * The information in ibcm_clpinfo is kept in wireformat and is setup at
2850Sstevel@tonic-gate  * init time, and used read-only after that
2860Sstevel@tonic-gate  */
2870Sstevel@tonic-gate ibcm_classportinfo_msg_t	ibcm_clpinfo;
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate char	*event_str[] = {
2900Sstevel@tonic-gate 	"NEVER SEE THIS             ",
2910Sstevel@tonic-gate 	"SESSION_ID                 ",
2920Sstevel@tonic-gate 	"CHAN_HDL                   ",
2930Sstevel@tonic-gate 	"LOCAL_COMID/HCA/PORT       ",
2940Sstevel@tonic-gate 	"LOCAL_QPN                  ",
2950Sstevel@tonic-gate 	"REMOTE_COMID/HCA           ",
2960Sstevel@tonic-gate 	"REMOTE_QPN                 ",
2970Sstevel@tonic-gate 	"BASE_TIME                  ",
2980Sstevel@tonic-gate 	"INCOMING_REQ               ",
2990Sstevel@tonic-gate 	"INCOMING_REP               ",
3000Sstevel@tonic-gate 	"INCOMING_RTU               ",
3010Sstevel@tonic-gate 	"INCOMING_COMEST            ",
3020Sstevel@tonic-gate 	"INCOMING_MRA               ",
3030Sstevel@tonic-gate 	"INCOMING_REJ               ",
3040Sstevel@tonic-gate 	"INCOMING_LAP               ",
3050Sstevel@tonic-gate 	"INCOMING_APR               ",
3060Sstevel@tonic-gate 	"INCOMING_DREQ              ",
3070Sstevel@tonic-gate 	"INCOMING_DREP              ",
3080Sstevel@tonic-gate 	"OUTGOING_REQ               ",
3090Sstevel@tonic-gate 	"OUTGOING_REP               ",
3100Sstevel@tonic-gate 	"OUTGOING_RTU               ",
3110Sstevel@tonic-gate 	"OUTGOING_LAP               ",
3120Sstevel@tonic-gate 	"OUTGOING_APR               ",
3130Sstevel@tonic-gate 	"OUTGOING_MRA               ",
3140Sstevel@tonic-gate 	"OUTGOING_REJ               ",
3150Sstevel@tonic-gate 	"OUTGOING_DREQ              ",
3160Sstevel@tonic-gate 	"OUTGOING_DREP              ",
3170Sstevel@tonic-gate 	"REQ_POST_COMPLETE          ",
3180Sstevel@tonic-gate 	"REP_POST_COMPLETE          ",
3190Sstevel@tonic-gate 	"RTU_POST_COMPLETE          ",
3200Sstevel@tonic-gate 	"MRA_POST_COMPLETE          ",
3210Sstevel@tonic-gate 	"REJ_POST_COMPLETE          ",
3220Sstevel@tonic-gate 	"LAP_POST_COMPLETE          ",
3230Sstevel@tonic-gate 	"APR_POST_COMPLETE          ",
3240Sstevel@tonic-gate 	"DREQ_POST_COMPLETE         ",
3250Sstevel@tonic-gate 	"DREP_POST_COMPLETE         ",
3260Sstevel@tonic-gate 	"TIMEOUT_REP                ",
3270Sstevel@tonic-gate 	"CALLED_REQ_RCVD_EVENT      ",
3280Sstevel@tonic-gate 	"RET_REQ_RCVD_EVENT         ",
3290Sstevel@tonic-gate 	"CALLED_REP_RCVD_EVENT      ",
3300Sstevel@tonic-gate 	"RET_REP_RCVD_EVENT         ",
3310Sstevel@tonic-gate 	"CALLED_CONN_EST_EVENT      ",
3320Sstevel@tonic-gate 	"RET_CONN_EST_EVENT         ",
3330Sstevel@tonic-gate 	"CALLED_CONN_FAIL_EVENT     ",
3340Sstevel@tonic-gate 	"RET_CONN_FAIL_EVENT        ",
3350Sstevel@tonic-gate 	"CALLED_CONN_CLOSE_EVENT    ",
3360Sstevel@tonic-gate 	"RET_CONN_CLOSE_EVENT       ",
3370Sstevel@tonic-gate 	"INIT_INIT                  ",
3380Sstevel@tonic-gate 	"INIT_INIT_FAIL             ",
3390Sstevel@tonic-gate 	"INIT_RTR                   ",
3400Sstevel@tonic-gate 	"INIT_RTR_FAIL              ",
3410Sstevel@tonic-gate 	"RTR_RTS                    ",
3420Sstevel@tonic-gate 	"RTR_RTS_FAIL               ",
3430Sstevel@tonic-gate 	"RTS_RTS                    ",
3440Sstevel@tonic-gate 	"RTS_RTS_FAIL               ",
3450Sstevel@tonic-gate 	"TO_ERROR                   ",
3460Sstevel@tonic-gate 	"ERROR_FAIL                 ",
3470Sstevel@tonic-gate 	"SET_ALT                    ",
3480Sstevel@tonic-gate 	"SET_ALT_FAIL               ",
3490Sstevel@tonic-gate 	"STALE_DETECT               ",
3501093Shiremath 	"OUTGOING_REQ_RETRY         ",
3511093Shiremath 	"OUTGOING_REP_RETRY         ",
3521093Shiremath 	"OUTGOING_LAP_RETRY         ",
3531093Shiremath 	"OUTGOING_MRA_RETRY         ",
3541093Shiremath 	"OUTGOING_DREQ_RETRY        ",
3550Sstevel@tonic-gate 	"NEVER SEE THIS             "
3560Sstevel@tonic-gate };
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate char	ibcm_debug_buf[IBCM_DEBUG_BUF_SIZE];
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate _NOTE(SCHEME_PROTECTS_DATA("used in a localized function consistently",
3610Sstevel@tonic-gate     ibcm_debug_buf))
3620Sstevel@tonic-gate _NOTE(READ_ONLY_DATA(ibcm_taskq))
3630Sstevel@tonic-gate 
3640Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(ibcm_timeout_list_lock, ibcm_timeout_list_flags))
3650Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(ibcm_timeout_list_lock, ibcm_timeout_list_hdr))
3660Sstevel@tonic-gate _NOTE(MUTEX_PROTECTS_DATA(ibcm_timeout_list_lock, ibcm_ud_timeout_list_hdr))
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate #ifdef DEBUG
3690Sstevel@tonic-gate int		ibcm_test_mode = 0;	/* set to 1, if running tests */
3700Sstevel@tonic-gate #endif
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate /* Module Driver Info */
3740Sstevel@tonic-gate static struct modlmisc ibcm_modlmisc = {
3750Sstevel@tonic-gate 	&mod_miscops,
3767862SRichard.Bean@Sun.COM 	"IB Communication Manager"
3770Sstevel@tonic-gate };
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate /* Module Linkage */
3800Sstevel@tonic-gate static struct modlinkage ibcm_modlinkage = {
3810Sstevel@tonic-gate 	MODREV_1,
3820Sstevel@tonic-gate 	&ibcm_modlmisc,
3830Sstevel@tonic-gate 	NULL
3840Sstevel@tonic-gate };
3850Sstevel@tonic-gate 
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate int
_init(void)3880Sstevel@tonic-gate _init(void)
3890Sstevel@tonic-gate {
3900Sstevel@tonic-gate 	int		rval;
3910Sstevel@tonic-gate 	ibcm_status_t	status;
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	status = ibcm_init();
3940Sstevel@tonic-gate 	if (status != IBCM_SUCCESS) {
3950Sstevel@tonic-gate 		IBTF_DPRINTF_L2(cmlog, "_init: ibcm failed %d", status);
3960Sstevel@tonic-gate 		return (EINVAL);
3970Sstevel@tonic-gate 	}
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	rval = mod_install(&ibcm_modlinkage);
4000Sstevel@tonic-gate 	if (rval != 0) {
4010Sstevel@tonic-gate 		IBTF_DPRINTF_L2(cmlog, "_init: ibcm mod_install failed %d",
4020Sstevel@tonic-gate 		    rval);
4030Sstevel@tonic-gate 		(void) ibcm_fini();
4040Sstevel@tonic-gate 	}
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	IBTF_DPRINTF_L5(cmlog, "_init: ibcm successful");
4070Sstevel@tonic-gate 	return (rval);
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate }
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 
4120Sstevel@tonic-gate int
_info(struct modinfo * modinfop)4130Sstevel@tonic-gate _info(struct modinfo *modinfop)
4140Sstevel@tonic-gate {
4150Sstevel@tonic-gate 	return (mod_info(&ibcm_modlinkage, modinfop));
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate 
4180Sstevel@tonic-gate 
4190Sstevel@tonic-gate int
_fini(void)4200Sstevel@tonic-gate _fini(void)
4210Sstevel@tonic-gate {
4220Sstevel@tonic-gate 	int status;
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 	if (ibcm_fini() != IBCM_SUCCESS)
4250Sstevel@tonic-gate 		return (EBUSY);
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	if ((status = mod_remove(&ibcm_modlinkage)) != 0) {
4280Sstevel@tonic-gate 		IBTF_DPRINTF_L2(cmlog, "_fini: ibcm mod_remove failed %d",
4290Sstevel@tonic-gate 		    status);
4300Sstevel@tonic-gate 		return (status);
4310Sstevel@tonic-gate 	}
4320Sstevel@tonic-gate 
4330Sstevel@tonic-gate 	IBTF_DPRINTF_L5(cmlog, "_fini: ibcm successful");
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	return (status);
4360Sstevel@tonic-gate }
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate /* Initializes all global mutex and CV in cm module */
4390Sstevel@tonic-gate static void
ibcm_init_locks()4400Sstevel@tonic-gate ibcm_init_locks()
4410Sstevel@tonic-gate {
4420Sstevel@tonic-gate 
4430Sstevel@tonic-gate 	/* Verify CM MAD sizes */
4440Sstevel@tonic-gate #ifdef DEBUG
4450Sstevel@tonic-gate 
4460Sstevel@tonic-gate 	if (ibcm_test_mode > 1) {
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate 		IBTF_DPRINTF_L1(cmlog, "REQ MAD SIZE %d",
4490Sstevel@tonic-gate 		    sizeof (ibcm_req_msg_t));
4500Sstevel@tonic-gate 		IBTF_DPRINTF_L1(cmlog, "REP MAD SIZE %d",
4510Sstevel@tonic-gate 		    sizeof (ibcm_rep_msg_t));
4520Sstevel@tonic-gate 		IBTF_DPRINTF_L1(cmlog, "RTU MAD SIZE %d",
4530Sstevel@tonic-gate 		    sizeof (ibcm_rtu_msg_t));
4540Sstevel@tonic-gate 		IBTF_DPRINTF_L1(cmlog, "MRA MAD SIZE %d",
4550Sstevel@tonic-gate 		    sizeof (ibcm_mra_msg_t));
4560Sstevel@tonic-gate 		IBTF_DPRINTF_L1(cmlog, "REJ MAD SIZE %d",
4570Sstevel@tonic-gate 		    sizeof (ibcm_rej_msg_t));
4580Sstevel@tonic-gate 		IBTF_DPRINTF_L1(cmlog, "LAP MAD SIZE %d",
4590Sstevel@tonic-gate 		    sizeof (ibcm_lap_msg_t));
4600Sstevel@tonic-gate 		IBTF_DPRINTF_L1(cmlog, "APR MAD SIZE %d",
4610Sstevel@tonic-gate 		    sizeof (ibcm_apr_msg_t));
4620Sstevel@tonic-gate 		IBTF_DPRINTF_L1(cmlog, "DREQ MAD SIZE %d",
4630Sstevel@tonic-gate 		    sizeof (ibcm_dreq_msg_t));
4640Sstevel@tonic-gate 		IBTF_DPRINTF_L1(cmlog, "DREP MAD SIZE %d",
4650Sstevel@tonic-gate 		    sizeof (ibcm_drep_msg_t));
4660Sstevel@tonic-gate 		IBTF_DPRINTF_L1(cmlog, "SIDR REQ MAD SIZE %d",
4670Sstevel@tonic-gate 		    sizeof (ibcm_sidr_req_msg_t));
4680Sstevel@tonic-gate 		IBTF_DPRINTF_L1(cmlog, "SIDR REP MAD SIZE %d",
4690Sstevel@tonic-gate 		    sizeof (ibcm_sidr_rep_msg_t));
4700Sstevel@tonic-gate 	}
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate #endif
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	/* Create all global locks within cm module */
4750Sstevel@tonic-gate 	mutex_init(&ibcm_svc_info_lock, NULL, MUTEX_DEFAULT, NULL);
476*9913SShantkumar.Hiremath@Sun.COM 	mutex_init(&ibcm_mcglist_lock, NULL, MUTEX_DEFAULT, NULL);
4770Sstevel@tonic-gate 	mutex_init(&ibcm_timeout_list_lock, NULL, MUTEX_DEFAULT, NULL);
4780Sstevel@tonic-gate 	mutex_init(&ibcm_global_hca_lock, NULL, MUTEX_DEFAULT, NULL);
4790Sstevel@tonic-gate 	mutex_init(&ibcm_sa_open_lock, NULL, MUTEX_DEFAULT, NULL);
4800Sstevel@tonic-gate 	mutex_init(&ibcm_recv_mutex, NULL, MUTEX_DEFAULT, NULL);
4810Sstevel@tonic-gate 	mutex_init(&ibcm_sm_notice_serialize_lock, NULL, MUTEX_DEFAULT, NULL);
4820Sstevel@tonic-gate 	mutex_init(&ibcm_qp_list_lock, NULL, MUTEX_DEFAULT, NULL);
4830Sstevel@tonic-gate 	mutex_init(&ibcm_trace_mutex, NULL, MUTEX_DEFAULT, NULL);
4840Sstevel@tonic-gate 	mutex_init(&ibcm_trace_print_mutex, NULL, MUTEX_DEFAULT, NULL);
4850Sstevel@tonic-gate 	cv_init(&ibcm_svc_info_cv, NULL, CV_DRIVER, NULL);
4860Sstevel@tonic-gate 	cv_init(&ibcm_timeout_list_cv, NULL, CV_DRIVER, NULL);
4870Sstevel@tonic-gate 	cv_init(&ibcm_timeout_thread_done_cv, NULL, CV_DRIVER, NULL);
4880Sstevel@tonic-gate 	cv_init(&ibcm_global_hca_cv, NULL, CV_DRIVER, NULL);
4890Sstevel@tonic-gate 	cv_init(&ibcm_sa_open_cv, NULL, CV_DRIVER, NULL);
4900Sstevel@tonic-gate 	avl_create(&ibcm_svc_avl_tree, ibcm_svc_compare,
4910Sstevel@tonic-gate 	    sizeof (ibcm_svc_info_t),
4920Sstevel@tonic-gate 	    offsetof(struct ibcm_svc_info_s, svc_link));
4930Sstevel@tonic-gate 
4940Sstevel@tonic-gate 	IBTF_DPRINTF_L5(cmlog, "ibcm_init_locks: done");
4950Sstevel@tonic-gate }
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate /* Destroys all global mutex and CV in cm module */
4980Sstevel@tonic-gate static void
ibcm_fini_locks()4990Sstevel@tonic-gate ibcm_fini_locks()
5000Sstevel@tonic-gate {
5010Sstevel@tonic-gate 	/* Destroy all global locks within cm module */
5020Sstevel@tonic-gate 	mutex_destroy(&ibcm_svc_info_lock);
503*9913SShantkumar.Hiremath@Sun.COM 	mutex_destroy(&ibcm_mcglist_lock);
5040Sstevel@tonic-gate 	mutex_destroy(&ibcm_timeout_list_lock);
5050Sstevel@tonic-gate 	mutex_destroy(&ibcm_global_hca_lock);
5060Sstevel@tonic-gate 	mutex_destroy(&ibcm_sa_open_lock);
5070Sstevel@tonic-gate 	mutex_destroy(&ibcm_recv_mutex);
5080Sstevel@tonic-gate 	mutex_destroy(&ibcm_sm_notice_serialize_lock);
5090Sstevel@tonic-gate 	mutex_destroy(&ibcm_qp_list_lock);
5100Sstevel@tonic-gate 	mutex_destroy(&ibcm_trace_mutex);
5110Sstevel@tonic-gate 	mutex_destroy(&ibcm_trace_print_mutex);
5120Sstevel@tonic-gate 	cv_destroy(&ibcm_svc_info_cv);
5130Sstevel@tonic-gate 	cv_destroy(&ibcm_timeout_list_cv);
5140Sstevel@tonic-gate 	cv_destroy(&ibcm_timeout_thread_done_cv);
5150Sstevel@tonic-gate 	cv_destroy(&ibcm_global_hca_cv);
5160Sstevel@tonic-gate 	cv_destroy(&ibcm_sa_open_cv);
5170Sstevel@tonic-gate 	avl_destroy(&ibcm_svc_avl_tree);
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 	IBTF_DPRINTF_L5(cmlog, "ibcm_fini_locks: done");
5200Sstevel@tonic-gate }
5210Sstevel@tonic-gate 
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate /* Initialize CM's classport info */
5240Sstevel@tonic-gate static void
ibcm_init_classportinfo()5250Sstevel@tonic-gate ibcm_init_classportinfo()
5260Sstevel@tonic-gate {
5270Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_clpinfo));
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	ibcm_clpinfo.BaseVersion = IBCM_MAD_BASE_VERSION;
5300Sstevel@tonic-gate 	ibcm_clpinfo.ClassVersion = IBCM_MAD_CLASS_VERSION;
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 	/* For now, CM supports same capabilities at all ports */
5330Sstevel@tonic-gate 	ibcm_clpinfo.CapabilityMask =
5340Sstevel@tonic-gate 	    h2b16(IBCM_CPINFO_CAP_RC | IBCM_CPINFO_CAP_SIDR);
5350Sstevel@tonic-gate 
5360Sstevel@tonic-gate 	/* Bits 0-7 are all 0 for Communication Mgmt Class */
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 	/* For now, CM has the same respvalue at all ports */
5390Sstevel@tonic-gate 	ibcm_clpinfo.RespTimeValue_plus =
5400Sstevel@tonic-gate 	    h2b32(ibt_usec2ib(ibcm_local_processing_time) & 0x1f);
5410Sstevel@tonic-gate 
5420Sstevel@tonic-gate 	/* For now, redirect fields are set to 0 */
5430Sstevel@tonic-gate 	/* Trap fields are not applicable to CM, hence set to 0 */
5440Sstevel@tonic-gate 
5450Sstevel@tonic-gate 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_clpinfo));
5460Sstevel@tonic-gate 	IBTF_DPRINTF_L5(cmlog, "ibcm_init_classportinfo: done");
5470Sstevel@tonic-gate }
5480Sstevel@tonic-gate 
5490Sstevel@tonic-gate /*
5500Sstevel@tonic-gate  * ibcm_init():
5510Sstevel@tonic-gate  * 	- call ibt_attach()
5520Sstevel@tonic-gate  * 	- create AVL trees
5530Sstevel@tonic-gate  *	- Attach HCA handlers that are already present before
5540Sstevel@tonic-gate  *	CM got loaded.
5550Sstevel@tonic-gate  *
5560Sstevel@tonic-gate  * Arguments:	NONE
5570Sstevel@tonic-gate  *
5580Sstevel@tonic-gate  * Return values:
5590Sstevel@tonic-gate  *	IBCM_SUCCESS - success
5600Sstevel@tonic-gate  */
5610Sstevel@tonic-gate static ibcm_status_t
ibcm_init(void)5620Sstevel@tonic-gate ibcm_init(void)
5630Sstevel@tonic-gate {
5640Sstevel@tonic-gate 	ibt_status_t	status;
5650Sstevel@tonic-gate 	kthread_t	*t;
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	IBTF_DPRINTF_L3(cmlog, "ibcm_init:");
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate 	ibcm_init_classportinfo();
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate 	if (ibcm_init_ids() != IBCM_SUCCESS) {
5720Sstevel@tonic-gate 		IBTF_DPRINTF_L1(cmlog, "ibcm_init: "
5730Sstevel@tonic-gate 		    "fatal error: vmem_create() failed");
5740Sstevel@tonic-gate 		return (IBCM_FAILURE);
5750Sstevel@tonic-gate 	}
5760Sstevel@tonic-gate 	ibcm_init_locks();
5770Sstevel@tonic-gate 
5780Sstevel@tonic-gate 	if (ibcm_ar_init() != IBCM_SUCCESS) {
5790Sstevel@tonic-gate 		IBTF_DPRINTF_L1(cmlog, "ibcm_init: "
5800Sstevel@tonic-gate 		    "fatal error: ibcm_ar_init() failed");
5810Sstevel@tonic-gate 		ibcm_fini_ids();
5820Sstevel@tonic-gate 		ibcm_fini_locks();
5830Sstevel@tonic-gate 		return (IBCM_FAILURE);
5840Sstevel@tonic-gate 	}
5851495Shiremath 	ibcm_rc_flow_control_init();
5860Sstevel@tonic-gate 
5870Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_taskq))
5880Sstevel@tonic-gate 	ibcm_taskq = system_taskq;
5890Sstevel@tonic-gate 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_taskq))
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_timeout_list_flags))
5920Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_timeout_thread_did))
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	/* Start the timeout list processing thread */
5950Sstevel@tonic-gate 	ibcm_timeout_list_flags = 0;
5960Sstevel@tonic-gate 	t = thread_create(NULL, 0, ibcm_process_tlist, 0, 0, &p0, TS_RUN,
5970Sstevel@tonic-gate 	    ibcm_timeout_thread_pri);
5980Sstevel@tonic-gate 	ibcm_timeout_thread_did = t->t_did;
5990Sstevel@tonic-gate 
6000Sstevel@tonic-gate 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_timeout_list_flags))
6010Sstevel@tonic-gate 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_timeout_thread_did))
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	/*
6040Sstevel@tonic-gate 	 * NOTE : if ibt_attach is done after ibcm_init_hcas, then some
6050Sstevel@tonic-gate 	 * HCA DR events may be lost. CM could call re-init hca list
6060Sstevel@tonic-gate 	 * again, but it is more complicated. Some HCA's DR's lost may
6070Sstevel@tonic-gate 	 * be HCA detach, which makes hca list re-syncing and locking more
6080Sstevel@tonic-gate 	 * complex
6090Sstevel@tonic-gate 	 */
6100Sstevel@tonic-gate 	status = ibt_attach(&ibcm_ibt_modinfo, NULL, NULL, &ibcm_ibt_handle);
6110Sstevel@tonic-gate 	if (status != IBT_SUCCESS) {
6120Sstevel@tonic-gate 		IBTF_DPRINTF_L2(cmlog, "ibcm_init(): ibt_attach failed %d",
6130Sstevel@tonic-gate 		    status);
6140Sstevel@tonic-gate 		(void) ibcm_ar_fini();
6151495Shiremath 		ibcm_stop_timeout_thread();
6160Sstevel@tonic-gate 		ibcm_fini_ids();
6170Sstevel@tonic-gate 		ibcm_fini_locks();
6181495Shiremath 		ibcm_rc_flow_control_fini();
6190Sstevel@tonic-gate 		return (IBCM_FAILURE);
6200Sstevel@tonic-gate 	}
6210Sstevel@tonic-gate 
6220Sstevel@tonic-gate 	/* Block all HCA attach/detach asyncs */
6230Sstevel@tonic-gate 	mutex_enter(&ibcm_global_hca_lock);
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 	ibcm_init_hcas();
6260Sstevel@tonic-gate 	ibcm_finit_state = IBCM_FINIT_IDLE;
6270Sstevel@tonic-gate 
628557Shiremath 	ibcm_path_cache_init();
6299891SRajkumar.Sivaprakasam@Sun.COM 	/*
6309891SRajkumar.Sivaprakasam@Sun.COM 	 * This callback will be used by IBTL to get the Node record for a
6319891SRajkumar.Sivaprakasam@Sun.COM 	 * given LID via the speccified HCA and port.
6329891SRajkumar.Sivaprakasam@Sun.COM 	 */
6339891SRajkumar.Sivaprakasam@Sun.COM 	ibtl_cm_set_node_info_cb(ibcm_ibtl_node_info);
634557Shiremath 
6350Sstevel@tonic-gate 	/* Unblock any waiting HCA DR asyncs in CM */
6360Sstevel@tonic-gate 	mutex_exit(&ibcm_global_hca_lock);
6370Sstevel@tonic-gate 
6380Sstevel@tonic-gate 	IBTF_DPRINTF_L4(cmlog, "ibcm_init: done");
6390Sstevel@tonic-gate 	return (IBCM_SUCCESS);
6400Sstevel@tonic-gate }
6410Sstevel@tonic-gate 
6420Sstevel@tonic-gate /* Allocates and initializes the "per hca" global data in CM */
6430Sstevel@tonic-gate static void
ibcm_init_hcas()6440Sstevel@tonic-gate ibcm_init_hcas()
6450Sstevel@tonic-gate {
6460Sstevel@tonic-gate 	uint_t	num_hcas = 0;
6470Sstevel@tonic-gate 	ib_guid_t *guid_array;
6480Sstevel@tonic-gate 	int i;
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 	IBTF_DPRINTF_L5(cmlog, "ibcm_init_hcas:");
6510Sstevel@tonic-gate 
6520Sstevel@tonic-gate 	/* Get the number of HCAs */
6530Sstevel@tonic-gate 	num_hcas = ibt_get_hca_list(&guid_array);
6540Sstevel@tonic-gate 	IBTF_DPRINTF_L4(cmlog, "ibcm_init_hcas: ibt_get_hca_list() "
6550Sstevel@tonic-gate 	    "returned %d hcas", num_hcas);
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ibcm_global_hca_lock));
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	for (i = 0; i < num_hcas; i++)
6600Sstevel@tonic-gate 		ibcm_hca_attach(guid_array[i]);
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	if (num_hcas)
6630Sstevel@tonic-gate 		ibt_free_hca_list(guid_array, num_hcas);
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 	IBTF_DPRINTF_L5(cmlog, "ibcm_init_hcas: done");
6660Sstevel@tonic-gate }
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate /*
6700Sstevel@tonic-gate  * ibcm_fini():
6710Sstevel@tonic-gate  * 	- Deregister w/ ibt
6720Sstevel@tonic-gate  * 	- Cleanup IBCM HCA listp
6730Sstevel@tonic-gate  * 	- Destroy mutexes
6740Sstevel@tonic-gate  *
6750Sstevel@tonic-gate  * Arguments:	NONE
6760Sstevel@tonic-gate  *
6770Sstevel@tonic-gate  * Return values:
6780Sstevel@tonic-gate  *	IBCM_SUCCESS - success
6790Sstevel@tonic-gate  */
6800Sstevel@tonic-gate static ibcm_status_t
ibcm_fini(void)6810Sstevel@tonic-gate ibcm_fini(void)
6820Sstevel@tonic-gate {
6830Sstevel@tonic-gate 	ibt_status_t	status;
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	IBTF_DPRINTF_L3(cmlog, "ibcm_fini:");
6860Sstevel@tonic-gate 
6870Sstevel@tonic-gate 	/*
6880Sstevel@tonic-gate 	 * CM assumes that the all general clients got rid of all the
6890Sstevel@tonic-gate 	 * established connections and service registrations, completed all
6900Sstevel@tonic-gate 	 * pending SIDR operations before a call to ibcm_fini()
6910Sstevel@tonic-gate 	 */
6920Sstevel@tonic-gate 
6930Sstevel@tonic-gate 	if (ibcm_ar_fini() != IBCM_SUCCESS) {
6940Sstevel@tonic-gate 		IBTF_DPRINTF_L2(cmlog, "ibcm_fini: ibcm_ar_fini failed");
6950Sstevel@tonic-gate 		return (IBCM_FAILURE);
6960Sstevel@tonic-gate 	}
6970Sstevel@tonic-gate 
6980Sstevel@tonic-gate 	/* cleanup the svcinfo list */
6990Sstevel@tonic-gate 	mutex_enter(&ibcm_svc_info_lock);
7000Sstevel@tonic-gate 	if (avl_first(&ibcm_svc_avl_tree) != NULL) {
7010Sstevel@tonic-gate 		IBTF_DPRINTF_L2(cmlog, "ibcm_fini: "
7020Sstevel@tonic-gate 		    "ibcm_svc_avl_tree is not empty");
7030Sstevel@tonic-gate 		mutex_exit(&ibcm_svc_info_lock);
7040Sstevel@tonic-gate 		return (IBCM_FAILURE);
7050Sstevel@tonic-gate 	}
7060Sstevel@tonic-gate 	mutex_exit(&ibcm_svc_info_lock);
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	/* disables any new hca attach/detaches */
7090Sstevel@tonic-gate 	mutex_enter(&ibcm_global_hca_lock);
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 	ibcm_finit_state = IBCM_FINIT_BUSY;
7120Sstevel@tonic-gate 
7130Sstevel@tonic-gate 	if (ibcm_fini_hcas() != IBCM_SUCCESS) {
7140Sstevel@tonic-gate 		IBTF_DPRINTF_L2(cmlog, "ibcm_fini: "
7150Sstevel@tonic-gate 		    "some hca's still have client resources");
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 		/* First, re-initialize the hcas */
7180Sstevel@tonic-gate 		ibcm_init_hcas();
7190Sstevel@tonic-gate 		/* and then enable the HCA asyncs */
7200Sstevel@tonic-gate 		ibcm_finit_state = IBCM_FINIT_IDLE;
7210Sstevel@tonic-gate 		mutex_exit(&ibcm_global_hca_lock);
7220Sstevel@tonic-gate 		if (ibcm_ar_init() != IBCM_SUCCESS) {
7230Sstevel@tonic-gate 			IBTF_DPRINTF_L1(cmlog, "ibcm_fini:ibcm_ar_init failed");
7240Sstevel@tonic-gate 		}
7250Sstevel@tonic-gate 		return (IBCM_FAILURE);
7260Sstevel@tonic-gate 	}
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_timeout_list_hdr))
7290Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_ud_timeout_list_hdr))
7300Sstevel@tonic-gate 
7310Sstevel@tonic-gate 	ASSERT(ibcm_timeout_list_hdr == NULL);
7320Sstevel@tonic-gate 	ASSERT(ibcm_ud_timeout_list_hdr == NULL);
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_timeout_list_hdr))
7350Sstevel@tonic-gate 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_ud_timeout_list_hdr))
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate 	/* Release any pending asyncs on ibcm_global_hca_lock */
7380Sstevel@tonic-gate 	ibcm_finit_state = IBCM_FINIT_SUCCESS;
7390Sstevel@tonic-gate 	mutex_exit(&ibcm_global_hca_lock);
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate 	ibcm_stop_timeout_thread();
7420Sstevel@tonic-gate 
7439891SRajkumar.Sivaprakasam@Sun.COM 	ibtl_cm_set_node_info_cb(NULL);
7440Sstevel@tonic-gate 	/*
7450Sstevel@tonic-gate 	 * Detach from IBTL. Waits until all pending asyncs are complete.
7460Sstevel@tonic-gate 	 * Above cv_broadcast wakes up any waiting hca attach/detach asyncs
7470Sstevel@tonic-gate 	 */
7480Sstevel@tonic-gate 	status = ibt_detach(ibcm_ibt_handle);
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	/* if detach fails, CM didn't free up some resources, so assert */
7510Sstevel@tonic-gate 	if (status != IBT_SUCCESS)
7527862SRichard.Bean@Sun.COM 		IBTF_DPRINTF_L1(cmlog, "ibcm_fini: ibt_detach failed %d",
7537862SRichard.Bean@Sun.COM 		    status);
7540Sstevel@tonic-gate 
755557Shiremath 	ibcm_rc_flow_control_fini();
756557Shiremath 
757557Shiremath 	ibcm_path_cache_fini();
7580Sstevel@tonic-gate 
7590Sstevel@tonic-gate 	ibcm_fini_ids();
7600Sstevel@tonic-gate 	ibcm_fini_locks();
7610Sstevel@tonic-gate 	IBTF_DPRINTF_L3(cmlog, "ibcm_fini: done");
7620Sstevel@tonic-gate 	return (IBCM_SUCCESS);
7630Sstevel@tonic-gate }
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate /* This routine exit's the ibcm timeout thread  */
7660Sstevel@tonic-gate static void
ibcm_stop_timeout_thread()7670Sstevel@tonic-gate ibcm_stop_timeout_thread()
7680Sstevel@tonic-gate {
7690Sstevel@tonic-gate 	mutex_enter(&ibcm_timeout_list_lock);
7700Sstevel@tonic-gate 
7710Sstevel@tonic-gate 	/* Stop the timeout list processing thread */
7720Sstevel@tonic-gate 	ibcm_timeout_list_flags =
7730Sstevel@tonic-gate 	    ibcm_timeout_list_flags | IBCM_TIMEOUT_THREAD_EXIT;
7740Sstevel@tonic-gate 
7750Sstevel@tonic-gate 	/* Wake up, if the timeout thread is on a cv_wait */
7760Sstevel@tonic-gate 	cv_signal(&ibcm_timeout_list_cv);
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	mutex_exit(&ibcm_timeout_list_lock);
7790Sstevel@tonic-gate 	thread_join(ibcm_timeout_thread_did);
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	IBTF_DPRINTF_L5(cmlog, "ibcm_stop_timeout_thread: done");
7820Sstevel@tonic-gate }
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate /* Attempts to release all the hca's associated with CM */
7860Sstevel@tonic-gate static ibcm_status_t
ibcm_fini_hcas()7870Sstevel@tonic-gate ibcm_fini_hcas()
7880Sstevel@tonic-gate {
7890Sstevel@tonic-gate 	ibcm_hca_info_t *hcap, *next;
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	IBTF_DPRINTF_L4(cmlog, "ibcm_fini_hcas:");
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ibcm_global_hca_lock));
7940Sstevel@tonic-gate 
7950Sstevel@tonic-gate 	hcap = ibcm_hca_listp;
7960Sstevel@tonic-gate 	while (hcap != NULL) {
7970Sstevel@tonic-gate 		next = hcap->hca_next;
7980Sstevel@tonic-gate 		if (ibcm_hca_detach(hcap) != IBCM_SUCCESS) {
7990Sstevel@tonic-gate 			ibcm_hca_listp = hcap;
8000Sstevel@tonic-gate 			return (IBCM_FAILURE);
8010Sstevel@tonic-gate 		}
8020Sstevel@tonic-gate 		hcap = next;
8030Sstevel@tonic-gate 	}
8040Sstevel@tonic-gate 
8050Sstevel@tonic-gate 	IBTF_DPRINTF_L4(cmlog, "ibcm_fini_hcas: SUCCEEDED");
8060Sstevel@tonic-gate 	return (IBCM_SUCCESS);
8070Sstevel@tonic-gate }
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate /*
8110Sstevel@tonic-gate  * ibcm_hca_attach():
8120Sstevel@tonic-gate  *	Called as an asynchronous event to notify CM of an attach of HCA.
8130Sstevel@tonic-gate  *	Here ibcm_hca_info_t is initialized and all fields are
8140Sstevel@tonic-gate  *	filled in along with SA Access handles and IBMA handles.
8150Sstevel@tonic-gate  *	Also called from ibcm_init to initialize ibcm_hca_info_t's for each
8160Sstevel@tonic-gate  *	hca's
8170Sstevel@tonic-gate  *
8180Sstevel@tonic-gate  * Arguments: (WILL CHANGE BASED ON ASYNC EVENT CODE)
8190Sstevel@tonic-gate  *	hca_guid	- HCA's guid
8200Sstevel@tonic-gate  *
8210Sstevel@tonic-gate  * Return values: NONE
8220Sstevel@tonic-gate  */
8230Sstevel@tonic-gate static void
ibcm_hca_attach(ib_guid_t hcaguid)8240Sstevel@tonic-gate ibcm_hca_attach(ib_guid_t hcaguid)
8250Sstevel@tonic-gate {
8260Sstevel@tonic-gate 	int			i;
8270Sstevel@tonic-gate 	ibt_status_t		status;
828*9913SShantkumar.Hiremath@Sun.COM 	uint8_t			nports = 0;
8290Sstevel@tonic-gate 	ibcm_hca_info_t		*hcap;
8300Sstevel@tonic-gate 	ibt_hca_attr_t		hca_attrs;
8310Sstevel@tonic-gate 
8320Sstevel@tonic-gate 	IBTF_DPRINTF_L3(cmlog, "ibcm_hca_attach: guid = 0x%llX", hcaguid);
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ibcm_global_hca_lock));
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*hcap))
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 	status = ibt_query_hca_byguid(hcaguid, &hca_attrs);
8390Sstevel@tonic-gate 	if (status != IBT_SUCCESS) {
8400Sstevel@tonic-gate 		IBTF_DPRINTF_L2(cmlog, "ibcm_hca_attach: "
8410Sstevel@tonic-gate 		    "ibt_query_hca_byguid failed = %d", status);
8420Sstevel@tonic-gate 		return;
8430Sstevel@tonic-gate 	}
8440Sstevel@tonic-gate 	nports = hca_attrs.hca_nports;
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 	IBTF_DPRINTF_L4(cmlog, "ibcm_hca_attach: num ports = %x", nports);
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	if ((hcap = ibcm_add_hca_entry(hcaguid, nports)) == NULL)
8490Sstevel@tonic-gate 		return;
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 	hcap->hca_guid = hcaguid;	/* Set GUID */
8520Sstevel@tonic-gate 	hcap->hca_num_ports = nports;	/* Set number of ports */
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 	if (ibcm_init_hca_ids(hcap) != IBCM_SUCCESS) {
8550Sstevel@tonic-gate 		ibcm_delete_hca_entry(hcap);
8560Sstevel@tonic-gate 		return;
8570Sstevel@tonic-gate 	}
8580Sstevel@tonic-gate 
8590Sstevel@tonic-gate 	/* Store the static hca attribute data */
8600Sstevel@tonic-gate 	hcap->hca_caps = hca_attrs.hca_flags;
8613241Shiremath 	hcap->hca_vendor_id = hca_attrs.hca_vendor_id;
8623241Shiremath 	hcap->hca_device_id = hca_attrs.hca_device_id;
8630Sstevel@tonic-gate 	hcap->hca_ack_delay = hca_attrs.hca_local_ack_delay;
8640Sstevel@tonic-gate 	hcap->hca_max_rdma_in_qp = hca_attrs.hca_max_rdma_in_qp;
8650Sstevel@tonic-gate 	hcap->hca_max_rdma_out_qp = hca_attrs.hca_max_rdma_out_qp;
8660Sstevel@tonic-gate 
8670Sstevel@tonic-gate 	/* loop thru nports and initialize IBMF handles */
8680Sstevel@tonic-gate 	for (i = 0; i < hcap->hca_num_ports; i++) {
8690Sstevel@tonic-gate 		status = ibt_get_port_state_byguid(hcaguid, i + 1, NULL, NULL);
8700Sstevel@tonic-gate 		if (status != IBT_SUCCESS) {
8710Sstevel@tonic-gate 			IBTF_DPRINTF_L2(cmlog, "ibcm_hca_attach: "
8720Sstevel@tonic-gate 			    "port_num %d state DOWN", i + 1);
8730Sstevel@tonic-gate 		}
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 		hcap->hca_port_info[i].port_hcap = hcap;
8760Sstevel@tonic-gate 		hcap->hca_port_info[i].port_num = i+1;
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 		if (ibcm_hca_init_port(hcap, i) != IBT_SUCCESS)
8790Sstevel@tonic-gate 			IBTF_DPRINTF_L2(cmlog, "ibcm_hca_attach: "
8800Sstevel@tonic-gate 			    "ibcm_hca_init_port failed %d port_num %d",
8810Sstevel@tonic-gate 			    status, i+1);
8820Sstevel@tonic-gate 	}
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 	/* create the "active" CM AVL tree */
8850Sstevel@tonic-gate 	avl_create(&hcap->hca_active_tree, ibcm_active_node_compare,
8860Sstevel@tonic-gate 	    sizeof (ibcm_state_data_t),
8870Sstevel@tonic-gate 	    offsetof(struct ibcm_state_data_s, avl_active_link));
8880Sstevel@tonic-gate 
8890Sstevel@tonic-gate 	/* create the "passive" CM AVL tree */
8900Sstevel@tonic-gate 	avl_create(&hcap->hca_passive_tree, ibcm_passive_node_compare,
8910Sstevel@tonic-gate 	    sizeof (ibcm_state_data_t),
8920Sstevel@tonic-gate 	    offsetof(struct ibcm_state_data_s, avl_passive_link));
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	/* create the "passive comid" CM AVL tree */
8950Sstevel@tonic-gate 	avl_create(&hcap->hca_passive_comid_tree,
8960Sstevel@tonic-gate 	    ibcm_passive_comid_node_compare,
8970Sstevel@tonic-gate 	    sizeof (ibcm_state_data_t),
8980Sstevel@tonic-gate 	    offsetof(struct ibcm_state_data_s, avl_passive_comid_link));
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	/*
9010Sstevel@tonic-gate 	 * Mark the state of the HCA to "attach" only at the end
9020Sstevel@tonic-gate 	 * Now CM starts accepting incoming MADs and client API calls
9030Sstevel@tonic-gate 	 */
9040Sstevel@tonic-gate 	hcap->hca_state = IBCM_HCA_ACTIVE;
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*hcap))
9070Sstevel@tonic-gate 
9080Sstevel@tonic-gate 	IBTF_DPRINTF_L3(cmlog, "ibcm_hca_attach: ATTACH Done");
9090Sstevel@tonic-gate }
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate /*
9120Sstevel@tonic-gate  * ibcm_hca_detach():
9130Sstevel@tonic-gate  *	Called as an asynchronous event to notify CM of a detach of HCA.
9140Sstevel@tonic-gate  *	Here ibcm_hca_info_t is freed up and all fields that
9150Sstevel@tonic-gate  *	were initialized earlier are cleaned up
9160Sstevel@tonic-gate  *
9170Sstevel@tonic-gate  * Arguments: (WILL CHANGE BASED ON ASYNC EVENT CODE)
9180Sstevel@tonic-gate  *	hca_guid    - HCA's guid
9190Sstevel@tonic-gate  *
9200Sstevel@tonic-gate  * Return values:
9210Sstevel@tonic-gate  *	IBCM_SUCCESS	- able to detach HCA
9220Sstevel@tonic-gate  *	IBCM_FAILURE	- failed to detach HCA
9230Sstevel@tonic-gate  */
9240Sstevel@tonic-gate static ibcm_status_t
ibcm_hca_detach(ibcm_hca_info_t * hcap)9250Sstevel@tonic-gate ibcm_hca_detach(ibcm_hca_info_t *hcap)
9260Sstevel@tonic-gate {
9270Sstevel@tonic-gate 	int		port_index, i;
9280Sstevel@tonic-gate 	ibcm_status_t	status = IBCM_SUCCESS;
9290Sstevel@tonic-gate 	clock_t		absolute_time;
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate 	IBTF_DPRINTF_L3(cmlog, "ibcm_hca_detach: hcap = 0x%p guid = 0x%llX",
9320Sstevel@tonic-gate 	    hcap, hcap->hca_guid);
9330Sstevel@tonic-gate 
9340Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ibcm_global_hca_lock));
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 	/*
9370Sstevel@tonic-gate 	 * Declare hca is going away to all CM clients. Wait until the
9380Sstevel@tonic-gate 	 * access count becomes zero.
9390Sstevel@tonic-gate 	 */
9400Sstevel@tonic-gate 	hcap->hca_state = IBCM_HCA_NOT_ACTIVE;
9410Sstevel@tonic-gate 
9428695SRajkumar.Sivaprakasam@Sun.COM 	/* wait on response CV */
9430Sstevel@tonic-gate 	absolute_time = ddi_get_lbolt() +
9440Sstevel@tonic-gate 	    drv_usectohz(ibcm_wait_for_acc_cnt_timeout);
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 	while (hcap->hca_acc_cnt > 0)
9470Sstevel@tonic-gate 		if (cv_timedwait(&ibcm_global_hca_cv, &ibcm_global_hca_lock,
9480Sstevel@tonic-gate 		    absolute_time) == -1)
9490Sstevel@tonic-gate 			break;
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 	if (hcap->hca_acc_cnt != 0) {
9520Sstevel@tonic-gate 		/* We got a timeout */
9538695SRajkumar.Sivaprakasam@Sun.COM 		IBTF_DPRINTF_L2(cmlog, "ibcm_hca_detach: Aborting due"
9548695SRajkumar.Sivaprakasam@Sun.COM 		    " to timeout on hca_acc_cnt %u, \n Some CM Clients are "
9558695SRajkumar.Sivaprakasam@Sun.COM 		    "still active, looks like we need to wait some more time "
9568695SRajkumar.Sivaprakasam@Sun.COM 		    "(ibcm_wait_for_acc_cnt_timeout).", hcap->hca_acc_cnt);
9570Sstevel@tonic-gate 		hcap->hca_state = IBCM_HCA_ACTIVE;
9580Sstevel@tonic-gate 		return (IBCM_FAILURE);
9590Sstevel@tonic-gate 	}
9600Sstevel@tonic-gate 
9610Sstevel@tonic-gate 	/*
9620Sstevel@tonic-gate 	 * First make sure, there are no active users of ibma handles,
9630Sstevel@tonic-gate 	 * and then de-register handles.
9640Sstevel@tonic-gate 	 */
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 	/* make sure that there are no "Service"s registered w/ this HCA. */
9670Sstevel@tonic-gate 	if (hcap->hca_svc_cnt != 0) {
9680Sstevel@tonic-gate 		IBTF_DPRINTF_L2(cmlog, "ibcm_hca_detach: "
9690Sstevel@tonic-gate 		    "Active services still there %d", hcap->hca_svc_cnt);
9700Sstevel@tonic-gate 		hcap->hca_state = IBCM_HCA_ACTIVE;
9710Sstevel@tonic-gate 		return (IBCM_FAILURE);
9720Sstevel@tonic-gate 	}
9730Sstevel@tonic-gate 
9740Sstevel@tonic-gate 	if (ibcm_check_sidr_clean(hcap) != IBCM_SUCCESS) {
9750Sstevel@tonic-gate 		IBTF_DPRINTF_L2(cmlog, "ibcm_hca_detach:"
9760Sstevel@tonic-gate 		    "There are active SIDR operations");
9770Sstevel@tonic-gate 		hcap->hca_state = IBCM_HCA_ACTIVE;
9780Sstevel@tonic-gate 		return (IBCM_FAILURE);
9790Sstevel@tonic-gate 	}
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 	if (ibcm_check_avl_clean(hcap) != IBCM_SUCCESS) {
9820Sstevel@tonic-gate 		IBTF_DPRINTF_L2(cmlog, "ibcm_hca_detach: "
9830Sstevel@tonic-gate 		    "There are active RC connections");
9840Sstevel@tonic-gate 		hcap->hca_state = IBCM_HCA_ACTIVE;
9850Sstevel@tonic-gate 		return (IBCM_FAILURE);
9860Sstevel@tonic-gate 	}
9870Sstevel@tonic-gate 
9880Sstevel@tonic-gate 	/*
9890Sstevel@tonic-gate 	 * Now, wait until all rc and sidr stateps go away
9900Sstevel@tonic-gate 	 * All these stateps must be short lived ones, waiting to be cleaned
9910Sstevel@tonic-gate 	 * up after some timeout value, based on the current state.
9920Sstevel@tonic-gate 	 */
9938695SRajkumar.Sivaprakasam@Sun.COM 	IBTF_DPRINTF_L3(cmlog, "ibcm_hca_detach:hca_guid = 0x%llX res_cnt = %d",
9940Sstevel@tonic-gate 	    hcap->hca_guid, hcap->hca_res_cnt);
9950Sstevel@tonic-gate 
9960Sstevel@tonic-gate 	while (hcap->hca_res_cnt > 0)
9979879SRamaswamy.Tummala@Sun.COM 		cv_wait(&ibcm_global_hca_cv, &ibcm_global_hca_lock);
9980Sstevel@tonic-gate 
9990Sstevel@tonic-gate 	/* Re-assert the while loop step above */
10000Sstevel@tonic-gate 	ASSERT(hcap->hca_sidr_list == NULL);
10010Sstevel@tonic-gate 	avl_destroy(&hcap->hca_active_tree);
10020Sstevel@tonic-gate 	avl_destroy(&hcap->hca_passive_tree);
10030Sstevel@tonic-gate 	avl_destroy(&hcap->hca_passive_comid_tree);
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate 	/*
10060Sstevel@tonic-gate 	 * Unregister all ports from IBMA
10070Sstevel@tonic-gate 	 * If there is a failure, re-initialize any free'd ibma handles. This
10080Sstevel@tonic-gate 	 * is required to receive the incoming mads
10090Sstevel@tonic-gate 	 */
10100Sstevel@tonic-gate 	status = IBCM_SUCCESS;
10110Sstevel@tonic-gate 	for (port_index = 0; port_index < hcap->hca_num_ports; port_index++) {
10120Sstevel@tonic-gate 		if ((status = ibcm_hca_fini_port(hcap, port_index)) !=
10130Sstevel@tonic-gate 		    IBCM_SUCCESS) {
10140Sstevel@tonic-gate 			IBTF_DPRINTF_L2(cmlog, "ibcm_hca_detach: "
10150Sstevel@tonic-gate 			    "Failed to free IBMA Handle for port_num %d",
10160Sstevel@tonic-gate 			    port_index + 1);
10170Sstevel@tonic-gate 			break;
10180Sstevel@tonic-gate 		}
10190Sstevel@tonic-gate 	}
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	/* If detach fails, re-initialize ibma handles for incoming mads */
10220Sstevel@tonic-gate 	if (status != IBCM_SUCCESS)  {
10230Sstevel@tonic-gate 		for (i = 0; i < port_index; i++) {
10240Sstevel@tonic-gate 			if (ibcm_hca_init_port(hcap, i) != IBT_SUCCESS)
10250Sstevel@tonic-gate 				IBTF_DPRINTF_L2(cmlog, "ibcm_hca_detach: "
10260Sstevel@tonic-gate 				    "Failed to re-allocate IBMA Handles for"
10270Sstevel@tonic-gate 				    " port_num %d", port_index + 1);
10280Sstevel@tonic-gate 		}
10290Sstevel@tonic-gate 		hcap->hca_state = IBCM_HCA_ACTIVE;
10300Sstevel@tonic-gate 		return (IBCM_FAILURE);
10310Sstevel@tonic-gate 	}
10320Sstevel@tonic-gate 
10330Sstevel@tonic-gate 	ibcm_fini_hca_ids(hcap);
10340Sstevel@tonic-gate 	ibcm_delete_hca_entry(hcap);
10350Sstevel@tonic-gate 
10360Sstevel@tonic-gate 	IBTF_DPRINTF_L3(cmlog, "ibcm_hca_detach: DETACH succeeded");
10370Sstevel@tonic-gate 	return (IBCM_SUCCESS);
10380Sstevel@tonic-gate }
10390Sstevel@tonic-gate 
10400Sstevel@tonic-gate /* Checks, if there are any active sidr state entries in the specified hca */
10410Sstevel@tonic-gate static ibcm_status_t
ibcm_check_sidr_clean(ibcm_hca_info_t * hcap)10420Sstevel@tonic-gate ibcm_check_sidr_clean(ibcm_hca_info_t *hcap)
10430Sstevel@tonic-gate {
10440Sstevel@tonic-gate 	ibcm_ud_state_data_t	*usp;
10450Sstevel@tonic-gate 	uint32_t		transient_cnt = 0;
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 	IBTF_DPRINTF_L5(cmlog, "ibcm_check_sidr_clean:");
10480Sstevel@tonic-gate 
10490Sstevel@tonic-gate 	rw_enter(&hcap->hca_sidr_list_lock, RW_WRITER);
10500Sstevel@tonic-gate 	usp = hcap->hca_sidr_list;	/* Point to the list */
10510Sstevel@tonic-gate 	while (usp != NULL) {
10520Sstevel@tonic-gate 		mutex_enter(&usp->ud_state_mutex);
10530Sstevel@tonic-gate 		if ((usp->ud_state != IBCM_STATE_SIDR_REP_SENT) &&
10540Sstevel@tonic-gate 		    (usp->ud_state != IBCM_STATE_TIMED_OUT) &&
10550Sstevel@tonic-gate 		    (usp->ud_state != IBCM_STATE_DELETE)) {
10560Sstevel@tonic-gate 
10570Sstevel@tonic-gate 			IBTF_DPRINTF_L3(cmlog, "ibcm_check_sidr_clean:"
10580Sstevel@tonic-gate 			    "usp = %p not in transient state = %d", usp,
10590Sstevel@tonic-gate 			    usp->ud_state);
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate 			mutex_exit(&usp->ud_state_mutex);
10620Sstevel@tonic-gate 			rw_exit(&hcap->hca_sidr_list_lock);
10630Sstevel@tonic-gate 			return (IBCM_FAILURE);
10640Sstevel@tonic-gate 		} else {
10650Sstevel@tonic-gate 			mutex_exit(&usp->ud_state_mutex);
10660Sstevel@tonic-gate 			++transient_cnt;
10670Sstevel@tonic-gate 		}
10680Sstevel@tonic-gate 
10690Sstevel@tonic-gate 		usp = usp->ud_nextp;
10700Sstevel@tonic-gate 	}
10710Sstevel@tonic-gate 	rw_exit(&hcap->hca_sidr_list_lock);
10720Sstevel@tonic-gate 
10730Sstevel@tonic-gate 	IBTF_DPRINTF_L4(cmlog, "ibcm_check_sidr_clean: transient_cnt %d",
10740Sstevel@tonic-gate 	    transient_cnt);
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate 	return (IBCM_SUCCESS);
10770Sstevel@tonic-gate }
10780Sstevel@tonic-gate 
10790Sstevel@tonic-gate /* Checks, if there are any active rc state entries, in the specified hca */
10800Sstevel@tonic-gate static ibcm_status_t
ibcm_check_avl_clean(ibcm_hca_info_t * hcap)10810Sstevel@tonic-gate ibcm_check_avl_clean(ibcm_hca_info_t *hcap)
10820Sstevel@tonic-gate 
10830Sstevel@tonic-gate {
10840Sstevel@tonic-gate 	ibcm_state_data_t	*sp;
10850Sstevel@tonic-gate 	avl_tree_t		*avl_tree;
10860Sstevel@tonic-gate 	uint32_t		transient_cnt = 0;
10870Sstevel@tonic-gate 
10880Sstevel@tonic-gate 	IBTF_DPRINTF_L5(cmlog, "ibcm_check_avl_clean:");
10890Sstevel@tonic-gate 	/*
10900Sstevel@tonic-gate 	 * Both the trees ie., active and passive must reference to all
10910Sstevel@tonic-gate 	 * statep's, so let's use one
10920Sstevel@tonic-gate 	 */
10930Sstevel@tonic-gate 	avl_tree = &hcap->hca_active_tree;
10940Sstevel@tonic-gate 
10950Sstevel@tonic-gate 	rw_enter(&hcap->hca_state_rwlock, RW_WRITER);
10960Sstevel@tonic-gate 
10970Sstevel@tonic-gate 	for (sp = avl_first(avl_tree); sp != NULL;
10980Sstevel@tonic-gate 	    sp = avl_walk(avl_tree, sp, AVL_AFTER)) {
10990Sstevel@tonic-gate 		mutex_enter(&sp->state_mutex);
11000Sstevel@tonic-gate 		if ((sp->state != IBCM_STATE_TIMEWAIT) &&
11010Sstevel@tonic-gate 		    (sp->state != IBCM_STATE_REJ_SENT) &&
11020Sstevel@tonic-gate 		    (sp->state != IBCM_STATE_DELETE)) {
11031093Shiremath 			IBTF_DPRINTF_L3(cmlog, "ibcm_check_avl_clean: "
11040Sstevel@tonic-gate 			    "sp = %p not in transient state = %d", sp,
11050Sstevel@tonic-gate 			    sp->state);
11060Sstevel@tonic-gate 			mutex_exit(&sp->state_mutex);
11070Sstevel@tonic-gate 			rw_exit(&hcap->hca_state_rwlock);
11080Sstevel@tonic-gate 			return (IBCM_FAILURE);
11090Sstevel@tonic-gate 		} else {
11100Sstevel@tonic-gate 			mutex_exit(&sp->state_mutex);
11110Sstevel@tonic-gate 			++transient_cnt;
11120Sstevel@tonic-gate 		}
11130Sstevel@tonic-gate 	}
11140Sstevel@tonic-gate 
11150Sstevel@tonic-gate 	rw_exit(&hcap->hca_state_rwlock);
11160Sstevel@tonic-gate 
11170Sstevel@tonic-gate 	IBTF_DPRINTF_L4(cmlog, "ibcm_check_avl_clean: transient_cnt %d",
11180Sstevel@tonic-gate 	    transient_cnt);
11190Sstevel@tonic-gate 
11200Sstevel@tonic-gate 	return (IBCM_SUCCESS);
11210Sstevel@tonic-gate }
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate /* Adds a new entry into CM's global hca list, if hca_guid is not there yet */
11240Sstevel@tonic-gate static ibcm_hca_info_t *
ibcm_add_hca_entry(ib_guid_t hcaguid,uint_t nports)11250Sstevel@tonic-gate ibcm_add_hca_entry(ib_guid_t hcaguid, uint_t nports)
11260Sstevel@tonic-gate {
11270Sstevel@tonic-gate 	ibcm_hca_info_t	*hcap;
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate 	IBTF_DPRINTF_L5(cmlog, "ibcm_add_hca_entry: guid = 0x%llX",
11300Sstevel@tonic-gate 	    hcaguid);
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ibcm_global_hca_lock));
11330Sstevel@tonic-gate 
11340Sstevel@tonic-gate 	/*
11350Sstevel@tonic-gate 	 * Check if this hca_guid already in the list
11360Sstevel@tonic-gate 	 * If yes, then ignore this and return NULL
11370Sstevel@tonic-gate 	 */
11380Sstevel@tonic-gate 
11390Sstevel@tonic-gate 	hcap = ibcm_hca_listp;
11400Sstevel@tonic-gate 
11410Sstevel@tonic-gate 	/* search for this HCA */
11420Sstevel@tonic-gate 	while (hcap != NULL) {
11430Sstevel@tonic-gate 		if (hcap->hca_guid == hcaguid) {
11440Sstevel@tonic-gate 			/* already exists */
11450Sstevel@tonic-gate 			IBTF_DPRINTF_L2(cmlog, "ibcm_add_hca_entry: "
11461093Shiremath 			    "hcap %p guid 0x%llX, entry already exists !!",
11471093Shiremath 			    hcap, hcap->hca_guid);
11480Sstevel@tonic-gate 			return (NULL);
11490Sstevel@tonic-gate 		}
11500Sstevel@tonic-gate 		hcap = hcap->hca_next;
11510Sstevel@tonic-gate 	}
11520Sstevel@tonic-gate 
11530Sstevel@tonic-gate 	/* Allocate storage for the new HCA entry found */
11540Sstevel@tonic-gate 	hcap = kmem_zalloc(sizeof (ibcm_hca_info_t) +
11550Sstevel@tonic-gate 	    (nports - 1) * sizeof (ibcm_port_info_t), KM_SLEEP);
11560Sstevel@tonic-gate 
11570Sstevel@tonic-gate 	/* initialize RW lock */
11580Sstevel@tonic-gate 	rw_init(&hcap->hca_state_rwlock, NULL, RW_DRIVER, NULL);
11590Sstevel@tonic-gate 	/* initialize SIDR list lock */
11600Sstevel@tonic-gate 	rw_init(&hcap->hca_sidr_list_lock, NULL, RW_DRIVER, NULL);
11610Sstevel@tonic-gate 	/* Insert "hcap" into the global HCA list maintained by CM */
11620Sstevel@tonic-gate 	hcap->hca_next = ibcm_hca_listp;
11630Sstevel@tonic-gate 	ibcm_hca_listp = hcap;
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate 	IBTF_DPRINTF_L5(cmlog, "ibcm_add_hca_entry: done hcap = 0x%p", hcap);
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate 	return (hcap);
11680Sstevel@tonic-gate 
11690Sstevel@tonic-gate }
11700Sstevel@tonic-gate 
11710Sstevel@tonic-gate /* deletes the given ibcm_hca_info_t from CM's global hca list */
11720Sstevel@tonic-gate void
ibcm_delete_hca_entry(ibcm_hca_info_t * hcap)11730Sstevel@tonic-gate ibcm_delete_hca_entry(ibcm_hca_info_t *hcap)
11740Sstevel@tonic-gate {
11750Sstevel@tonic-gate 	ibcm_hca_info_t	*headp, *prevp = NULL;
11760Sstevel@tonic-gate 
11770Sstevel@tonic-gate 	/* ibcm_hca_global_lock is held */
11780Sstevel@tonic-gate 	IBTF_DPRINTF_L5(cmlog, "ibcm_delete_hca_entry: guid = 0x%llX "
11790Sstevel@tonic-gate 	    "hcap = 0x%p", hcap->hca_guid, hcap);
11800Sstevel@tonic-gate 
11810Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ibcm_global_hca_lock));
11820Sstevel@tonic-gate 
11830Sstevel@tonic-gate 	headp = ibcm_hca_listp;
11840Sstevel@tonic-gate 	while (headp != NULL) {
11850Sstevel@tonic-gate 		if (headp == hcap) {
11860Sstevel@tonic-gate 			IBTF_DPRINTF_L3(cmlog, "ibcm_delete_hca_entry: "
11870Sstevel@tonic-gate 			    "deleting hcap %p hcaguid %llX", hcap,
11880Sstevel@tonic-gate 			    hcap->hca_guid);
11890Sstevel@tonic-gate 			if (prevp) {
11900Sstevel@tonic-gate 				prevp->hca_next = headp->hca_next;
11910Sstevel@tonic-gate 			} else {
11920Sstevel@tonic-gate 				prevp = headp->hca_next;
11930Sstevel@tonic-gate 				ibcm_hca_listp = prevp;
11940Sstevel@tonic-gate 			}
11950Sstevel@tonic-gate 			rw_destroy(&hcap->hca_state_rwlock);
11960Sstevel@tonic-gate 			rw_destroy(&hcap->hca_sidr_list_lock);
11970Sstevel@tonic-gate 			kmem_free(hcap, sizeof (ibcm_hca_info_t) +
11980Sstevel@tonic-gate 			    (hcap->hca_num_ports - 1) *
11990Sstevel@tonic-gate 			    sizeof (ibcm_port_info_t));
12000Sstevel@tonic-gate 			return;
12010Sstevel@tonic-gate 		}
12020Sstevel@tonic-gate 
12030Sstevel@tonic-gate 		prevp = headp;
12040Sstevel@tonic-gate 		headp = headp->hca_next;
12050Sstevel@tonic-gate 	}
12060Sstevel@tonic-gate }
12070Sstevel@tonic-gate 
12080Sstevel@tonic-gate /*
12090Sstevel@tonic-gate  * ibcm_find_hca_entry:
12100Sstevel@tonic-gate  *	Given a HCA's GUID find out ibcm_hca_info_t entry for that HCA
12110Sstevel@tonic-gate  *	This entry can be then used to access AVL tree/SIDR list etc.
12120Sstevel@tonic-gate  *	If entry exists and in HCA ATTACH state, then hca's ref cnt is
12130Sstevel@tonic-gate  *	incremented and entry returned. Else NULL returned.
12140Sstevel@tonic-gate  *
12150Sstevel@tonic-gate  *	All functions that use ibcm_find_hca_entry and get a non-NULL
12160Sstevel@tonic-gate  *	return values must call ibcm_dec_hca_acc_cnt to decrement the
12170Sstevel@tonic-gate  *	respective hca ref cnt. There shouldn't be any usage of
12180Sstevel@tonic-gate  *	ibcm_hca_info_t * returned from ibcm_find_hca_entry,
12190Sstevel@tonic-gate  *	after decrementing the hca_acc_cnt
12200Sstevel@tonic-gate  *
12210Sstevel@tonic-gate  * INPUTS:
12220Sstevel@tonic-gate  *	hca_guid	- HCA's guid
12230Sstevel@tonic-gate  *
12240Sstevel@tonic-gate  * RETURN VALUE:
12250Sstevel@tonic-gate  *	hcap		- if a match is found, else NULL
12260Sstevel@tonic-gate  */
12270Sstevel@tonic-gate ibcm_hca_info_t *
ibcm_find_hca_entry(ib_guid_t hca_guid)12280Sstevel@tonic-gate ibcm_find_hca_entry(ib_guid_t hca_guid)
12290Sstevel@tonic-gate {
12300Sstevel@tonic-gate 	ibcm_hca_info_t *hcap;
12310Sstevel@tonic-gate 
12320Sstevel@tonic-gate 	IBTF_DPRINTF_L5(cmlog, "ibcm_find_hca_entry: guid = 0x%llX", hca_guid);
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate 	mutex_enter(&ibcm_global_hca_lock);
12350Sstevel@tonic-gate 
12360Sstevel@tonic-gate 	hcap = ibcm_hca_listp;
12370Sstevel@tonic-gate 	/* search for this HCA */
12380Sstevel@tonic-gate 	while (hcap != NULL) {
12390Sstevel@tonic-gate 		if (hcap->hca_guid == hca_guid)
12400Sstevel@tonic-gate 			break;
12410Sstevel@tonic-gate 		hcap = hcap->hca_next;
12420Sstevel@tonic-gate 	}
12430Sstevel@tonic-gate 
12440Sstevel@tonic-gate 	/* if no hcap for the hca_guid, return NULL */
12450Sstevel@tonic-gate 	if (hcap == NULL) {
12460Sstevel@tonic-gate 		mutex_exit(&ibcm_global_hca_lock);
12470Sstevel@tonic-gate 		return (NULL);
12480Sstevel@tonic-gate 	}
12490Sstevel@tonic-gate 
12500Sstevel@tonic-gate 	/* return hcap, only if it valid to use */
12510Sstevel@tonic-gate 	if (hcap->hca_state == IBCM_HCA_ACTIVE) {
12520Sstevel@tonic-gate 		++(hcap->hca_acc_cnt);
12530Sstevel@tonic-gate 
12540Sstevel@tonic-gate 		IBTF_DPRINTF_L5(cmlog, "ibcm_find_hca_entry: "
12550Sstevel@tonic-gate 		    "found hcap = 0x%p hca_acc_cnt %u", hcap,
12560Sstevel@tonic-gate 		    hcap->hca_acc_cnt);
12570Sstevel@tonic-gate 
12580Sstevel@tonic-gate 		mutex_exit(&ibcm_global_hca_lock);
12590Sstevel@tonic-gate 		return (hcap);
12600Sstevel@tonic-gate 	} else {
12610Sstevel@tonic-gate 		mutex_exit(&ibcm_global_hca_lock);
12620Sstevel@tonic-gate 
12630Sstevel@tonic-gate 		IBTF_DPRINTF_L2(cmlog, "ibcm_find_hca_entry: "
12640Sstevel@tonic-gate 		    "found hcap = 0x%p not in active state", hcap);
12650Sstevel@tonic-gate 		return (NULL);
12660Sstevel@tonic-gate 	}
12670Sstevel@tonic-gate }
12680Sstevel@tonic-gate 
12690Sstevel@tonic-gate /*
12700Sstevel@tonic-gate  * Searches for ibcm_hca_info_t entry based on hca_guid, but doesn't increment
12710Sstevel@tonic-gate  * the hca's reference count. This function is used, where the calling context
12720Sstevel@tonic-gate  * is attempting to delete hcap itself and hence acc_cnt cannot be incremented
12730Sstevel@tonic-gate  * OR assumes that valid hcap must be available in ibcm's global hca list.
12740Sstevel@tonic-gate  */
12750Sstevel@tonic-gate ibcm_hca_info_t *
ibcm_find_hcap_entry(ib_guid_t hca_guid)12760Sstevel@tonic-gate ibcm_find_hcap_entry(ib_guid_t hca_guid)
12770Sstevel@tonic-gate {
12780Sstevel@tonic-gate 	ibcm_hca_info_t *hcap;
12790Sstevel@tonic-gate 
12800Sstevel@tonic-gate 	IBTF_DPRINTF_L5(cmlog, "ibcm_find_hcap_entry: guid = 0x%llX", hca_guid);
12810Sstevel@tonic-gate 
12820Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ibcm_global_hca_lock));
12830Sstevel@tonic-gate 
12840Sstevel@tonic-gate 	hcap = ibcm_hca_listp;
12850Sstevel@tonic-gate 	/* search for this HCA */
12860Sstevel@tonic-gate 	while (hcap != NULL) {
12870Sstevel@tonic-gate 		if (hcap->hca_guid == hca_guid)
12880Sstevel@tonic-gate 			break;
12890Sstevel@tonic-gate 		hcap = hcap->hca_next;
12900Sstevel@tonic-gate 	}
12910Sstevel@tonic-gate 
12920Sstevel@tonic-gate 	if (hcap == NULL)
12930Sstevel@tonic-gate 		IBTF_DPRINTF_L2(cmlog, "ibcm_find_hcap_entry: No hcap found for"
12940Sstevel@tonic-gate 		    " hca_guid 0x%llX", hca_guid);
12950Sstevel@tonic-gate 	else
12960Sstevel@tonic-gate 		IBTF_DPRINTF_L5(cmlog, "ibcm_find_hcap_entry: hcap found for"
12970Sstevel@tonic-gate 		    " hca_guid 0x%llX", hca_guid);
12980Sstevel@tonic-gate 
12990Sstevel@tonic-gate 	return (hcap);
13000Sstevel@tonic-gate }
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate /* increment the hca's temporary reference count */
13030Sstevel@tonic-gate ibcm_status_t
ibcm_inc_hca_acc_cnt(ibcm_hca_info_t * hcap)13040Sstevel@tonic-gate ibcm_inc_hca_acc_cnt(ibcm_hca_info_t *hcap)
13050Sstevel@tonic-gate {
13060Sstevel@tonic-gate 	mutex_enter(&ibcm_global_hca_lock);
13070Sstevel@tonic-gate 	if (hcap->hca_state == IBCM_HCA_ACTIVE) {
13080Sstevel@tonic-gate 		++(hcap->hca_acc_cnt);
13090Sstevel@tonic-gate 		IBTF_DPRINTF_L5(cmlog, "ibcm_inc_hca_acc_cnt: "
13100Sstevel@tonic-gate 		    "hcap = 0x%p  acc_cnt = %d ", hcap, hcap->hca_acc_cnt);
13110Sstevel@tonic-gate 		mutex_exit(&ibcm_global_hca_lock);
13120Sstevel@tonic-gate 		return (IBCM_SUCCESS);
13130Sstevel@tonic-gate 	} else {
13140Sstevel@tonic-gate 		IBTF_DPRINTF_L2(cmlog, "ibcm_inc_hca_acc_cnt: "
13150Sstevel@tonic-gate 		    "hcap INACTIVE 0x%p  acc_cnt = %d ", hcap,
13160Sstevel@tonic-gate 		    hcap->hca_acc_cnt);
13170Sstevel@tonic-gate 		mutex_exit(&ibcm_global_hca_lock);
13180Sstevel@tonic-gate 		return (IBCM_FAILURE);
13190Sstevel@tonic-gate 	}
13200Sstevel@tonic-gate }
13210Sstevel@tonic-gate 
13220Sstevel@tonic-gate /* decrement the hca's ref count, and wake up any waiting threads */
13230Sstevel@tonic-gate void
ibcm_dec_hca_acc_cnt(ibcm_hca_info_t * hcap)13240Sstevel@tonic-gate ibcm_dec_hca_acc_cnt(ibcm_hca_info_t *hcap)
13250Sstevel@tonic-gate {
13260Sstevel@tonic-gate 	mutex_enter(&ibcm_global_hca_lock);
13270Sstevel@tonic-gate 	ASSERT(hcap->hca_acc_cnt > 0);
13280Sstevel@tonic-gate 	--(hcap->hca_acc_cnt);
13291093Shiremath 	IBTF_DPRINTF_L5(cmlog, "ibcm_dec_hca_acc_cnt: hcap = 0x%p "
13300Sstevel@tonic-gate 	    "acc_cnt = %d", hcap, hcap->hca_acc_cnt);
13310Sstevel@tonic-gate 	if ((hcap->hca_state == IBCM_HCA_NOT_ACTIVE) &&
13320Sstevel@tonic-gate 	    (hcap->hca_acc_cnt == 0)) {
13330Sstevel@tonic-gate 		IBTF_DPRINTF_L3(cmlog, "ibcm_dec_hca_acc_cnt: "
13340Sstevel@tonic-gate 		    "cv_broadcast for hcap = 0x%p", hcap);
13350Sstevel@tonic-gate 		cv_broadcast(&ibcm_global_hca_cv);
13360Sstevel@tonic-gate 	}
13370Sstevel@tonic-gate 	mutex_exit(&ibcm_global_hca_lock);
13380Sstevel@tonic-gate }
13390Sstevel@tonic-gate 
13400Sstevel@tonic-gate /* increment the hca's resource count */
13410Sstevel@tonic-gate void
ibcm_inc_hca_res_cnt(ibcm_hca_info_t * hcap)13420Sstevel@tonic-gate ibcm_inc_hca_res_cnt(ibcm_hca_info_t *hcap)
13430Sstevel@tonic-gate 
13440Sstevel@tonic-gate {
13450Sstevel@tonic-gate 	mutex_enter(&ibcm_global_hca_lock);
13460Sstevel@tonic-gate 	++(hcap->hca_res_cnt);
13471093Shiremath 	IBTF_DPRINTF_L5(cmlog, "ibcm_inc_hca_res_cnt: hcap = 0x%p "
13480Sstevel@tonic-gate 	    "ref_cnt = %d", hcap, hcap->hca_res_cnt);
13490Sstevel@tonic-gate 	mutex_exit(&ibcm_global_hca_lock);
13500Sstevel@tonic-gate }
13510Sstevel@tonic-gate 
13520Sstevel@tonic-gate /* decrement the hca's resource count, and wake up any waiting threads */
13530Sstevel@tonic-gate void
ibcm_dec_hca_res_cnt(ibcm_hca_info_t * hcap)13540Sstevel@tonic-gate ibcm_dec_hca_res_cnt(ibcm_hca_info_t *hcap)
13550Sstevel@tonic-gate {
13560Sstevel@tonic-gate 	mutex_enter(&ibcm_global_hca_lock);
13570Sstevel@tonic-gate 	ASSERT(hcap->hca_res_cnt > 0);
13580Sstevel@tonic-gate 	--(hcap->hca_res_cnt);
13591093Shiremath 	IBTF_DPRINTF_L5(cmlog, "ibcm_dec_hca_res_cnt: hcap = 0x%p "
13600Sstevel@tonic-gate 	    "ref_cnt = %d", hcap, hcap->hca_res_cnt);
13610Sstevel@tonic-gate 	if ((hcap->hca_state == IBCM_HCA_NOT_ACTIVE) &&
13620Sstevel@tonic-gate 	    (hcap->hca_res_cnt == 0)) {
13630Sstevel@tonic-gate 		IBTF_DPRINTF_L3(cmlog, "ibcm_dec_hca_res_cnt: "
13640Sstevel@tonic-gate 		    "cv_broadcast for hcap = 0x%p", hcap);
13650Sstevel@tonic-gate 		cv_broadcast(&ibcm_global_hca_cv);
13660Sstevel@tonic-gate 	}
13670Sstevel@tonic-gate 	mutex_exit(&ibcm_global_hca_lock);
13680Sstevel@tonic-gate }
13690Sstevel@tonic-gate 
13700Sstevel@tonic-gate /* increment the hca's service count */
13710Sstevel@tonic-gate void
ibcm_inc_hca_svc_cnt(ibcm_hca_info_t * hcap)13720Sstevel@tonic-gate ibcm_inc_hca_svc_cnt(ibcm_hca_info_t *hcap)
13730Sstevel@tonic-gate 
13740Sstevel@tonic-gate {
13750Sstevel@tonic-gate 	mutex_enter(&ibcm_global_hca_lock);
13760Sstevel@tonic-gate 	++(hcap->hca_svc_cnt);
13771093Shiremath 	IBTF_DPRINTF_L5(cmlog, "ibcm_inc_hca_svc_cnt: hcap = 0x%p "
13780Sstevel@tonic-gate 	    "svc_cnt = %d", hcap, hcap->hca_svc_cnt);
13790Sstevel@tonic-gate 	mutex_exit(&ibcm_global_hca_lock);
13800Sstevel@tonic-gate }
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate /* decrement the hca's service count */
13830Sstevel@tonic-gate void
ibcm_dec_hca_svc_cnt(ibcm_hca_info_t * hcap)13840Sstevel@tonic-gate ibcm_dec_hca_svc_cnt(ibcm_hca_info_t *hcap)
13850Sstevel@tonic-gate {
13860Sstevel@tonic-gate 	mutex_enter(&ibcm_global_hca_lock);
13870Sstevel@tonic-gate 	ASSERT(hcap->hca_svc_cnt > 0);
13880Sstevel@tonic-gate 	--(hcap->hca_svc_cnt);
13891093Shiremath 	IBTF_DPRINTF_L5(cmlog, "ibcm_dec_hca_svc_cnt: hcap = 0x%p "
13900Sstevel@tonic-gate 	    "svc_cnt = %d", hcap, hcap->hca_svc_cnt);
13910Sstevel@tonic-gate 	mutex_exit(&ibcm_global_hca_lock);
13920Sstevel@tonic-gate }
13930Sstevel@tonic-gate 
1394557Shiremath /*
13951093Shiremath  * The following code manages three classes of requests that CM makes to
13961093Shiremath  * the fabric.  Those three classes are SA_ACCESS, REQ/REP/RTU, and DREQ/DREP.
13971093Shiremath  * The main issue is that the fabric can become very busy, and the CM
13981093Shiremath  * protocols rely on responses being made based on a predefined timeout
13991093Shiremath  * value.  By managing how many simultaneous sessions are allowed, there
14001093Shiremath  * is observed extremely high reliability of CM protocol succeeding when
14011093Shiremath  * it should.
14021093Shiremath  *
14031093Shiremath  * SA_ACCESS and DREQ/DREP are managed at the thread level, whereby the
14041093Shiremath  * thread blocks until there are less than some number of threads doing
14051093Shiremath  * similar requests.
14061093Shiremath  *
14071093Shiremath  * REQ/REP/RTU requests beyond a given limit are added to a list,
14081093Shiremath  * allowing the thread to return immediately to its caller in the
14091093Shiremath  * case where the "mode" is IBT_NONBLOCKING.  This is the mode used
14101093Shiremath  * by uDAPL and seems to be an important feature/behavior.
1411557Shiremath  */
1412557Shiremath 
14131093Shiremath static int
ibcm_ok_to_start(struct ibcm_open_s * openp)14141093Shiremath ibcm_ok_to_start(struct ibcm_open_s *openp)
14151093Shiremath {
14161093Shiremath 	return (openp->sends < openp->sends_hiwat &&
14171093Shiremath 	    openp->in_progress < openp->in_progress_max);
14181093Shiremath }
14191093Shiremath 
14201093Shiremath void
ibcm_open_done(ibcm_state_data_t * statep)14211093Shiremath ibcm_open_done(ibcm_state_data_t *statep)
14221093Shiremath {
14231093Shiremath 	int run;
14244045Sbillt 	ibcm_state_data_t **linkp, *tmp;
14251093Shiremath 
14261093Shiremath 	ASSERT(MUTEX_HELD(&statep->state_mutex));
14271093Shiremath 	if (statep->open_flow == 1) {
14281093Shiremath 		statep->open_flow = 0;
14291093Shiremath 		mutex_enter(&ibcm_open.mutex);
14304045Sbillt 		if (statep->open_link == NULL) {
14314045Sbillt 			ibcm_open.in_progress--;
14324045Sbillt 			run = ibcm_ok_to_start(&ibcm_open);
14334045Sbillt 		} else {
14344045Sbillt 			ibcm_open.queued--;
14354045Sbillt 			linkp = &ibcm_open.head.open_link;
14364045Sbillt 			while (*linkp != statep)
14374045Sbillt 				linkp = &((*linkp)->open_link);
14384045Sbillt 			*linkp = statep->open_link;
14394045Sbillt 			statep->open_link = NULL;
14404045Sbillt 			/*
14414045Sbillt 			 * If we remove what tail pointed to, we need
14424045Sbillt 			 * to reassign tail (it is never NULL).
14434045Sbillt 			 * tail points to head for the empty list.
14444045Sbillt 			 */
14454045Sbillt 			if (ibcm_open.tail == statep) {
14464045Sbillt 				tmp = &ibcm_open.head;
14474045Sbillt 				while (tmp->open_link != &ibcm_open.head)
14484045Sbillt 					tmp = tmp->open_link;
14494045Sbillt 				ibcm_open.tail = tmp;
14504045Sbillt 			}
14514045Sbillt 			run = 0;
14524045Sbillt 		}
14531093Shiremath 		mutex_exit(&ibcm_open.mutex);
14541093Shiremath 		if (run)
14551093Shiremath 			ibcm_run_tlist_thread();
14561093Shiremath 	}
14571093Shiremath }
1458557Shiremath 
14591093Shiremath /* dtrace */
14601093Shiremath void
ibcm_open_wait(hrtime_t delta)14611093Shiremath ibcm_open_wait(hrtime_t delta)
14621093Shiremath {
14631093Shiremath 	if (delta > 1000000)
14641093Shiremath 		IBTF_DPRINTF_L2(cmlog, "ibcm_open_wait: flow more %lld", delta);
14651093Shiremath }
14661093Shiremath 
14671093Shiremath void
ibcm_open_start(ibcm_state_data_t * statep)14681093Shiremath ibcm_open_start(ibcm_state_data_t *statep)
14691093Shiremath {
14701093Shiremath 	ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_REQ);
14711093Shiremath 
14721093Shiremath 	mutex_enter(&statep->state_mutex);
14731093Shiremath 	ibcm_open_wait(gethrtime() - statep->post_time);
14741093Shiremath 	mutex_exit(&statep->state_mutex);
14751093Shiremath 
14761093Shiremath 	ibcm_post_rc_mad(statep, statep->stored_msg, ibcm_post_req_complete,
14771093Shiremath 	    statep);
14781093Shiremath 
14791093Shiremath 	mutex_enter(&statep->state_mutex);
14801093Shiremath 	IBCM_REF_CNT_DECR(statep);
14811093Shiremath 	mutex_exit(&statep->state_mutex);
14821093Shiremath }
14831093Shiremath 
14841093Shiremath void
ibcm_open_enqueue(ibcm_state_data_t * statep)14851093Shiremath ibcm_open_enqueue(ibcm_state_data_t *statep)
14861093Shiremath {
14871093Shiremath 	int run;
1488557Shiremath 
14891093Shiremath 	mutex_enter(&statep->state_mutex);
14901093Shiremath 	statep->post_time = gethrtime();
14911093Shiremath 	mutex_exit(&statep->state_mutex);
14921093Shiremath 	mutex_enter(&ibcm_open.mutex);
14931093Shiremath 	if (ibcm_open.queued == 0 && ibcm_ok_to_start(&ibcm_open)) {
14941093Shiremath 		ibcm_open.in_progress++;
14951093Shiremath 		mutex_exit(&ibcm_open.mutex);
14961093Shiremath 		ibcm_open_start(statep);
14971093Shiremath 	} else {
14981093Shiremath 		ibcm_open.queued++;
14994045Sbillt 		statep->open_link = &ibcm_open.head;
15001093Shiremath 		ibcm_open.tail->open_link = statep;
15011093Shiremath 		ibcm_open.tail = statep;
15021093Shiremath 		run = ibcm_ok_to_start(&ibcm_open);
15031093Shiremath 		mutex_exit(&ibcm_open.mutex);
15041093Shiremath 		if (run)
15051093Shiremath 			ibcm_run_tlist_thread();
15061093Shiremath 	}
15071093Shiremath }
15081093Shiremath 
15091093Shiremath ibcm_state_data_t *
ibcm_open_dequeue(void)15101093Shiremath ibcm_open_dequeue(void)
15111093Shiremath {
15121093Shiremath 	ibcm_state_data_t *statep;
1513557Shiremath 
15141093Shiremath 	ASSERT(MUTEX_HELD(&ibcm_open.mutex));
15151093Shiremath 	ibcm_open.queued--;
15161093Shiremath 	ibcm_open.in_progress++;
15171093Shiremath 	statep = ibcm_open.head.open_link;
15181093Shiremath 	ibcm_open.head.open_link = statep->open_link;
15191093Shiremath 	statep->open_link = NULL;
15204045Sbillt 	/*
15214045Sbillt 	 * If we remove what tail pointed to, we need
15224045Sbillt 	 * to reassign tail (it is never NULL).
15234045Sbillt 	 * tail points to head for the empty list.
15244045Sbillt 	 */
15251093Shiremath 	if (ibcm_open.tail == statep)
15261093Shiremath 		ibcm_open.tail = &ibcm_open.head;
15271093Shiremath 	return (statep);
15281093Shiremath }
15291093Shiremath 
15301093Shiremath void
ibcm_check_for_opens(void)15311093Shiremath ibcm_check_for_opens(void)
15321093Shiremath {
15331093Shiremath 	ibcm_state_data_t 	*statep;
15341093Shiremath 
15351093Shiremath 	mutex_enter(&ibcm_open.mutex);
15361093Shiremath 
15371093Shiremath 	while (ibcm_open.queued > 0) {
15381093Shiremath 		if (ibcm_ok_to_start(&ibcm_open)) {
15391093Shiremath 			statep = ibcm_open_dequeue();
15401093Shiremath 			mutex_exit(&ibcm_open.mutex);
15411093Shiremath 
15421093Shiremath 			ibcm_open_start(statep);
15431093Shiremath 
15441093Shiremath 			mutex_enter(&ibcm_open.mutex);
15451093Shiremath 		} else {
15461093Shiremath 			break;
15471093Shiremath 		}
15481093Shiremath 	}
15491093Shiremath 	mutex_exit(&ibcm_open.mutex);
15501093Shiremath }
15511093Shiremath 
1552557Shiremath 
1553557Shiremath static void
ibcm_flow_init(ibcm_flow_t * flow,uint_t simul_max)1554557Shiremath ibcm_flow_init(ibcm_flow_t *flow, uint_t simul_max)
1555557Shiremath {
15561093Shiremath 	flow->list			= NULL;
15571093Shiremath 	flow->simul			= 0;
15581093Shiremath 	flow->waiters_per_chunk		= 4;
15591093Shiremath 	flow->simul_max			= simul_max;
15601093Shiremath 	flow->lowat			= simul_max - flow->waiters_per_chunk;
15611093Shiremath 	flow->lowat_default		= flow->lowat;
1562557Shiremath 	/* stats */
15631093Shiremath 	flow->total			= 0;
1564557Shiremath }
1565557Shiremath 
1566557Shiremath static void
ibcm_rc_flow_control_init(void)1567557Shiremath ibcm_rc_flow_control_init(void)
15680Sstevel@tonic-gate {
15691093Shiremath 	mutex_init(&ibcm_open.mutex, NULL, MUTEX_DEFAULT, NULL);
15701093Shiremath 	mutex_enter(&ibcm_open.mutex);
15711093Shiremath 	ibcm_flow_init(&ibcm_close_flow, ibcm_close_simul_max);
15721093Shiremath 	ibcm_flow_init(&ibcm_lapr_flow, ibcm_lapr_simul_max);
1573557Shiremath 	ibcm_flow_init(&ibcm_saa_flow, ibcm_saa_simul_max);
15741093Shiremath 
15751093Shiremath 	ibcm_open.queued 		= 0;
15761093Shiremath 	ibcm_open.exit_deferred 	= 0;
15771093Shiremath 	ibcm_open.in_progress 		= 0;
15781093Shiremath 	ibcm_open.in_progress_max 	= 16;
15791093Shiremath 	ibcm_open.sends 		= 0;
15801093Shiremath 	ibcm_open.sends_max 		= 0;
15811093Shiremath 	ibcm_open.sends_lowat 		= 8;
15821093Shiremath 	ibcm_open.sends_hiwat 		= 16;
15831093Shiremath 	ibcm_open.tail 			= &ibcm_open.head;
15841093Shiremath 	ibcm_open.head.open_link 	= NULL;
15851093Shiremath 	mutex_exit(&ibcm_open.mutex);
15863241Shiremath 
15873241Shiremath 	mutex_init(&ibcm_close.mutex, NULL, MUTEX_DEFAULT, NULL);
15883241Shiremath 	mutex_enter(&ibcm_close.mutex);
15893241Shiremath 	ibcm_close.tail			= &ibcm_close.head;
15903241Shiremath 	ibcm_close.head.close_link 	= NULL;
15913241Shiremath 	mutex_exit(&ibcm_close.mutex);
1592557Shiremath }
1593557Shiremath 
1594557Shiremath static void
ibcm_rc_flow_control_fini(void)1595557Shiremath ibcm_rc_flow_control_fini(void)
1596557Shiremath {
15971093Shiremath 	mutex_destroy(&ibcm_open.mutex);
15983241Shiremath 	mutex_destroy(&ibcm_close.mutex);
1599557Shiremath }
1600557Shiremath 
1601557Shiremath static ibcm_flow1_t *
ibcm_flow_find(ibcm_flow_t * flow)1602557Shiremath ibcm_flow_find(ibcm_flow_t *flow)
1603557Shiremath {
1604557Shiremath 	ibcm_flow1_t *flow1;
1605557Shiremath 	ibcm_flow1_t *f;
1606557Shiremath 
1607557Shiremath 	f = flow->list;
1608557Shiremath 	if (f) {	/* most likely code path */
1609557Shiremath 		while (f->link != NULL)
1610557Shiremath 			f = f->link;
1611557Shiremath 		if (f->waiters < flow->waiters_per_chunk)
1612557Shiremath 			return (f);
1613557Shiremath 	}
1614557Shiremath 
1615557Shiremath 	/* There was no flow1 list element ready for another waiter */
16161093Shiremath 	mutex_exit(&ibcm_open.mutex);
1617557Shiremath 	flow1 = kmem_alloc(sizeof (*flow1), KM_SLEEP);
16181093Shiremath 	mutex_enter(&ibcm_open.mutex);
1619557Shiremath 
1620557Shiremath 	f = flow->list;
1621557Shiremath 	if (f) {
1622557Shiremath 		while (f->link != NULL)
1623557Shiremath 			f = f->link;
1624557Shiremath 		if (f->waiters < flow->waiters_per_chunk) {
1625557Shiremath 			kmem_free(flow1, sizeof (*flow1));
1626557Shiremath 			return (f);
1627557Shiremath 		}
1628557Shiremath 		f->link = flow1;
1629557Shiremath 	} else {
1630557Shiremath 		flow->list = flow1;
1631557Shiremath 	}
1632557Shiremath 	cv_init(&flow1->cv, NULL, CV_DRIVER, NULL);
1633557Shiremath 	flow1->waiters = 0;
1634557Shiremath 	flow1->link = NULL;
1635557Shiremath 	return (flow1);
1636557Shiremath }
1637557Shiremath 
1638557Shiremath static void
ibcm_flow_enter(ibcm_flow_t * flow)1639557Shiremath ibcm_flow_enter(ibcm_flow_t *flow)
1640557Shiremath {
16411093Shiremath 	mutex_enter(&ibcm_open.mutex);
1642557Shiremath 	if (flow->list == NULL && flow->simul < flow->simul_max) {
1643557Shiremath 		flow->simul++;
1644557Shiremath 		flow->total++;
16451093Shiremath 		mutex_exit(&ibcm_open.mutex);
1646557Shiremath 	} else {
1647557Shiremath 		ibcm_flow1_t *flow1;
1648557Shiremath 
1649557Shiremath 		flow1 = ibcm_flow_find(flow);
1650557Shiremath 		flow1->waiters++;
16511093Shiremath 		cv_wait(&flow1->cv, &ibcm_open.mutex);
1652557Shiremath 		if (--flow1->waiters == 0) {
1653557Shiremath 			cv_destroy(&flow1->cv);
16541093Shiremath 			mutex_exit(&ibcm_open.mutex);
1655557Shiremath 			kmem_free(flow1, sizeof (*flow1));
16561093Shiremath 		} else
16571093Shiremath 			mutex_exit(&ibcm_open.mutex);
16580Sstevel@tonic-gate 	}
1659557Shiremath }
1660557Shiremath 
1661557Shiremath static void
ibcm_flow_exit(ibcm_flow_t * flow)1662557Shiremath ibcm_flow_exit(ibcm_flow_t *flow)
1663557Shiremath {
16641093Shiremath 	mutex_enter(&ibcm_open.mutex);
1665557Shiremath 	if (--flow->simul < flow->lowat) {
16661093Shiremath 		if (flow->lowat < flow->lowat_default)
16671093Shiremath 			flow->lowat++;
1668557Shiremath 		if (flow->list) {
1669557Shiremath 			ibcm_flow1_t *flow1;
1670557Shiremath 
1671557Shiremath 			flow1 = flow->list;
1672557Shiremath 			flow->list = flow1->link;	/* unlink */
1673557Shiremath 			flow1->link = NULL;		/* be clean */
1674557Shiremath 			flow->total += flow1->waiters;
1675557Shiremath 			flow->simul += flow1->waiters;
1676557Shiremath 			cv_broadcast(&flow1->cv);
1677557Shiremath 		}
16780Sstevel@tonic-gate 	}
16791093Shiremath 	mutex_exit(&ibcm_open.mutex);
16801093Shiremath }
16811093Shiremath 
16821093Shiremath void
ibcm_flow_inc(void)16831093Shiremath ibcm_flow_inc(void)
16841093Shiremath {
16851093Shiremath 	mutex_enter(&ibcm_open.mutex);
16861093Shiremath 	if (++ibcm_open.sends > ibcm_open.sends_max) {
16871093Shiremath 		ibcm_open.sends_max = ibcm_open.sends;
16881093Shiremath 		IBTF_DPRINTF_L2(cmlog, "ibcm_flow_inc: sends max = %d",
16891093Shiremath 		    ibcm_open.sends_max);
16901093Shiremath 	}
16911093Shiremath 	mutex_exit(&ibcm_open.mutex);
1692557Shiremath }
1693557Shiremath 
1694557Shiremath static void
ibcm_check_send_cmpltn_time(hrtime_t delta,char * event_msg)16951093Shiremath ibcm_check_send_cmpltn_time(hrtime_t delta, char *event_msg)
1696557Shiremath {
16971093Shiremath 	if (delta > 4000000LL) {
16981093Shiremath 		IBTF_DPRINTF_L2(cmlog, "ibcm_check_send_cmpltn_time: "
16991093Shiremath 		    "%s: %lldns", event_msg, delta);
1700557Shiremath 	}
17010Sstevel@tonic-gate }
17020Sstevel@tonic-gate 
17030Sstevel@tonic-gate void
ibcm_flow_dec(hrtime_t time,char * mad_type)17041093Shiremath ibcm_flow_dec(hrtime_t time, char *mad_type)
17050Sstevel@tonic-gate {
17061093Shiremath 	int flow_exit = 0;
17071093Shiremath 	int run = 0;
17081093Shiremath 
17091093Shiremath 	if (ibcm_dtrace)
17101093Shiremath 		ibcm_check_send_cmpltn_time(gethrtime() - time, mad_type);
17111093Shiremath 	mutex_enter(&ibcm_open.mutex);
17121093Shiremath 	ibcm_open.sends--;
17131093Shiremath 	if (ibcm_open.sends < ibcm_open.sends_lowat) {
17141093Shiremath 		run = ibcm_ok_to_start(&ibcm_open);
17151093Shiremath 		if (ibcm_open.exit_deferred) {
17161093Shiremath 			ibcm_open.exit_deferred--;
17171093Shiremath 			flow_exit = 1;
17181093Shiremath 		}
17191093Shiremath 	}
17201093Shiremath 	mutex_exit(&ibcm_open.mutex);
17211093Shiremath 	if (flow_exit)
17221093Shiremath 		ibcm_flow_exit(&ibcm_close_flow);
17231093Shiremath 	if (run)
17241093Shiremath 		ibcm_run_tlist_thread();
1725557Shiremath }
1726557Shiremath 
1727557Shiremath void
ibcm_close_enqueue(ibcm_state_data_t * statep)17283241Shiremath ibcm_close_enqueue(ibcm_state_data_t *statep)
17293241Shiremath {
17303241Shiremath 	mutex_enter(&ibcm_close.mutex);
17313241Shiremath 	statep->close_link = NULL;
17323241Shiremath 	ibcm_close.tail->close_link = statep;
17333241Shiremath 	ibcm_close.tail = statep;
17343241Shiremath 	mutex_exit(&ibcm_close.mutex);
17353241Shiremath 	ibcm_run_tlist_thread();
17363241Shiremath }
17373241Shiremath 
17383241Shiremath void
ibcm_check_for_async_close()17393241Shiremath ibcm_check_for_async_close()
17403241Shiremath {
17413241Shiremath 	ibcm_state_data_t 	*statep;
17423241Shiremath 
17433241Shiremath 	mutex_enter(&ibcm_close.mutex);
17443241Shiremath 
17453241Shiremath 	while (ibcm_close.head.close_link) {
17463241Shiremath 		statep = ibcm_close.head.close_link;
17473241Shiremath 		ibcm_close.head.close_link = statep->close_link;
17483241Shiremath 		statep->close_link = NULL;
17493241Shiremath 		if (ibcm_close.tail == statep)
17503241Shiremath 			ibcm_close.tail = &ibcm_close.head;
17513241Shiremath 		mutex_exit(&ibcm_close.mutex);
17523241Shiremath 		ibcm_close_start(statep);
17533241Shiremath 		mutex_enter(&ibcm_close.mutex);
17543241Shiremath 	}
17553241Shiremath 	mutex_exit(&ibcm_close.mutex);
17563241Shiremath }
17573241Shiremath 
17583241Shiremath void
ibcm_close_enter(void)17591093Shiremath ibcm_close_enter(void)
17600Sstevel@tonic-gate {
1761557Shiremath 	ibcm_flow_enter(&ibcm_close_flow);
17620Sstevel@tonic-gate }
17630Sstevel@tonic-gate 
17640Sstevel@tonic-gate void
ibcm_close_exit(void)17651093Shiremath ibcm_close_exit(void)
17660Sstevel@tonic-gate {
17671093Shiremath 	int flow_exit;
17681093Shiremath 
17691093Shiremath 	mutex_enter(&ibcm_open.mutex);
17701093Shiremath 	if (ibcm_open.sends < ibcm_open.sends_lowat ||
17711093Shiremath 	    ibcm_open.exit_deferred >= 4)
17721093Shiremath 		flow_exit = 1;
17731093Shiremath 	else {
17741093Shiremath 		flow_exit = 0;
17751093Shiremath 		ibcm_open.exit_deferred++;
17761093Shiremath 	}
17771093Shiremath 	mutex_exit(&ibcm_open.mutex);
17781093Shiremath 	if (flow_exit)
17791093Shiremath 		ibcm_flow_exit(&ibcm_close_flow);
17801093Shiremath }
17811093Shiremath 
17821093Shiremath /*
17831093Shiremath  * This function needs to be called twice to finish our flow
17841093Shiremath  * control accounting when closing down a connection.  One
17851093Shiremath  * call has send_done set to 1, while the other has it set to 0.
17861093Shiremath  * Because of retries, this could get called more than once
17871093Shiremath  * with either 0 or 1, but additional calls have no effect.
17881093Shiremath  */
17891093Shiremath void
ibcm_close_done(ibcm_state_data_t * statep,int send_done)17901093Shiremath ibcm_close_done(ibcm_state_data_t *statep, int send_done)
17911093Shiremath {
17921093Shiremath 	int flow_exit;
17931093Shiremath 
17941093Shiremath 	ASSERT(MUTEX_HELD(&statep->state_mutex));
17951093Shiremath 	if (statep->close_flow == 1) {
17961093Shiremath 		if (send_done)
17971093Shiremath 			statep->close_flow = 3;
17981093Shiremath 		else
17991093Shiremath 			statep->close_flow = 2;
18001093Shiremath 	} else if ((send_done && statep->close_flow == 2) ||
18011093Shiremath 	    (!send_done && statep->close_flow == 3)) {
18021093Shiremath 		statep->close_flow = 0;
18031093Shiremath 		mutex_enter(&ibcm_open.mutex);
18041093Shiremath 		if (ibcm_open.sends < ibcm_open.sends_lowat ||
18051093Shiremath 		    ibcm_open.exit_deferred >= 4)
18061093Shiremath 			flow_exit = 1;
18071093Shiremath 		else {
18081093Shiremath 			flow_exit = 0;
18091093Shiremath 			ibcm_open.exit_deferred++;
18101093Shiremath 		}
18111093Shiremath 		mutex_exit(&ibcm_open.mutex);
18121093Shiremath 		if (flow_exit)
18131093Shiremath 			ibcm_flow_exit(&ibcm_close_flow);
18141093Shiremath 	}
18150Sstevel@tonic-gate }
18160Sstevel@tonic-gate 
18170Sstevel@tonic-gate void
ibcm_lapr_enter(void)18181093Shiremath ibcm_lapr_enter(void)
18190Sstevel@tonic-gate {
18201093Shiremath 	ibcm_flow_enter(&ibcm_lapr_flow);
18211093Shiremath }
18221093Shiremath 
18231093Shiremath void
ibcm_lapr_exit(void)18241093Shiremath ibcm_lapr_exit(void)
18251093Shiremath {
18261093Shiremath 	ibcm_flow_exit(&ibcm_lapr_flow);
18270Sstevel@tonic-gate }
18280Sstevel@tonic-gate 
18290Sstevel@tonic-gate void
ibcm_sa_access_enter()18300Sstevel@tonic-gate ibcm_sa_access_enter()
18310Sstevel@tonic-gate {
1832557Shiremath 	ibcm_flow_enter(&ibcm_saa_flow);
18330Sstevel@tonic-gate }
18340Sstevel@tonic-gate 
18350Sstevel@tonic-gate void
ibcm_sa_access_exit()18360Sstevel@tonic-gate ibcm_sa_access_exit()
18370Sstevel@tonic-gate {
1838557Shiremath 	ibcm_flow_exit(&ibcm_saa_flow);
18390Sstevel@tonic-gate }
18400Sstevel@tonic-gate 
18410Sstevel@tonic-gate static void
ibcm_sm_notice_handler(ibmf_saa_handle_t saa_handle,ibmf_saa_subnet_event_t saa_event_code,ibmf_saa_event_details_t * saa_event_details,void * callback_arg)18420Sstevel@tonic-gate ibcm_sm_notice_handler(ibmf_saa_handle_t saa_handle,
18430Sstevel@tonic-gate     ibmf_saa_subnet_event_t saa_event_code,
18440Sstevel@tonic-gate     ibmf_saa_event_details_t *saa_event_details,
18450Sstevel@tonic-gate     void *callback_arg)
18460Sstevel@tonic-gate {
18470Sstevel@tonic-gate 	ibcm_port_info_t	*portp = (ibcm_port_info_t *)callback_arg;
18480Sstevel@tonic-gate 	ibt_subnet_event_code_t code;
18490Sstevel@tonic-gate 	ibt_subnet_event_t	event;
18500Sstevel@tonic-gate 	uint8_t			event_status;
18510Sstevel@tonic-gate 
18520Sstevel@tonic-gate 	IBTF_DPRINTF_L3(cmlog, "ibcm_sm_notice_handler: saa_hdl %p, code = %d",
18530Sstevel@tonic-gate 	    saa_handle, saa_event_code);
18540Sstevel@tonic-gate 
18550Sstevel@tonic-gate 	mutex_enter(&ibcm_sm_notice_serialize_lock);
18560Sstevel@tonic-gate 
18570Sstevel@tonic-gate 	switch (saa_event_code) {
18580Sstevel@tonic-gate 	case IBMF_SAA_EVENT_MCG_CREATED:
18590Sstevel@tonic-gate 		code = IBT_SM_EVENT_MCG_CREATED;
18600Sstevel@tonic-gate 		break;
18610Sstevel@tonic-gate 	case IBMF_SAA_EVENT_MCG_DELETED:
18620Sstevel@tonic-gate 		code = IBT_SM_EVENT_MCG_DELETED;
18630Sstevel@tonic-gate 		break;
18640Sstevel@tonic-gate 	case IBMF_SAA_EVENT_GID_AVAILABLE:
18650Sstevel@tonic-gate 		code = IBT_SM_EVENT_GID_AVAIL;
1866557Shiremath 		ibcm_path_cache_purge();
18670Sstevel@tonic-gate 		break;
18680Sstevel@tonic-gate 	case IBMF_SAA_EVENT_GID_UNAVAILABLE:
18690Sstevel@tonic-gate 		code = IBT_SM_EVENT_GID_UNAVAIL;
1870557Shiremath 		ibcm_path_cache_purge();
18710Sstevel@tonic-gate 		break;
18720Sstevel@tonic-gate 	case IBMF_SAA_EVENT_SUBSCRIBER_STATUS_CHG:
18730Sstevel@tonic-gate 		event_status =
18740Sstevel@tonic-gate 		    saa_event_details->ie_producer_event_status_mask &
18750Sstevel@tonic-gate 		    IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SM;
18760Sstevel@tonic-gate 		if (event_status == (portp->port_event_status &
18770Sstevel@tonic-gate 		    IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SM)) {
18780Sstevel@tonic-gate 			mutex_exit(&ibcm_sm_notice_serialize_lock);
18790Sstevel@tonic-gate 			return;	/* no change */
18800Sstevel@tonic-gate 		}
18810Sstevel@tonic-gate 		portp->port_event_status = event_status;
18820Sstevel@tonic-gate 		if (event_status == IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SM)
18830Sstevel@tonic-gate 			code = IBT_SM_EVENT_AVAILABLE;
18840Sstevel@tonic-gate 		else
18850Sstevel@tonic-gate 			code = IBT_SM_EVENT_UNAVAILABLE;
18860Sstevel@tonic-gate 		break;
18870Sstevel@tonic-gate 	default:
18880Sstevel@tonic-gate 		mutex_exit(&ibcm_sm_notice_serialize_lock);
18890Sstevel@tonic-gate 		return;
18900Sstevel@tonic-gate 	}
18910Sstevel@tonic-gate 
18920Sstevel@tonic-gate 	mutex_enter(&ibcm_global_hca_lock);
18930Sstevel@tonic-gate 
18940Sstevel@tonic-gate 	/* don't send the event if we're tearing down */
18950Sstevel@tonic-gate 	if (!IBCM_ACCESS_HCA_OK(portp->port_hcap)) {
18960Sstevel@tonic-gate 		mutex_exit(&ibcm_global_hca_lock);
18970Sstevel@tonic-gate 		mutex_exit(&ibcm_sm_notice_serialize_lock);
18980Sstevel@tonic-gate 		return;
18990Sstevel@tonic-gate 	}
19000Sstevel@tonic-gate 
19010Sstevel@tonic-gate 	++(portp->port_hcap->hca_acc_cnt);
19020Sstevel@tonic-gate 	mutex_exit(&ibcm_global_hca_lock);
19030Sstevel@tonic-gate 
19040Sstevel@tonic-gate 	event.sm_notice_gid = saa_event_details->ie_gid;
19050Sstevel@tonic-gate 	ibtl_cm_sm_notice_handler(portp->port_sgid0, code, &event);
19060Sstevel@tonic-gate 
19070Sstevel@tonic-gate 	mutex_exit(&ibcm_sm_notice_serialize_lock);
19080Sstevel@tonic-gate 
19090Sstevel@tonic-gate 	ibcm_dec_hca_acc_cnt(portp->port_hcap);
19100Sstevel@tonic-gate }
19110Sstevel@tonic-gate 
19120Sstevel@tonic-gate void
ibt_register_subnet_notices(ibt_clnt_hdl_t ibt_hdl,ibt_sm_notice_handler_t sm_notice_handler,void * private)19130Sstevel@tonic-gate ibt_register_subnet_notices(ibt_clnt_hdl_t ibt_hdl,
19140Sstevel@tonic-gate     ibt_sm_notice_handler_t sm_notice_handler, void *private)
19150Sstevel@tonic-gate {
19160Sstevel@tonic-gate 	ibcm_port_info_t	*portp;
19170Sstevel@tonic-gate 	ibcm_hca_info_t		*hcap;
19180Sstevel@tonic-gate 	uint8_t			port;
19190Sstevel@tonic-gate 	int			num_failed_sgids;
19200Sstevel@tonic-gate 	ibtl_cm_sm_init_fail_t	*ifail;
19210Sstevel@tonic-gate 	ib_gid_t		*sgidp;
19220Sstevel@tonic-gate 
1923*9913SShantkumar.Hiremath@Sun.COM 	IBTF_DPRINTF_L3(cmlog, "ibt_register_subnet_notices(%p, %s)",
1924*9913SShantkumar.Hiremath@Sun.COM 	    ibt_hdl, ibtl_cm_get_clnt_name(ibt_hdl));
19250Sstevel@tonic-gate 
19260Sstevel@tonic-gate 	mutex_enter(&ibcm_sm_notice_serialize_lock);
19270Sstevel@tonic-gate 
19280Sstevel@tonic-gate 	ibtl_cm_set_sm_notice_handler(ibt_hdl, sm_notice_handler, private);
19290Sstevel@tonic-gate 	if (sm_notice_handler == NULL) {
19300Sstevel@tonic-gate 		mutex_exit(&ibcm_sm_notice_serialize_lock);
19310Sstevel@tonic-gate 		return;
19320Sstevel@tonic-gate 	}
19330Sstevel@tonic-gate 
19340Sstevel@tonic-gate 	/* for each port, if service is not available, make a call */
19350Sstevel@tonic-gate 	mutex_enter(&ibcm_global_hca_lock);
19360Sstevel@tonic-gate 	num_failed_sgids = 0;
19370Sstevel@tonic-gate 	hcap = ibcm_hca_listp;
19380Sstevel@tonic-gate 	while (hcap != NULL) {
19390Sstevel@tonic-gate 		portp = hcap->hca_port_info;
19400Sstevel@tonic-gate 		for (port = 0; port < hcap->hca_num_ports; port++) {
19410Sstevel@tonic-gate 			if (!(portp->port_event_status &
19420Sstevel@tonic-gate 			    IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SM))
19430Sstevel@tonic-gate 				num_failed_sgids++;
19440Sstevel@tonic-gate 			portp++;
19450Sstevel@tonic-gate 		}
19460Sstevel@tonic-gate 		hcap = hcap->hca_next;
19470Sstevel@tonic-gate 	}
19480Sstevel@tonic-gate 	if (num_failed_sgids != 0) {
19490Sstevel@tonic-gate 		ifail = kmem_alloc(sizeof (*ifail) +
19500Sstevel@tonic-gate 		    (num_failed_sgids - 1) * sizeof (ib_gid_t), KM_SLEEP);
19510Sstevel@tonic-gate 		ifail->smf_num_sgids = num_failed_sgids;
19520Sstevel@tonic-gate 		ifail->smf_ibt_hdl = ibt_hdl;
19530Sstevel@tonic-gate 		sgidp = &ifail->smf_sgid[0];
19540Sstevel@tonic-gate 		hcap = ibcm_hca_listp;
19550Sstevel@tonic-gate 		while (hcap != NULL) {
19560Sstevel@tonic-gate 			portp = hcap->hca_port_info;
19570Sstevel@tonic-gate 			for (port = 0; port < hcap->hca_num_ports; port++) {
19580Sstevel@tonic-gate 				if (!(portp->port_event_status &
19590Sstevel@tonic-gate 				    IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SM))
19600Sstevel@tonic-gate 					*sgidp++ = portp->port_sgid0;
19610Sstevel@tonic-gate 				portp++;
19620Sstevel@tonic-gate 			}
19630Sstevel@tonic-gate 			hcap = hcap->hca_next;
19640Sstevel@tonic-gate 		}
19650Sstevel@tonic-gate 	}
19660Sstevel@tonic-gate 	mutex_exit(&ibcm_global_hca_lock);
19670Sstevel@tonic-gate 
19680Sstevel@tonic-gate 	if (num_failed_sgids != 0) {
19690Sstevel@tonic-gate 		ibtl_cm_sm_notice_init_failure(ifail);
19700Sstevel@tonic-gate 		kmem_free(ifail, sizeof (*ifail) +
19710Sstevel@tonic-gate 		    (num_failed_sgids - 1) * sizeof (ib_gid_t));
19720Sstevel@tonic-gate 	}
19730Sstevel@tonic-gate 	mutex_exit(&ibcm_sm_notice_serialize_lock);
19740Sstevel@tonic-gate }
19750Sstevel@tonic-gate 
19760Sstevel@tonic-gate /* The following is run from a taskq because we've seen the stack overflow. */
19770Sstevel@tonic-gate static void
ibcm_init_saa(void * arg)19780Sstevel@tonic-gate ibcm_init_saa(void *arg)
19790Sstevel@tonic-gate {
19800Sstevel@tonic-gate 	ibcm_port_info_t		*portp = (ibcm_port_info_t *)arg;
19810Sstevel@tonic-gate 	int				status;
19820Sstevel@tonic-gate 	ib_guid_t			port_guid;
19830Sstevel@tonic-gate 	ibmf_saa_subnet_event_args_t	event_args;
19840Sstevel@tonic-gate 
19850Sstevel@tonic-gate 	port_guid = portp->port_sgid0.gid_guid;
19860Sstevel@tonic-gate 
19870Sstevel@tonic-gate 	IBTF_DPRINTF_L3(cmlog, "ibcm_init_saa: port guid %llX", port_guid);
19880Sstevel@tonic-gate 
19890Sstevel@tonic-gate 	event_args.is_event_callback_arg = portp;
19900Sstevel@tonic-gate 	event_args.is_event_callback = ibcm_sm_notice_handler;
19910Sstevel@tonic-gate 
19920Sstevel@tonic-gate 	if ((status = ibmf_sa_session_open(port_guid, 0, &event_args,
19930Sstevel@tonic-gate 	    IBMF_VERSION, 0, &portp->port_ibmf_saa_hdl)) != IBMF_SUCCESS) {
19941093Shiremath 		IBTF_DPRINTF_L2(cmlog, "ibcm_init_saa: "
19950Sstevel@tonic-gate 		    "ibmf_sa_session_open failed for port guid %llX "
19960Sstevel@tonic-gate 		    "status = %d", port_guid, status);
19970Sstevel@tonic-gate 	} else {
19981093Shiremath 		IBTF_DPRINTF_L2(cmlog, "ibcm_init_saa: "
19990Sstevel@tonic-gate 		    "registered sa_hdl 0x%p for port guid %llX",
20000Sstevel@tonic-gate 		    portp->port_ibmf_saa_hdl, port_guid);
20010Sstevel@tonic-gate 	}
20020Sstevel@tonic-gate 
20030Sstevel@tonic-gate 	mutex_enter(&ibcm_sa_open_lock);
20040Sstevel@tonic-gate 	portp->port_saa_open_in_progress = 0;
20050Sstevel@tonic-gate 	cv_broadcast(&ibcm_sa_open_cv);
20060Sstevel@tonic-gate 	mutex_exit(&ibcm_sa_open_lock);
20070Sstevel@tonic-gate }
20080Sstevel@tonic-gate 
20090Sstevel@tonic-gate void
ibcm_init_saa_handle(ibcm_hca_info_t * hcap,uint8_t port)20100Sstevel@tonic-gate ibcm_init_saa_handle(ibcm_hca_info_t *hcap, uint8_t port)
20110Sstevel@tonic-gate {
20120Sstevel@tonic-gate 	ibmf_saa_handle_t	saa_handle;
20130Sstevel@tonic-gate 	uint8_t			port_index = port - 1;
20140Sstevel@tonic-gate 	ibcm_port_info_t	*portp = &hcap->hca_port_info[port_index];
20150Sstevel@tonic-gate 	ibt_status_t		ibt_status;
20160Sstevel@tonic-gate 
20170Sstevel@tonic-gate 	if (port_index >= hcap->hca_num_ports)
20180Sstevel@tonic-gate 		return;
20190Sstevel@tonic-gate 
20200Sstevel@tonic-gate 	mutex_enter(&ibcm_sa_open_lock);
20210Sstevel@tonic-gate 	if (portp->port_saa_open_in_progress) {
20220Sstevel@tonic-gate 		mutex_exit(&ibcm_sa_open_lock);
20230Sstevel@tonic-gate 		return;
20240Sstevel@tonic-gate 	}
20250Sstevel@tonic-gate 
20260Sstevel@tonic-gate 	saa_handle = portp->port_ibmf_saa_hdl;
20270Sstevel@tonic-gate 	if (saa_handle != NULL) {
20280Sstevel@tonic-gate 		mutex_exit(&ibcm_sa_open_lock);
20290Sstevel@tonic-gate 		return;
20300Sstevel@tonic-gate 	}
20310Sstevel@tonic-gate 
20320Sstevel@tonic-gate 	portp->port_saa_open_in_progress = 1;
20330Sstevel@tonic-gate 	mutex_exit(&ibcm_sa_open_lock);
20340Sstevel@tonic-gate 
20350Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(portp->port_event_status))
20360Sstevel@tonic-gate 
20370Sstevel@tonic-gate 	/* The assumption is that we're getting event notifications */
20380Sstevel@tonic-gate 	portp->port_event_status = IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SM;
20390Sstevel@tonic-gate 
20400Sstevel@tonic-gate 	_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(portp->port_event_status))
20410Sstevel@tonic-gate 
20420Sstevel@tonic-gate 	ibt_status = ibt_get_port_state_byguid(portp->port_hcap->hca_guid,
20430Sstevel@tonic-gate 	    portp->port_num, &portp->port_sgid0, NULL);
20440Sstevel@tonic-gate 	if (ibt_status != IBT_SUCCESS) {
20451093Shiremath 		IBTF_DPRINTF_L2(cmlog, "ibcm_init_saa_handle: "
20460Sstevel@tonic-gate 		    "ibt_get_port_state_byguid failed for guid %llX "
20470Sstevel@tonic-gate 		    "with status %d", portp->port_hcap->hca_guid, ibt_status);
20480Sstevel@tonic-gate 		mutex_enter(&ibcm_sa_open_lock);
20490Sstevel@tonic-gate 		portp->port_saa_open_in_progress = 0;
20500Sstevel@tonic-gate 		cv_broadcast(&ibcm_sa_open_cv);
20510Sstevel@tonic-gate 		mutex_exit(&ibcm_sa_open_lock);
20520Sstevel@tonic-gate 		return;
20530Sstevel@tonic-gate 	}
20540Sstevel@tonic-gate 	/* if the port is UP, try sa_session_open */
20550Sstevel@tonic-gate 	(void) taskq_dispatch(ibcm_taskq, ibcm_init_saa, portp, TQ_SLEEP);
20560Sstevel@tonic-gate }
20570Sstevel@tonic-gate 
20580Sstevel@tonic-gate 
20590Sstevel@tonic-gate ibmf_saa_handle_t
ibcm_get_saa_handle(ibcm_hca_info_t * hcap,uint8_t port)20600Sstevel@tonic-gate ibcm_get_saa_handle(ibcm_hca_info_t *hcap, uint8_t port)
20610Sstevel@tonic-gate {
20620Sstevel@tonic-gate 	ibmf_saa_handle_t	saa_handle;
20630Sstevel@tonic-gate 	uint8_t			port_index = port - 1;
20640Sstevel@tonic-gate 	ibcm_port_info_t	*portp = &hcap->hca_port_info[port_index];
20650Sstevel@tonic-gate 	ibt_status_t		ibt_status;
20660Sstevel@tonic-gate 
20670Sstevel@tonic-gate 	if (port_index >= hcap->hca_num_ports)
20680Sstevel@tonic-gate 		return (NULL);
20690Sstevel@tonic-gate 
20700Sstevel@tonic-gate 	mutex_enter(&ibcm_sa_open_lock);
20710Sstevel@tonic-gate 	while (portp->port_saa_open_in_progress) {
20720Sstevel@tonic-gate 		cv_wait(&ibcm_sa_open_cv, &ibcm_sa_open_lock);
20730Sstevel@tonic-gate 	}
20740Sstevel@tonic-gate 
20750Sstevel@tonic-gate 	saa_handle = portp->port_ibmf_saa_hdl;
20760Sstevel@tonic-gate 	if (saa_handle != NULL) {
20770Sstevel@tonic-gate 		mutex_exit(&ibcm_sa_open_lock);
20780Sstevel@tonic-gate 		return (saa_handle);
20790Sstevel@tonic-gate 	}
20800Sstevel@tonic-gate 
20810Sstevel@tonic-gate 	portp->port_saa_open_in_progress = 1;
20820Sstevel@tonic-gate 	mutex_exit(&ibcm_sa_open_lock);
20830Sstevel@tonic-gate 
20840Sstevel@tonic-gate 	ibt_status = ibt_get_port_state_byguid(portp->port_hcap->hca_guid,
20850Sstevel@tonic-gate 	    portp->port_num, &portp->port_sgid0, NULL);
20860Sstevel@tonic-gate 	if (ibt_status != IBT_SUCCESS) {
20871093Shiremath 		IBTF_DPRINTF_L2(cmlog, "ibcm_get_saa_handle: "
20880Sstevel@tonic-gate 		    "ibt_get_port_state_byguid failed for guid %llX "
20890Sstevel@tonic-gate 		    "with status %d", portp->port_hcap->hca_guid, ibt_status);
20900Sstevel@tonic-gate 		mutex_enter(&ibcm_sa_open_lock);
20910Sstevel@tonic-gate 		portp->port_saa_open_in_progress = 0;
20920Sstevel@tonic-gate 		cv_broadcast(&ibcm_sa_open_cv);
20930Sstevel@tonic-gate 		mutex_exit(&ibcm_sa_open_lock);
20940Sstevel@tonic-gate 		return (NULL);
20950Sstevel@tonic-gate 	}
20960Sstevel@tonic-gate 	/* if the port is UP, try sa_session_open */
20970Sstevel@tonic-gate 	(void) taskq_dispatch(ibcm_taskq, ibcm_init_saa, portp, TQ_SLEEP);
20980Sstevel@tonic-gate 
20990Sstevel@tonic-gate 	mutex_enter(&ibcm_sa_open_lock);
21000Sstevel@tonic-gate 	while (portp->port_saa_open_in_progress) {
21010Sstevel@tonic-gate 		cv_wait(&ibcm_sa_open_cv, &ibcm_sa_open_lock);
21020Sstevel@tonic-gate 	}
21030Sstevel@tonic-gate 	saa_handle = portp->port_ibmf_saa_hdl;
21040Sstevel@tonic-gate 	mutex_exit(&ibcm_sa_open_lock);
21050Sstevel@tonic-gate 	return (saa_handle);
21060Sstevel@tonic-gate }
21070Sstevel@tonic-gate 
21080Sstevel@tonic-gate 
21090Sstevel@tonic-gate /*
21100Sstevel@tonic-gate  * ibcm_hca_init_port():
21110Sstevel@tonic-gate  * 	- Register port with IBMA
21120Sstevel@tonic-gate  *
21130Sstevel@tonic-gate  * Arguments:
21140Sstevel@tonic-gate  *	hcap		- HCA's guid
21150Sstevel@tonic-gate  *	port_index	- port number minus 1
21160Sstevel@tonic-gate  *
21170Sstevel@tonic-gate  * Return values:
21180Sstevel@tonic-gate  *	IBCM_SUCCESS - success
21190Sstevel@tonic-gate  */
21200Sstevel@tonic-gate ibt_status_t
ibcm_hca_init_port(ibcm_hca_info_t * hcap,uint8_t port_index)21210Sstevel@tonic-gate ibcm_hca_init_port(ibcm_hca_info_t *hcap, uint8_t port_index)
21220Sstevel@tonic-gate {
21230Sstevel@tonic-gate 	int			status;
21240Sstevel@tonic-gate 	ibmf_register_info_t	*ibmf_reg;
21250Sstevel@tonic-gate 
21260Sstevel@tonic-gate 	IBTF_DPRINTF_L4(cmlog, "ibcm_hca_init_port: hcap = 0x%p port_num %d",
21270Sstevel@tonic-gate 	    hcap, port_index + 1);
21280Sstevel@tonic-gate 
21290Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ibcm_global_hca_lock));
21300Sstevel@tonic-gate 
21310Sstevel@tonic-gate 	_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(hcap->hca_port_info))
21320Sstevel@tonic-gate 
21330Sstevel@tonic-gate 	if (hcap->hca_port_info[port_index].port_ibmf_hdl == NULL) {
21340Sstevel@tonic-gate 		/* Register with IBMF */
21350Sstevel@tonic-gate 		ibmf_reg = &hcap->hca_port_info[port_index].port_ibmf_reg;
21360Sstevel@tonic-gate 		ibmf_reg->ir_ci_guid = hcap->hca_guid;
21370Sstevel@tonic-gate 		ibmf_reg->ir_port_num = port_index + 1;
21380Sstevel@tonic-gate 		ibmf_reg->ir_client_class = COMM_MGT_MANAGER_AGENT;
21390Sstevel@tonic-gate 
21400Sstevel@tonic-gate 		/*
21410Sstevel@tonic-gate 		 * register with management framework
21420Sstevel@tonic-gate 		 */
21430Sstevel@tonic-gate 		status = ibmf_register(ibmf_reg, IBMF_VERSION,
21440Sstevel@tonic-gate 		    IBMF_REG_FLAG_NO_OFFLOAD, NULL, NULL,
21450Sstevel@tonic-gate 		    &(hcap->hca_port_info[port_index].port_ibmf_hdl),
21460Sstevel@tonic-gate 		    &(hcap->hca_port_info[port_index].port_ibmf_caps));
21470Sstevel@tonic-gate 
21480Sstevel@tonic-gate 		if (status != IBMF_SUCCESS) {
21490Sstevel@tonic-gate 			IBTF_DPRINTF_L2(cmlog, "ibcm_hca_init_port: "
21500Sstevel@tonic-gate 			    "ibmf_register failed for port_num %x, "
21510Sstevel@tonic-gate 			    "status = %x", port_index + 1, status);
21520Sstevel@tonic-gate 			return (ibcm_ibmf_analyze_error(status));
21530Sstevel@tonic-gate 		}
21540Sstevel@tonic-gate 
21550Sstevel@tonic-gate 		hcap->hca_port_info[port_index].port_qp1.qp_cm =
21560Sstevel@tonic-gate 		    IBMF_QP_HANDLE_DEFAULT;
21570Sstevel@tonic-gate 		hcap->hca_port_info[port_index].port_qp1.qp_port =
21580Sstevel@tonic-gate 		    &(hcap->hca_port_info[port_index]);
21590Sstevel@tonic-gate 
21600Sstevel@tonic-gate 		/*
21610Sstevel@tonic-gate 		 * Register the read callback with IBMF.
21620Sstevel@tonic-gate 		 * Since we just did an ibmf_register, handle is
21630Sstevel@tonic-gate 		 * valid and ibcm_recv_cb() is valid so we can
21640Sstevel@tonic-gate 		 * safely assert for success of ibmf_setup_recv_cb()
21650Sstevel@tonic-gate 		 *
21660Sstevel@tonic-gate 		 * Depending on the "state" of the HCA,
21670Sstevel@tonic-gate 		 * CM may drop incoming packets
21680Sstevel@tonic-gate 		 */
21690Sstevel@tonic-gate 		status = ibmf_setup_async_cb(
21700Sstevel@tonic-gate 		    hcap->hca_port_info[port_index].port_ibmf_hdl,
21710Sstevel@tonic-gate 		    IBMF_QP_HANDLE_DEFAULT, ibcm_recv_cb,
21720Sstevel@tonic-gate 		    &(hcap->hca_port_info[port_index].port_qp1), 0);
21730Sstevel@tonic-gate 		ASSERT(status == IBMF_SUCCESS);
21740Sstevel@tonic-gate 
21750Sstevel@tonic-gate 		IBTF_DPRINTF_L5(cmlog, "ibcm_hca_init_port: "
21760Sstevel@tonic-gate 		    "IBMF hdl[%x] = 0x%p", port_index,
21770Sstevel@tonic-gate 		    hcap->hca_port_info[port_index].port_ibmf_hdl);
21780Sstevel@tonic-gate 
21790Sstevel@tonic-gate 		/* Attempt to get the saa_handle for this port */
21800Sstevel@tonic-gate 		ibcm_init_saa_handle(hcap, port_index + 1);
21810Sstevel@tonic-gate 	}
21820Sstevel@tonic-gate 
21830Sstevel@tonic-gate 	return (IBT_SUCCESS);
21840Sstevel@tonic-gate }
21850Sstevel@tonic-gate 
21860Sstevel@tonic-gate /*
21870Sstevel@tonic-gate  * useful, to re attempt to initialize port ibma handles from elsewhere in
21880Sstevel@tonic-gate  * cm code
21890Sstevel@tonic-gate  */
21900Sstevel@tonic-gate ibt_status_t
ibcm_hca_reinit_port(ibcm_hca_info_t * hcap,uint8_t port_index)21910Sstevel@tonic-gate ibcm_hca_reinit_port(ibcm_hca_info_t *hcap, uint8_t port_index)
21920Sstevel@tonic-gate {
21930Sstevel@tonic-gate 	ibt_status_t	status;
21940Sstevel@tonic-gate 
21950Sstevel@tonic-gate 	IBTF_DPRINTF_L5(cmlog, "ibcm_hca_reinit_port: hcap 0x%p port_num %d",
21960Sstevel@tonic-gate 	    hcap, port_index + 1);
21970Sstevel@tonic-gate 
21980Sstevel@tonic-gate 	mutex_enter(&ibcm_global_hca_lock);
21990Sstevel@tonic-gate 	status = ibcm_hca_init_port(hcap, port_index);
22000Sstevel@tonic-gate 	mutex_exit(&ibcm_global_hca_lock);
22010Sstevel@tonic-gate 	return (status);
22020Sstevel@tonic-gate }
22030Sstevel@tonic-gate 
22040Sstevel@tonic-gate 
22050Sstevel@tonic-gate /*
22060Sstevel@tonic-gate  * ibcm_hca_fini_port():
22070Sstevel@tonic-gate  * 	- Deregister port with IBMA
22080Sstevel@tonic-gate  *
22090Sstevel@tonic-gate  * Arguments:
22100Sstevel@tonic-gate  *	hcap		- HCA's guid
22110Sstevel@tonic-gate  *	port_index	- port number minus 1
22120Sstevel@tonic-gate  *
22130Sstevel@tonic-gate  * Return values:
22140Sstevel@tonic-gate  *	IBCM_SUCCESS - success
22150Sstevel@tonic-gate  */
22160Sstevel@tonic-gate static ibcm_status_t
ibcm_hca_fini_port(ibcm_hca_info_t * hcap,uint8_t port_index)22170Sstevel@tonic-gate ibcm_hca_fini_port(ibcm_hca_info_t *hcap, uint8_t port_index)
22180Sstevel@tonic-gate {
22190Sstevel@tonic-gate 	int			ibmf_status;
22200Sstevel@tonic-gate 	ibcm_status_t		ibcm_status;
22210Sstevel@tonic-gate 
22220Sstevel@tonic-gate 	IBTF_DPRINTF_L4(cmlog, "ibcm_hca_fini_port: hcap = 0x%p port_num %d ",
22230Sstevel@tonic-gate 	    hcap, port_index + 1);
22240Sstevel@tonic-gate 
22250Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&ibcm_global_hca_lock));
22260Sstevel@tonic-gate 
22270Sstevel@tonic-gate 	if (hcap->hca_port_info[port_index].port_ibmf_saa_hdl != NULL) {
22280Sstevel@tonic-gate 		IBTF_DPRINTF_L5(cmlog, "ibcm_hca_fini_port: "
22290Sstevel@tonic-gate 		    "ibmf_sa_session_close IBMF SAA hdl %p",
22300Sstevel@tonic-gate 		    hcap->hca_port_info[port_index].port_ibmf_saa_hdl);
22310Sstevel@tonic-gate 
22320Sstevel@tonic-gate 		ibmf_status = ibmf_sa_session_close(
22330Sstevel@tonic-gate 		    &hcap->hca_port_info[port_index].port_ibmf_saa_hdl, 0);
22340Sstevel@tonic-gate 		if (ibmf_status != IBMF_SUCCESS) {
22351093Shiremath 			IBTF_DPRINTF_L2(cmlog, "ibcm_hca_fini_port: "
22360Sstevel@tonic-gate 			    "ibmf_sa_session_close of port %d returned %x",
22370Sstevel@tonic-gate 			    port_index + 1, ibmf_status);
22380Sstevel@tonic-gate 			return (IBCM_FAILURE);
22390Sstevel@tonic-gate 		}
22400Sstevel@tonic-gate 	}
22410Sstevel@tonic-gate 
22420Sstevel@tonic-gate 	if (hcap->hca_port_info[port_index].port_ibmf_hdl != NULL) {
22430Sstevel@tonic-gate 		IBTF_DPRINTF_L5(cmlog, "ibcm_hca_fini_port: "
22440Sstevel@tonic-gate 		    "ibmf_unregister IBMF Hdl %p",
22450Sstevel@tonic-gate 		    hcap->hca_port_info[port_index].port_ibmf_hdl);
22460Sstevel@tonic-gate 
22470Sstevel@tonic-gate 		/* clean-up all the ibmf qp's allocated on this port */
22480Sstevel@tonic-gate 		ibcm_status = ibcm_free_allqps(hcap, port_index + 1);
22490Sstevel@tonic-gate 
22500Sstevel@tonic-gate 		if (ibcm_status != IBCM_SUCCESS) {
22510Sstevel@tonic-gate 
22521093Shiremath 			IBTF_DPRINTF_L2(cmlog, "ibcm_hca_fini_port: "
22530Sstevel@tonic-gate 			    "ibcm_free_allqps failed for port_num %d",
22540Sstevel@tonic-gate 			    port_index + 1);
22550Sstevel@tonic-gate 			return (IBCM_FAILURE);
22560Sstevel@tonic-gate 		}
22570Sstevel@tonic-gate 
22580Sstevel@tonic-gate 		/* Tear down the receive callback */
22590Sstevel@tonic-gate 		ibmf_status = ibmf_tear_down_async_cb(
22600Sstevel@tonic-gate 		    hcap->hca_port_info[port_index].port_ibmf_hdl,
22610Sstevel@tonic-gate 		    IBMF_QP_HANDLE_DEFAULT, 0);
22620Sstevel@tonic-gate 
22630Sstevel@tonic-gate 		if (ibmf_status != IBMF_SUCCESS) {
22641093Shiremath 			IBTF_DPRINTF_L2(cmlog, "ibcm_hca_fini_port: "
22650Sstevel@tonic-gate 			    "ibmf_tear_down_async_cb failed %d port_num %d",
22660Sstevel@tonic-gate 			    ibmf_status, port_index + 1);
22670Sstevel@tonic-gate 			return (IBCM_FAILURE);
22680Sstevel@tonic-gate 		}
22690Sstevel@tonic-gate 
22700Sstevel@tonic-gate 		/* Now, unregister with IBMF */
22710Sstevel@tonic-gate 		ibmf_status = ibmf_unregister(
22720Sstevel@tonic-gate 		    &hcap->hca_port_info[port_index].port_ibmf_hdl, 0);
22730Sstevel@tonic-gate 		IBTF_DPRINTF_L4(cmlog, "ibcm_hca_fini_port: "
22740Sstevel@tonic-gate 		    "ibmf_unregister of port_num %x returned %x",
22750Sstevel@tonic-gate 		    port_index + 1, ibmf_status);
22760Sstevel@tonic-gate 
22770Sstevel@tonic-gate 		if (ibmf_status == IBMF_SUCCESS)
22787862SRichard.Bean@Sun.COM 			hcap->hca_port_info[port_index].port_ibmf_hdl = NULL;
22790Sstevel@tonic-gate 		else {
22801093Shiremath 			IBTF_DPRINTF_L2(cmlog, "ibcm_hca_fini_port: "
22810Sstevel@tonic-gate 			    "ibmf_unregister failed %d port_num %d",
22820Sstevel@tonic-gate 			    ibmf_status, port_index + 1);
22830Sstevel@tonic-gate 			return (IBCM_FAILURE);
22840Sstevel@tonic-gate 		}
22850Sstevel@tonic-gate 	}
22860Sstevel@tonic-gate 	return (IBCM_SUCCESS);
22870Sstevel@tonic-gate }
22880Sstevel@tonic-gate 
22890Sstevel@tonic-gate /*
22900Sstevel@tonic-gate  * ibcm_comm_est_handler():
22910Sstevel@tonic-gate  *	Check if the given channel is in ESTABLISHED state or not
22920Sstevel@tonic-gate  *
22930Sstevel@tonic-gate  * Arguments:
22940Sstevel@tonic-gate  *	eventp	- A pointer to an ibt_async_event_t struct
22950Sstevel@tonic-gate  *
22960Sstevel@tonic-gate  * Return values: NONE
22970Sstevel@tonic-gate  */
22980Sstevel@tonic-gate static void
ibcm_comm_est_handler(ibt_async_event_t * eventp)22990Sstevel@tonic-gate ibcm_comm_est_handler(ibt_async_event_t *eventp)
23000Sstevel@tonic-gate {
23010Sstevel@tonic-gate 	ibcm_state_data_t	*statep;
23020Sstevel@tonic-gate 
23030Sstevel@tonic-gate 	IBTF_DPRINTF_L4(cmlog, "ibcm_comm_est_handler:");
23040Sstevel@tonic-gate 
23050Sstevel@tonic-gate 	/* Both QP and EEC handles can't be NULL */
23060Sstevel@tonic-gate 	if (eventp->ev_chan_hdl == NULL) {
23070Sstevel@tonic-gate 		IBTF_DPRINTF_L2(cmlog, "ibcm_comm_est_handler: "
23080Sstevel@tonic-gate 		    "both QP and EEC handles are NULL");
23090Sstevel@tonic-gate 		return;
23100Sstevel@tonic-gate 	}
23110Sstevel@tonic-gate 
23120Sstevel@tonic-gate 	/* get the "statep" from qp/eec handles */
23130Sstevel@tonic-gate 	IBCM_GET_CHAN_PRIVATE(eventp->ev_chan_hdl, statep);
23140Sstevel@tonic-gate 	if (statep == NULL) {
23150Sstevel@tonic-gate 		IBTF_DPRINTF_L2(cmlog, "ibcm_comm_est_handler: statep is NULL");
23160Sstevel@tonic-gate 		return;
23170Sstevel@tonic-gate 	}
23180Sstevel@tonic-gate 
23190Sstevel@tonic-gate 	mutex_enter(&statep->state_mutex);
23200Sstevel@tonic-gate 
23210Sstevel@tonic-gate 	IBCM_RELEASE_CHAN_PRIVATE(eventp->ev_chan_hdl);
23220Sstevel@tonic-gate 
23230Sstevel@tonic-gate 	IBTF_DPRINTF_L4(cmlog, "ibcm_comm_est_handler: statep = %p", statep);
23240Sstevel@tonic-gate 
23250Sstevel@tonic-gate 	IBCM_REF_CNT_INCR(statep);
23260Sstevel@tonic-gate 
23270Sstevel@tonic-gate 	if ((statep->state == IBCM_STATE_REP_SENT) ||
23280Sstevel@tonic-gate 	    (statep->state == IBCM_STATE_MRA_REP_RCVD)) {
23290Sstevel@tonic-gate 		timeout_id_t	timer_val = statep->timerid;
23300Sstevel@tonic-gate 
23310Sstevel@tonic-gate 		statep->state = IBCM_STATE_TRANSIENT_ESTABLISHED;
23320Sstevel@tonic-gate 
23330Sstevel@tonic-gate 		if (timer_val) {
23340Sstevel@tonic-gate 			statep->timerid = 0;
23350Sstevel@tonic-gate 			mutex_exit(&statep->state_mutex);
23360Sstevel@tonic-gate 			(void) untimeout(timer_val);
23370Sstevel@tonic-gate 		} else
23380Sstevel@tonic-gate 			mutex_exit(&statep->state_mutex);
23390Sstevel@tonic-gate 
23400Sstevel@tonic-gate 		/* CM doesn't have RTU message here */
23410Sstevel@tonic-gate 		ibcm_cep_state_rtu(statep, NULL);
23420Sstevel@tonic-gate 
23430Sstevel@tonic-gate 	} else {
2344557Shiremath 		if (statep->state == IBCM_STATE_ESTABLISHED ||
2345557Shiremath 		    statep->state == IBCM_STATE_TRANSIENT_ESTABLISHED) {
23460Sstevel@tonic-gate 			IBTF_DPRINTF_L4(cmlog, "ibcm_comm_est_handler: "
23470Sstevel@tonic-gate 			    "Channel already in ESTABLISHED state");
23480Sstevel@tonic-gate 		} else {
23490Sstevel@tonic-gate 			/* An unexpected behavior from remote */
23500Sstevel@tonic-gate 			IBTF_DPRINTF_L2(cmlog, "ibcm_comm_est_handler: "
23510Sstevel@tonic-gate 			    "Unexpected in state = %d", statep->state);
23520Sstevel@tonic-gate 		}
23530Sstevel@tonic-gate 		mutex_exit(&statep->state_mutex);
23540Sstevel@tonic-gate 
23550Sstevel@tonic-gate 		ibcm_insert_trace(statep, IBCM_TRACE_INCOMING_COMEST);
23560Sstevel@tonic-gate 	}
23570Sstevel@tonic-gate 
23580Sstevel@tonic-gate 	mutex_enter(&statep->state_mutex);
23590Sstevel@tonic-gate 	IBCM_REF_CNT_DECR(statep);
23600Sstevel@tonic-gate 	mutex_exit(&statep->state_mutex);
23610Sstevel@tonic-gate }
23620Sstevel@tonic-gate 
23630Sstevel@tonic-gate 
23640Sstevel@tonic-gate /*
23650Sstevel@tonic-gate  * ibcm_async_handler():
23660Sstevel@tonic-gate  *	CM's Async Handler
23670Sstevel@tonic-gate  *	(Handles ATTACH, DETACH, COM_EST events)
23680Sstevel@tonic-gate  *
23690Sstevel@tonic-gate  * Arguments:
23700Sstevel@tonic-gate  *	eventp	- A pointer to an ibt_async_event_t struct
23710Sstevel@tonic-gate  *
23720Sstevel@tonic-gate  * Return values: None
23730Sstevel@tonic-gate  *
23740Sstevel@tonic-gate  * NOTE : CM assumes that all HCA DR events are delivered sequentially
23750Sstevel@tonic-gate  * i.e., until ibcm_async_handler  completes for a given HCA DR, framework
23760Sstevel@tonic-gate  * shall not invoke ibcm_async_handler with another DR event for the same
23770Sstevel@tonic-gate  * HCA
23780Sstevel@tonic-gate  */
23790Sstevel@tonic-gate /* ARGSUSED */
23800Sstevel@tonic-gate void
ibcm_async_handler(void * clnt_hdl,ibt_hca_hdl_t hca_hdl,ibt_async_code_t code,ibt_async_event_t * eventp)23810Sstevel@tonic-gate ibcm_async_handler(void *clnt_hdl, ibt_hca_hdl_t hca_hdl,
23820Sstevel@tonic-gate     ibt_async_code_t code, ibt_async_event_t *eventp)
23830Sstevel@tonic-gate {
23840Sstevel@tonic-gate 	ibcm_hca_info_t		*hcap;
23850Sstevel@tonic-gate 	ibcm_port_up_t		*pup;
23860Sstevel@tonic-gate 
23870Sstevel@tonic-gate 	IBTF_DPRINTF_L3(cmlog, "ibcm_async_handler: "
23880Sstevel@tonic-gate 	    "clnt_hdl = %p, code = 0x%x, eventp = 0x%p",
23890Sstevel@tonic-gate 	    clnt_hdl, code, eventp);
23900Sstevel@tonic-gate 
23910Sstevel@tonic-gate 	mutex_enter(&ibcm_global_hca_lock);
23920Sstevel@tonic-gate 
23930Sstevel@tonic-gate 	/* If fini is going to complete successfully, then return */
23940Sstevel@tonic-gate 	if (ibcm_finit_state != IBCM_FINIT_IDLE) {
23950Sstevel@tonic-gate 
23960Sstevel@tonic-gate 		/*
23970Sstevel@tonic-gate 		 * This finit state implies one of the following:
23980Sstevel@tonic-gate 		 * Init either didn't start or didn't complete OR
23990Sstevel@tonic-gate 		 * Fini is about to return SUCCESS and release the global lock.
24000Sstevel@tonic-gate 		 * In all these cases, it is safe to ignore the async.
24010Sstevel@tonic-gate 		 */
24020Sstevel@tonic-gate 
24030Sstevel@tonic-gate 		IBTF_DPRINTF_L2(cmlog, "ibcm_async_handler: ignoring event %x, "
24040Sstevel@tonic-gate 		    "as either init didn't complete or fini about to succeed",
24050Sstevel@tonic-gate 		    code);
24060Sstevel@tonic-gate 		mutex_exit(&ibcm_global_hca_lock);
24070Sstevel@tonic-gate 		return;
24080Sstevel@tonic-gate 	}
24090Sstevel@tonic-gate 
24100Sstevel@tonic-gate 	switch (code) {
24119891SRajkumar.Sivaprakasam@Sun.COM 	case IBT_PORT_CHANGE_EVENT:
24129891SRajkumar.Sivaprakasam@Sun.COM 		if ((eventp->ev_port_flags & IBT_PORT_CHANGE_SM_LID) == 0)
24139891SRajkumar.Sivaprakasam@Sun.COM 			break;
24149891SRajkumar.Sivaprakasam@Sun.COM 	/* FALLTHROUGH */
24159891SRajkumar.Sivaprakasam@Sun.COM 	case IBT_CLNT_REREG_EVENT:
24160Sstevel@tonic-gate 	case IBT_EVENT_PORT_UP:
24170Sstevel@tonic-gate 		mutex_exit(&ibcm_global_hca_lock);
24180Sstevel@tonic-gate 		pup = kmem_alloc(sizeof (ibcm_port_up_t), KM_SLEEP);
24190Sstevel@tonic-gate 		_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*pup))
24200Sstevel@tonic-gate 		pup->pup_hca_guid = eventp->ev_hca_guid;
24210Sstevel@tonic-gate 		pup->pup_port = eventp->ev_port;
24220Sstevel@tonic-gate 		_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*pup))
24230Sstevel@tonic-gate 		(void) taskq_dispatch(ibcm_taskq,
24240Sstevel@tonic-gate 		    ibcm_service_record_rewrite_task, pup, TQ_SLEEP);
2425557Shiremath 		ibcm_path_cache_purge();
24260Sstevel@tonic-gate 		return;
24270Sstevel@tonic-gate 
24280Sstevel@tonic-gate 	case IBT_HCA_ATTACH_EVENT:
24290Sstevel@tonic-gate 
24300Sstevel@tonic-gate 		/* eventp->ev_hcaguid is the HCA GUID of interest */
24310Sstevel@tonic-gate 		ibcm_hca_attach(eventp->ev_hca_guid);
24320Sstevel@tonic-gate 		break;
24330Sstevel@tonic-gate 
24340Sstevel@tonic-gate 	case IBT_HCA_DETACH_EVENT:
24350Sstevel@tonic-gate 
24360Sstevel@tonic-gate 		/* eventp->ev_hca_guid is the HCA GUID of interest */
24370Sstevel@tonic-gate 		if ((hcap = ibcm_find_hcap_entry(eventp->ev_hca_guid)) ==
24380Sstevel@tonic-gate 		    NULL) {
24390Sstevel@tonic-gate 			IBTF_DPRINTF_L2(cmlog, "ibcm_async_handler:"
24400Sstevel@tonic-gate 			    " hca %llX doesn't exist", eventp->ev_hca_guid);
24410Sstevel@tonic-gate 			break;
24420Sstevel@tonic-gate 		}
24430Sstevel@tonic-gate 
24440Sstevel@tonic-gate 		(void) ibcm_hca_detach(hcap);
24450Sstevel@tonic-gate 		break;
24460Sstevel@tonic-gate 
24470Sstevel@tonic-gate 	case IBT_EVENT_COM_EST_QP:
24480Sstevel@tonic-gate 		/* eventp->ev_qp_hdl is the ibt_qp_hdl_t of interest */
24490Sstevel@tonic-gate 	case IBT_EVENT_COM_EST_EEC:
24500Sstevel@tonic-gate 		/* eventp->ev_eec_hdl is the ibt_eec_hdl_t of interest */
24510Sstevel@tonic-gate 		ibcm_comm_est_handler(eventp);
24520Sstevel@tonic-gate 		break;
24530Sstevel@tonic-gate 	default:
24540Sstevel@tonic-gate 		break;
24550Sstevel@tonic-gate 	}
24560Sstevel@tonic-gate 
24570Sstevel@tonic-gate 	/* Unblock, any blocked fini/init operations */
24580Sstevel@tonic-gate 	mutex_exit(&ibcm_global_hca_lock);
24590Sstevel@tonic-gate }
2460