Print this page
7127 remove -Wno-missing-braces from Makefile.uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/ib/mgt/ibcm/ibcm_impl.c
+++ new/usr/src/uts/common/io/ib/mgt/ibcm/ibcm_impl.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 */
25 25
26 26 /*
27 27 * ibcm_impl.c
28 28 *
29 29 * contains internal functions of IB CM module.
30 30 *
31 31 * TBD:
32 32 * 1. HCA CATASTROPHIC/RECOVERED not handled yet
33 33 */
34 34
35 35 #include <sys/ib/mgt/ibcm/ibcm_impl.h>
36 36 #include <sys/disp.h>
37 37
38 38
39 39 /* function prototypes */
40 40 static ibcm_status_t ibcm_init(void);
41 41 static ibcm_status_t ibcm_fini(void);
42 42
43 43 /* Routines to initialize and destroy CM global locks and CVs */
44 44 static void ibcm_init_locks(void);
45 45 static void ibcm_fini_locks(void);
46 46
47 47 /* Routines that initialize/teardown CM's global hca structures */
48 48 static void ibcm_init_hcas();
49 49 static ibcm_status_t ibcm_fini_hcas();
50 50
51 51 static void ibcm_init_classportinfo();
52 52 static void ibcm_stop_timeout_thread();
53 53
54 54 /* Routines that handle HCA attach/detach asyncs */
55 55 static void ibcm_hca_attach(ib_guid_t);
56 56 static ibcm_status_t ibcm_hca_detach(ibcm_hca_info_t *);
57 57
58 58 /* Routines that initialize the HCA's port related fields */
59 59 static ibt_status_t ibcm_hca_init_port(ibcm_hca_info_t *hcap,
60 60 uint8_t port_index);
61 61 static ibcm_status_t ibcm_hca_fini_port(ibcm_hca_info_t *hcap,
62 62 uint8_t port_index);
63 63
64 64 static void ibcm_rc_flow_control_init(void);
65 65 static void ibcm_rc_flow_control_fini(void);
66 66
67 67 /*
68 68 * Routines that check if hca's avl trees and sidr lists are free of any
69 69 * active client resources ie., RC or UD state structures in certain states
70 70 */
71 71 static ibcm_status_t ibcm_check_avl_clean(ibcm_hca_info_t *hcap);
72 72 static ibcm_status_t ibcm_check_sidr_clean(ibcm_hca_info_t *hcap);
73 73
74 74 /* Add a new hca structure to CM's global hca list */
75 75 static ibcm_hca_info_t *ibcm_add_hca_entry(ib_guid_t hcaguid, uint_t nports);
76 76
77 77 static void ibcm_comm_est_handler(ibt_async_event_t *);
78 78 void ibcm_async_handler(void *, ibt_hca_hdl_t,
79 79 ibt_async_code_t, ibt_async_event_t *);
80 80
81 81 /* Global variables */
82 82 char cmlog[] = "ibcm"; /* for debug log messages */
83 83 ibt_clnt_hdl_t ibcm_ibt_handle; /* IBT handle */
84 84 kmutex_t ibcm_svc_info_lock; /* list lock */
85 85 kcondvar_t ibcm_svc_info_cv; /* cv for deregister */
86 86 kmutex_t ibcm_recv_mutex;
87 87 avl_tree_t ibcm_svc_avl_tree;
88 88 taskq_t *ibcm_taskq = NULL;
89 89 int taskq_dispatch_fail_cnt;
90 90
91 91 kmutex_t ibcm_mcglist_lock; /* MCG list lock */
92 92 kmutex_t ibcm_trace_mutex; /* Trace mutex */
93 93 kmutex_t ibcm_trace_print_mutex; /* Trace print mutex */
94 94 int ibcm_conn_max_trcnt = IBCM_MAX_CONN_TRCNT;
95 95
96 96 int ibcm_enable_trace = 2; /* Trace level 4 by default */
97 97 int ibcm_dtrace = 0; /* conditionally enable more dtrace */
98 98
99 99 _NOTE(MUTEX_PROTECTS_DATA(ibcm_svc_info_lock, ibcm_svc_info_s::{svc_bind_list
100 100 svc_ref_cnt svc_to_delete}))
101 101
102 102 _NOTE(MUTEX_PROTECTS_DATA(ibcm_svc_info_lock, ibcm_svc_bind_s::{sbind_link}))
103 103
104 104 _NOTE(MUTEX_PROTECTS_DATA(ibcm_trace_mutex, ibcm_conn_trace_s))
105 105
106 106 _NOTE(DATA_READABLE_WITHOUT_LOCK(ibcm_conn_trace_s))
107 107
108 108 _NOTE(MUTEX_PROTECTS_DATA(ibcm_trace_print_mutex, ibcm_debug_buf))
109 109
110 110 _NOTE(DATA_READABLE_WITHOUT_LOCK(ibcm_debug_buf))
111 111
112 112 /*
113 113 * Initial state is INIT. All hca dr's return success immediately in this
114 114 * state, without adding or deleting any hca's to CM.
115 115 */
116 116 ibcm_finit_state_t ibcm_finit_state = IBCM_FINIT_INIT;
117 117
118 118 /* mutex and cv to manage hca's reference and resource count(s) */
119 119 kmutex_t ibcm_global_hca_lock;
120 120 kcondvar_t ibcm_global_hca_cv;
121 121
122 122 /* mutex and cv to sa session open */
123 123 kmutex_t ibcm_sa_open_lock;
124 124 kcondvar_t ibcm_sa_open_cv;
125 125 int ibcm_sa_timeout_delay = 1; /* in ticks */
126 126 _NOTE(MUTEX_PROTECTS_DATA(ibcm_sa_open_lock,
127 127 ibcm_port_info_s::{port_ibmf_saa_hdl port_saa_open_in_progress}))
128 128
129 129 _NOTE(DATA_READABLE_WITHOUT_LOCK(ibcm_port_info_s::{port_ibmf_saa_hdl}))
130 130
131 131 /* serialize sm notice callbacks */
132 132 kmutex_t ibcm_sm_notice_serialize_lock;
133 133
134 134 _NOTE(LOCK_ORDER(ibcm_sm_notice_serialize_lock ibcm_global_hca_lock))
135 135
136 136 _NOTE(MUTEX_PROTECTS_DATA(ibcm_global_hca_lock, ibcm_hca_info_s::{hca_state
137 137 hca_svc_cnt hca_acc_cnt hca_res_cnt hca_next}))
138 138
139 139 _NOTE(MUTEX_PROTECTS_DATA(ibcm_global_hca_lock,
140 140 ibcm_port_info_s::{port_ibmf_hdl}))
141 141
142 142 _NOTE(MUTEX_PROTECTS_DATA(ibcm_sm_notice_serialize_lock,
143 143 ibcm_port_info_s::{port_event_status}))
144 144
145 145 _NOTE(DATA_READABLE_WITHOUT_LOCK(ibcm_hca_info_s::{hca_state}))
146 146 _NOTE(DATA_READABLE_WITHOUT_LOCK(
147 147 ibcm_hca_info_s::{hca_port_info.port_ibmf_hdl}))
148 148
149 149 /* mutex for CM's qp list management */
150 150 kmutex_t ibcm_qp_list_lock;
151 151
152 152 _NOTE(MUTEX_PROTECTS_DATA(ibcm_qp_list_lock, ibcm_port_info_s::{port_qplist}))
153 153 _NOTE(MUTEX_PROTECTS_DATA(ibcm_qp_list_lock, ibcm_qp_list_s))
154 154 _NOTE(MUTEX_PROTECTS_DATA(ibcm_qp_list_lock, ibcm_qp_list_s))
155 155
156 156 kcondvar_t ibcm_timeout_list_cv;
157 157 kcondvar_t ibcm_timeout_thread_done_cv;
158 158 kt_did_t ibcm_timeout_thread_did;
159 159 ibcm_state_data_t *ibcm_timeout_list_hdr, *ibcm_timeout_list_tail;
160 160 ibcm_ud_state_data_t *ibcm_ud_timeout_list_hdr, *ibcm_ud_timeout_list_tail;
161 161 kmutex_t ibcm_timeout_list_lock;
162 162 uint8_t ibcm_timeout_list_flags = 0;
163 163 pri_t ibcm_timeout_thread_pri = MINCLSYSPRI;
164 164
165 165 _NOTE(MUTEX_PROTECTS_DATA(ibcm_timeout_list_lock,
166 166 ibcm_state_data_s::timeout_next))
167 167
168 168 _NOTE(MUTEX_PROTECTS_DATA(ibcm_timeout_list_lock,
169 169 ibcm_ud_state_data_s::ud_timeout_next))
170 170
171 171 /*
172 172 * Flow control logic for open_rc_channel uses the following.
173 173 */
174 174
175 175 struct ibcm_open_s {
176 176 kmutex_t mutex;
177 177 kcondvar_t cv;
178 178 uint8_t task_running;
179 179 uint_t queued;
180 180 uint_t exit_deferred;
181 181 uint_t in_progress;
182 182 uint_t in_progress_max;
183 183 uint_t sends;
184 184 uint_t sends_max;
185 185 uint_t sends_lowat;
186 186 uint_t sends_hiwat;
187 187 ibcm_state_data_t *tail;
188 188 ibcm_state_data_t head;
189 189 } ibcm_open;
190 190
191 191 /*
192 192 * Flow control logic for SA access and close_rc_channel calls follows.
193 193 */
194 194
195 195 int ibcm_close_simul_max = 12;
196 196 int ibcm_lapr_simul_max = 12;
197 197 int ibcm_saa_simul_max = 8;
198 198
199 199 typedef struct ibcm_flow1_s {
200 200 struct ibcm_flow1_s *link;
201 201 kcondvar_t cv;
202 202 uint8_t waiters; /* 1 to IBCM_FLOW_SIMUL_MAX */
203 203 } ibcm_flow1_t;
204 204
205 205 typedef struct ibcm_flow_s {
206 206 ibcm_flow1_t *list;
207 207 uint_t simul; /* #requests currently outstanding */
208 208 uint_t simul_max;
209 209 uint_t waiters_per_chunk;
210 210 uint_t lowat;
211 211 uint_t lowat_default;
212 212 /* statistics */
213 213 uint_t total;
214 214 } ibcm_flow_t;
215 215
216 216 ibcm_flow_t ibcm_saa_flow;
217 217 ibcm_flow_t ibcm_close_flow;
218 218 ibcm_flow_t ibcm_lapr_flow;
219 219
220 220 /* NONBLOCKING close requests are queued */
221 221 struct ibcm_close_s {
222 222 kmutex_t mutex;
223 223 ibcm_state_data_t *tail;
224 224 ibcm_state_data_t head;
225 225 } ibcm_close;
226 226
227 227 static ibt_clnt_modinfo_t ibcm_ibt_modinfo = { /* Client's modinfop */
228 228 IBTI_V_CURR,
229 229 IBT_CM,
230 230 ibcm_async_handler,
231 231 NULL,
232 232 "IBCM"
233 233 };
234 234
235 235 /* IBCM's list of HCAs registered with it */
236 236 static ibcm_hca_info_t *ibcm_hca_listp = NULL; /* CM's HCA list */
237 237
238 238 /* Array of CM state call table functions */
239 239 ibcm_state_handler_t ibcm_sm_funcs_tbl[] = {
240 240 ibcm_process_req_msg,
241 241 ibcm_process_mra_msg,
242 242 ibcm_process_rej_msg,
243 243 ibcm_process_rep_msg,
244 244 ibcm_process_rtu_msg,
245 245 ibcm_process_dreq_msg,
246 246 ibcm_process_drep_msg,
247 247 ibcm_process_sidr_req_msg,
248 248 ibcm_process_sidr_rep_msg,
249 249 ibcm_process_lap_msg,
250 250 ibcm_process_apr_msg
251 251 };
252 252
253 253 /* the following globals are CM tunables */
254 254 ibt_rnr_nak_time_t ibcm_default_rnr_nak_time = IBT_RNR_NAK_655ms;
255 255
256 256 uint8_t ibcm_max_retries = IBCM_MAX_RETRIES;
257 257 clock_t ibcm_local_processing_time = IBCM_LOCAL_RESPONSE_TIME;
258 258 clock_t ibcm_remote_response_time = IBCM_REMOTE_RESPONSE_TIME;
259 259 ib_time_t ibcm_max_sidr_rep_proctime = IBCM_MAX_SIDR_PROCESS_TIME;
260 260 ib_time_t ibcm_max_sidr_pktlife_time = IBCM_MAX_SIDR_PKT_LIFE_TIME;
261 261
262 262 ib_time_t ibcm_max_sidr_rep_store_time = 18;
263 263 uint32_t ibcm_wait_for_acc_cnt_timeout = 2000000; /* 2 sec */
264 264
265 265 ib_time_t ibcm_max_ib_pkt_lt = IBCM_MAX_IB_PKT_LT;
266 266 ib_time_t ibcm_max_ib_mad_pkt_lt = IBCM_MAX_IB_MAD_PKT_LT;
267 267
268 268 /*
269 269 * This delay accounts for time involved in various activities as follows :
270 270 *
271 271 * IBMF delays for posting the MADs in non-blocking mode
272 272 * IBMF delays for receiving the MADs and delivering to CM
273 273 * CM delays in processing the MADs before invoking client handlers,
274 274 * Any other delays associated with HCA driver in processing the MADs and
275 275 * other subsystems that CM may invoke (ex : SA, HCA driver)
276 276 */
277 277 uint32_t ibcm_sw_delay = 1000; /* 1000us / 1ms */
278 278 uint32_t ibcm_max_sa_retries = IBCM_MAX_SA_RETRIES + 1;
279 279
280 280 /* approx boot time */
281 281 uint32_t ibcm_adj_btime = 4; /* 4 seconds */
282 282
283 283 /*
284 284 * The information in ibcm_clpinfo is kept in wireformat and is setup at
285 285 * init time, and used read-only after that
286 286 */
287 287 ibcm_classportinfo_msg_t ibcm_clpinfo;
288 288
289 289 char *event_str[] = {
290 290 "NEVER SEE THIS ",
291 291 "SESSION_ID ",
292 292 "CHAN_HDL ",
293 293 "LOCAL_COMID/HCA/PORT ",
294 294 "LOCAL_QPN ",
295 295 "REMOTE_COMID/HCA ",
296 296 "REMOTE_QPN ",
297 297 "BASE_TIME ",
298 298 "INCOMING_REQ ",
299 299 "INCOMING_REP ",
300 300 "INCOMING_RTU ",
301 301 "INCOMING_COMEST ",
302 302 "INCOMING_MRA ",
303 303 "INCOMING_REJ ",
304 304 "INCOMING_LAP ",
305 305 "INCOMING_APR ",
306 306 "INCOMING_DREQ ",
307 307 "INCOMING_DREP ",
308 308 "OUTGOING_REQ ",
309 309 "OUTGOING_REP ",
310 310 "OUTGOING_RTU ",
311 311 "OUTGOING_LAP ",
312 312 "OUTGOING_APR ",
313 313 "OUTGOING_MRA ",
314 314 "OUTGOING_REJ ",
315 315 "OUTGOING_DREQ ",
316 316 "OUTGOING_DREP ",
317 317 "REQ_POST_COMPLETE ",
318 318 "REP_POST_COMPLETE ",
319 319 "RTU_POST_COMPLETE ",
320 320 "MRA_POST_COMPLETE ",
321 321 "REJ_POST_COMPLETE ",
322 322 "LAP_POST_COMPLETE ",
323 323 "APR_POST_COMPLETE ",
324 324 "DREQ_POST_COMPLETE ",
325 325 "DREP_POST_COMPLETE ",
326 326 "TIMEOUT_REP ",
327 327 "CALLED_REQ_RCVD_EVENT ",
328 328 "RET_REQ_RCVD_EVENT ",
329 329 "CALLED_REP_RCVD_EVENT ",
330 330 "RET_REP_RCVD_EVENT ",
331 331 "CALLED_CONN_EST_EVENT ",
332 332 "RET_CONN_EST_EVENT ",
333 333 "CALLED_CONN_FAIL_EVENT ",
334 334 "RET_CONN_FAIL_EVENT ",
335 335 "CALLED_CONN_CLOSE_EVENT ",
336 336 "RET_CONN_CLOSE_EVENT ",
337 337 "INIT_INIT ",
338 338 "INIT_INIT_FAIL ",
339 339 "INIT_RTR ",
340 340 "INIT_RTR_FAIL ",
341 341 "RTR_RTS ",
342 342 "RTR_RTS_FAIL ",
343 343 "RTS_RTS ",
344 344 "RTS_RTS_FAIL ",
345 345 "TO_ERROR ",
346 346 "ERROR_FAIL ",
347 347 "SET_ALT ",
348 348 "SET_ALT_FAIL ",
349 349 "STALE_DETECT ",
350 350 "OUTGOING_REQ_RETRY ",
351 351 "OUTGOING_REP_RETRY ",
352 352 "OUTGOING_LAP_RETRY ",
353 353 "OUTGOING_MRA_RETRY ",
354 354 "OUTGOING_DREQ_RETRY ",
355 355 "NEVER SEE THIS "
356 356 };
357 357
358 358 char ibcm_debug_buf[IBCM_DEBUG_BUF_SIZE];
359 359
360 360 _NOTE(SCHEME_PROTECTS_DATA("used in a localized function consistently",
361 361 ibcm_debug_buf))
362 362 _NOTE(READ_ONLY_DATA(ibcm_taskq))
363 363
364 364 _NOTE(MUTEX_PROTECTS_DATA(ibcm_timeout_list_lock, ibcm_timeout_list_flags))
365 365 _NOTE(MUTEX_PROTECTS_DATA(ibcm_timeout_list_lock, ibcm_timeout_list_hdr))
366 366 _NOTE(MUTEX_PROTECTS_DATA(ibcm_timeout_list_lock, ibcm_ud_timeout_list_hdr))
367 367
368 368 #ifdef DEBUG
369 369 int ibcm_test_mode = 0; /* set to 1, if running tests */
370 370 #endif
371 371
↓ open down ↓ |
371 lines elided |
↑ open up ↑ |
372 372
373 373 /* Module Driver Info */
374 374 static struct modlmisc ibcm_modlmisc = {
375 375 &mod_miscops,
376 376 "IB Communication Manager"
377 377 };
378 378
379 379 /* Module Linkage */
380 380 static struct modlinkage ibcm_modlinkage = {
381 381 MODREV_1,
382 - &ibcm_modlmisc,
383 - NULL
382 + { &ibcm_modlmisc, NULL }
384 383 };
385 384
386 385
387 386 int
388 387 _init(void)
389 388 {
390 389 int rval;
391 390 ibcm_status_t status;
392 391
393 392 status = ibcm_init();
394 393 if (status != IBCM_SUCCESS) {
395 394 IBTF_DPRINTF_L2(cmlog, "_init: ibcm failed %d", status);
396 395 return (EINVAL);
397 396 }
398 397
399 398 rval = mod_install(&ibcm_modlinkage);
400 399 if (rval != 0) {
401 400 IBTF_DPRINTF_L2(cmlog, "_init: ibcm mod_install failed %d",
402 401 rval);
403 402 (void) ibcm_fini();
404 403 }
405 404
406 405 IBTF_DPRINTF_L5(cmlog, "_init: ibcm successful");
407 406 return (rval);
408 407
409 408 }
410 409
411 410
412 411 int
413 412 _info(struct modinfo *modinfop)
414 413 {
415 414 return (mod_info(&ibcm_modlinkage, modinfop));
416 415 }
417 416
418 417
419 418 int
420 419 _fini(void)
421 420 {
422 421 int status;
423 422
424 423 if (ibcm_fini() != IBCM_SUCCESS)
425 424 return (EBUSY);
426 425
427 426 if ((status = mod_remove(&ibcm_modlinkage)) != 0) {
428 427 IBTF_DPRINTF_L2(cmlog, "_fini: ibcm mod_remove failed %d",
429 428 status);
430 429 return (status);
431 430 }
432 431
433 432 IBTF_DPRINTF_L5(cmlog, "_fini: ibcm successful");
434 433
435 434 return (status);
436 435 }
437 436
438 437 /* Initializes all global mutex and CV in cm module */
439 438 static void
440 439 ibcm_init_locks()
441 440 {
442 441
443 442 /* Verify CM MAD sizes */
444 443 #ifdef DEBUG
445 444
446 445 if (ibcm_test_mode > 1) {
447 446
448 447 IBTF_DPRINTF_L1(cmlog, "REQ MAD SIZE %d",
449 448 sizeof (ibcm_req_msg_t));
450 449 IBTF_DPRINTF_L1(cmlog, "REP MAD SIZE %d",
451 450 sizeof (ibcm_rep_msg_t));
452 451 IBTF_DPRINTF_L1(cmlog, "RTU MAD SIZE %d",
453 452 sizeof (ibcm_rtu_msg_t));
454 453 IBTF_DPRINTF_L1(cmlog, "MRA MAD SIZE %d",
455 454 sizeof (ibcm_mra_msg_t));
456 455 IBTF_DPRINTF_L1(cmlog, "REJ MAD SIZE %d",
457 456 sizeof (ibcm_rej_msg_t));
458 457 IBTF_DPRINTF_L1(cmlog, "LAP MAD SIZE %d",
459 458 sizeof (ibcm_lap_msg_t));
460 459 IBTF_DPRINTF_L1(cmlog, "APR MAD SIZE %d",
461 460 sizeof (ibcm_apr_msg_t));
462 461 IBTF_DPRINTF_L1(cmlog, "DREQ MAD SIZE %d",
463 462 sizeof (ibcm_dreq_msg_t));
464 463 IBTF_DPRINTF_L1(cmlog, "DREP MAD SIZE %d",
465 464 sizeof (ibcm_drep_msg_t));
466 465 IBTF_DPRINTF_L1(cmlog, "SIDR REQ MAD SIZE %d",
467 466 sizeof (ibcm_sidr_req_msg_t));
468 467 IBTF_DPRINTF_L1(cmlog, "SIDR REP MAD SIZE %d",
469 468 sizeof (ibcm_sidr_rep_msg_t));
470 469 }
471 470
472 471 #endif
473 472
474 473 /* Create all global locks within cm module */
475 474 mutex_init(&ibcm_svc_info_lock, NULL, MUTEX_DEFAULT, NULL);
476 475 mutex_init(&ibcm_mcglist_lock, NULL, MUTEX_DEFAULT, NULL);
477 476 mutex_init(&ibcm_timeout_list_lock, NULL, MUTEX_DEFAULT, NULL);
478 477 mutex_init(&ibcm_global_hca_lock, NULL, MUTEX_DEFAULT, NULL);
479 478 mutex_init(&ibcm_sa_open_lock, NULL, MUTEX_DEFAULT, NULL);
480 479 mutex_init(&ibcm_recv_mutex, NULL, MUTEX_DEFAULT, NULL);
481 480 mutex_init(&ibcm_sm_notice_serialize_lock, NULL, MUTEX_DEFAULT, NULL);
482 481 mutex_init(&ibcm_qp_list_lock, NULL, MUTEX_DEFAULT, NULL);
483 482 mutex_init(&ibcm_trace_mutex, NULL, MUTEX_DEFAULT, NULL);
484 483 mutex_init(&ibcm_trace_print_mutex, NULL, MUTEX_DEFAULT, NULL);
485 484 cv_init(&ibcm_svc_info_cv, NULL, CV_DRIVER, NULL);
486 485 cv_init(&ibcm_timeout_list_cv, NULL, CV_DRIVER, NULL);
487 486 cv_init(&ibcm_timeout_thread_done_cv, NULL, CV_DRIVER, NULL);
488 487 cv_init(&ibcm_global_hca_cv, NULL, CV_DRIVER, NULL);
489 488 cv_init(&ibcm_sa_open_cv, NULL, CV_DRIVER, NULL);
490 489 avl_create(&ibcm_svc_avl_tree, ibcm_svc_compare,
491 490 sizeof (ibcm_svc_info_t),
492 491 offsetof(struct ibcm_svc_info_s, svc_link));
493 492
494 493 IBTF_DPRINTF_L5(cmlog, "ibcm_init_locks: done");
495 494 }
496 495
497 496 /* Destroys all global mutex and CV in cm module */
498 497 static void
499 498 ibcm_fini_locks()
500 499 {
501 500 /* Destroy all global locks within cm module */
502 501 mutex_destroy(&ibcm_svc_info_lock);
503 502 mutex_destroy(&ibcm_mcglist_lock);
504 503 mutex_destroy(&ibcm_timeout_list_lock);
505 504 mutex_destroy(&ibcm_global_hca_lock);
506 505 mutex_destroy(&ibcm_sa_open_lock);
507 506 mutex_destroy(&ibcm_recv_mutex);
508 507 mutex_destroy(&ibcm_sm_notice_serialize_lock);
509 508 mutex_destroy(&ibcm_qp_list_lock);
510 509 mutex_destroy(&ibcm_trace_mutex);
511 510 mutex_destroy(&ibcm_trace_print_mutex);
512 511 cv_destroy(&ibcm_svc_info_cv);
513 512 cv_destroy(&ibcm_timeout_list_cv);
514 513 cv_destroy(&ibcm_timeout_thread_done_cv);
515 514 cv_destroy(&ibcm_global_hca_cv);
516 515 cv_destroy(&ibcm_sa_open_cv);
517 516 avl_destroy(&ibcm_svc_avl_tree);
518 517
519 518 IBTF_DPRINTF_L5(cmlog, "ibcm_fini_locks: done");
520 519 }
521 520
522 521
523 522 /* Initialize CM's classport info */
524 523 static void
525 524 ibcm_init_classportinfo()
526 525 {
527 526 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_clpinfo));
528 527
529 528 ibcm_clpinfo.BaseVersion = IBCM_MAD_BASE_VERSION;
530 529 ibcm_clpinfo.ClassVersion = IBCM_MAD_CLASS_VERSION;
531 530
532 531 /* For now, CM supports same capabilities at all ports */
533 532 ibcm_clpinfo.CapabilityMask =
534 533 h2b16(IBCM_CPINFO_CAP_RC | IBCM_CPINFO_CAP_SIDR);
535 534
536 535 /* Bits 0-7 are all 0 for Communication Mgmt Class */
537 536
538 537 /* For now, CM has the same respvalue at all ports */
539 538 ibcm_clpinfo.RespTimeValue_plus =
540 539 h2b32(ibt_usec2ib(ibcm_local_processing_time) & 0x1f);
541 540
542 541 /* For now, redirect fields are set to 0 */
543 542 /* Trap fields are not applicable to CM, hence set to 0 */
544 543
545 544 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_clpinfo));
546 545 IBTF_DPRINTF_L5(cmlog, "ibcm_init_classportinfo: done");
547 546 }
548 547
549 548 /*
550 549 * ibcm_init():
551 550 * - call ibt_attach()
552 551 * - create AVL trees
553 552 * - Attach HCA handlers that are already present before
554 553 * CM got loaded.
555 554 *
556 555 * Arguments: NONE
557 556 *
558 557 * Return values:
559 558 * IBCM_SUCCESS - success
560 559 */
561 560 static ibcm_status_t
562 561 ibcm_init(void)
563 562 {
564 563 ibt_status_t status;
565 564 kthread_t *t;
566 565
567 566 IBTF_DPRINTF_L3(cmlog, "ibcm_init:");
568 567
569 568 ibcm_init_classportinfo();
570 569
571 570 if (ibcm_init_ids() != IBCM_SUCCESS) {
572 571 IBTF_DPRINTF_L1(cmlog, "ibcm_init: "
573 572 "fatal error: vmem_create() failed");
574 573 return (IBCM_FAILURE);
575 574 }
576 575 ibcm_init_locks();
577 576
578 577 if (ibcm_ar_init() != IBCM_SUCCESS) {
579 578 IBTF_DPRINTF_L1(cmlog, "ibcm_init: "
580 579 "fatal error: ibcm_ar_init() failed");
581 580 ibcm_fini_ids();
582 581 ibcm_fini_locks();
583 582 return (IBCM_FAILURE);
584 583 }
585 584 ibcm_rc_flow_control_init();
586 585
587 586 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_taskq))
588 587 ibcm_taskq = system_taskq;
589 588 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_taskq))
590 589
591 590 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_timeout_list_flags))
592 591 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_timeout_thread_did))
593 592
594 593 /* Start the timeout list processing thread */
595 594 ibcm_timeout_list_flags = 0;
596 595 t = thread_create(NULL, 0, ibcm_process_tlist, 0, 0, &p0, TS_RUN,
597 596 ibcm_timeout_thread_pri);
598 597 ibcm_timeout_thread_did = t->t_did;
599 598
600 599 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_timeout_list_flags))
601 600 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_timeout_thread_did))
602 601
603 602 /*
604 603 * NOTE : if ibt_attach is done after ibcm_init_hcas, then some
605 604 * HCA DR events may be lost. CM could call re-init hca list
606 605 * again, but it is more complicated. Some HCA's DR's lost may
607 606 * be HCA detach, which makes hca list re-syncing and locking more
608 607 * complex
609 608 */
610 609 status = ibt_attach(&ibcm_ibt_modinfo, NULL, NULL, &ibcm_ibt_handle);
611 610 if (status != IBT_SUCCESS) {
612 611 IBTF_DPRINTF_L2(cmlog, "ibcm_init(): ibt_attach failed %d",
613 612 status);
614 613 (void) ibcm_ar_fini();
615 614 ibcm_stop_timeout_thread();
616 615 ibcm_fini_ids();
617 616 ibcm_fini_locks();
618 617 ibcm_rc_flow_control_fini();
619 618 return (IBCM_FAILURE);
620 619 }
621 620
622 621 /* Block all HCA attach/detach asyncs */
623 622 mutex_enter(&ibcm_global_hca_lock);
624 623
625 624 ibcm_init_hcas();
626 625 ibcm_finit_state = IBCM_FINIT_IDLE;
627 626
628 627 ibcm_path_cache_init();
629 628 /*
630 629 * This callback will be used by IBTL to get the Node record for a
631 630 * given LID via the speccified HCA and port.
632 631 */
633 632 ibtl_cm_set_node_info_cb(ibcm_ibtl_node_info);
634 633
635 634 /* Unblock any waiting HCA DR asyncs in CM */
636 635 mutex_exit(&ibcm_global_hca_lock);
637 636
638 637 IBTF_DPRINTF_L4(cmlog, "ibcm_init: done");
639 638 return (IBCM_SUCCESS);
640 639 }
641 640
642 641 /* Allocates and initializes the "per hca" global data in CM */
643 642 static void
644 643 ibcm_init_hcas()
645 644 {
646 645 uint_t num_hcas = 0;
647 646 ib_guid_t *guid_array;
648 647 int i;
649 648
650 649 IBTF_DPRINTF_L5(cmlog, "ibcm_init_hcas:");
651 650
652 651 /* Get the number of HCAs */
653 652 num_hcas = ibt_get_hca_list(&guid_array);
654 653 IBTF_DPRINTF_L4(cmlog, "ibcm_init_hcas: ibt_get_hca_list() "
655 654 "returned %d hcas", num_hcas);
656 655
657 656 ASSERT(MUTEX_HELD(&ibcm_global_hca_lock));
658 657
659 658 for (i = 0; i < num_hcas; i++)
660 659 ibcm_hca_attach(guid_array[i]);
661 660
662 661 if (num_hcas)
663 662 ibt_free_hca_list(guid_array, num_hcas);
664 663
665 664 IBTF_DPRINTF_L5(cmlog, "ibcm_init_hcas: done");
666 665 }
667 666
668 667
669 668 /*
670 669 * ibcm_fini():
671 670 * - Deregister w/ ibt
672 671 * - Cleanup IBCM HCA listp
673 672 * - Destroy mutexes
674 673 *
675 674 * Arguments: NONE
676 675 *
677 676 * Return values:
678 677 * IBCM_SUCCESS - success
679 678 */
680 679 static ibcm_status_t
681 680 ibcm_fini(void)
682 681 {
683 682 ibt_status_t status;
684 683
685 684 IBTF_DPRINTF_L3(cmlog, "ibcm_fini:");
686 685
687 686 /*
688 687 * CM assumes that the all general clients got rid of all the
689 688 * established connections and service registrations, completed all
690 689 * pending SIDR operations before a call to ibcm_fini()
691 690 */
692 691
693 692 if (ibcm_ar_fini() != IBCM_SUCCESS) {
694 693 IBTF_DPRINTF_L2(cmlog, "ibcm_fini: ibcm_ar_fini failed");
695 694 return (IBCM_FAILURE);
696 695 }
697 696
698 697 /* cleanup the svcinfo list */
699 698 mutex_enter(&ibcm_svc_info_lock);
700 699 if (avl_first(&ibcm_svc_avl_tree) != NULL) {
701 700 IBTF_DPRINTF_L2(cmlog, "ibcm_fini: "
702 701 "ibcm_svc_avl_tree is not empty");
703 702 mutex_exit(&ibcm_svc_info_lock);
704 703 return (IBCM_FAILURE);
705 704 }
706 705 mutex_exit(&ibcm_svc_info_lock);
707 706
708 707 /* disables any new hca attach/detaches */
709 708 mutex_enter(&ibcm_global_hca_lock);
710 709
711 710 ibcm_finit_state = IBCM_FINIT_BUSY;
712 711
713 712 if (ibcm_fini_hcas() != IBCM_SUCCESS) {
714 713 IBTF_DPRINTF_L2(cmlog, "ibcm_fini: "
715 714 "some hca's still have client resources");
716 715
717 716 /* First, re-initialize the hcas */
718 717 ibcm_init_hcas();
719 718 /* and then enable the HCA asyncs */
720 719 ibcm_finit_state = IBCM_FINIT_IDLE;
721 720 mutex_exit(&ibcm_global_hca_lock);
722 721 if (ibcm_ar_init() != IBCM_SUCCESS) {
723 722 IBTF_DPRINTF_L1(cmlog, "ibcm_fini:ibcm_ar_init failed");
724 723 }
725 724 return (IBCM_FAILURE);
726 725 }
727 726
728 727 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_timeout_list_hdr))
729 728 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_ud_timeout_list_hdr))
730 729
731 730 ASSERT(ibcm_timeout_list_hdr == NULL);
732 731 ASSERT(ibcm_ud_timeout_list_hdr == NULL);
733 732
734 733 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_timeout_list_hdr))
735 734 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_ud_timeout_list_hdr))
736 735
737 736 /* Release any pending asyncs on ibcm_global_hca_lock */
738 737 ibcm_finit_state = IBCM_FINIT_SUCCESS;
739 738 mutex_exit(&ibcm_global_hca_lock);
740 739
741 740 ibcm_stop_timeout_thread();
742 741
743 742 ibtl_cm_set_node_info_cb(NULL);
744 743 /*
745 744 * Detach from IBTL. Waits until all pending asyncs are complete.
746 745 * Above cv_broadcast wakes up any waiting hca attach/detach asyncs
747 746 */
748 747 status = ibt_detach(ibcm_ibt_handle);
749 748
750 749 /* if detach fails, CM didn't free up some resources, so assert */
751 750 if (status != IBT_SUCCESS)
752 751 IBTF_DPRINTF_L1(cmlog, "ibcm_fini: ibt_detach failed %d",
753 752 status);
754 753
755 754 ibcm_rc_flow_control_fini();
756 755
757 756 ibcm_path_cache_fini();
758 757
759 758 ibcm_fini_ids();
760 759 ibcm_fini_locks();
761 760 IBTF_DPRINTF_L3(cmlog, "ibcm_fini: done");
762 761 return (IBCM_SUCCESS);
763 762 }
764 763
765 764 /* This routine exit's the ibcm timeout thread */
766 765 static void
767 766 ibcm_stop_timeout_thread()
768 767 {
769 768 mutex_enter(&ibcm_timeout_list_lock);
770 769
771 770 /* Stop the timeout list processing thread */
772 771 ibcm_timeout_list_flags =
773 772 ibcm_timeout_list_flags | IBCM_TIMEOUT_THREAD_EXIT;
774 773
775 774 /* Wake up, if the timeout thread is on a cv_wait */
776 775 cv_signal(&ibcm_timeout_list_cv);
777 776
778 777 mutex_exit(&ibcm_timeout_list_lock);
779 778 thread_join(ibcm_timeout_thread_did);
780 779
781 780 IBTF_DPRINTF_L5(cmlog, "ibcm_stop_timeout_thread: done");
782 781 }
783 782
784 783
785 784 /* Attempts to release all the hca's associated with CM */
786 785 static ibcm_status_t
787 786 ibcm_fini_hcas()
788 787 {
789 788 ibcm_hca_info_t *hcap, *next;
790 789
791 790 IBTF_DPRINTF_L4(cmlog, "ibcm_fini_hcas:");
792 791
793 792 ASSERT(MUTEX_HELD(&ibcm_global_hca_lock));
794 793
795 794 hcap = ibcm_hca_listp;
796 795 while (hcap != NULL) {
797 796 next = hcap->hca_next;
798 797 if (ibcm_hca_detach(hcap) != IBCM_SUCCESS) {
799 798 ibcm_hca_listp = hcap;
800 799 return (IBCM_FAILURE);
801 800 }
802 801 hcap = next;
803 802 }
804 803
805 804 IBTF_DPRINTF_L4(cmlog, "ibcm_fini_hcas: SUCCEEDED");
806 805 return (IBCM_SUCCESS);
807 806 }
808 807
809 808
810 809 /*
811 810 * ibcm_hca_attach():
812 811 * Called as an asynchronous event to notify CM of an attach of HCA.
813 812 * Here ibcm_hca_info_t is initialized and all fields are
814 813 * filled in along with SA Access handles and IBMA handles.
815 814 * Also called from ibcm_init to initialize ibcm_hca_info_t's for each
816 815 * hca's
817 816 *
818 817 * Arguments: (WILL CHANGE BASED ON ASYNC EVENT CODE)
819 818 * hca_guid - HCA's guid
820 819 *
821 820 * Return values: NONE
822 821 */
823 822 static void
824 823 ibcm_hca_attach(ib_guid_t hcaguid)
825 824 {
826 825 int i;
827 826 ibt_status_t status;
828 827 uint8_t nports = 0;
829 828 ibcm_hca_info_t *hcap;
830 829 ibt_hca_attr_t hca_attrs;
831 830
832 831 IBTF_DPRINTF_L3(cmlog, "ibcm_hca_attach: guid = 0x%llX", hcaguid);
833 832
834 833 ASSERT(MUTEX_HELD(&ibcm_global_hca_lock));
835 834
836 835 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*hcap))
837 836
838 837 status = ibt_query_hca_byguid(hcaguid, &hca_attrs);
839 838 if (status != IBT_SUCCESS) {
840 839 IBTF_DPRINTF_L2(cmlog, "ibcm_hca_attach: "
841 840 "ibt_query_hca_byguid failed = %d", status);
842 841 return;
843 842 }
844 843 nports = hca_attrs.hca_nports;
845 844
846 845 IBTF_DPRINTF_L4(cmlog, "ibcm_hca_attach: num ports = %x", nports);
847 846
848 847 if ((hcap = ibcm_add_hca_entry(hcaguid, nports)) == NULL)
849 848 return;
850 849
851 850 hcap->hca_guid = hcaguid; /* Set GUID */
852 851 hcap->hca_num_ports = nports; /* Set number of ports */
853 852
854 853 if (ibcm_init_hca_ids(hcap) != IBCM_SUCCESS) {
855 854 ibcm_delete_hca_entry(hcap);
856 855 return;
857 856 }
858 857
859 858 /* Store the static hca attribute data */
860 859 hcap->hca_caps = hca_attrs.hca_flags;
861 860 hcap->hca_vendor_id = hca_attrs.hca_vendor_id;
862 861 hcap->hca_device_id = hca_attrs.hca_device_id;
863 862 hcap->hca_ack_delay = hca_attrs.hca_local_ack_delay;
864 863 hcap->hca_max_rdma_in_qp = hca_attrs.hca_max_rdma_in_qp;
865 864 hcap->hca_max_rdma_out_qp = hca_attrs.hca_max_rdma_out_qp;
866 865
867 866 /* loop thru nports and initialize IBMF handles */
868 867 for (i = 0; i < hcap->hca_num_ports; i++) {
869 868 status = ibt_get_port_state_byguid(hcaguid, i + 1, NULL, NULL);
870 869 if (status != IBT_SUCCESS) {
871 870 IBTF_DPRINTF_L2(cmlog, "ibcm_hca_attach: "
872 871 "port_num %d state DOWN", i + 1);
873 872 }
874 873
875 874 hcap->hca_port_info[i].port_hcap = hcap;
876 875 hcap->hca_port_info[i].port_num = i+1;
877 876
878 877 if (ibcm_hca_init_port(hcap, i) != IBT_SUCCESS)
879 878 IBTF_DPRINTF_L2(cmlog, "ibcm_hca_attach: "
880 879 "ibcm_hca_init_port failed %d port_num %d",
881 880 status, i+1);
882 881 }
883 882
884 883 /* create the "active" CM AVL tree */
885 884 avl_create(&hcap->hca_active_tree, ibcm_active_node_compare,
886 885 sizeof (ibcm_state_data_t),
887 886 offsetof(struct ibcm_state_data_s, avl_active_link));
888 887
889 888 /* create the "passive" CM AVL tree */
890 889 avl_create(&hcap->hca_passive_tree, ibcm_passive_node_compare,
891 890 sizeof (ibcm_state_data_t),
892 891 offsetof(struct ibcm_state_data_s, avl_passive_link));
893 892
894 893 /* create the "passive comid" CM AVL tree */
895 894 avl_create(&hcap->hca_passive_comid_tree,
896 895 ibcm_passive_comid_node_compare,
897 896 sizeof (ibcm_state_data_t),
898 897 offsetof(struct ibcm_state_data_s, avl_passive_comid_link));
899 898
900 899 /*
901 900 * Mark the state of the HCA to "attach" only at the end
902 901 * Now CM starts accepting incoming MADs and client API calls
903 902 */
904 903 hcap->hca_state = IBCM_HCA_ACTIVE;
905 904
906 905 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*hcap))
907 906
908 907 IBTF_DPRINTF_L3(cmlog, "ibcm_hca_attach: ATTACH Done");
909 908 }
910 909
911 910 /*
912 911 * ibcm_hca_detach():
913 912 * Called as an asynchronous event to notify CM of a detach of HCA.
914 913 * Here ibcm_hca_info_t is freed up and all fields that
915 914 * were initialized earlier are cleaned up
916 915 *
917 916 * Arguments: (WILL CHANGE BASED ON ASYNC EVENT CODE)
918 917 * hca_guid - HCA's guid
919 918 *
920 919 * Return values:
921 920 * IBCM_SUCCESS - able to detach HCA
922 921 * IBCM_FAILURE - failed to detach HCA
923 922 */
924 923 static ibcm_status_t
925 924 ibcm_hca_detach(ibcm_hca_info_t *hcap)
926 925 {
927 926 int port_index, i;
928 927 ibcm_status_t status = IBCM_SUCCESS;
929 928 clock_t absolute_time;
930 929
931 930 IBTF_DPRINTF_L3(cmlog, "ibcm_hca_detach: hcap = 0x%p guid = 0x%llX",
932 931 hcap, hcap->hca_guid);
933 932
934 933 ASSERT(MUTEX_HELD(&ibcm_global_hca_lock));
935 934
936 935 /*
937 936 * Declare hca is going away to all CM clients. Wait until the
938 937 * access count becomes zero.
939 938 */
940 939 hcap->hca_state = IBCM_HCA_NOT_ACTIVE;
941 940
942 941 /* wait on response CV */
943 942 absolute_time = ddi_get_lbolt() +
944 943 drv_usectohz(ibcm_wait_for_acc_cnt_timeout);
945 944
946 945 while (hcap->hca_acc_cnt > 0)
947 946 if (cv_timedwait(&ibcm_global_hca_cv, &ibcm_global_hca_lock,
948 947 absolute_time) == -1)
949 948 break;
950 949
951 950 if (hcap->hca_acc_cnt != 0) {
952 951 /* We got a timeout */
953 952 IBTF_DPRINTF_L2(cmlog, "ibcm_hca_detach: Aborting due"
954 953 " to timeout on hca_acc_cnt %u, \n Some CM Clients are "
955 954 "still active, looks like we need to wait some more time "
956 955 "(ibcm_wait_for_acc_cnt_timeout).", hcap->hca_acc_cnt);
957 956 hcap->hca_state = IBCM_HCA_ACTIVE;
958 957 return (IBCM_FAILURE);
959 958 }
960 959
961 960 /*
962 961 * First make sure, there are no active users of ibma handles,
963 962 * and then de-register handles.
964 963 */
965 964
966 965 /* make sure that there are no "Service"s registered w/ this HCA. */
967 966 if (hcap->hca_svc_cnt != 0) {
968 967 IBTF_DPRINTF_L2(cmlog, "ibcm_hca_detach: "
969 968 "Active services still there %d", hcap->hca_svc_cnt);
970 969 hcap->hca_state = IBCM_HCA_ACTIVE;
971 970 return (IBCM_FAILURE);
972 971 }
973 972
974 973 if (ibcm_check_sidr_clean(hcap) != IBCM_SUCCESS) {
975 974 IBTF_DPRINTF_L2(cmlog, "ibcm_hca_detach:"
976 975 "There are active SIDR operations");
977 976 hcap->hca_state = IBCM_HCA_ACTIVE;
978 977 return (IBCM_FAILURE);
979 978 }
980 979
981 980 if (ibcm_check_avl_clean(hcap) != IBCM_SUCCESS) {
982 981 IBTF_DPRINTF_L2(cmlog, "ibcm_hca_detach: "
983 982 "There are active RC connections");
984 983 hcap->hca_state = IBCM_HCA_ACTIVE;
985 984 return (IBCM_FAILURE);
986 985 }
987 986
988 987 /*
989 988 * Now, wait until all rc and sidr stateps go away
990 989 * All these stateps must be short lived ones, waiting to be cleaned
991 990 * up after some timeout value, based on the current state.
992 991 */
993 992 IBTF_DPRINTF_L3(cmlog, "ibcm_hca_detach:hca_guid = 0x%llX res_cnt = %d",
994 993 hcap->hca_guid, hcap->hca_res_cnt);
995 994
996 995 while (hcap->hca_res_cnt > 0)
997 996 cv_wait(&ibcm_global_hca_cv, &ibcm_global_hca_lock);
998 997
999 998 /* Re-assert the while loop step above */
1000 999 ASSERT(hcap->hca_sidr_list == NULL);
1001 1000 avl_destroy(&hcap->hca_active_tree);
1002 1001 avl_destroy(&hcap->hca_passive_tree);
1003 1002 avl_destroy(&hcap->hca_passive_comid_tree);
1004 1003
1005 1004 /*
1006 1005 * Unregister all ports from IBMA
1007 1006 * If there is a failure, re-initialize any free'd ibma handles. This
1008 1007 * is required to receive the incoming mads
1009 1008 */
1010 1009 status = IBCM_SUCCESS;
1011 1010 for (port_index = 0; port_index < hcap->hca_num_ports; port_index++) {
1012 1011 if ((status = ibcm_hca_fini_port(hcap, port_index)) !=
1013 1012 IBCM_SUCCESS) {
1014 1013 IBTF_DPRINTF_L2(cmlog, "ibcm_hca_detach: "
1015 1014 "Failed to free IBMA Handle for port_num %d",
1016 1015 port_index + 1);
1017 1016 break;
1018 1017 }
1019 1018 }
1020 1019
1021 1020 /* If detach fails, re-initialize ibma handles for incoming mads */
1022 1021 if (status != IBCM_SUCCESS) {
1023 1022 for (i = 0; i < port_index; i++) {
1024 1023 if (ibcm_hca_init_port(hcap, i) != IBT_SUCCESS)
1025 1024 IBTF_DPRINTF_L2(cmlog, "ibcm_hca_detach: "
1026 1025 "Failed to re-allocate IBMA Handles for"
1027 1026 " port_num %d", port_index + 1);
1028 1027 }
1029 1028 hcap->hca_state = IBCM_HCA_ACTIVE;
1030 1029 return (IBCM_FAILURE);
1031 1030 }
1032 1031
1033 1032 ibcm_fini_hca_ids(hcap);
1034 1033 ibcm_delete_hca_entry(hcap);
1035 1034
1036 1035 IBTF_DPRINTF_L3(cmlog, "ibcm_hca_detach: DETACH succeeded");
1037 1036 return (IBCM_SUCCESS);
1038 1037 }
1039 1038
1040 1039 /* Checks, if there are any active sidr state entries in the specified hca */
1041 1040 static ibcm_status_t
1042 1041 ibcm_check_sidr_clean(ibcm_hca_info_t *hcap)
1043 1042 {
1044 1043 ibcm_ud_state_data_t *usp;
1045 1044 uint32_t transient_cnt = 0;
1046 1045
1047 1046 IBTF_DPRINTF_L5(cmlog, "ibcm_check_sidr_clean:");
1048 1047
1049 1048 rw_enter(&hcap->hca_sidr_list_lock, RW_WRITER);
1050 1049 usp = hcap->hca_sidr_list; /* Point to the list */
1051 1050 while (usp != NULL) {
1052 1051 mutex_enter(&usp->ud_state_mutex);
1053 1052 if ((usp->ud_state != IBCM_STATE_SIDR_REP_SENT) &&
1054 1053 (usp->ud_state != IBCM_STATE_TIMED_OUT) &&
1055 1054 (usp->ud_state != IBCM_STATE_DELETE)) {
1056 1055
1057 1056 IBTF_DPRINTF_L3(cmlog, "ibcm_check_sidr_clean:"
1058 1057 "usp = %p not in transient state = %d", usp,
1059 1058 usp->ud_state);
1060 1059
1061 1060 mutex_exit(&usp->ud_state_mutex);
1062 1061 rw_exit(&hcap->hca_sidr_list_lock);
1063 1062 return (IBCM_FAILURE);
1064 1063 } else {
1065 1064 mutex_exit(&usp->ud_state_mutex);
1066 1065 ++transient_cnt;
1067 1066 }
1068 1067
1069 1068 usp = usp->ud_nextp;
1070 1069 }
1071 1070 rw_exit(&hcap->hca_sidr_list_lock);
1072 1071
1073 1072 IBTF_DPRINTF_L4(cmlog, "ibcm_check_sidr_clean: transient_cnt %d",
1074 1073 transient_cnt);
1075 1074
1076 1075 return (IBCM_SUCCESS);
1077 1076 }
1078 1077
1079 1078 /* Checks, if there are any active rc state entries, in the specified hca */
1080 1079 static ibcm_status_t
1081 1080 ibcm_check_avl_clean(ibcm_hca_info_t *hcap)
1082 1081
1083 1082 {
1084 1083 ibcm_state_data_t *sp;
1085 1084 avl_tree_t *avl_tree;
1086 1085 uint32_t transient_cnt = 0;
1087 1086
1088 1087 IBTF_DPRINTF_L5(cmlog, "ibcm_check_avl_clean:");
1089 1088 /*
1090 1089 * Both the trees ie., active and passive must reference to all
1091 1090 * statep's, so let's use one
1092 1091 */
1093 1092 avl_tree = &hcap->hca_active_tree;
1094 1093
1095 1094 rw_enter(&hcap->hca_state_rwlock, RW_WRITER);
1096 1095
1097 1096 for (sp = avl_first(avl_tree); sp != NULL;
1098 1097 sp = avl_walk(avl_tree, sp, AVL_AFTER)) {
1099 1098 mutex_enter(&sp->state_mutex);
1100 1099 if ((sp->state != IBCM_STATE_TIMEWAIT) &&
1101 1100 (sp->state != IBCM_STATE_REJ_SENT) &&
1102 1101 (sp->state != IBCM_STATE_DELETE)) {
1103 1102 IBTF_DPRINTF_L3(cmlog, "ibcm_check_avl_clean: "
1104 1103 "sp = %p not in transient state = %d", sp,
1105 1104 sp->state);
1106 1105 mutex_exit(&sp->state_mutex);
1107 1106 rw_exit(&hcap->hca_state_rwlock);
1108 1107 return (IBCM_FAILURE);
1109 1108 } else {
1110 1109 mutex_exit(&sp->state_mutex);
1111 1110 ++transient_cnt;
1112 1111 }
1113 1112 }
1114 1113
1115 1114 rw_exit(&hcap->hca_state_rwlock);
1116 1115
1117 1116 IBTF_DPRINTF_L4(cmlog, "ibcm_check_avl_clean: transient_cnt %d",
1118 1117 transient_cnt);
1119 1118
1120 1119 return (IBCM_SUCCESS);
1121 1120 }
1122 1121
1123 1122 /* Adds a new entry into CM's global hca list, if hca_guid is not there yet */
1124 1123 static ibcm_hca_info_t *
1125 1124 ibcm_add_hca_entry(ib_guid_t hcaguid, uint_t nports)
1126 1125 {
1127 1126 ibcm_hca_info_t *hcap;
1128 1127
1129 1128 IBTF_DPRINTF_L5(cmlog, "ibcm_add_hca_entry: guid = 0x%llX",
1130 1129 hcaguid);
1131 1130
1132 1131 ASSERT(MUTEX_HELD(&ibcm_global_hca_lock));
1133 1132
1134 1133 /*
1135 1134 * Check if this hca_guid already in the list
1136 1135 * If yes, then ignore this and return NULL
1137 1136 */
1138 1137
1139 1138 hcap = ibcm_hca_listp;
1140 1139
1141 1140 /* search for this HCA */
1142 1141 while (hcap != NULL) {
1143 1142 if (hcap->hca_guid == hcaguid) {
1144 1143 /* already exists */
1145 1144 IBTF_DPRINTF_L2(cmlog, "ibcm_add_hca_entry: "
1146 1145 "hcap %p guid 0x%llX, entry already exists !!",
1147 1146 hcap, hcap->hca_guid);
1148 1147 return (NULL);
1149 1148 }
1150 1149 hcap = hcap->hca_next;
1151 1150 }
1152 1151
1153 1152 /* Allocate storage for the new HCA entry found */
1154 1153 hcap = kmem_zalloc(sizeof (ibcm_hca_info_t) +
1155 1154 (nports - 1) * sizeof (ibcm_port_info_t), KM_SLEEP);
1156 1155
1157 1156 /* initialize RW lock */
1158 1157 rw_init(&hcap->hca_state_rwlock, NULL, RW_DRIVER, NULL);
1159 1158 /* initialize SIDR list lock */
1160 1159 rw_init(&hcap->hca_sidr_list_lock, NULL, RW_DRIVER, NULL);
1161 1160 /* Insert "hcap" into the global HCA list maintained by CM */
1162 1161 hcap->hca_next = ibcm_hca_listp;
1163 1162 ibcm_hca_listp = hcap;
1164 1163
1165 1164 IBTF_DPRINTF_L5(cmlog, "ibcm_add_hca_entry: done hcap = 0x%p", hcap);
1166 1165
1167 1166 return (hcap);
1168 1167
1169 1168 }
1170 1169
1171 1170 /* deletes the given ibcm_hca_info_t from CM's global hca list */
1172 1171 void
1173 1172 ibcm_delete_hca_entry(ibcm_hca_info_t *hcap)
1174 1173 {
1175 1174 ibcm_hca_info_t *headp, *prevp = NULL;
1176 1175
1177 1176 /* ibcm_hca_global_lock is held */
1178 1177 IBTF_DPRINTF_L5(cmlog, "ibcm_delete_hca_entry: guid = 0x%llX "
1179 1178 "hcap = 0x%p", hcap->hca_guid, hcap);
1180 1179
1181 1180 ASSERT(MUTEX_HELD(&ibcm_global_hca_lock));
1182 1181
1183 1182 headp = ibcm_hca_listp;
1184 1183 while (headp != NULL) {
1185 1184 if (headp == hcap) {
1186 1185 IBTF_DPRINTF_L3(cmlog, "ibcm_delete_hca_entry: "
1187 1186 "deleting hcap %p hcaguid %llX", hcap,
1188 1187 hcap->hca_guid);
1189 1188 if (prevp) {
1190 1189 prevp->hca_next = headp->hca_next;
1191 1190 } else {
1192 1191 prevp = headp->hca_next;
1193 1192 ibcm_hca_listp = prevp;
1194 1193 }
1195 1194 rw_destroy(&hcap->hca_state_rwlock);
1196 1195 rw_destroy(&hcap->hca_sidr_list_lock);
1197 1196 kmem_free(hcap, sizeof (ibcm_hca_info_t) +
1198 1197 (hcap->hca_num_ports - 1) *
1199 1198 sizeof (ibcm_port_info_t));
1200 1199 return;
1201 1200 }
1202 1201
1203 1202 prevp = headp;
1204 1203 headp = headp->hca_next;
1205 1204 }
1206 1205 }
1207 1206
1208 1207 /*
1209 1208 * ibcm_find_hca_entry:
1210 1209 * Given a HCA's GUID find out ibcm_hca_info_t entry for that HCA
1211 1210 * This entry can be then used to access AVL tree/SIDR list etc.
1212 1211 * If entry exists and in HCA ATTACH state, then hca's ref cnt is
1213 1212 * incremented and entry returned. Else NULL returned.
1214 1213 *
1215 1214 * All functions that use ibcm_find_hca_entry and get a non-NULL
1216 1215 * return values must call ibcm_dec_hca_acc_cnt to decrement the
1217 1216 * respective hca ref cnt. There shouldn't be any usage of
1218 1217 * ibcm_hca_info_t * returned from ibcm_find_hca_entry,
1219 1218 * after decrementing the hca_acc_cnt
1220 1219 *
1221 1220 * INPUTS:
1222 1221 * hca_guid - HCA's guid
1223 1222 *
1224 1223 * RETURN VALUE:
1225 1224 * hcap - if a match is found, else NULL
1226 1225 */
1227 1226 ibcm_hca_info_t *
1228 1227 ibcm_find_hca_entry(ib_guid_t hca_guid)
1229 1228 {
1230 1229 ibcm_hca_info_t *hcap;
1231 1230
1232 1231 IBTF_DPRINTF_L5(cmlog, "ibcm_find_hca_entry: guid = 0x%llX", hca_guid);
1233 1232
1234 1233 mutex_enter(&ibcm_global_hca_lock);
1235 1234
1236 1235 hcap = ibcm_hca_listp;
1237 1236 /* search for this HCA */
1238 1237 while (hcap != NULL) {
1239 1238 if (hcap->hca_guid == hca_guid)
1240 1239 break;
1241 1240 hcap = hcap->hca_next;
1242 1241 }
1243 1242
1244 1243 /* if no hcap for the hca_guid, return NULL */
1245 1244 if (hcap == NULL) {
1246 1245 mutex_exit(&ibcm_global_hca_lock);
1247 1246 return (NULL);
1248 1247 }
1249 1248
1250 1249 /* return hcap, only if it valid to use */
1251 1250 if (hcap->hca_state == IBCM_HCA_ACTIVE) {
1252 1251 ++(hcap->hca_acc_cnt);
1253 1252
1254 1253 IBTF_DPRINTF_L5(cmlog, "ibcm_find_hca_entry: "
1255 1254 "found hcap = 0x%p hca_acc_cnt %u", hcap,
1256 1255 hcap->hca_acc_cnt);
1257 1256
1258 1257 mutex_exit(&ibcm_global_hca_lock);
1259 1258 return (hcap);
1260 1259 } else {
1261 1260 mutex_exit(&ibcm_global_hca_lock);
1262 1261
1263 1262 IBTF_DPRINTF_L2(cmlog, "ibcm_find_hca_entry: "
1264 1263 "found hcap = 0x%p not in active state", hcap);
1265 1264 return (NULL);
1266 1265 }
1267 1266 }
1268 1267
1269 1268 /*
1270 1269 * Searches for ibcm_hca_info_t entry based on hca_guid, but doesn't increment
1271 1270 * the hca's reference count. This function is used, where the calling context
1272 1271 * is attempting to delete hcap itself and hence acc_cnt cannot be incremented
1273 1272 * OR assumes that valid hcap must be available in ibcm's global hca list.
1274 1273 */
1275 1274 ibcm_hca_info_t *
1276 1275 ibcm_find_hcap_entry(ib_guid_t hca_guid)
1277 1276 {
1278 1277 ibcm_hca_info_t *hcap;
1279 1278
1280 1279 IBTF_DPRINTF_L5(cmlog, "ibcm_find_hcap_entry: guid = 0x%llX", hca_guid);
1281 1280
1282 1281 ASSERT(MUTEX_HELD(&ibcm_global_hca_lock));
1283 1282
1284 1283 hcap = ibcm_hca_listp;
1285 1284 /* search for this HCA */
1286 1285 while (hcap != NULL) {
1287 1286 if (hcap->hca_guid == hca_guid)
1288 1287 break;
1289 1288 hcap = hcap->hca_next;
1290 1289 }
1291 1290
1292 1291 if (hcap == NULL)
1293 1292 IBTF_DPRINTF_L2(cmlog, "ibcm_find_hcap_entry: No hcap found for"
1294 1293 " hca_guid 0x%llX", hca_guid);
1295 1294 else
1296 1295 IBTF_DPRINTF_L5(cmlog, "ibcm_find_hcap_entry: hcap found for"
1297 1296 " hca_guid 0x%llX", hca_guid);
1298 1297
1299 1298 return (hcap);
1300 1299 }
1301 1300
1302 1301 /* increment the hca's temporary reference count */
1303 1302 ibcm_status_t
1304 1303 ibcm_inc_hca_acc_cnt(ibcm_hca_info_t *hcap)
1305 1304 {
1306 1305 mutex_enter(&ibcm_global_hca_lock);
1307 1306 if (hcap->hca_state == IBCM_HCA_ACTIVE) {
1308 1307 ++(hcap->hca_acc_cnt);
1309 1308 IBTF_DPRINTF_L5(cmlog, "ibcm_inc_hca_acc_cnt: "
1310 1309 "hcap = 0x%p acc_cnt = %d ", hcap, hcap->hca_acc_cnt);
1311 1310 mutex_exit(&ibcm_global_hca_lock);
1312 1311 return (IBCM_SUCCESS);
1313 1312 } else {
1314 1313 IBTF_DPRINTF_L2(cmlog, "ibcm_inc_hca_acc_cnt: "
1315 1314 "hcap INACTIVE 0x%p acc_cnt = %d ", hcap,
1316 1315 hcap->hca_acc_cnt);
1317 1316 mutex_exit(&ibcm_global_hca_lock);
1318 1317 return (IBCM_FAILURE);
1319 1318 }
1320 1319 }
1321 1320
1322 1321 /* decrement the hca's ref count, and wake up any waiting threads */
1323 1322 void
1324 1323 ibcm_dec_hca_acc_cnt(ibcm_hca_info_t *hcap)
1325 1324 {
1326 1325 mutex_enter(&ibcm_global_hca_lock);
1327 1326 ASSERT(hcap->hca_acc_cnt > 0);
1328 1327 --(hcap->hca_acc_cnt);
1329 1328 IBTF_DPRINTF_L5(cmlog, "ibcm_dec_hca_acc_cnt: hcap = 0x%p "
1330 1329 "acc_cnt = %d", hcap, hcap->hca_acc_cnt);
1331 1330 if ((hcap->hca_state == IBCM_HCA_NOT_ACTIVE) &&
1332 1331 (hcap->hca_acc_cnt == 0)) {
1333 1332 IBTF_DPRINTF_L3(cmlog, "ibcm_dec_hca_acc_cnt: "
1334 1333 "cv_broadcast for hcap = 0x%p", hcap);
1335 1334 cv_broadcast(&ibcm_global_hca_cv);
1336 1335 }
1337 1336 mutex_exit(&ibcm_global_hca_lock);
1338 1337 }
1339 1338
1340 1339 /* increment the hca's resource count */
1341 1340 void
1342 1341 ibcm_inc_hca_res_cnt(ibcm_hca_info_t *hcap)
1343 1342
1344 1343 {
1345 1344 mutex_enter(&ibcm_global_hca_lock);
1346 1345 ++(hcap->hca_res_cnt);
1347 1346 IBTF_DPRINTF_L5(cmlog, "ibcm_inc_hca_res_cnt: hcap = 0x%p "
1348 1347 "ref_cnt = %d", hcap, hcap->hca_res_cnt);
1349 1348 mutex_exit(&ibcm_global_hca_lock);
1350 1349 }
1351 1350
1352 1351 /* decrement the hca's resource count, and wake up any waiting threads */
1353 1352 void
1354 1353 ibcm_dec_hca_res_cnt(ibcm_hca_info_t *hcap)
1355 1354 {
1356 1355 mutex_enter(&ibcm_global_hca_lock);
1357 1356 ASSERT(hcap->hca_res_cnt > 0);
1358 1357 --(hcap->hca_res_cnt);
1359 1358 IBTF_DPRINTF_L5(cmlog, "ibcm_dec_hca_res_cnt: hcap = 0x%p "
1360 1359 "ref_cnt = %d", hcap, hcap->hca_res_cnt);
1361 1360 if ((hcap->hca_state == IBCM_HCA_NOT_ACTIVE) &&
1362 1361 (hcap->hca_res_cnt == 0)) {
1363 1362 IBTF_DPRINTF_L3(cmlog, "ibcm_dec_hca_res_cnt: "
1364 1363 "cv_broadcast for hcap = 0x%p", hcap);
1365 1364 cv_broadcast(&ibcm_global_hca_cv);
1366 1365 }
1367 1366 mutex_exit(&ibcm_global_hca_lock);
1368 1367 }
1369 1368
1370 1369 /* increment the hca's service count */
1371 1370 void
1372 1371 ibcm_inc_hca_svc_cnt(ibcm_hca_info_t *hcap)
1373 1372
1374 1373 {
1375 1374 mutex_enter(&ibcm_global_hca_lock);
1376 1375 ++(hcap->hca_svc_cnt);
1377 1376 IBTF_DPRINTF_L5(cmlog, "ibcm_inc_hca_svc_cnt: hcap = 0x%p "
1378 1377 "svc_cnt = %d", hcap, hcap->hca_svc_cnt);
1379 1378 mutex_exit(&ibcm_global_hca_lock);
1380 1379 }
1381 1380
1382 1381 /* decrement the hca's service count */
1383 1382 void
1384 1383 ibcm_dec_hca_svc_cnt(ibcm_hca_info_t *hcap)
1385 1384 {
1386 1385 mutex_enter(&ibcm_global_hca_lock);
1387 1386 ASSERT(hcap->hca_svc_cnt > 0);
1388 1387 --(hcap->hca_svc_cnt);
1389 1388 IBTF_DPRINTF_L5(cmlog, "ibcm_dec_hca_svc_cnt: hcap = 0x%p "
1390 1389 "svc_cnt = %d", hcap, hcap->hca_svc_cnt);
1391 1390 mutex_exit(&ibcm_global_hca_lock);
1392 1391 }
1393 1392
1394 1393 /*
1395 1394 * The following code manages three classes of requests that CM makes to
1396 1395 * the fabric. Those three classes are SA_ACCESS, REQ/REP/RTU, and DREQ/DREP.
1397 1396 * The main issue is that the fabric can become very busy, and the CM
1398 1397 * protocols rely on responses being made based on a predefined timeout
1399 1398 * value. By managing how many simultaneous sessions are allowed, there
1400 1399 * is observed extremely high reliability of CM protocol succeeding when
1401 1400 * it should.
1402 1401 *
1403 1402 * SA_ACCESS and DREQ/DREP are managed at the thread level, whereby the
1404 1403 * thread blocks until there are less than some number of threads doing
1405 1404 * similar requests.
1406 1405 *
1407 1406 * REQ/REP/RTU requests beyond a given limit are added to a list,
1408 1407 * allowing the thread to return immediately to its caller in the
1409 1408 * case where the "mode" is IBT_NONBLOCKING. This is the mode used
1410 1409 * by uDAPL and seems to be an important feature/behavior.
1411 1410 */
1412 1411
1413 1412 static int
1414 1413 ibcm_ok_to_start(struct ibcm_open_s *openp)
1415 1414 {
1416 1415 return (openp->sends < openp->sends_hiwat &&
1417 1416 openp->in_progress < openp->in_progress_max);
1418 1417 }
1419 1418
1420 1419 void
1421 1420 ibcm_open_done(ibcm_state_data_t *statep)
1422 1421 {
1423 1422 int run;
1424 1423 ibcm_state_data_t **linkp, *tmp;
1425 1424
1426 1425 ASSERT(MUTEX_HELD(&statep->state_mutex));
1427 1426 if (statep->open_flow == 1) {
1428 1427 statep->open_flow = 0;
1429 1428 mutex_enter(&ibcm_open.mutex);
1430 1429 if (statep->open_link == NULL) {
1431 1430 ibcm_open.in_progress--;
1432 1431 run = ibcm_ok_to_start(&ibcm_open);
1433 1432 } else {
1434 1433 ibcm_open.queued--;
1435 1434 linkp = &ibcm_open.head.open_link;
1436 1435 while (*linkp != statep)
1437 1436 linkp = &((*linkp)->open_link);
1438 1437 *linkp = statep->open_link;
1439 1438 statep->open_link = NULL;
1440 1439 /*
1441 1440 * If we remove what tail pointed to, we need
1442 1441 * to reassign tail (it is never NULL).
1443 1442 * tail points to head for the empty list.
1444 1443 */
1445 1444 if (ibcm_open.tail == statep) {
1446 1445 tmp = &ibcm_open.head;
1447 1446 while (tmp->open_link != &ibcm_open.head)
1448 1447 tmp = tmp->open_link;
1449 1448 ibcm_open.tail = tmp;
1450 1449 }
1451 1450 run = 0;
1452 1451 }
1453 1452 mutex_exit(&ibcm_open.mutex);
1454 1453 if (run)
1455 1454 ibcm_run_tlist_thread();
1456 1455 }
1457 1456 }
1458 1457
1459 1458 /* dtrace */
1460 1459 void
1461 1460 ibcm_open_wait(hrtime_t delta)
1462 1461 {
1463 1462 if (delta > 1000000)
1464 1463 IBTF_DPRINTF_L2(cmlog, "ibcm_open_wait: flow more %lld", delta);
1465 1464 }
1466 1465
1467 1466 void
1468 1467 ibcm_open_start(ibcm_state_data_t *statep)
1469 1468 {
1470 1469 ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_REQ);
1471 1470
1472 1471 mutex_enter(&statep->state_mutex);
1473 1472 ibcm_open_wait(gethrtime() - statep->post_time);
1474 1473 mutex_exit(&statep->state_mutex);
1475 1474
1476 1475 ibcm_post_rc_mad(statep, statep->stored_msg, ibcm_post_req_complete,
1477 1476 statep);
1478 1477
1479 1478 mutex_enter(&statep->state_mutex);
1480 1479 IBCM_REF_CNT_DECR(statep);
1481 1480 mutex_exit(&statep->state_mutex);
1482 1481 }
1483 1482
1484 1483 void
1485 1484 ibcm_open_enqueue(ibcm_state_data_t *statep)
1486 1485 {
1487 1486 int run;
1488 1487
1489 1488 mutex_enter(&statep->state_mutex);
1490 1489 statep->post_time = gethrtime();
1491 1490 mutex_exit(&statep->state_mutex);
1492 1491 mutex_enter(&ibcm_open.mutex);
1493 1492 if (ibcm_open.queued == 0 && ibcm_ok_to_start(&ibcm_open)) {
1494 1493 ibcm_open.in_progress++;
1495 1494 mutex_exit(&ibcm_open.mutex);
1496 1495 ibcm_open_start(statep);
1497 1496 } else {
1498 1497 ibcm_open.queued++;
1499 1498 statep->open_link = &ibcm_open.head;
1500 1499 ibcm_open.tail->open_link = statep;
1501 1500 ibcm_open.tail = statep;
1502 1501 run = ibcm_ok_to_start(&ibcm_open);
1503 1502 mutex_exit(&ibcm_open.mutex);
1504 1503 if (run)
1505 1504 ibcm_run_tlist_thread();
1506 1505 }
1507 1506 }
1508 1507
1509 1508 ibcm_state_data_t *
1510 1509 ibcm_open_dequeue(void)
1511 1510 {
1512 1511 ibcm_state_data_t *statep;
1513 1512
1514 1513 ASSERT(MUTEX_HELD(&ibcm_open.mutex));
1515 1514 ibcm_open.queued--;
1516 1515 ibcm_open.in_progress++;
1517 1516 statep = ibcm_open.head.open_link;
1518 1517 ibcm_open.head.open_link = statep->open_link;
1519 1518 statep->open_link = NULL;
1520 1519 /*
1521 1520 * If we remove what tail pointed to, we need
1522 1521 * to reassign tail (it is never NULL).
1523 1522 * tail points to head for the empty list.
1524 1523 */
1525 1524 if (ibcm_open.tail == statep)
1526 1525 ibcm_open.tail = &ibcm_open.head;
1527 1526 return (statep);
1528 1527 }
1529 1528
1530 1529 void
1531 1530 ibcm_check_for_opens(void)
1532 1531 {
1533 1532 ibcm_state_data_t *statep;
1534 1533
1535 1534 mutex_enter(&ibcm_open.mutex);
1536 1535
1537 1536 while (ibcm_open.queued > 0) {
1538 1537 if (ibcm_ok_to_start(&ibcm_open)) {
1539 1538 statep = ibcm_open_dequeue();
1540 1539 mutex_exit(&ibcm_open.mutex);
1541 1540
1542 1541 ibcm_open_start(statep);
1543 1542
1544 1543 mutex_enter(&ibcm_open.mutex);
1545 1544 } else {
1546 1545 break;
1547 1546 }
1548 1547 }
1549 1548 mutex_exit(&ibcm_open.mutex);
1550 1549 }
1551 1550
1552 1551
1553 1552 static void
1554 1553 ibcm_flow_init(ibcm_flow_t *flow, uint_t simul_max)
1555 1554 {
1556 1555 flow->list = NULL;
1557 1556 flow->simul = 0;
1558 1557 flow->waiters_per_chunk = 4;
1559 1558 flow->simul_max = simul_max;
1560 1559 flow->lowat = simul_max - flow->waiters_per_chunk;
1561 1560 flow->lowat_default = flow->lowat;
1562 1561 /* stats */
1563 1562 flow->total = 0;
1564 1563 }
1565 1564
1566 1565 static void
1567 1566 ibcm_rc_flow_control_init(void)
1568 1567 {
1569 1568 mutex_init(&ibcm_open.mutex, NULL, MUTEX_DEFAULT, NULL);
1570 1569 mutex_enter(&ibcm_open.mutex);
1571 1570 ibcm_flow_init(&ibcm_close_flow, ibcm_close_simul_max);
1572 1571 ibcm_flow_init(&ibcm_lapr_flow, ibcm_lapr_simul_max);
1573 1572 ibcm_flow_init(&ibcm_saa_flow, ibcm_saa_simul_max);
1574 1573
1575 1574 ibcm_open.queued = 0;
1576 1575 ibcm_open.exit_deferred = 0;
1577 1576 ibcm_open.in_progress = 0;
1578 1577 ibcm_open.in_progress_max = 16;
1579 1578 ibcm_open.sends = 0;
1580 1579 ibcm_open.sends_max = 0;
1581 1580 ibcm_open.sends_lowat = 8;
1582 1581 ibcm_open.sends_hiwat = 16;
1583 1582 ibcm_open.tail = &ibcm_open.head;
1584 1583 ibcm_open.head.open_link = NULL;
1585 1584 mutex_exit(&ibcm_open.mutex);
1586 1585
1587 1586 mutex_init(&ibcm_close.mutex, NULL, MUTEX_DEFAULT, NULL);
1588 1587 mutex_enter(&ibcm_close.mutex);
1589 1588 ibcm_close.tail = &ibcm_close.head;
1590 1589 ibcm_close.head.close_link = NULL;
1591 1590 mutex_exit(&ibcm_close.mutex);
1592 1591 }
1593 1592
1594 1593 static void
1595 1594 ibcm_rc_flow_control_fini(void)
1596 1595 {
1597 1596 mutex_destroy(&ibcm_open.mutex);
1598 1597 mutex_destroy(&ibcm_close.mutex);
1599 1598 }
1600 1599
1601 1600 static ibcm_flow1_t *
1602 1601 ibcm_flow_find(ibcm_flow_t *flow)
1603 1602 {
1604 1603 ibcm_flow1_t *flow1;
1605 1604 ibcm_flow1_t *f;
1606 1605
1607 1606 f = flow->list;
1608 1607 if (f) { /* most likely code path */
1609 1608 while (f->link != NULL)
1610 1609 f = f->link;
1611 1610 if (f->waiters < flow->waiters_per_chunk)
1612 1611 return (f);
1613 1612 }
1614 1613
1615 1614 /* There was no flow1 list element ready for another waiter */
1616 1615 mutex_exit(&ibcm_open.mutex);
1617 1616 flow1 = kmem_alloc(sizeof (*flow1), KM_SLEEP);
1618 1617 mutex_enter(&ibcm_open.mutex);
1619 1618
1620 1619 f = flow->list;
1621 1620 if (f) {
1622 1621 while (f->link != NULL)
1623 1622 f = f->link;
1624 1623 if (f->waiters < flow->waiters_per_chunk) {
1625 1624 kmem_free(flow1, sizeof (*flow1));
1626 1625 return (f);
1627 1626 }
1628 1627 f->link = flow1;
1629 1628 } else {
1630 1629 flow->list = flow1;
1631 1630 }
1632 1631 cv_init(&flow1->cv, NULL, CV_DRIVER, NULL);
1633 1632 flow1->waiters = 0;
1634 1633 flow1->link = NULL;
1635 1634 return (flow1);
1636 1635 }
1637 1636
1638 1637 static void
1639 1638 ibcm_flow_enter(ibcm_flow_t *flow)
1640 1639 {
1641 1640 mutex_enter(&ibcm_open.mutex);
1642 1641 if (flow->list == NULL && flow->simul < flow->simul_max) {
1643 1642 flow->simul++;
1644 1643 flow->total++;
1645 1644 mutex_exit(&ibcm_open.mutex);
1646 1645 } else {
1647 1646 ibcm_flow1_t *flow1;
1648 1647
1649 1648 flow1 = ibcm_flow_find(flow);
1650 1649 flow1->waiters++;
1651 1650 cv_wait(&flow1->cv, &ibcm_open.mutex);
1652 1651 if (--flow1->waiters == 0) {
1653 1652 cv_destroy(&flow1->cv);
1654 1653 mutex_exit(&ibcm_open.mutex);
1655 1654 kmem_free(flow1, sizeof (*flow1));
1656 1655 } else
1657 1656 mutex_exit(&ibcm_open.mutex);
1658 1657 }
1659 1658 }
1660 1659
1661 1660 static void
1662 1661 ibcm_flow_exit(ibcm_flow_t *flow)
1663 1662 {
1664 1663 mutex_enter(&ibcm_open.mutex);
1665 1664 if (--flow->simul < flow->lowat) {
1666 1665 if (flow->lowat < flow->lowat_default)
1667 1666 flow->lowat++;
1668 1667 if (flow->list) {
1669 1668 ibcm_flow1_t *flow1;
1670 1669
1671 1670 flow1 = flow->list;
1672 1671 flow->list = flow1->link; /* unlink */
1673 1672 flow1->link = NULL; /* be clean */
1674 1673 flow->total += flow1->waiters;
1675 1674 flow->simul += flow1->waiters;
1676 1675 cv_broadcast(&flow1->cv);
1677 1676 }
1678 1677 }
1679 1678 mutex_exit(&ibcm_open.mutex);
1680 1679 }
1681 1680
1682 1681 void
1683 1682 ibcm_flow_inc(void)
1684 1683 {
1685 1684 mutex_enter(&ibcm_open.mutex);
1686 1685 if (++ibcm_open.sends > ibcm_open.sends_max) {
1687 1686 ibcm_open.sends_max = ibcm_open.sends;
1688 1687 IBTF_DPRINTF_L2(cmlog, "ibcm_flow_inc: sends max = %d",
1689 1688 ibcm_open.sends_max);
1690 1689 }
1691 1690 mutex_exit(&ibcm_open.mutex);
1692 1691 }
1693 1692
1694 1693 static void
1695 1694 ibcm_check_send_cmpltn_time(hrtime_t delta, char *event_msg)
1696 1695 {
1697 1696 if (delta > 4000000LL) {
1698 1697 IBTF_DPRINTF_L2(cmlog, "ibcm_check_send_cmpltn_time: "
1699 1698 "%s: %lldns", event_msg, delta);
1700 1699 }
1701 1700 }
1702 1701
1703 1702 void
1704 1703 ibcm_flow_dec(hrtime_t time, char *mad_type)
1705 1704 {
1706 1705 int flow_exit = 0;
1707 1706 int run = 0;
1708 1707
1709 1708 if (ibcm_dtrace)
1710 1709 ibcm_check_send_cmpltn_time(gethrtime() - time, mad_type);
1711 1710 mutex_enter(&ibcm_open.mutex);
1712 1711 ibcm_open.sends--;
1713 1712 if (ibcm_open.sends < ibcm_open.sends_lowat) {
1714 1713 run = ibcm_ok_to_start(&ibcm_open);
1715 1714 if (ibcm_open.exit_deferred) {
1716 1715 ibcm_open.exit_deferred--;
1717 1716 flow_exit = 1;
1718 1717 }
1719 1718 }
1720 1719 mutex_exit(&ibcm_open.mutex);
1721 1720 if (flow_exit)
1722 1721 ibcm_flow_exit(&ibcm_close_flow);
1723 1722 if (run)
1724 1723 ibcm_run_tlist_thread();
1725 1724 }
1726 1725
1727 1726 void
1728 1727 ibcm_close_enqueue(ibcm_state_data_t *statep)
1729 1728 {
1730 1729 mutex_enter(&ibcm_close.mutex);
1731 1730 statep->close_link = NULL;
1732 1731 ibcm_close.tail->close_link = statep;
1733 1732 ibcm_close.tail = statep;
1734 1733 mutex_exit(&ibcm_close.mutex);
1735 1734 ibcm_run_tlist_thread();
1736 1735 }
1737 1736
1738 1737 void
1739 1738 ibcm_check_for_async_close()
1740 1739 {
1741 1740 ibcm_state_data_t *statep;
1742 1741
1743 1742 mutex_enter(&ibcm_close.mutex);
1744 1743
1745 1744 while (ibcm_close.head.close_link) {
1746 1745 statep = ibcm_close.head.close_link;
1747 1746 ibcm_close.head.close_link = statep->close_link;
1748 1747 statep->close_link = NULL;
1749 1748 if (ibcm_close.tail == statep)
1750 1749 ibcm_close.tail = &ibcm_close.head;
1751 1750 mutex_exit(&ibcm_close.mutex);
1752 1751 ibcm_close_start(statep);
1753 1752 mutex_enter(&ibcm_close.mutex);
1754 1753 }
1755 1754 mutex_exit(&ibcm_close.mutex);
1756 1755 }
1757 1756
1758 1757 void
1759 1758 ibcm_close_enter(void)
1760 1759 {
1761 1760 ibcm_flow_enter(&ibcm_close_flow);
1762 1761 }
1763 1762
1764 1763 void
1765 1764 ibcm_close_exit(void)
1766 1765 {
1767 1766 int flow_exit;
1768 1767
1769 1768 mutex_enter(&ibcm_open.mutex);
1770 1769 if (ibcm_open.sends < ibcm_open.sends_lowat ||
1771 1770 ibcm_open.exit_deferred >= 4)
1772 1771 flow_exit = 1;
1773 1772 else {
1774 1773 flow_exit = 0;
1775 1774 ibcm_open.exit_deferred++;
1776 1775 }
1777 1776 mutex_exit(&ibcm_open.mutex);
1778 1777 if (flow_exit)
1779 1778 ibcm_flow_exit(&ibcm_close_flow);
1780 1779 }
1781 1780
1782 1781 /*
1783 1782 * This function needs to be called twice to finish our flow
1784 1783 * control accounting when closing down a connection. One
1785 1784 * call has send_done set to 1, while the other has it set to 0.
1786 1785 * Because of retries, this could get called more than once
1787 1786 * with either 0 or 1, but additional calls have no effect.
1788 1787 */
1789 1788 void
1790 1789 ibcm_close_done(ibcm_state_data_t *statep, int send_done)
1791 1790 {
1792 1791 int flow_exit;
1793 1792
1794 1793 ASSERT(MUTEX_HELD(&statep->state_mutex));
1795 1794 if (statep->close_flow == 1) {
1796 1795 if (send_done)
1797 1796 statep->close_flow = 3;
1798 1797 else
1799 1798 statep->close_flow = 2;
1800 1799 } else if ((send_done && statep->close_flow == 2) ||
1801 1800 (!send_done && statep->close_flow == 3)) {
1802 1801 statep->close_flow = 0;
1803 1802 mutex_enter(&ibcm_open.mutex);
1804 1803 if (ibcm_open.sends < ibcm_open.sends_lowat ||
1805 1804 ibcm_open.exit_deferred >= 4)
1806 1805 flow_exit = 1;
1807 1806 else {
1808 1807 flow_exit = 0;
1809 1808 ibcm_open.exit_deferred++;
1810 1809 }
1811 1810 mutex_exit(&ibcm_open.mutex);
1812 1811 if (flow_exit)
1813 1812 ibcm_flow_exit(&ibcm_close_flow);
1814 1813 }
1815 1814 }
1816 1815
1817 1816 void
1818 1817 ibcm_lapr_enter(void)
1819 1818 {
1820 1819 ibcm_flow_enter(&ibcm_lapr_flow);
1821 1820 }
1822 1821
1823 1822 void
1824 1823 ibcm_lapr_exit(void)
1825 1824 {
1826 1825 ibcm_flow_exit(&ibcm_lapr_flow);
1827 1826 }
1828 1827
1829 1828 void
1830 1829 ibcm_sa_access_enter()
1831 1830 {
1832 1831 ibcm_flow_enter(&ibcm_saa_flow);
1833 1832 }
1834 1833
1835 1834 void
1836 1835 ibcm_sa_access_exit()
1837 1836 {
1838 1837 ibcm_flow_exit(&ibcm_saa_flow);
1839 1838 }
1840 1839
1841 1840 static void
1842 1841 ibcm_sm_notice_handler(ibmf_saa_handle_t saa_handle,
1843 1842 ibmf_saa_subnet_event_t saa_event_code,
1844 1843 ibmf_saa_event_details_t *saa_event_details,
1845 1844 void *callback_arg)
1846 1845 {
1847 1846 ibcm_port_info_t *portp = (ibcm_port_info_t *)callback_arg;
1848 1847 ibt_subnet_event_code_t code;
1849 1848 ibt_subnet_event_t event;
1850 1849 uint8_t event_status;
1851 1850
1852 1851 IBTF_DPRINTF_L3(cmlog, "ibcm_sm_notice_handler: saa_hdl %p, code = %d",
1853 1852 saa_handle, saa_event_code);
1854 1853
1855 1854 mutex_enter(&ibcm_sm_notice_serialize_lock);
1856 1855
1857 1856 switch (saa_event_code) {
1858 1857 case IBMF_SAA_EVENT_MCG_CREATED:
1859 1858 code = IBT_SM_EVENT_MCG_CREATED;
1860 1859 break;
1861 1860 case IBMF_SAA_EVENT_MCG_DELETED:
1862 1861 code = IBT_SM_EVENT_MCG_DELETED;
1863 1862 break;
1864 1863 case IBMF_SAA_EVENT_GID_AVAILABLE:
1865 1864 code = IBT_SM_EVENT_GID_AVAIL;
1866 1865 ibcm_path_cache_purge();
1867 1866 break;
1868 1867 case IBMF_SAA_EVENT_GID_UNAVAILABLE:
1869 1868 code = IBT_SM_EVENT_GID_UNAVAIL;
1870 1869 ibcm_path_cache_purge();
1871 1870 break;
1872 1871 case IBMF_SAA_EVENT_SUBSCRIBER_STATUS_CHG:
1873 1872 event_status =
1874 1873 saa_event_details->ie_producer_event_status_mask &
1875 1874 IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SM;
1876 1875 if (event_status == (portp->port_event_status &
1877 1876 IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SM)) {
1878 1877 mutex_exit(&ibcm_sm_notice_serialize_lock);
1879 1878 return; /* no change */
1880 1879 }
1881 1880 portp->port_event_status = event_status;
1882 1881 if (event_status == IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SM)
1883 1882 code = IBT_SM_EVENT_AVAILABLE;
1884 1883 else
1885 1884 code = IBT_SM_EVENT_UNAVAILABLE;
1886 1885 break;
1887 1886 default:
1888 1887 mutex_exit(&ibcm_sm_notice_serialize_lock);
1889 1888 return;
1890 1889 }
1891 1890
1892 1891 mutex_enter(&ibcm_global_hca_lock);
1893 1892
1894 1893 /* don't send the event if we're tearing down */
1895 1894 if (!IBCM_ACCESS_HCA_OK(portp->port_hcap)) {
1896 1895 mutex_exit(&ibcm_global_hca_lock);
1897 1896 mutex_exit(&ibcm_sm_notice_serialize_lock);
1898 1897 return;
1899 1898 }
1900 1899
1901 1900 ++(portp->port_hcap->hca_acc_cnt);
1902 1901 mutex_exit(&ibcm_global_hca_lock);
1903 1902
1904 1903 event.sm_notice_gid = saa_event_details->ie_gid;
1905 1904 ibtl_cm_sm_notice_handler(portp->port_sgid0, code, &event);
1906 1905
1907 1906 mutex_exit(&ibcm_sm_notice_serialize_lock);
1908 1907
1909 1908 ibcm_dec_hca_acc_cnt(portp->port_hcap);
1910 1909 }
1911 1910
1912 1911 void
1913 1912 ibt_register_subnet_notices(ibt_clnt_hdl_t ibt_hdl,
1914 1913 ibt_sm_notice_handler_t sm_notice_handler, void *private)
1915 1914 {
1916 1915 ibcm_port_info_t *portp;
1917 1916 ibcm_hca_info_t *hcap;
1918 1917 uint8_t port;
1919 1918 int num_failed_sgids;
1920 1919 ibtl_cm_sm_init_fail_t *ifail;
1921 1920 ib_gid_t *sgidp;
1922 1921
1923 1922 IBTF_DPRINTF_L3(cmlog, "ibt_register_subnet_notices(%p, %s)",
1924 1923 ibt_hdl, ibtl_cm_get_clnt_name(ibt_hdl));
1925 1924
1926 1925 mutex_enter(&ibcm_sm_notice_serialize_lock);
1927 1926
1928 1927 ibtl_cm_set_sm_notice_handler(ibt_hdl, sm_notice_handler, private);
1929 1928 if (sm_notice_handler == NULL) {
1930 1929 mutex_exit(&ibcm_sm_notice_serialize_lock);
1931 1930 return;
1932 1931 }
1933 1932
1934 1933 /* for each port, if service is not available, make a call */
1935 1934 mutex_enter(&ibcm_global_hca_lock);
1936 1935 num_failed_sgids = 0;
1937 1936 hcap = ibcm_hca_listp;
1938 1937 while (hcap != NULL) {
1939 1938 portp = hcap->hca_port_info;
1940 1939 for (port = 0; port < hcap->hca_num_ports; port++) {
1941 1940 if (!(portp->port_event_status &
1942 1941 IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SM))
1943 1942 num_failed_sgids++;
1944 1943 portp++;
1945 1944 }
1946 1945 hcap = hcap->hca_next;
1947 1946 }
1948 1947 if (num_failed_sgids != 0) {
1949 1948 ifail = kmem_alloc(sizeof (*ifail) +
1950 1949 (num_failed_sgids - 1) * sizeof (ib_gid_t), KM_SLEEP);
1951 1950 ifail->smf_num_sgids = num_failed_sgids;
1952 1951 ifail->smf_ibt_hdl = ibt_hdl;
1953 1952 sgidp = &ifail->smf_sgid[0];
1954 1953 hcap = ibcm_hca_listp;
1955 1954 while (hcap != NULL) {
1956 1955 portp = hcap->hca_port_info;
1957 1956 for (port = 0; port < hcap->hca_num_ports; port++) {
1958 1957 if (!(portp->port_event_status &
1959 1958 IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SM))
1960 1959 *sgidp++ = portp->port_sgid0;
1961 1960 portp++;
1962 1961 }
1963 1962 hcap = hcap->hca_next;
1964 1963 }
1965 1964 }
1966 1965 mutex_exit(&ibcm_global_hca_lock);
1967 1966
1968 1967 if (num_failed_sgids != 0) {
1969 1968 ibtl_cm_sm_notice_init_failure(ifail);
1970 1969 kmem_free(ifail, sizeof (*ifail) +
1971 1970 (num_failed_sgids - 1) * sizeof (ib_gid_t));
1972 1971 }
1973 1972 mutex_exit(&ibcm_sm_notice_serialize_lock);
1974 1973 }
1975 1974
1976 1975 /* The following is run from a taskq because we've seen the stack overflow. */
1977 1976 static void
1978 1977 ibcm_init_saa(void *arg)
1979 1978 {
1980 1979 ibcm_port_info_t *portp = (ibcm_port_info_t *)arg;
1981 1980 int status;
1982 1981 ib_guid_t port_guid;
1983 1982 ibmf_saa_subnet_event_args_t event_args;
1984 1983
1985 1984 port_guid = portp->port_sgid0.gid_guid;
1986 1985
1987 1986 IBTF_DPRINTF_L3(cmlog, "ibcm_init_saa: port guid %llX", port_guid);
1988 1987
1989 1988 event_args.is_event_callback_arg = portp;
1990 1989 event_args.is_event_callback = ibcm_sm_notice_handler;
1991 1990
1992 1991 if ((status = ibmf_sa_session_open(port_guid, 0, &event_args,
1993 1992 IBMF_VERSION, 0, &portp->port_ibmf_saa_hdl)) != IBMF_SUCCESS) {
1994 1993 IBTF_DPRINTF_L2(cmlog, "ibcm_init_saa: "
1995 1994 "ibmf_sa_session_open failed for port guid %llX "
1996 1995 "status = %d", port_guid, status);
1997 1996 } else {
1998 1997 IBTF_DPRINTF_L2(cmlog, "ibcm_init_saa: "
1999 1998 "registered sa_hdl 0x%p for port guid %llX",
2000 1999 portp->port_ibmf_saa_hdl, port_guid);
2001 2000 }
2002 2001
2003 2002 mutex_enter(&ibcm_sa_open_lock);
2004 2003 portp->port_saa_open_in_progress = 0;
2005 2004 cv_broadcast(&ibcm_sa_open_cv);
2006 2005 mutex_exit(&ibcm_sa_open_lock);
2007 2006 }
2008 2007
2009 2008 void
2010 2009 ibcm_init_saa_handle(ibcm_hca_info_t *hcap, uint8_t port)
2011 2010 {
2012 2011 ibmf_saa_handle_t saa_handle;
2013 2012 uint8_t port_index = port - 1;
2014 2013 ibcm_port_info_t *portp = &hcap->hca_port_info[port_index];
2015 2014 ibt_status_t ibt_status;
2016 2015
2017 2016 if (port_index >= hcap->hca_num_ports)
2018 2017 return;
2019 2018
2020 2019 mutex_enter(&ibcm_sa_open_lock);
2021 2020 if (portp->port_saa_open_in_progress) {
2022 2021 mutex_exit(&ibcm_sa_open_lock);
2023 2022 return;
2024 2023 }
2025 2024
2026 2025 saa_handle = portp->port_ibmf_saa_hdl;
2027 2026 if (saa_handle != NULL) {
2028 2027 mutex_exit(&ibcm_sa_open_lock);
2029 2028 return;
2030 2029 }
2031 2030
2032 2031 portp->port_saa_open_in_progress = 1;
2033 2032 mutex_exit(&ibcm_sa_open_lock);
2034 2033
2035 2034 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(portp->port_event_status))
2036 2035
2037 2036 /* The assumption is that we're getting event notifications */
2038 2037 portp->port_event_status = IBMF_SAA_EVENT_STATUS_MASK_PRODUCER_SM;
2039 2038
2040 2039 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(portp->port_event_status))
2041 2040
2042 2041 ibt_status = ibt_get_port_state_byguid(portp->port_hcap->hca_guid,
2043 2042 portp->port_num, &portp->port_sgid0, NULL);
2044 2043 if (ibt_status != IBT_SUCCESS) {
2045 2044 IBTF_DPRINTF_L2(cmlog, "ibcm_init_saa_handle: "
2046 2045 "ibt_get_port_state_byguid failed for guid %llX "
2047 2046 "with status %d", portp->port_hcap->hca_guid, ibt_status);
2048 2047 mutex_enter(&ibcm_sa_open_lock);
2049 2048 portp->port_saa_open_in_progress = 0;
2050 2049 cv_broadcast(&ibcm_sa_open_cv);
2051 2050 mutex_exit(&ibcm_sa_open_lock);
2052 2051 return;
2053 2052 }
2054 2053 /* if the port is UP, try sa_session_open */
2055 2054 (void) taskq_dispatch(ibcm_taskq, ibcm_init_saa, portp, TQ_SLEEP);
2056 2055 }
2057 2056
2058 2057
2059 2058 ibmf_saa_handle_t
2060 2059 ibcm_get_saa_handle(ibcm_hca_info_t *hcap, uint8_t port)
2061 2060 {
2062 2061 ibmf_saa_handle_t saa_handle;
2063 2062 uint8_t port_index = port - 1;
2064 2063 ibcm_port_info_t *portp = &hcap->hca_port_info[port_index];
2065 2064 ibt_status_t ibt_status;
2066 2065
2067 2066 if (port_index >= hcap->hca_num_ports)
2068 2067 return (NULL);
2069 2068
2070 2069 mutex_enter(&ibcm_sa_open_lock);
2071 2070 while (portp->port_saa_open_in_progress) {
2072 2071 cv_wait(&ibcm_sa_open_cv, &ibcm_sa_open_lock);
2073 2072 }
2074 2073
2075 2074 saa_handle = portp->port_ibmf_saa_hdl;
2076 2075 if (saa_handle != NULL) {
2077 2076 mutex_exit(&ibcm_sa_open_lock);
2078 2077 return (saa_handle);
2079 2078 }
2080 2079
2081 2080 portp->port_saa_open_in_progress = 1;
2082 2081 mutex_exit(&ibcm_sa_open_lock);
2083 2082
2084 2083 ibt_status = ibt_get_port_state_byguid(portp->port_hcap->hca_guid,
2085 2084 portp->port_num, &portp->port_sgid0, NULL);
2086 2085 if (ibt_status != IBT_SUCCESS) {
2087 2086 IBTF_DPRINTF_L2(cmlog, "ibcm_get_saa_handle: "
2088 2087 "ibt_get_port_state_byguid failed for guid %llX "
2089 2088 "with status %d", portp->port_hcap->hca_guid, ibt_status);
2090 2089 mutex_enter(&ibcm_sa_open_lock);
2091 2090 portp->port_saa_open_in_progress = 0;
2092 2091 cv_broadcast(&ibcm_sa_open_cv);
2093 2092 mutex_exit(&ibcm_sa_open_lock);
2094 2093 return (NULL);
2095 2094 }
2096 2095 /* if the port is UP, try sa_session_open */
2097 2096 (void) taskq_dispatch(ibcm_taskq, ibcm_init_saa, portp, TQ_SLEEP);
2098 2097
2099 2098 mutex_enter(&ibcm_sa_open_lock);
2100 2099 while (portp->port_saa_open_in_progress) {
2101 2100 cv_wait(&ibcm_sa_open_cv, &ibcm_sa_open_lock);
2102 2101 }
2103 2102 saa_handle = portp->port_ibmf_saa_hdl;
2104 2103 mutex_exit(&ibcm_sa_open_lock);
2105 2104 return (saa_handle);
2106 2105 }
2107 2106
2108 2107
2109 2108 /*
2110 2109 * ibcm_hca_init_port():
2111 2110 * - Register port with IBMA
2112 2111 *
2113 2112 * Arguments:
2114 2113 * hcap - HCA's guid
2115 2114 * port_index - port number minus 1
2116 2115 *
2117 2116 * Return values:
2118 2117 * IBCM_SUCCESS - success
2119 2118 */
2120 2119 ibt_status_t
2121 2120 ibcm_hca_init_port(ibcm_hca_info_t *hcap, uint8_t port_index)
2122 2121 {
2123 2122 int status;
2124 2123 ibmf_register_info_t *ibmf_reg;
2125 2124
2126 2125 IBTF_DPRINTF_L4(cmlog, "ibcm_hca_init_port: hcap = 0x%p port_num %d",
2127 2126 hcap, port_index + 1);
2128 2127
2129 2128 ASSERT(MUTEX_HELD(&ibcm_global_hca_lock));
2130 2129
2131 2130 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(hcap->hca_port_info))
2132 2131
2133 2132 if (hcap->hca_port_info[port_index].port_ibmf_hdl == NULL) {
2134 2133 /* Register with IBMF */
2135 2134 ibmf_reg = &hcap->hca_port_info[port_index].port_ibmf_reg;
2136 2135 ibmf_reg->ir_ci_guid = hcap->hca_guid;
2137 2136 ibmf_reg->ir_port_num = port_index + 1;
2138 2137 ibmf_reg->ir_client_class = COMM_MGT_MANAGER_AGENT;
2139 2138
2140 2139 /*
2141 2140 * register with management framework
2142 2141 */
2143 2142 status = ibmf_register(ibmf_reg, IBMF_VERSION,
2144 2143 IBMF_REG_FLAG_NO_OFFLOAD, NULL, NULL,
2145 2144 &(hcap->hca_port_info[port_index].port_ibmf_hdl),
2146 2145 &(hcap->hca_port_info[port_index].port_ibmf_caps));
2147 2146
2148 2147 if (status != IBMF_SUCCESS) {
2149 2148 IBTF_DPRINTF_L2(cmlog, "ibcm_hca_init_port: "
2150 2149 "ibmf_register failed for port_num %x, "
2151 2150 "status = %x", port_index + 1, status);
2152 2151 return (ibcm_ibmf_analyze_error(status));
2153 2152 }
2154 2153
2155 2154 hcap->hca_port_info[port_index].port_qp1.qp_cm =
2156 2155 IBMF_QP_HANDLE_DEFAULT;
2157 2156 hcap->hca_port_info[port_index].port_qp1.qp_port =
2158 2157 &(hcap->hca_port_info[port_index]);
2159 2158
2160 2159 /*
2161 2160 * Register the read callback with IBMF.
2162 2161 * Since we just did an ibmf_register, handle is
2163 2162 * valid and ibcm_recv_cb() is valid so we can
2164 2163 * safely assert for success of ibmf_setup_recv_cb()
2165 2164 *
2166 2165 * Depending on the "state" of the HCA,
2167 2166 * CM may drop incoming packets
2168 2167 */
2169 2168 status = ibmf_setup_async_cb(
2170 2169 hcap->hca_port_info[port_index].port_ibmf_hdl,
2171 2170 IBMF_QP_HANDLE_DEFAULT, ibcm_recv_cb,
2172 2171 &(hcap->hca_port_info[port_index].port_qp1), 0);
2173 2172 ASSERT(status == IBMF_SUCCESS);
2174 2173
2175 2174 IBTF_DPRINTF_L5(cmlog, "ibcm_hca_init_port: "
2176 2175 "IBMF hdl[%x] = 0x%p", port_index,
2177 2176 hcap->hca_port_info[port_index].port_ibmf_hdl);
2178 2177
2179 2178 /* Attempt to get the saa_handle for this port */
2180 2179 ibcm_init_saa_handle(hcap, port_index + 1);
2181 2180 }
2182 2181
2183 2182 return (IBT_SUCCESS);
2184 2183 }
2185 2184
2186 2185 /*
2187 2186 * useful, to re attempt to initialize port ibma handles from elsewhere in
2188 2187 * cm code
2189 2188 */
2190 2189 ibt_status_t
2191 2190 ibcm_hca_reinit_port(ibcm_hca_info_t *hcap, uint8_t port_index)
2192 2191 {
2193 2192 ibt_status_t status;
2194 2193
2195 2194 IBTF_DPRINTF_L5(cmlog, "ibcm_hca_reinit_port: hcap 0x%p port_num %d",
2196 2195 hcap, port_index + 1);
2197 2196
2198 2197 mutex_enter(&ibcm_global_hca_lock);
2199 2198 status = ibcm_hca_init_port(hcap, port_index);
2200 2199 mutex_exit(&ibcm_global_hca_lock);
2201 2200 return (status);
2202 2201 }
2203 2202
2204 2203
2205 2204 /*
2206 2205 * ibcm_hca_fini_port():
2207 2206 * - Deregister port with IBMA
2208 2207 *
2209 2208 * Arguments:
2210 2209 * hcap - HCA's guid
2211 2210 * port_index - port number minus 1
2212 2211 *
2213 2212 * Return values:
2214 2213 * IBCM_SUCCESS - success
2215 2214 */
2216 2215 static ibcm_status_t
2217 2216 ibcm_hca_fini_port(ibcm_hca_info_t *hcap, uint8_t port_index)
2218 2217 {
2219 2218 int ibmf_status;
2220 2219 ibcm_status_t ibcm_status;
2221 2220
2222 2221 IBTF_DPRINTF_L4(cmlog, "ibcm_hca_fini_port: hcap = 0x%p port_num %d ",
2223 2222 hcap, port_index + 1);
2224 2223
2225 2224 ASSERT(MUTEX_HELD(&ibcm_global_hca_lock));
2226 2225
2227 2226 if (hcap->hca_port_info[port_index].port_ibmf_saa_hdl != NULL) {
2228 2227 IBTF_DPRINTF_L5(cmlog, "ibcm_hca_fini_port: "
2229 2228 "ibmf_sa_session_close IBMF SAA hdl %p",
2230 2229 hcap->hca_port_info[port_index].port_ibmf_saa_hdl);
2231 2230
2232 2231 ibmf_status = ibmf_sa_session_close(
2233 2232 &hcap->hca_port_info[port_index].port_ibmf_saa_hdl, 0);
2234 2233 if (ibmf_status != IBMF_SUCCESS) {
2235 2234 IBTF_DPRINTF_L2(cmlog, "ibcm_hca_fini_port: "
2236 2235 "ibmf_sa_session_close of port %d returned %x",
2237 2236 port_index + 1, ibmf_status);
2238 2237 return (IBCM_FAILURE);
2239 2238 }
2240 2239 }
2241 2240
2242 2241 if (hcap->hca_port_info[port_index].port_ibmf_hdl != NULL) {
2243 2242 IBTF_DPRINTF_L5(cmlog, "ibcm_hca_fini_port: "
2244 2243 "ibmf_unregister IBMF Hdl %p",
2245 2244 hcap->hca_port_info[port_index].port_ibmf_hdl);
2246 2245
2247 2246 /* clean-up all the ibmf qp's allocated on this port */
2248 2247 ibcm_status = ibcm_free_allqps(hcap, port_index + 1);
2249 2248
2250 2249 if (ibcm_status != IBCM_SUCCESS) {
2251 2250
2252 2251 IBTF_DPRINTF_L2(cmlog, "ibcm_hca_fini_port: "
2253 2252 "ibcm_free_allqps failed for port_num %d",
2254 2253 port_index + 1);
2255 2254 return (IBCM_FAILURE);
2256 2255 }
2257 2256
2258 2257 /* Tear down the receive callback */
2259 2258 ibmf_status = ibmf_tear_down_async_cb(
2260 2259 hcap->hca_port_info[port_index].port_ibmf_hdl,
2261 2260 IBMF_QP_HANDLE_DEFAULT, 0);
2262 2261
2263 2262 if (ibmf_status != IBMF_SUCCESS) {
2264 2263 IBTF_DPRINTF_L2(cmlog, "ibcm_hca_fini_port: "
2265 2264 "ibmf_tear_down_async_cb failed %d port_num %d",
2266 2265 ibmf_status, port_index + 1);
2267 2266 return (IBCM_FAILURE);
2268 2267 }
2269 2268
2270 2269 /* Now, unregister with IBMF */
2271 2270 ibmf_status = ibmf_unregister(
2272 2271 &hcap->hca_port_info[port_index].port_ibmf_hdl, 0);
2273 2272 IBTF_DPRINTF_L4(cmlog, "ibcm_hca_fini_port: "
2274 2273 "ibmf_unregister of port_num %x returned %x",
2275 2274 port_index + 1, ibmf_status);
2276 2275
2277 2276 if (ibmf_status == IBMF_SUCCESS)
2278 2277 hcap->hca_port_info[port_index].port_ibmf_hdl = NULL;
2279 2278 else {
2280 2279 IBTF_DPRINTF_L2(cmlog, "ibcm_hca_fini_port: "
2281 2280 "ibmf_unregister failed %d port_num %d",
2282 2281 ibmf_status, port_index + 1);
2283 2282 return (IBCM_FAILURE);
2284 2283 }
2285 2284 }
2286 2285 return (IBCM_SUCCESS);
2287 2286 }
2288 2287
2289 2288 /*
2290 2289 * ibcm_comm_est_handler():
2291 2290 * Check if the given channel is in ESTABLISHED state or not
2292 2291 *
2293 2292 * Arguments:
2294 2293 * eventp - A pointer to an ibt_async_event_t struct
2295 2294 *
2296 2295 * Return values: NONE
2297 2296 */
2298 2297 static void
2299 2298 ibcm_comm_est_handler(ibt_async_event_t *eventp)
2300 2299 {
2301 2300 ibcm_state_data_t *statep;
2302 2301
2303 2302 IBTF_DPRINTF_L4(cmlog, "ibcm_comm_est_handler:");
2304 2303
2305 2304 /* Both QP and EEC handles can't be NULL */
2306 2305 if (eventp->ev_chan_hdl == NULL) {
2307 2306 IBTF_DPRINTF_L2(cmlog, "ibcm_comm_est_handler: "
2308 2307 "both QP and EEC handles are NULL");
2309 2308 return;
2310 2309 }
2311 2310
2312 2311 /* get the "statep" from qp/eec handles */
2313 2312 IBCM_GET_CHAN_PRIVATE(eventp->ev_chan_hdl, statep);
2314 2313 if (statep == NULL) {
2315 2314 IBTF_DPRINTF_L2(cmlog, "ibcm_comm_est_handler: statep is NULL");
2316 2315 return;
2317 2316 }
2318 2317
2319 2318 mutex_enter(&statep->state_mutex);
2320 2319
2321 2320 IBCM_RELEASE_CHAN_PRIVATE(eventp->ev_chan_hdl);
2322 2321
2323 2322 IBTF_DPRINTF_L4(cmlog, "ibcm_comm_est_handler: statep = %p", statep);
2324 2323
2325 2324 IBCM_REF_CNT_INCR(statep);
2326 2325
2327 2326 if ((statep->state == IBCM_STATE_REP_SENT) ||
2328 2327 (statep->state == IBCM_STATE_MRA_REP_RCVD)) {
2329 2328 timeout_id_t timer_val = statep->timerid;
2330 2329
2331 2330 statep->state = IBCM_STATE_TRANSIENT_ESTABLISHED;
2332 2331
2333 2332 if (timer_val) {
2334 2333 statep->timerid = 0;
2335 2334 mutex_exit(&statep->state_mutex);
2336 2335 (void) untimeout(timer_val);
2337 2336 } else
2338 2337 mutex_exit(&statep->state_mutex);
2339 2338
2340 2339 /* CM doesn't have RTU message here */
2341 2340 ibcm_cep_state_rtu(statep, NULL);
2342 2341
2343 2342 } else {
2344 2343 if (statep->state == IBCM_STATE_ESTABLISHED ||
2345 2344 statep->state == IBCM_STATE_TRANSIENT_ESTABLISHED) {
2346 2345 IBTF_DPRINTF_L4(cmlog, "ibcm_comm_est_handler: "
2347 2346 "Channel already in ESTABLISHED state");
2348 2347 } else {
2349 2348 /* An unexpected behavior from remote */
2350 2349 IBTF_DPRINTF_L2(cmlog, "ibcm_comm_est_handler: "
2351 2350 "Unexpected in state = %d", statep->state);
2352 2351 }
2353 2352 mutex_exit(&statep->state_mutex);
2354 2353
2355 2354 ibcm_insert_trace(statep, IBCM_TRACE_INCOMING_COMEST);
2356 2355 }
2357 2356
2358 2357 mutex_enter(&statep->state_mutex);
2359 2358 IBCM_REF_CNT_DECR(statep);
2360 2359 mutex_exit(&statep->state_mutex);
2361 2360 }
2362 2361
2363 2362
2364 2363 /*
2365 2364 * ibcm_async_handler():
2366 2365 * CM's Async Handler
2367 2366 * (Handles ATTACH, DETACH, COM_EST events)
2368 2367 *
2369 2368 * Arguments:
2370 2369 * eventp - A pointer to an ibt_async_event_t struct
2371 2370 *
2372 2371 * Return values: None
2373 2372 *
2374 2373 * NOTE : CM assumes that all HCA DR events are delivered sequentially
2375 2374 * i.e., until ibcm_async_handler completes for a given HCA DR, framework
2376 2375 * shall not invoke ibcm_async_handler with another DR event for the same
2377 2376 * HCA
2378 2377 */
2379 2378 /* ARGSUSED */
2380 2379 void
2381 2380 ibcm_async_handler(void *clnt_hdl, ibt_hca_hdl_t hca_hdl,
2382 2381 ibt_async_code_t code, ibt_async_event_t *eventp)
2383 2382 {
2384 2383 ibcm_hca_info_t *hcap;
2385 2384 ibcm_port_up_t *pup;
2386 2385
2387 2386 IBTF_DPRINTF_L3(cmlog, "ibcm_async_handler: "
2388 2387 "clnt_hdl = %p, code = 0x%x, eventp = 0x%p",
2389 2388 clnt_hdl, code, eventp);
2390 2389
2391 2390 mutex_enter(&ibcm_global_hca_lock);
2392 2391
2393 2392 /* If fini is going to complete successfully, then return */
2394 2393 if (ibcm_finit_state != IBCM_FINIT_IDLE) {
2395 2394
2396 2395 /*
2397 2396 * This finit state implies one of the following:
2398 2397 * Init either didn't start or didn't complete OR
2399 2398 * Fini is about to return SUCCESS and release the global lock.
2400 2399 * In all these cases, it is safe to ignore the async.
2401 2400 */
2402 2401
2403 2402 IBTF_DPRINTF_L2(cmlog, "ibcm_async_handler: ignoring event %x, "
2404 2403 "as either init didn't complete or fini about to succeed",
2405 2404 code);
2406 2405 mutex_exit(&ibcm_global_hca_lock);
2407 2406 return;
2408 2407 }
2409 2408
2410 2409 switch (code) {
2411 2410 case IBT_PORT_CHANGE_EVENT:
2412 2411 if ((eventp->ev_port_flags & IBT_PORT_CHANGE_SM_LID) == 0)
2413 2412 break;
2414 2413 /* FALLTHROUGH */
2415 2414 case IBT_CLNT_REREG_EVENT:
2416 2415 case IBT_EVENT_PORT_UP:
2417 2416 mutex_exit(&ibcm_global_hca_lock);
2418 2417 pup = kmem_alloc(sizeof (ibcm_port_up_t), KM_SLEEP);
2419 2418 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*pup))
2420 2419 pup->pup_hca_guid = eventp->ev_hca_guid;
2421 2420 pup->pup_port = eventp->ev_port;
2422 2421 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*pup))
2423 2422 (void) taskq_dispatch(ibcm_taskq,
2424 2423 ibcm_service_record_rewrite_task, pup, TQ_SLEEP);
2425 2424 ibcm_path_cache_purge();
2426 2425 return;
2427 2426
2428 2427 case IBT_HCA_ATTACH_EVENT:
2429 2428
2430 2429 /* eventp->ev_hcaguid is the HCA GUID of interest */
2431 2430 ibcm_hca_attach(eventp->ev_hca_guid);
2432 2431 break;
2433 2432
2434 2433 case IBT_HCA_DETACH_EVENT:
2435 2434
2436 2435 /* eventp->ev_hca_guid is the HCA GUID of interest */
2437 2436 if ((hcap = ibcm_find_hcap_entry(eventp->ev_hca_guid)) ==
2438 2437 NULL) {
2439 2438 IBTF_DPRINTF_L2(cmlog, "ibcm_async_handler:"
2440 2439 " hca %llX doesn't exist", eventp->ev_hca_guid);
2441 2440 break;
2442 2441 }
2443 2442
2444 2443 (void) ibcm_hca_detach(hcap);
2445 2444 break;
2446 2445
2447 2446 case IBT_EVENT_COM_EST_QP:
2448 2447 /* eventp->ev_qp_hdl is the ibt_qp_hdl_t of interest */
2449 2448 case IBT_EVENT_COM_EST_EEC:
2450 2449 /* eventp->ev_eec_hdl is the ibt_eec_hdl_t of interest */
2451 2450 ibcm_comm_est_handler(eventp);
2452 2451 break;
2453 2452 default:
2454 2453 break;
2455 2454 }
2456 2455
2457 2456 /* Unblock, any blocked fini/init operations */
2458 2457 mutex_exit(&ibcm_global_hca_lock);
2459 2458 }
↓ open down ↓ |
2066 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX