1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 */
25
26 /*
27 * ibcm_utils.c
28 *
29 * contains internal lookup functions of IB CM module
30 * along with some other miscellaneous stuff
31 *
32 * TBD:
33 * 1. Code needed to ensure that if any clients are using a service then
34 * don't de-register it.
35 */
36
37 #include <sys/ib/mgt/ibcm/ibcm_impl.h>
38 #include <sys/ddi.h>
39
40
41 /* statics */
42 static vmem_t *ibcm_local_sid_arena;
43 static vmem_t *ibcm_ip_sid_arena;
44 static ib_svc_id_t ibcm_local_sid_seed;
45 static ib_com_id_t ibcm_local_cid_seed;
46 _NOTE(READ_ONLY_DATA({ibcm_local_sid_arena ibcm_local_sid_seed
47 ibcm_ip_sid_arena ibcm_local_cid_seed}))
48 static void ibcm_delete_state_from_avl(ibcm_state_data_t *statep);
49 static void ibcm_init_conn_trace(ibcm_state_data_t *statep);
50 static void ibcm_fini_conn_trace(ibcm_state_data_t *statep);
51 static void ibcm_dump_conn_trbuf(void *statep, char *line_prefix,
52 char *buf, int buf_size);
53 extern ibt_status_t ibcm_get_node_rec(ibmf_saa_handle_t, sa_node_record_t *,
54 uint64_t c_mask, void *, size_t *);
55
56 /*
57 * ibcm_lookup_msg:
58 *
59 * Retrieves an existing state structure or creates a new one if none found.
60 * This function is used during
61 * Passive connection side for INCOMING REQ/REJ/RTU/MRA/DREQ/DREP/LAP msgs
62 * Active connection side for INCOMING REP/REJ/MRA/DREQ/DREP/APR msgs
63 * Active side CM for outgoing REQ message.
64 *
65 * NOTE: Only return IBCM_LOOKUP_FAIL if lookup failed to find a match.
66 *
67 * Arguments are:-
68 * event_type - type of message
69 * incoming REQ, REP, REJ, MRA, RTU
70 * remote_qpn - Remote QP number
71 * comid - local/remote comid
72 * remote_hca_guid - Remote HCA GUID
73 * hcap - HCA entry ptr
74 * rstatep - return statep pointer
75 *
76 * Return Values:
77 * IBCM_LOOKUP_NEW - new statep allocated
78 * IBCM_LOOKUP_EXISTS - found an existing entry
79 * IBCM_LOOKUP_FAIL - No lookup entry found
80 * IBCM_MEMORY_FAILURE - Memory allocs failed
81 */
82 ibcm_status_t
ibcm_lookup_msg(ibcm_event_type_t event_type,ib_com_id_t comid,ib_qpn_t remote_qpn,ib_guid_t remote_hca_guid,ibcm_hca_info_t * hcap,ibcm_state_data_t ** rstatep)83 ibcm_lookup_msg(ibcm_event_type_t event_type, ib_com_id_t comid,
84 ib_qpn_t remote_qpn, ib_guid_t remote_hca_guid, ibcm_hca_info_t *hcap,
85 ibcm_state_data_t **rstatep)
86 {
87 avl_index_t where;
88 ibcm_state_data_t *sp;
89
90 IBTF_DPRINTF_L4(cmlog, "ibcm_lookup_msg: event = 0x%x, comid = 0x%x",
91 event_type, comid);
92 IBTF_DPRINTF_L4(cmlog, "ibcm_lookup_msg: rem_qpn = 0x%lX, "
93 "rem_hca_guid = 0x%llX", remote_qpn, remote_hca_guid);
94
95 ASSERT(rw_lock_held(&hcap->hca_state_rwlock));
96
97 /*
98 * Lookup in "hca_passive_tree" for IBCM_INCOMING_REQ and
99 * IBCM_INCOMING_REP_STALE;
100 *
101 * Lookup in "hca_passive_comid_tree" for IBCM_INCOMING_REQ_STALE
102 *
103 * All other lookups in "hca_active_tree".
104 *
105 * NOTE: "hca_active_tree" lookups are based on the local comid.
106 * "hca_passive_state_tree" lookups are based on remote QPN
107 * and remote hca GUID.
108 *
109 * Call avl_find to lookup in the respective tree and save result in
110 * "sp". If "sp" is null it implies that no match was found. If so,
111 * allocate a new ibcm_state_data_t and insert it into the AVL tree(s).
112 */
113 if ((event_type == IBCM_INCOMING_REQ) ||
114 (event_type == IBCM_INCOMING_REP_STALE)) {
115 ibcm_passive_node_info_t info;
116
117 info.info_qpn = remote_qpn;
118 info.info_hca_guid = remote_hca_guid;
119
120 /* Lookup based on Remote QPN and Remote GUID in Passive Tree */
121 sp = avl_find(&hcap->hca_passive_tree, &info, &where);
122 } else if ((event_type == IBCM_INCOMING_REQ_STALE) ||
123 (event_type == IBCM_INCOMING_REJ_RCOMID)) {
124 ibcm_passive_comid_node_info_t info;
125
126 info.info_comid = comid;
127 info.info_hca_guid = remote_hca_guid;
128
129 /* Lookup based on Remote COMID in Passive Tree */
130 sp = avl_find(&hcap->hca_passive_comid_tree, &info, &where);
131 } else { /* any other event including IBCM_OUTGOING_REQ */
132 /* Lookup based on Local comid in Active Tree */
133 sp = avl_find(&hcap->hca_active_tree, &comid, &where);
134 }
135
136 /* matching entry found !! */
137 if (sp != NULL) {
138 IBTF_DPRINTF_L4(cmlog, "ibcm_lookup_msg: match found "
139 "statep = %p", sp);
140 if (event_type == IBCM_INCOMING_REQ)
141 kmem_free(*rstatep, sizeof (ibcm_state_data_t));
142 *rstatep = sp; /* return the matched statep */
143
144 mutex_enter(&(sp->state_mutex));
145 IBCM_REF_CNT_INCR(sp); /* increment the ref count */
146 mutex_exit(&(sp->state_mutex));
147
148 return (IBCM_LOOKUP_EXISTS);
149 }
150
151 /*
152 * If we came here then it implies that CM didn't
153 * find a matching entry. We will create a new entry in avl tree,
154 * if event_type is INCOMING/OUTGOING REQ, REQ_STALE/REP_STALE.
155 * statep is created for INCOMING/OUTGOING REQ.
156 * For all other event_types we return lookup failure
157 */
158 if (!((event_type == IBCM_INCOMING_REQ) ||
159 (event_type == IBCM_INCOMING_REQ_STALE) ||
160 (event_type == IBCM_INCOMING_REP_STALE) ||
161 (event_type == IBCM_OUTGOING_REQ))) {
162 IBTF_DPRINTF_L2(cmlog, "ibcm_lookup_msg: failed for "
163 "event type %x remote_comid = 0x%x",
164 event_type, comid);
165
166 return (IBCM_LOOKUP_FAIL);
167 }
168
169 if ((event_type == IBCM_INCOMING_REQ) ||
170 (event_type == IBCM_OUTGOING_REQ)) {
171
172 /* fill in the new ibcm_state_data */
173 sp = *rstatep;
174
175 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sp))
176
177 /* initialize statep */
178 mutex_init(&sp->state_mutex, NULL, MUTEX_DEFAULT, NULL);
179 cv_init(&sp->block_client_cv, NULL, CV_DRIVER, NULL);
180 cv_init(&sp->block_mad_cv, NULL, CV_DRIVER, NULL);
181
182 sp->hcap = hcap;
183 IBCM_REF_CNT_INCR(sp);
184 sp->local_comid = comid;
185
186 if (ibcm_enable_trace != 0)
187 ibcm_init_conn_trace(sp);
188
189 if (event_type == IBCM_INCOMING_REQ) { /* Passive side */
190 sp->state = IBCM_STATE_REQ_RCVD;
191 sp->clnt_proceed = IBCM_BLOCK;
192 sp->close_nocb_state = IBCM_UNBLOCK;
193 sp->remote_hca_guid = remote_hca_guid;
194 sp->remote_qpn = remote_qpn;
195
196 } else if (event_type == IBCM_OUTGOING_REQ) { /* Active side */
197 sp->close_nocb_state = IBCM_UNBLOCK;
198 sp->state = IBCM_STATE_IDLE;
199 }
200
201 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*sp))
202
203 } else {
204 sp = *rstatep; /* for incoming REQ/REP STALE only */
205 }
206
207 if ((event_type == IBCM_INCOMING_REQ) ||
208 (event_type == IBCM_INCOMING_REP_STALE)) {
209
210 /* First, insert a new "sp" into "hca_passive_tree" @ "where" */
211 avl_insert(&(hcap->hca_passive_tree), (void *)sp, where);
212
213 if (event_type == IBCM_INCOMING_REQ) { /* Only INCOMING_REQ */
214 /*
215 * We have to do an avl_find() to figure out
216 * "where" to insert the statep into the active tree.
217 *
218 * CM doesn't care for avl_find's retval.
219 */
220 (void) avl_find(&hcap->hca_active_tree,
221 &sp->local_comid, &where);
222
223 /* Next, insert the "sp" into "hca_active_tree" */
224 avl_insert(&hcap->hca_active_tree, (void *)sp, where);
225 }
226 } else if (event_type == IBCM_INCOMING_REQ_STALE) {
227 avl_insert(&(hcap->hca_passive_comid_tree), (void *)sp, where);
228 } else { /* IBCM_OUTGOING_REQ */
229 /* Insert the new sp only into "hca_active_tree", @ "where" */
230 avl_insert(&(hcap->hca_active_tree), (void *)sp, where);
231 }
232
233 return (IBCM_LOOKUP_NEW); /* return new lookup */
234 }
235
236
237 /*
238 * ibcm_active_node_compare:
239 * - AVL active tree node compare
240 *
241 * Arguments:
242 * p1 : pointer to local comid
243 * p2 : pointer to passed ibcm_state_data_t
244 *
245 * Return values:
246 * 0 : match found
247 * -1 : no match but insert to left side of the tree
248 * +1 : no match but insert to right side of the tree
249 */
250 int
ibcm_active_node_compare(const void * p1,const void * p2)251 ibcm_active_node_compare(const void *p1, const void *p2)
252 {
253 ib_com_id_t *local_comid = (ib_com_id_t *)p1;
254 ibcm_state_data_t *statep = (ibcm_state_data_t *)p2;
255
256 IBTF_DPRINTF_L5(cmlog, "ibcm_active_node_compare: "
257 "comid: 0x%x, statep: 0x%p", *local_comid, statep);
258
259 if (*local_comid > statep->local_comid) {
260 return (+1);
261 } else if (*local_comid < statep->local_comid) {
262 return (-1);
263 } else {
264 return (0);
265 }
266 }
267
268
269 /*
270 * ibcm_passive_node_compare:
271 * - AVL passive tree node compare (passive side)
272 *
273 * Arguments:
274 * p1 : pointer to ibcm_passive_node_info (remote qpn and remote guid)
275 * p2 : pointer to passed ibcm_state_data_t
276 *
277 * Return values:
278 * 0 : match found
279 * -1 : no match but insert to left side of the tree
280 * +1 : no match but insert to right side of the tree
281 */
282 int
ibcm_passive_node_compare(const void * p1,const void * p2)283 ibcm_passive_node_compare(const void *p1, const void *p2)
284 {
285 ibcm_state_data_t *statep = (ibcm_state_data_t *)p2;
286 ibcm_passive_node_info_t *infop = (ibcm_passive_node_info_t *)p1;
287
288 IBTF_DPRINTF_L5(cmlog, "ibcm_passive_node_compare: "
289 "statep: 0x%p, p1: 0x%p", statep, p1);
290
291 /*
292 * PASSIVE SIDE: (REQ, REP, MRA, REJ)
293 * always search by active COMID
294 */
295 if (infop->info_qpn > statep->remote_qpn) {
296 return (+1);
297 } else if (infop->info_qpn < statep->remote_qpn) {
298 return (-1);
299 } else {
300 if (infop->info_hca_guid < statep->remote_hca_guid) {
301 return (-1);
302 } else if (infop->info_hca_guid > statep->remote_hca_guid) {
303 return (+1);
304 } else {
305 return (0);
306 }
307 }
308 }
309
310 /*
311 * ibcm_passive_comid_node_compare:
312 * - AVL passive comid tree node compare (passive side)
313 *
314 * Arguments:
315 * p1 : pointer to ibcm_passive_comid_node_info
316 * (remote comid and remote guid)
317 * p2 : pointer to passed ibcm_state_data_t
318 *
319 * Return values:
320 * 0 : match found
321 * -1 : no match but insert to left side of the tree
322 * +1 : no match but insert to right side of the tree
323 */
324 int
ibcm_passive_comid_node_compare(const void * p1,const void * p2)325 ibcm_passive_comid_node_compare(const void *p1, const void *p2)
326 {
327 ibcm_state_data_t *statep = (ibcm_state_data_t *)p2;
328 ibcm_passive_comid_node_info_t *infop =
329 (ibcm_passive_comid_node_info_t *)p1;
330
331 IBTF_DPRINTF_L5(cmlog, "ibcm_passive_comid_node_compare: "
332 "statep: 0x%p, p1: 0x%p", statep, p1);
333
334 if (infop->info_comid > statep->remote_comid) {
335 return (+1);
336 } else if (infop->info_comid < statep->remote_comid) {
337 return (-1);
338 } else {
339 if (infop->info_hca_guid < statep->remote_hca_guid) {
340 return (-1);
341 } else if (infop->info_hca_guid > statep->remote_hca_guid) {
342 return (+1);
343 } else {
344 return (0);
345 }
346 }
347 }
348
349
350 void
ibcm_delete_state_from_avl(ibcm_state_data_t * statep)351 ibcm_delete_state_from_avl(ibcm_state_data_t *statep)
352 {
353 avl_index_t a_where = 0;
354 avl_index_t p_where = 0;
355 avl_index_t pcomid_where = 0;
356 ibcm_hca_info_t *hcap;
357 ibcm_state_data_t *active_nodep, *passive_nodep;
358 ibcm_state_data_t *passive_comid_nodep;
359 ibcm_passive_node_info_t info;
360 ibcm_passive_comid_node_info_t info_comid;
361
362 IBTF_DPRINTF_L4(cmlog, "ibcm_delete_state_from_avl: statep 0x%p",
363 statep);
364
365 if (statep == NULL) {
366 IBTF_DPRINTF_L2(cmlog, "ibcm_delete_state_from_avl: statep"
367 " NULL");
368 return;
369 }
370
371 hcap = statep->hcap;
372
373 /*
374 * Once the avl tree lock is acquired, no other thread can increment
375 * ref cnt, until tree lock is exit'ed. Since the statep is removed
376 * from the avl's after acquiring lock below, no other thread can
377 * increment the ref cnt after acquiring the lock below
378 */
379
380 rw_enter(&hcap->hca_state_rwlock, RW_WRITER);
381
382 /* Lookup based on Local comid in the active tree */
383 active_nodep = avl_find(&hcap->hca_active_tree, &(statep->local_comid),
384 &a_where);
385
386 /* Lookup based on Remote QPN and Remote GUID in the passive tree */
387 info.info_qpn = statep->remote_qpn;
388 info.info_hca_guid = statep->remote_hca_guid;
389 passive_nodep = avl_find(&hcap->hca_passive_tree, &info, &p_where);
390
391 /* Lookup based on Remote Comid and Remote GUID in the passive tree */
392 info_comid.info_comid = statep->remote_comid;
393 info_comid.info_hca_guid = statep->remote_hca_guid;
394 passive_comid_nodep = avl_find(&hcap->hca_passive_comid_tree,
395 &info_comid, &pcomid_where);
396
397 /* remove it from the tree, destroy record and the nodep */
398 if (active_nodep == statep) {
399 avl_remove(&hcap->hca_active_tree, active_nodep);
400 }
401
402 if (passive_nodep == statep) {
403 avl_remove(&hcap->hca_passive_tree, passive_nodep);
404 }
405
406 if (passive_comid_nodep == statep) {
407 avl_remove(&hcap->hca_passive_comid_tree, passive_comid_nodep);
408 }
409
410 rw_exit(&hcap->hca_state_rwlock);
411 }
412
413 /*
414 * ibcm_dealloc_state_data:
415 * Deallocates all buffers and the memory of state structure
416 * This routine can be called on statep that has ref_cnt of 0, and that is
417 * already deleted from the avl tree's
418 *
419 * Arguments are:-
420 * statep - statep to be deleted
421 *
422 * Return Values: NONE
423 */
424 void
ibcm_dealloc_state_data(ibcm_state_data_t * statep)425 ibcm_dealloc_state_data(ibcm_state_data_t *statep)
426 {
427 timeout_id_t timer_val;
428 int dump_trace;
429 IBTF_DPRINTF_L4(cmlog, "ibcm_dealloc_state_data: statep 0x%p", statep);
430
431 if (statep == NULL) {
432 IBTF_DPRINTF_L2(cmlog, "ibcm_dealloc_state_data: statep NULL");
433 return;
434 }
435
436 /* ref_cnt is 0 */
437 /* If timer is running - expire it */
438 mutex_enter(&statep->state_mutex);
439 timer_val = statep->timerid;
440 if (timer_val != 0) {
441 statep->timerid = 0;
442 mutex_exit(&statep->state_mutex);
443 (void) untimeout(timer_val);
444 } else
445 mutex_exit(&statep->state_mutex);
446
447 /* release the ref cnt on the associated ibmf qp */
448 if (statep->stored_reply_addr.cm_qp_entry != NULL)
449 ibcm_release_qp(statep->stored_reply_addr.cm_qp_entry);
450
451 if (statep->stored_msg != NULL)
452 (void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl,
453 &statep->stored_msg);
454
455 if (statep->dreq_msg != NULL)
456 (void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl,
457 &statep->dreq_msg);
458
459 if (statep->drep_msg != NULL)
460 (void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl,
461 &statep->drep_msg);
462
463 if (statep->mra_msg != NULL)
464 (void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl,
465 &statep->mra_msg);
466
467 if (statep->lapr_msg != NULL)
468 (void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl,
469 &statep->lapr_msg);
470
471 if (statep->defer_cm_msg != NULL)
472 kmem_free(statep->defer_cm_msg, IBCM_MSG_SIZE);
473
474 IBTF_DPRINTF_L4(cmlog, "ibcm_dealloc_state_data: done for sp = 0x%p",
475 statep);
476
477 /* Ensure the thread doing ref cnt decr releases the mutex */
478 mutex_enter(&statep->state_mutex);
479 dump_trace = statep->cm_retries > 0;
480 mutex_exit(&statep->state_mutex);
481
482 /*
483 * now call the mutex_destroy() and cv_destroy()
484 */
485 mutex_destroy(&statep->state_mutex);
486
487 cv_destroy(&statep->block_client_cv);
488 cv_destroy(&statep->block_mad_cv);
489
490 /* free the comid */
491 ibcm_free_comid(statep->hcap, statep->local_comid);
492
493 /* Decrement the resource on hcap */
494 ibcm_dec_hca_res_cnt(statep->hcap);
495
496 /* dump the trace data into ibtf_debug_buf */
497 if ((ibcm_enable_trace & 4) || dump_trace)
498 ibcm_dump_conn_trace(statep);
499
500 ibcm_fini_conn_trace(statep);
501
502 /* free the statep */
503 kmem_free(statep, sizeof (ibcm_state_data_t));
504 }
505
506 /*
507 * ibcm_delete_state_data:
508 * Deletes the state from avl trees, and tries to deallocate state
509 *
510 * Arguments are:-
511 * statep - statep to be deleted
512 *
513 * Return Values: NONE
514 */
515 void
ibcm_delete_state_data(ibcm_state_data_t * statep)516 ibcm_delete_state_data(ibcm_state_data_t *statep)
517 {
518 IBTF_DPRINTF_L4(cmlog, "ibcm_delete_state_data:");
519
520 ibcm_delete_state_from_avl(statep);
521
522 /* Must acquire the state mutex to set delete_state_data */
523 mutex_enter(&statep->state_mutex);
524 if (statep->ref_cnt > 0) {
525 statep->delete_state_data = B_TRUE;
526 IBTF_DPRINTF_L4(cmlog, "ibcm_delete_state_data: statep 0x%p "
527 "ref_cnt = %x", statep, statep->ref_cnt);
528 mutex_exit(&statep->state_mutex);
529 return;
530 }
531 mutex_exit(&statep->state_mutex);
532
533 ibcm_dealloc_state_data(statep);
534 }
535
536 /*
537 * ibcm_find_sidr_entry:
538 * Routines for CM SIDR state structure list manipulation.
539 * Finds an entry based on lid, gid and grh exists fields
540 *
541 * INPUTS:
542 * lid: LID of incoming SIDR REQ
543 * gid: GID of incoming SIDR REQ
544 * grh_exists: TRUE if GRH exists in the incoming SIDR REQ
545 * req_id: Request ID
546 * hcap: CM State table to search for SIDR state structure
547 * statep: Returns a valid state structure, if one exists based
548 * on lid, gid and grh_exists fields
549 * flag: IBCM_FLAG_LOOKUP - just lookup
550 * IBCM_FLAG_LOOKUP_AND_ADD - if lookup fails, add it.
551 * Return Values:
552 * IBCM_LOOKUP_EXISTS - found an existing entry
553 * IBCM_LOOKUP_FAIL - failed to find an entry
554 * IBCM_LOOKUP_NEW - created a new entry
555 */
556 ibcm_status_t
ibcm_find_sidr_entry(ibcm_sidr_srch_t * srch_param,ibcm_hca_info_t * hcap,ibcm_ud_state_data_t ** ud_statep,ibcm_lookup_flag_t flag)557 ibcm_find_sidr_entry(ibcm_sidr_srch_t *srch_param, ibcm_hca_info_t *hcap,
558 ibcm_ud_state_data_t **ud_statep, ibcm_lookup_flag_t flag)
559 {
560 ibcm_status_t status;
561 ibcm_ud_state_data_t *usp;
562
563 IBTF_DPRINTF_L5(cmlog, "ibcm_find_sidr_entry: srch_params are:"
564 "lid=%x, (%llX, %llX), grh: %x, id: %x",
565 srch_param->srch_lid, srch_param->srch_gid.gid_prefix,
566 srch_param->srch_gid.gid_guid, srch_param->srch_grh_exists,
567 srch_param->srch_req_id);
568
569 if (flag == IBCM_FLAG_ADD) {
570 *ud_statep = ibcm_add_sidr_entry(srch_param, hcap);
571 return (IBCM_LOOKUP_NEW);
572 }
573
574 usp = hcap->hca_sidr_list; /* Point to the list */
575
576 /* traverse the list for a matching entry */
577 while (usp != NULL) {
578 IBTF_DPRINTF_L5(cmlog, "ibcm_find_sidr_entry: "
579 "lid=%x, (%llX, %llX), grh: %x, id: %x",
580 usp->ud_sidr_req_lid, usp->ud_sidr_req_gid.gid_prefix,
581 usp->ud_sidr_req_gid.gid_guid, usp->ud_grh_exists,
582 usp->ud_req_id);
583
584 if ((usp->ud_sidr_req_lid == srch_param->srch_lid) &&
585 ((srch_param->srch_gid.gid_prefix == 0) ||
586 (srch_param->srch_gid.gid_prefix ==
587 usp->ud_sidr_req_gid.gid_prefix)) &&
588 ((srch_param->srch_gid.gid_guid == 0) ||
589 (srch_param->srch_gid.gid_guid ==
590 usp->ud_sidr_req_gid.gid_guid)) &&
591 (srch_param->srch_req_id == usp->ud_req_id) &&
592 (usp->ud_grh_exists == srch_param->srch_grh_exists) &&
593 (usp->ud_mode == srch_param->srch_mode)) { /* found match */
594 *ud_statep = usp;
595 IBTF_DPRINTF_L5(cmlog, "ibcm_find_sidr_entry: "
596 "found usp = %p", usp);
597 mutex_enter(&usp->ud_state_mutex);
598 IBCM_UD_REF_CNT_INCR(usp);
599 mutex_exit(&usp->ud_state_mutex);
600
601 return (IBCM_LOOKUP_EXISTS);
602 }
603 usp = usp->ud_nextp;
604 }
605
606 /*
607 * If code came here --> it couldn't find a match.
608 * OR
609 * the "hcap->hca_sidr_list" was NULL
610 */
611 if (flag == IBCM_FLAG_LOOKUP) {
612 IBTF_DPRINTF_L3(cmlog, "ibcm_find_sidr_entry: no match found "
613 "lid=%x, (%llX, %llX), grh: %x, id: %x",
614 srch_param->srch_lid, srch_param->srch_gid.gid_prefix,
615 srch_param->srch_gid.gid_guid, srch_param->srch_grh_exists,
616 srch_param->srch_req_id);
617 status = IBCM_LOOKUP_FAIL;
618 } else {
619 *ud_statep = ibcm_add_sidr_entry(srch_param, hcap);
620 status = IBCM_LOOKUP_NEW;
621 }
622
623 return (status);
624 }
625
626
627 /*
628 * ibcm_add_sidr_entry:
629 * Adds a SIDR entry. Called *ONLY* from ibcm_find_sidr_entry()
630 *
631 * INPUTS:
632 * lid: LID of incoming SIDR REQ
633 * gid: GID of incoming SIDR REQ
634 * grh_exists: TRUE if GRH exists in the incoming SIDR REQ
635 * req_id: Request ID
636 * hcap: CM State table to search for SIDR state structure
637 * Return Values: NONE
638 */
639 ibcm_ud_state_data_t *
ibcm_add_sidr_entry(ibcm_sidr_srch_t * srch_param,ibcm_hca_info_t * hcap)640 ibcm_add_sidr_entry(ibcm_sidr_srch_t *srch_param, ibcm_hca_info_t *hcap)
641 {
642 ibcm_ud_state_data_t *ud_statep;
643
644 IBTF_DPRINTF_L5(cmlog, "ibcm_add_sidr_entry: lid=%x, guid=%llX, "
645 "grh = %x req_id = %x", srch_param->srch_lid,
646 srch_param->srch_gid.gid_guid, srch_param->srch_grh_exists,
647 srch_param->srch_req_id);
648
649 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ud_statep))
650
651 /* didn't find the entry - so create new */
652 ud_statep = kmem_zalloc(sizeof (ibcm_ud_state_data_t), KM_SLEEP);
653
654 mutex_init(&ud_statep->ud_state_mutex, NULL, MUTEX_DEFAULT, NULL);
655 cv_init(&ud_statep->ud_block_client_cv, NULL, CV_DRIVER, NULL);
656
657 /* Initialize some ud_statep fields */
658 mutex_enter(&ud_statep->ud_state_mutex);
659 ud_statep->ud_hcap = hcap;
660 ud_statep->ud_req_id = srch_param->srch_req_id;
661 ud_statep->ud_ref_cnt = 1;
662 ud_statep->ud_grh_exists = srch_param->srch_grh_exists;
663 ud_statep->ud_sidr_req_lid = srch_param->srch_lid;
664 ud_statep->ud_sidr_req_gid = srch_param->srch_gid;
665 ud_statep->ud_mode = srch_param->srch_mode;
666 ud_statep->ud_max_cm_retries = ibcm_max_retries;
667 mutex_exit(&ud_statep->ud_state_mutex);
668
669 /* Update the list */
670 ud_statep->ud_nextp = hcap->hca_sidr_list;
671 hcap->hca_sidr_list = ud_statep;
672
673 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*ud_statep))
674
675 return (ud_statep);
676 }
677
678
679 /*
680 * ibcm_delete_ud_state_data:
681 * Deletes a given state structure
682 *
683 * Arguments are:-
684 * statep - statep to be deleted
685 *
686 * Return Values: NONE
687 */
688 void
ibcm_delete_ud_state_data(ibcm_ud_state_data_t * ud_statep)689 ibcm_delete_ud_state_data(ibcm_ud_state_data_t *ud_statep)
690 {
691 ibcm_ud_state_data_t *prevp, *headp;
692 ibcm_hca_info_t *hcap;
693
694 IBTF_DPRINTF_L4(cmlog, "ibcm_delete_ud_state_data: ud_statep 0x%p",
695 ud_statep);
696
697 if (ud_statep == NULL || ud_statep->ud_hcap == NULL) {
698 IBTF_DPRINTF_L2(cmlog, "ibcm_delete_ud_state_data: "
699 "ud_statep or hcap is NULL");
700 return;
701 }
702
703 hcap = ud_statep->ud_hcap;
704
705 rw_enter(&hcap->hca_sidr_list_lock, RW_WRITER);
706
707 /* Next, remove this from the HCA SIDR list */
708 if (hcap->hca_sidr_list != NULL) {
709 prevp = NULL;
710 headp = hcap->hca_sidr_list;
711
712 while (headp != NULL) {
713 /* delete the matching entry */
714 if (headp == ud_statep) {
715 if (prevp) {
716 prevp->ud_nextp = headp->ud_nextp;
717 } else {
718 prevp = headp->ud_nextp;
719 hcap->hca_sidr_list = prevp;
720 }
721 break;
722 }
723 prevp = headp;
724 headp = headp->ud_nextp;
725 }
726 }
727
728 rw_exit(&hcap->hca_sidr_list_lock);
729
730 /*
731 * While ref_cnt > 0
732 * - implies someone else is accessing the statep (possibly in
733 * a timeout function handler etc.)
734 * - don't delete statep unless they are done otherwise potentially
735 * one could access released memory and panic.
736 */
737 mutex_enter(&ud_statep->ud_state_mutex);
738 if (ud_statep->ud_ref_cnt > 0) {
739 ud_statep->ud_delete_state_data = B_TRUE;
740 IBTF_DPRINTF_L4(cmlog, "ibcm_delete_ud_state_data: "
741 "ud_statep 0x%p ud_ref_cnt = %x", ud_statep,
742 ud_statep->ud_ref_cnt);
743 mutex_exit(&ud_statep->ud_state_mutex);
744 return;
745 }
746 mutex_exit(&ud_statep->ud_state_mutex);
747
748 ibcm_dealloc_ud_state_data(ud_statep);
749 }
750
751 /*
752 * ibcm_ud_dealloc_state_data:
753 * Deallocates a given ud state structure
754 *
755 * Arguments are:-
756 * ud statep - ud statep to be deleted
757 *
758 * Return Values: NONE
759 */
760 void
ibcm_dealloc_ud_state_data(ibcm_ud_state_data_t * ud_statep)761 ibcm_dealloc_ud_state_data(ibcm_ud_state_data_t *ud_statep)
762 {
763 timeout_id_t timer_val;
764
765 IBTF_DPRINTF_L4(cmlog, "ibcm_dealloc_ud_state_data: ud_statep 0x%p",
766 ud_statep);
767
768 /* If timer is running - expire it */
769 mutex_enter(&ud_statep->ud_state_mutex);
770 if (ud_statep->ud_timerid) {
771 timer_val = ud_statep->ud_timerid;
772 ud_statep->ud_timerid = 0;
773 mutex_exit(&ud_statep->ud_state_mutex);
774 (void) untimeout(timer_val);
775 IBTF_DPRINTF_L2(cmlog, "ibcm_dealloc_ud_state_data: "
776 "Unexpected timer id 0x%p ud_statep 0x%p", timer_val,
777 ud_statep);
778 } else
779 mutex_exit(&ud_statep->ud_state_mutex);
780
781 if (ud_statep->ud_stored_msg != NULL) {
782 (void) ibcm_free_out_msg(
783 ud_statep->ud_stored_reply_addr.ibmf_hdl,
784 &ud_statep->ud_stored_msg);
785 }
786
787 /* release the ref cnt on the associated ibmf qp */
788 ASSERT(ud_statep->ud_stored_reply_addr.cm_qp_entry != NULL);
789 ibcm_release_qp(ud_statep->ud_stored_reply_addr.cm_qp_entry);
790
791 /* Ensure the thread doing ref cnt decr releases the mutex */
792 mutex_enter(&ud_statep->ud_state_mutex);
793 mutex_exit(&ud_statep->ud_state_mutex);
794
795 /* now do the mutex_destroy() and cv_destroy() */
796 mutex_destroy(&ud_statep->ud_state_mutex);
797
798 cv_destroy(&ud_statep->ud_block_client_cv);
799
800 /* free the req id on SIDR REQ sender side */
801 if (ud_statep->ud_mode == IBCM_ACTIVE_MODE)
802 ibcm_free_reqid(ud_statep->ud_hcap, ud_statep->ud_req_id);
803
804 /* Decrement the resource on hcap */
805 ibcm_dec_hca_res_cnt(ud_statep->ud_hcap);
806
807 /* free the statep */
808 kmem_free(ud_statep, sizeof (ibcm_ud_state_data_t));
809 }
810
811
812 /*
813 * ibcm_init_ids:
814 * Create the vmem arenas for the various global ids
815 *
816 * Arguments are:-
817 * NONE
818 *
819 * Return Values: ibcm_status_t
820 */
821
822 ibcm_status_t
ibcm_init_ids(void)823 ibcm_init_ids(void)
824 {
825 timespec_t tv;
826
827 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_local_sid_arena))
828 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_ip_sid_arena))
829 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_local_sid_seed))
830 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(ibcm_local_cid_seed))
831
832 ibcm_local_sid_arena = vmem_create("ibcm_local_sid",
833 (void *)IBCM_INITIAL_SID, IBCM_MAX_LOCAL_SIDS, 1, NULL, NULL, NULL,
834 0, VM_SLEEP | VMC_IDENTIFIER);
835
836 if (!ibcm_local_sid_arena)
837 return (IBCM_FAILURE);
838
839 ibcm_ip_sid_arena = vmem_create("ibcm_ip_sid", (void *)IBCM_INITIAL_SID,
840 IBCM_MAX_IP_SIDS, 1, NULL, NULL, NULL, 0,
841 VM_SLEEP | VMC_IDENTIFIER);
842
843 if (!ibcm_ip_sid_arena)
844 return (IBCM_FAILURE);
845
846 /* create a random starting value for local service ids */
847 gethrestime(&tv);
848 ibcm_local_sid_seed = ((uint64_t)tv.tv_sec << 20) & 0x007FFFFFFFF00000;
849 ASSERT((ibcm_local_sid_seed & IB_SID_AGN_MASK) == 0);
850 ibcm_local_sid_seed |= IB_SID_AGN_LOCAL;
851
852 ibcm_local_cid_seed = (ib_com_id_t)tv.tv_sec;
853 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_local_sid_arena))
854 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_local_sid_seed))
855 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_ip_sid_arena))
856 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(ibcm_local_cid_seed))
857
858 return (IBCM_SUCCESS);
859 }
860
861
862 /*
863 * ibcm_init_hca_ids:
864 * Create the vmem arenas for the various hca level ids
865 *
866 * Arguments are:-
867 * hcap pointer to ibcm_hca_info_t
868 *
869 * Return Values: ibcm_status_t
870 */
871 ibcm_status_t
ibcm_init_hca_ids(ibcm_hca_info_t * hcap)872 ibcm_init_hca_ids(ibcm_hca_info_t *hcap)
873 {
874 hcap->hca_comid_arena = vmem_create("ibcm_com_ids",
875 (void *)IBCM_INITIAL_COMID, IBCM_MAX_COMIDS,
876 1, NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER);
877
878 if (!hcap->hca_comid_arena)
879 return (IBCM_FAILURE);
880
881 hcap->hca_reqid_arena = vmem_create("ibcm_req_ids",
882 (void *)IBCM_INITIAL_REQID, IBCM_MAX_REQIDS,
883 1, NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER);
884
885 if (!hcap->hca_reqid_arena) {
886 vmem_destroy(hcap->hca_comid_arena);
887 return (IBCM_FAILURE);
888 }
889
890 return (IBCM_SUCCESS);
891 }
892
893 /*
894 * ibcm_free_ids:
895 * Destroy the vmem arenas for the various ids
896 *
897 * Arguments are:-
898 * NONE
899 *
900 * Return Values: NONE
901 */
902 void
ibcm_fini_ids(void)903 ibcm_fini_ids(void)
904 {
905 /* All arenas shall be valid */
906 vmem_destroy(ibcm_local_sid_arena);
907 vmem_destroy(ibcm_ip_sid_arena);
908 }
909
910 /*
911 * ibcm_free_hca_ids:
912 * Destroy the vmem arenas for the various ids
913 *
914 * Arguments are:-
915 * hcap pointer to ibcm_hca_info_t
916 *
917 * Return Values: NONE
918 */
919 void
ibcm_fini_hca_ids(ibcm_hca_info_t * hcap)920 ibcm_fini_hca_ids(ibcm_hca_info_t *hcap)
921 {
922 /* All arenas shall be valid */
923 vmem_destroy(hcap->hca_comid_arena);
924 vmem_destroy(hcap->hca_reqid_arena);
925 }
926
927 /* Communication id management routines ie., allocate, free up comids */
928
929 /*
930 * ibcm_alloc_comid:
931 * Allocate a new communication id
932 *
933 * Arguments are:-
934 * hcap : pointer to ibcm_hca_info_t
935 * comid: pointer to the newly allocated communication id
936 *
937 * Return Values: ibt_status_t
938 */
939 ibcm_status_t
ibcm_alloc_comid(ibcm_hca_info_t * hcap,ib_com_id_t * comidp)940 ibcm_alloc_comid(ibcm_hca_info_t *hcap, ib_com_id_t *comidp)
941 {
942 ib_com_id_t comid;
943
944 /* Use next fit, so least recently used com id is allocated */
945 comid = (ib_com_id_t)(uintptr_t)vmem_alloc(hcap->hca_comid_arena, 1,
946 VM_SLEEP | VM_NEXTFIT);
947
948 IBTF_DPRINTF_L4(cmlog, "ibcm_alloc_comid: hcap 0x%p comid 0x%lX", hcap,
949 comid);
950
951 /*
952 * As comid is 32 bits, and maximum connections possible are 2^24
953 * per hca, comid allocation would never fail
954 */
955 *comidp = comid + ibcm_local_cid_seed;
956 if (comid == 0) {
957 IBTF_DPRINTF_L2(cmlog, "ibcm_alloc_comid: hcap 0x%p"
958 "no more comids available", hcap);
959 return (IBCM_FAILURE);
960 }
961
962 return (IBCM_SUCCESS);
963 }
964
965 /*
966 * ibcm_free_comid:
967 * Releases the given Communication Id
968 *
969 * Arguments are:
970 * hcap : pointer to ibcm_hca_info_t
971 * comid : Communication id to be free'd
972 *
973 * Return Values: NONE
974 */
975 void
ibcm_free_comid(ibcm_hca_info_t * hcap,ib_com_id_t comid)976 ibcm_free_comid(ibcm_hca_info_t *hcap, ib_com_id_t comid)
977 {
978 IBTF_DPRINTF_L4(cmlog, "ibcm_free_comid: hcap 0x%p"
979 "comid %x", hcap, comid);
980 comid -= ibcm_local_cid_seed;
981 vmem_free(hcap->hca_comid_arena, (void *)(uintptr_t)comid, 1);
982 }
983
984 /* Allocate and Free local service ids */
985
986 /*
987 * ibcm_alloc_local_sids:
988 * Create and destroy the vmem arenas for the service ids
989 *
990 * Arguments are:-
991 * Number of contiguous SIDs needed
992 *
993 * Return Values: starting SID
994 */
995 ib_svc_id_t
ibcm_alloc_local_sids(int num_sids)996 ibcm_alloc_local_sids(int num_sids)
997 {
998 ib_svc_id_t sid;
999
1000 sid = (ib_svc_id_t)(uintptr_t)vmem_alloc(ibcm_local_sid_arena,
1001 num_sids, VM_SLEEP | VM_NEXTFIT);
1002
1003 IBTF_DPRINTF_L4(cmlog, "ibcm_alloc_local_sids: ServiceID 0x%llX "
1004 "num_sids %d", sid, num_sids);
1005 if (sid == 0) {
1006 IBTF_DPRINTF_L2(cmlog, "ibcm_alloc_local_sids: "
1007 "no more local sids available");
1008 } else {
1009 ASSERT((ibcm_local_sid_seed & IB_SID_AGN_MASK) ==
1010 IB_SID_AGN_LOCAL);
1011 sid += ibcm_local_sid_seed;
1012 IBTF_DPRINTF_L4(cmlog, "ibcm_alloc_local_sids: Success: "
1013 "allocated 0x%llX:%d", sid, num_sids);
1014 }
1015 return (sid);
1016 }
1017
1018 /*
1019 * ibcm_free_local_sids:
1020 * Releases the given Local service id
1021 *
1022 * Arguments are:
1023 * num_sids: Number of local service id's to be free'd
1024 * service_id: Starting local service id that needs to be free'd
1025 *
1026 * Return Values: NONE
1027 */
1028 void
ibcm_free_local_sids(ib_svc_id_t service_id,int num_sids)1029 ibcm_free_local_sids(ib_svc_id_t service_id, int num_sids)
1030 {
1031 service_id -= ibcm_local_sid_seed;
1032 IBTF_DPRINTF_L4(cmlog, "ibcm_free_local_sids: "
1033 "service_id 0x%llX num_sids %d", service_id, num_sids);
1034 vmem_free(ibcm_local_sid_arena,
1035 (void *)(uintptr_t)service_id, num_sids);
1036 }
1037
1038 /*
1039 * ibcm_alloc_ip_sid:
1040 * Allocate a local IP SID.
1041 */
1042 ib_svc_id_t
ibcm_alloc_ip_sid()1043 ibcm_alloc_ip_sid()
1044 {
1045 ib_svc_id_t sid;
1046
1047 sid = (ib_svc_id_t)(uintptr_t)vmem_alloc(ibcm_ip_sid_arena, 1,
1048 VM_SLEEP | VM_NEXTFIT);
1049 if (sid == 0) {
1050 IBTF_DPRINTF_L2(cmlog, "ibcm_alloc_ip_sid: no more RDMA IP "
1051 "SIDs available");
1052 } else {
1053 sid += IB_SID_IPADDR_PREFIX;
1054 IBTF_DPRINTF_L4(cmlog, "ibcm_alloc_ip_sid: Success: RDMA IP SID"
1055 " allocated : 0x%016llX", sid);
1056 }
1057 return (sid);
1058 }
1059
1060 /*
1061 * ibcm_free_ip_sid:
1062 * Releases the given IP Service ID
1063 */
1064 void
ibcm_free_ip_sid(ib_svc_id_t sid)1065 ibcm_free_ip_sid(ib_svc_id_t sid)
1066 {
1067 sid -= IB_SID_IPADDR_PREFIX;
1068 vmem_free(ibcm_ip_sid_arena, (void *)(uintptr_t)sid, 1);
1069 }
1070
1071
1072 /* Allocate and free request id routines for SIDR */
1073
1074 /*
1075 * ibcm_alloc_reqid:
1076 * Allocate a new SIDR REQ request id
1077 *
1078 * Arguments are:-
1079 * hcap : pointer to ibcm_hca_info_t
1080 * *reqid : pointer to the new request id returned
1081 *
1082 * Return Values: ibcm_status_t
1083 */
1084 ibcm_status_t
ibcm_alloc_reqid(ibcm_hca_info_t * hcap,uint32_t * reqid)1085 ibcm_alloc_reqid(ibcm_hca_info_t *hcap, uint32_t *reqid)
1086 {
1087 /* Use next fit, so least recently used com id is allocated */
1088 *reqid = (uint32_t)(uintptr_t)vmem_alloc(hcap->hca_reqid_arena, 1,
1089 VM_SLEEP | VM_NEXTFIT);
1090
1091 IBTF_DPRINTF_L4(cmlog, "ibcm_alloc_reqid: hcap 0x%p reqid %x", hcap,
1092 *reqid);
1093 if (!(*reqid)) {
1094 IBTF_DPRINTF_L2(cmlog, "ibcm_alloc_reqid: "
1095 "no more req ids available");
1096 return (IBCM_FAILURE);
1097 }
1098 return (IBCM_SUCCESS);
1099 }
1100
1101 /*
1102 * ibcm_free_reqid:
1103 * Releases the given SIDR REQ request id
1104 *
1105 * Arguments are:
1106 * hcap : pointer to ibcm_hca_info_t
1107 * reqid : Request id to be free'd
1108 *
1109 * Return Values: NONE
1110 */
1111 void
ibcm_free_reqid(ibcm_hca_info_t * hcap,uint32_t reqid)1112 ibcm_free_reqid(ibcm_hca_info_t *hcap, uint32_t reqid)
1113 {
1114 IBTF_DPRINTF_L4(cmlog, "ibcm_free_reqid: hcap 0x%p reqid %x", hcap,
1115 reqid);
1116 vmem_free(hcap->hca_reqid_arena, (void *)(uintptr_t)reqid, 1);
1117 }
1118
1119 /*
1120 * ibcm_generate_tranid:
1121 * Generate a new transaction id based on args
1122 *
1123 * Arguments are:-
1124 * event_type CM Message REQ/DREQ/LAP
1125 * id 32 bit identifier
1126 * cm_tran_priv CM private data to be filled in top 28 MSB bits of
1127 * tran id
1128 *
1129 *
1130 * Return Value: uint64_t
1131 */
1132 uint64_t
ibcm_generate_tranid(uint8_t event,uint32_t id,uint32_t cm_tran_priv)1133 ibcm_generate_tranid(uint8_t event, uint32_t id, uint32_t cm_tran_priv)
1134 {
1135 /*
1136 * copy comid to bits 31-0 of tran id,
1137 * attr id to bits 35-32 of tran id,
1138 * cm_priv to bits 63-36 of tran id
1139 */
1140 if (cm_tran_priv == 0)
1141 /*
1142 * The below ensures that no duplicate transaction id is
1143 * generated atleast for next 6 months. Calculations:
1144 * (2^28)/(1000 * 60 * 24 * 30) = 6 approx
1145 */
1146 cm_tran_priv = gethrtime() >> 20; /* ~time in ms */
1147
1148 return ((((uint64_t)cm_tran_priv << 36) | (uint64_t)event << 32) | id);
1149 }
1150
1151 #ifdef DEBUG
1152
1153 /*
1154 * ibcm_decode_tranid:
1155 * Decodes a given transaction id, assuming certain format.
1156 *
1157 * Arguments are:-
1158 * tran_id Transaction id to be decoded
1159 * cm_tran_priv CM private data retrieved from transaction id
1160 *
1161 * Return Value: None
1162 */
1163 void
ibcm_decode_tranid(uint64_t tran_id,uint32_t * cm_tran_priv)1164 ibcm_decode_tranid(uint64_t tran_id, uint32_t *cm_tran_priv)
1165 {
1166 ib_com_id_t id;
1167 ibcm_event_type_t event;
1168
1169 id = tran_id & 0xFFFFFFFF;
1170 event = (tran_id >> 32) & 0xF;
1171
1172 IBTF_DPRINTF_L5(cmlog, "ibcm_decode_tranid: id = 0x%x, event = %x",
1173 id, event);
1174
1175 if (cm_tran_priv) {
1176 *cm_tran_priv = tran_id >> 36;
1177 IBTF_DPRINTF_L5(cmlog, "ibcm_decode_tranid: "
1178 "cm_tran_priv = %x", *cm_tran_priv);
1179 }
1180 }
1181
1182 #endif
1183
1184 /*
1185 * Service ID entry create and lookup functions
1186 */
1187
1188 /*
1189 * ibcm_svc_compare:
1190 * - AVL svc tree node compare
1191 *
1192 * Arguments:
1193 * p1 : pointer to local comid
1194 * p2 : pointer to passed ibcm_state_data_t
1195 *
1196 * Return values:
1197 * 0 : match found
1198 * -1 : no match but insert to left side of the tree
1199 * +1 : no match but insert to right side of the tree
1200 */
1201 int
ibcm_svc_compare(const void * p1,const void * p2)1202 ibcm_svc_compare(const void *p1, const void *p2)
1203 {
1204 ibcm_svc_lookup_t *sidp = (ibcm_svc_lookup_t *)p1;
1205 ibcm_svc_info_t *svcp = (ibcm_svc_info_t *)p2;
1206 ib_svc_id_t start_sid = sidp->sid;
1207 ib_svc_id_t end_sid = start_sid + sidp->num_sids - 1;
1208
1209 IBTF_DPRINTF_L5(cmlog, "ibcm_svc_compare: "
1210 "sid: 0x%llx, numsids: %d, node_sid: 0x%llx node_num_sids: %d",
1211 sidp->sid, sidp->num_sids, svcp->svc_id, svcp->svc_num_sids);
1212
1213 ASSERT(MUTEX_HELD(&ibcm_svc_info_lock));
1214
1215 if (svcp->svc_id > end_sid)
1216 return (-1);
1217 if (svcp->svc_id + svcp->svc_num_sids - 1 < start_sid)
1218 return (+1);
1219 return (0); /* means there is some overlap of SIDs */
1220 }
1221
1222
1223 /*
1224 * ibcm_create_svc_entry:
1225 * Make sure no conflicting entry exists, then allocate it.
1226 * Fill in the critical "look up" details that are provided
1227 * in the arguments before dropping the lock.
1228 *
1229 * Return values:
1230 * Pointer to ibcm_svc_info_t, if created, otherwise NULL.
1231 */
1232 ibcm_svc_info_t *
ibcm_create_svc_entry(ib_svc_id_t sid,int num_sids)1233 ibcm_create_svc_entry(ib_svc_id_t sid, int num_sids)
1234 {
1235 ibcm_svc_info_t *svcp;
1236 ibcm_svc_info_t *svcinfop;
1237 ibcm_svc_lookup_t svc;
1238 avl_index_t where = 0;
1239
1240 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*svcinfop))
1241
1242 /* assume success, and avoid kmem while holding the writer lock */
1243 svcinfop = kmem_zalloc(sizeof (*svcinfop), KM_SLEEP);
1244 svcinfop->svc_id = sid;
1245 svcinfop->svc_num_sids = num_sids;
1246
1247 svc.sid = sid;
1248 svc.num_sids = num_sids;
1249
1250 mutex_enter(&ibcm_svc_info_lock);
1251 #ifdef __lock_lint
1252 ibcm_svc_compare(NULL, NULL);
1253 #endif
1254 svcp = avl_find(&ibcm_svc_avl_tree, &svc, &where);
1255 if (svcp != NULL) { /* overlab exists */
1256 mutex_exit(&ibcm_svc_info_lock);
1257 kmem_free(svcinfop, sizeof (*svcinfop));
1258 return (NULL);
1259 }
1260 avl_insert(&ibcm_svc_avl_tree, (void *)svcinfop, where);
1261 mutex_exit(&ibcm_svc_info_lock);
1262
1263 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*svcinfop))
1264
1265 return (svcinfop);
1266 }
1267
1268 /*
1269 * ibcm_find_svc_entry:
1270 * Finds a ibcm_svc_info_t entry into the CM's global table.
1271 * The search done here assumes the list is sorted by SID.
1272 *
1273 * Arguments are:
1274 * sid - Service ID to look up
1275 *
1276 * Return values:
1277 * Pointer to ibcm_svc_info_t, if found, otherwise NULL.
1278 */
1279 ibcm_svc_info_t *
ibcm_find_svc_entry(ib_svc_id_t sid)1280 ibcm_find_svc_entry(ib_svc_id_t sid)
1281 {
1282 ibcm_svc_info_t *svcp;
1283 ibcm_svc_lookup_t svc;
1284
1285 IBTF_DPRINTF_L3(cmlog, "ibcm_find_svc_entry: finding SID 0x%llX", sid);
1286
1287 ASSERT(MUTEX_HELD(&ibcm_svc_info_lock));
1288
1289 svc.sid = sid;
1290 svc.num_sids = 1;
1291 #ifdef __lock_lint
1292 ibcm_svc_compare(NULL, NULL);
1293 #endif
1294 svcp = avl_find(&ibcm_svc_avl_tree, &svc, NULL);
1295 if (svcp != NULL) {
1296 IBTF_DPRINTF_L3(cmlog, "ibcm_find_svc_entry: "
1297 "found SID = 0x%llX", sid);
1298 return (svcp); /* found it */
1299 }
1300 IBTF_DPRINTF_L3(cmlog, "ibcm_find_svc_entry: SID %llX not found", sid);
1301 return (NULL);
1302 }
1303
1304 /*
1305 * ibcm_alloc_ibmf_msg:
1306 * Allocate an ibmf message structure and the additional memory required for
1307 * sending an outgoing CM mad. The ibmf message structure contains two
1308 * ibmf_msg_bufs_t fields, one for the incoming MAD and one for the outgoing
1309 * MAD. The CM must allocate the memory for the outgoing MAD. The msg_buf
1310 * field has three buffers: the mad header, the class header, and the class
1311 * data. To simplify the code and reduce the number of kmem_zalloc() calls,
1312 * ibcm_alloc_ibmf_msg will allocate one buffer and set the pointers to the
1313 * right offsets. No class header is needed so only the mad header and class
1314 * data fields are used.
1315 */
1316 ibt_status_t
ibcm_alloc_out_msg(ibmf_handle_t ibmf_handle,ibmf_msg_t ** ibmf_msgpp,uint8_t method)1317 ibcm_alloc_out_msg(ibmf_handle_t ibmf_handle, ibmf_msg_t **ibmf_msgpp,
1318 uint8_t method)
1319 {
1320 ib_mad_hdr_t *output_mad_hdr;
1321 int sa_retval;
1322
1323 if ((sa_retval =
1324 ibmf_alloc_msg(ibmf_handle, IBMF_ALLOC_SLEEP, ibmf_msgpp)) !=
1325 IBMF_SUCCESS) {
1326 IBTF_DPRINTF_L1(cmlog, "ibcm_alloc_out_msg: "
1327 "ibmf_alloc_msg failed with IBMF_ALLOC_SLEEP");
1328 return (ibcm_ibmf_analyze_error(sa_retval));
1329 }
1330
1331 (*ibmf_msgpp)->im_msgbufs_send.im_bufs_mad_hdr = kmem_zalloc(
1332 IBCM_MAD_SIZE, KM_SLEEP);
1333
1334 (*ibmf_msgpp)->im_msgbufs_send.im_bufs_cl_data_len = IBCM_MSG_SIZE;
1335 (*ibmf_msgpp)->im_msgbufs_send.im_bufs_cl_data =
1336 (uchar_t *)((*ibmf_msgpp)->im_msgbufs_send.im_bufs_mad_hdr) +
1337 IBCM_MAD_HDR_SIZE;
1338
1339 /* initialize generic CM MAD header fields */
1340 output_mad_hdr = IBCM_OUT_HDRP((*ibmf_msgpp));
1341 output_mad_hdr->BaseVersion = IBCM_MAD_BASE_VERSION;
1342 output_mad_hdr->MgmtClass = MAD_MGMT_CLASS_COMM_MGT;
1343 output_mad_hdr->ClassVersion = IBCM_MAD_CLASS_VERSION;
1344 output_mad_hdr->R_Method = method;
1345
1346 return (IBT_SUCCESS);
1347 }
1348
1349 /*
1350 * ibcm_free_ibmf_msg:
1351 * Frees the buffer and ibmf message associated with an outgoing CM message.
1352 * This function should only be used to free messages created by
1353 * ibcm_alloc_out_msg. Will return IBCM_FAILURE if the ibmf_free_msg() call
1354 * fails and IBCM_SUCCESS otherwise.
1355 */
1356 ibcm_status_t
ibcm_free_out_msg(ibmf_handle_t ibmf_handle,ibmf_msg_t ** ibmf_msgpp)1357 ibcm_free_out_msg(ibmf_handle_t ibmf_handle, ibmf_msg_t **ibmf_msgpp)
1358 {
1359 int ibmf_status;
1360
1361 kmem_free((*ibmf_msgpp)->im_msgbufs_send.im_bufs_mad_hdr,
1362 IBCM_MAD_SIZE);
1363
1364 if ((ibmf_status = ibmf_free_msg(ibmf_handle, ibmf_msgpp)) !=
1365 IBMF_SUCCESS) {
1366 IBTF_DPRINTF_L2(cmlog, "ibcm_free_out_msg: "
1367 "ibmf_free_msg failed %d", ibmf_status);
1368 return (IBCM_FAILURE);
1369 } else
1370 return (IBCM_SUCCESS);
1371 }
1372
1373 ibcm_qp_list_t *
ibcm_find_qp(ibcm_hca_info_t * hcap,int port_no,ib_pkey_t pkey)1374 ibcm_find_qp(ibcm_hca_info_t *hcap, int port_no, ib_pkey_t pkey)
1375 {
1376 ibcm_qp_list_t *entry;
1377 ibmf_qp_handle_t ibmf_qp;
1378 int ibmf_status;
1379
1380 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*entry))
1381
1382 mutex_enter(&ibcm_qp_list_lock);
1383
1384 /*
1385 * CM currently does not track port up and down status. If tracking of
1386 * " port status" is added in the future, then CM could be optimized to
1387 * re-use other ports on hcap, if the port associated with the above
1388 * port_no is down. But, the issue of "reachability" needs to be
1389 * handled, before selecting an alternative port different from above.
1390 */
1391 entry = hcap->hca_port_info[port_no-1].port_qplist;
1392 while (entry != NULL) {
1393 if (entry->qp_pkey == pkey) {
1394 ++entry->qp_ref_cnt;
1395 mutex_exit(&ibcm_qp_list_lock);
1396 return (entry);
1397 }
1398 entry = entry->qp_next;
1399 }
1400
1401 /*
1402 * entry not found, attempt to alloc a qp
1403 * This may be optimized in the future, to allocate ibmf qp's
1404 * once the "CM mgmt pkeys" are precisely known.
1405 */
1406 ibmf_status = ibmf_alloc_qp(
1407 hcap->hca_port_info[port_no-1].port_ibmf_hdl, pkey, IB_GSI_QKEY,
1408 IBMF_ALT_QP_MAD_NO_RMPP, &ibmf_qp);
1409
1410 if (ibmf_status != IBMF_SUCCESS) {
1411 mutex_exit(&ibcm_qp_list_lock);
1412 IBTF_DPRINTF_L2(cmlog, "ibcm_find_qp: failed to alloc IBMF QP"
1413 "for Pkey = %x port_no = %x status = %d hcaguid = %llXp",
1414 pkey, port_no, ibmf_status, hcap->hca_guid);
1415 /*
1416 * This may be optimized in the future, so as CM would attempt
1417 * to re-use other QP's whose ref cnt is 0 in the respective
1418 * port_qplist, by doing an ibmf_modify_qp with pkey above.
1419 */
1420 return (NULL);
1421 }
1422
1423 entry = kmem_alloc(sizeof (ibcm_qp_list_t), KM_SLEEP);
1424 entry->qp_next = hcap->hca_port_info[port_no-1].port_qplist;
1425 hcap->hca_port_info[port_no-1].port_qplist = entry;
1426 entry->qp_cm = ibmf_qp;
1427 entry->qp_ref_cnt = 1;
1428 entry->qp_pkey = pkey;
1429 entry->qp_port = &(hcap->hca_port_info[port_no-1]);
1430
1431 mutex_exit(&ibcm_qp_list_lock);
1432
1433 /* set-up the handler */
1434 ibmf_status = ibmf_setup_async_cb(
1435 hcap->hca_port_info[port_no-1].port_ibmf_hdl, ibmf_qp,
1436 ibcm_recv_cb, entry, 0);
1437
1438 ASSERT(ibmf_status == IBMF_SUCCESS);
1439
1440 #ifdef DEBUG
1441 ibcm_query_qp(hcap->hca_port_info[port_no-1].port_ibmf_hdl, ibmf_qp);
1442 #endif
1443
1444 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*entry))
1445
1446 return (entry);
1447 }
1448
1449 void
ibcm_release_qp(ibcm_qp_list_t * cm_qp_entry)1450 ibcm_release_qp(ibcm_qp_list_t *cm_qp_entry)
1451 {
1452 mutex_enter(&ibcm_qp_list_lock);
1453 --cm_qp_entry->qp_ref_cnt;
1454 ASSERT(cm_qp_entry->qp_ref_cnt >= 0);
1455 mutex_exit(&ibcm_qp_list_lock);
1456 }
1457
1458
1459 /* called holding the ibcm_qp_list_lock mutex */
1460 ibcm_status_t
ibcm_free_qp(ibcm_qp_list_t * cm_qp_entry)1461 ibcm_free_qp(ibcm_qp_list_t *cm_qp_entry)
1462 {
1463 int ibmf_status;
1464
1465 IBTF_DPRINTF_L5(cmlog, "ibcm_free_qp: qp_hdl %p ref_cnt %d pkey %x",
1466 cm_qp_entry->qp_cm, cm_qp_entry->qp_ref_cnt, cm_qp_entry->qp_pkey);
1467
1468 /* check, there are no users of this ibmf qp */
1469 if (cm_qp_entry->qp_ref_cnt != 0)
1470 return (IBCM_FAILURE);
1471
1472 /* Tear down the receive callback */
1473 ibmf_status = ibmf_tear_down_async_cb(
1474 cm_qp_entry->qp_port->port_ibmf_hdl, cm_qp_entry->qp_cm, 0);
1475 if (ibmf_status != IBMF_SUCCESS) {
1476 IBTF_DPRINTF_L2(cmlog, "ibcm_free_qp: "
1477 "ibmf_tear_down_async_cb failed %d port_num %d",
1478 ibmf_status, cm_qp_entry->qp_port->port_num);
1479 return (IBCM_FAILURE);
1480 }
1481
1482 ibmf_status = ibmf_free_qp(cm_qp_entry->qp_port->port_ibmf_hdl,
1483 &cm_qp_entry->qp_cm, 0);
1484 if (ibmf_status != IBMF_SUCCESS) {
1485 IBTF_DPRINTF_L2(cmlog, "ibcm_free_qp: ibmf_free_qp failed for"
1486 " ibmf_status %d qp hdl %p port_no %x", ibmf_status,
1487 cm_qp_entry->qp_cm, cm_qp_entry->qp_port->port_num);
1488 return (IBCM_FAILURE);
1489 }
1490
1491 return (IBCM_SUCCESS);
1492 }
1493
1494 ibcm_status_t
ibcm_free_allqps(ibcm_hca_info_t * hcap,int port_no)1495 ibcm_free_allqps(ibcm_hca_info_t *hcap, int port_no)
1496 {
1497 ibcm_qp_list_t *entry, *freed;
1498 ibcm_status_t ibcm_status = IBCM_SUCCESS;
1499
1500 IBTF_DPRINTF_L5(cmlog, "ibcm_free_allqps: hcap %p port_no %d", hcap,
1501 port_no);
1502
1503 mutex_enter(&ibcm_qp_list_lock);
1504 entry = hcap->hca_port_info[port_no-1].port_qplist;
1505 while ((entry != NULL) &&
1506 ((ibcm_status = ibcm_free_qp(entry)) == IBCM_SUCCESS)) {
1507 freed = entry;
1508 entry = entry->qp_next;
1509 kmem_free(freed, sizeof (ibcm_qp_list_t));
1510 }
1511
1512 if (ibcm_status != IBCM_SUCCESS) /* sanity the linked list */
1513 hcap->hca_port_info[port_no-1].port_qplist = entry;
1514 else /* all ibmf qp's of port must have been free'd successfully */
1515 hcap->hca_port_info[port_no-1].port_qplist = NULL;
1516
1517 mutex_exit(&ibcm_qp_list_lock);
1518 return (ibcm_status);
1519 }
1520
1521 /*
1522 * ibt_bind_service() and ibt_get_paths() needs the following helper function
1523 * to handle endianess in case of Service Data.
1524 */
1525 void
ibcm_swizzle_from_srv(ibt_srv_data_t * sb_data,uint8_t * service_bytes)1526 ibcm_swizzle_from_srv(ibt_srv_data_t *sb_data, uint8_t *service_bytes)
1527 {
1528 uint8_t *p8 = service_bytes;
1529 uint16_t *p16;
1530 uint32_t *p32;
1531 uint64_t *p64;
1532 int i;
1533
1534 for (i = 0; i < 16; i++)
1535 *p8++ = sb_data->s_data8[i];
1536
1537 p16 = (uint16_t *)p8;
1538 for (i = 0; i < 8; i++)
1539 *p16++ = h2b16(sb_data->s_data16[i]);
1540
1541 p32 = (uint32_t *)p16;
1542 for (i = 0; i < 4; i++)
1543 *p32++ = h2b32(sb_data->s_data32[i]);
1544
1545 p64 = (uint64_t *)p32;
1546 for (i = 0; i < 2; i++)
1547 *p64++ = h2b64(sb_data->s_data64[i]);
1548 }
1549
1550 void
ibcm_swizzle_to_srv(uint8_t * service_bytes,ibt_srv_data_t * sb_data)1551 ibcm_swizzle_to_srv(uint8_t *service_bytes, ibt_srv_data_t *sb_data)
1552 {
1553 uint8_t *p8 = service_bytes;
1554 uint16_t *p16;
1555 uint32_t *p32;
1556 uint64_t *p64;
1557 int i;
1558
1559 for (i = 0; i < 16; i++)
1560 sb_data->s_data8[i] = *p8++;
1561
1562 p16 = (uint16_t *)p8;
1563 for (i = 0; i < 8; i++)
1564 sb_data->s_data16[i] = h2b16(*p16++);
1565
1566 p32 = (uint32_t *)p16;
1567 for (i = 0; i < 4; i++)
1568 sb_data->s_data32[i] = h2b32(*p32++);
1569 p64 = (uint64_t *)p32;
1570
1571 for (i = 0; i < 2; i++)
1572 sb_data->s_data64[i] = h2b64(*p64++);
1573 }
1574
1575 /* Trace related functions */
1576
1577 void
ibcm_init_conn_trace(ibcm_state_data_t * sp)1578 ibcm_init_conn_trace(ibcm_state_data_t *sp)
1579 {
1580 IBTF_DPRINTF_L5(cmlog, "ibcm_init_conn_trace: statep %p", sp);
1581
1582 /* Initialize trace related fields */
1583
1584 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sp->conn_trace))
1585 sp->conn_trace = kmem_zalloc(sizeof (ibcm_conn_trace_t), KM_SLEEP);
1586 if ((ibcm_enable_trace & 1) == 0)
1587 sp->conn_trace->conn_base_tm = gethrtime();
1588 sp->conn_trace->conn_allocated_trcnt = ibcm_conn_max_trcnt;
1589 sp->conn_trace->conn_trace_events =
1590 kmem_zalloc(sp->conn_trace->conn_allocated_trcnt, KM_SLEEP);
1591 sp->conn_trace->conn_trace_event_times =
1592 kmem_zalloc(sp->conn_trace->conn_allocated_trcnt *
1593 sizeof (tm_diff_type), KM_SLEEP);
1594 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*sp->conn_trace))
1595 }
1596
1597 void
ibcm_fini_conn_trace(ibcm_state_data_t * statep)1598 ibcm_fini_conn_trace(ibcm_state_data_t *statep)
1599 {
1600 IBTF_DPRINTF_L5(cmlog, "ibcm_fini_conn_trace: statep %p tracep %p",
1601 statep, statep->conn_trace);
1602
1603 /* free the trace data */
1604 if (statep->conn_trace) {
1605 if (statep->conn_trace->conn_trace_events)
1606 kmem_free(statep->conn_trace->conn_trace_events,
1607 statep->conn_trace->conn_allocated_trcnt);
1608 if (statep->conn_trace->conn_trace_event_times)
1609 kmem_free(statep->conn_trace->conn_trace_event_times,
1610 statep->conn_trace->conn_allocated_trcnt *
1611 sizeof (tm_diff_type));
1612
1613 kmem_free(statep->conn_trace, sizeof (ibcm_conn_trace_t));
1614 }
1615 }
1616
1617 /* mostly used to profile connection establishment times with dtrace */
1618 void
ibcm_established(hrtime_t time_diff)1619 ibcm_established(hrtime_t time_diff)
1620 {
1621 if (time_diff > 1000000000LL) /* 1 second */
1622 IBTF_DPRINTF_L2(cmlog, "slow connection time (%d seconds)",
1623 (uint_t)(time_diff >> 30));
1624 }
1625
1626 void
ibcm_insert_trace(void * statep,ibcm_state_rc_trace_qualifier_t event_qualifier)1627 ibcm_insert_trace(void *statep, ibcm_state_rc_trace_qualifier_t event_qualifier)
1628 {
1629 ibcm_conn_trace_t *conn_trace;
1630 uint8_t conn_trace_ind;
1631 hrtime_t time_diff;
1632 hrtime_t hrt;
1633
1634 if (!(((ibcm_state_data_t *)statep)->conn_trace))
1635 return;
1636
1637 conn_trace = ((ibcm_state_data_t *)statep)->conn_trace;
1638
1639 if (!conn_trace->conn_trace_events)
1640 return;
1641
1642 IBTF_DPRINTF_L5(cmlog, "ibcm_insert_trace: statep %p event %d",
1643 statep, event_qualifier);
1644
1645 mutex_enter(&ibcm_trace_mutex);
1646
1647 /* No more trace memory available, hence return */
1648 if (conn_trace->conn_trace_ind == conn_trace->conn_allocated_trcnt) {
1649 mutex_exit(&ibcm_trace_mutex);
1650 return;
1651 } else
1652 ++conn_trace->conn_trace_ind;
1653
1654 conn_trace_ind = conn_trace->conn_trace_ind - 1;
1655
1656 conn_trace->conn_trace_events[conn_trace_ind] = event_qualifier;
1657
1658 if ((ibcm_enable_trace & 1) == 0) {
1659 hrt = gethrtime();
1660 time_diff = hrt - conn_trace->conn_base_tm;
1661 if (event_qualifier == IBCM_TRACE_CALLED_CONN_EST_EVENT)
1662 ibcm_established(time_diff);
1663 time_diff >>= 10;
1664 if (time_diff >= TM_DIFF_MAX) {
1665 /* RESET, future times are relative to new base time. */
1666 conn_trace->conn_base_tm = hrt;
1667 time_diff = 0;
1668 }
1669 conn_trace->conn_trace_event_times[conn_trace_ind] = time_diff;
1670 }
1671
1672 mutex_exit(&ibcm_trace_mutex);
1673
1674 IBTF_DPRINTF_L5(cmlog, "ibcm_insert_trace: statep %p inserted event %d",
1675 statep, event_qualifier);
1676 }
1677
1678 void
ibcm_dump_conn_trace(void * statep)1679 ibcm_dump_conn_trace(void *statep)
1680 {
1681 IBTF_DPRINTF_L5(cmlog, "ibcm_dump_conn_trace: statep %p",
1682 statep);
1683
1684 mutex_enter(&ibcm_trace_print_mutex);
1685 ibcm_debug_buf[0] = '\0';
1686 ibcm_dump_conn_trbuf(statep, "ibcm: ", ibcm_debug_buf,
1687 IBCM_DEBUG_BUF_SIZE);
1688 if (ibcm_debug_buf[0] != '\0')
1689 IBTF_DPRINTF_L2(cmlog, "\n%s", ibcm_debug_buf);
1690
1691 #ifdef DEBUG
1692
1693 if (ibcm_test_mode > 1)
1694 cmn_err(CE_CONT, "IBCM DEBUG TRACE:\n%s", ibcm_debug_buf);
1695 #endif
1696
1697 mutex_exit(&ibcm_trace_print_mutex);
1698 }
1699
1700 void
ibcm_dump_conn_trbuf(void * statep,char * line_prefix,char * buf,int buf_size)1701 ibcm_dump_conn_trbuf(void *statep, char *line_prefix, char *buf, int buf_size)
1702 {
1703 ibcm_conn_trace_t *conn_trace;
1704 int tr_ind;
1705 ibcm_state_data_t *sp;
1706 int cur_size = 0; /* size of item copied */
1707 int rem_size; /* remaining size in trace buffer */
1708 int next_data = 0; /* location where next item copied */
1709
1710 if ((buf == NULL) || (buf_size <= 0))
1711 return;
1712
1713 sp = (ibcm_state_data_t *)statep;
1714
1715 if (!sp->conn_trace)
1716 return;
1717
1718 conn_trace = sp->conn_trace;
1719
1720 if (!conn_trace->conn_trace_events)
1721 return;
1722
1723 rem_size = buf_size;
1724
1725 /* Print connection level global data */
1726
1727 /* Print statep, local comid, local qpn */
1728 cur_size = snprintf(&buf[next_data], rem_size, "%s%s0x%p\n%s%s0x%p\n"
1729 "%s%s0x%x/%llx/%d\n%s%s0x%x\n%s%s0x%x/%llx\n%s%s0x%x\n%s%s%llu\n",
1730 line_prefix, event_str[IBCM_DISPLAY_SID], (void *)sp,
1731 line_prefix, event_str[IBCM_DISPLAY_CHAN], (void *)sp->channel,
1732 line_prefix, event_str[IBCM_DISPLAY_LCID], sp->local_comid,
1733 (longlong_t)sp->local_hca_guid, sp->prim_port,
1734 line_prefix, event_str[IBCM_DISPLAY_LQPN], sp->local_qpn,
1735 line_prefix, event_str[IBCM_DISPLAY_RCID], sp->remote_comid,
1736 (longlong_t)sp->remote_hca_guid,
1737 line_prefix, event_str[IBCM_DISPLAY_RQPN], sp->remote_qpn,
1738 line_prefix, event_str[IBCM_DISPLAY_TM], conn_trace->conn_base_tm);
1739
1740 rem_size = rem_size - cur_size;
1741 if (rem_size <= 0) {
1742 buf[buf_size-1] = '\n';
1743 return;
1744 }
1745
1746 next_data = next_data + cur_size;
1747
1748 for (tr_ind = 0; tr_ind < conn_trace->conn_trace_ind; tr_ind++) {
1749 cur_size = snprintf(&buf[next_data], rem_size,
1750 "%s%sTM_DIFF %u\n", line_prefix,
1751 event_str[conn_trace->conn_trace_events[tr_ind]],
1752 conn_trace->conn_trace_event_times[tr_ind]);
1753 rem_size = rem_size - cur_size;
1754 if (rem_size <= 0) {
1755 buf[buf_size-1] = '\n';
1756 return;
1757 }
1758 next_data = next_data + cur_size;
1759 }
1760
1761 buf[next_data] = '\0';
1762 IBTF_DPRINTF_L5(cmlog, "ibcm_dump_conn_trbuf: statep %p "
1763 "debug buf size %d bytes", statep, next_data);
1764 }
1765
1766
1767 #ifdef DEBUG
1768
1769 void
ibcm_query_qp(ibmf_handle_t ibmf_hdl,ibmf_qp_handle_t ibmf_qp)1770 ibcm_query_qp(ibmf_handle_t ibmf_hdl, ibmf_qp_handle_t ibmf_qp)
1771 {
1772 uint8_t qp_port_num;
1773 ib_qpn_t qp_num;
1774 ib_pkey_t qp_pkey;
1775 ib_qkey_t qp_qkey;
1776 int ibmf_status;
1777
1778 if (ibmf_qp == IBMF_QP_HANDLE_DEFAULT) {
1779 IBTF_DPRINTF_L4(cmlog, "ibcm_query_qp: QP1");
1780 return;
1781 }
1782
1783 ibmf_status =
1784 ibmf_query_qp(ibmf_hdl, ibmf_qp, &qp_num, &qp_pkey, &qp_qkey,
1785 &qp_port_num, 0);
1786
1787 ASSERT(ibmf_status == IBMF_SUCCESS);
1788
1789 IBTF_DPRINTF_L5(cmlog, "ibcm_query_qp: qpn %x qkey %x pkey %x port %d",
1790 qp_num, qp_qkey, qp_pkey, qp_port_num);
1791 }
1792
1793 /*
1794 * ibcm_dump_raw_message:
1795 * dumps 256 bytes of data of a raw message (REP/REQ/DREQ ...)
1796 * (can be called from the kernel debugger w/ the message pointer)
1797 *
1798 * Arguments:
1799 * msgp - the messages that needs to be dumped
1800 *
1801 * Return values: NONE
1802 */
1803 void
ibcm_dump_raw_message(uchar_t * c)1804 ibcm_dump_raw_message(uchar_t *c)
1805 {
1806 int i;
1807
1808 for (i = 0; i < IBCM_MAD_SIZE; i += 16) {
1809 /* print in batches of 16 chars at a time */
1810 IBTF_DPRINTF_L4(cmlog,
1811 "%x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
1812 c[i], c[i + 1], c[i + 2], c[i + 3], c[i + 4], c[i + 5],
1813 c[i + 6], c[i + 7], c[i + 8], c[i + 9], c[i + 10],
1814 c[i + 11], c[i + 12], c[i + 13], c[i + 14], c[i + 15]);
1815 }
1816 }
1817
1818
1819 /*
1820 * ibcm_dump_srv_rec:
1821 * Dumps Service Records.
1822 *
1823 * Arguments:
1824 * srv_rec - the pointer to sa_service_record_t struct.
1825 *
1826 * Return values: NONE
1827 */
1828 void
ibcm_dump_srvrec(sa_service_record_t * srv_rec)1829 ibcm_dump_srvrec(sa_service_record_t *srv_rec)
1830 {
1831 uint8_t i;
1832
1833 IBTF_DPRINTF_L4(cmlog, "ibcm_dump_srvrec: Service Records");
1834 IBTF_DPRINTF_L4(cmlog, "SID : 0x%016llX", srv_rec->ServiceID);
1835 IBTF_DPRINTF_L4(cmlog, "Svc GID : 0x%016llX:0x%016llX",
1836 srv_rec->ServiceGID.gid_prefix, srv_rec->ServiceGID.gid_guid);
1837 IBTF_DPRINTF_L4(cmlog, "Svc PKey : 0x%X", srv_rec->ServiceP_Key);
1838
1839 IBTF_DPRINTF_L4(cmlog, "Svc Lease : 0x%lX", srv_rec->ServiceLease);
1840 IBTF_DPRINTF_L4(cmlog, "Svc Key-hi: 0x%016llX", srv_rec->ServiceKey_hi);
1841 IBTF_DPRINTF_L4(cmlog, "Svc Key-lo: 0x%016llX", srv_rec->ServiceKey_lo);
1842 IBTF_DPRINTF_L4(cmlog, "Svc Name : %s", srv_rec->ServiceName);
1843 IBTF_DPRINTF_L4(cmlog, "Svc Data : ");
1844 for (i = 0; i < IB_SVC_DATA_LEN; i += 8) {
1845 IBTF_DPRINTF_L4(cmlog,
1846 "\t 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X, 0x%X",
1847 srv_rec->ServiceData[i], srv_rec->ServiceData[i+1],
1848 srv_rec->ServiceData[i+2], srv_rec->ServiceData[i+3],
1849 srv_rec->ServiceData[i+4], srv_rec->ServiceData[i+5],
1850 srv_rec->ServiceData[i+6], srv_rec->ServiceData[i+7]);
1851 }
1852 }
1853
1854
1855 /*
1856 * ibcm_dump_pathrec:
1857 * Dumps Path Records.
1858 *
1859 * Arguments:
1860 * path_rec - the pointer to sa_path_record_t struct.
1861 *
1862 * Return values: NONE
1863 */
1864 void
ibcm_dump_pathrec(sa_path_record_t * path_rec)1865 ibcm_dump_pathrec(sa_path_record_t *path_rec)
1866 {
1867 IBTF_DPRINTF_L5(cmlog, "Path Record:");
1868 IBTF_DPRINTF_L5(cmlog, "SGID: (sn_prefix) %016llX",
1869 path_rec->SGID.gid_prefix);
1870 IBTF_DPRINTF_L5(cmlog, "SGID: (GUID) %016llX",
1871 path_rec->SGID.gid_guid);
1872 IBTF_DPRINTF_L5(cmlog, "DGID: (sn_prefix) %016llX",
1873 path_rec->DGID.gid_prefix);
1874 IBTF_DPRINTF_L5(cmlog, "DGID: (GUID) %016llX",
1875 path_rec->DGID.gid_guid);
1876 IBTF_DPRINTF_L5(cmlog, "SLID: %04X", path_rec->SLID);
1877 IBTF_DPRINTF_L5(cmlog, "DLID: %04X", path_rec->DLID);
1878 IBTF_DPRINTF_L5(cmlog, "Raw Traffic: %01X", path_rec->RawTraffic);
1879 IBTF_DPRINTF_L5(cmlog, "Flow Label: %05X", path_rec->FlowLabel);
1880 IBTF_DPRINTF_L5(cmlog, "Hop Limit: %02X", path_rec->HopLimit);
1881 IBTF_DPRINTF_L5(cmlog, "TClass: %02X", path_rec->TClass);
1882 IBTF_DPRINTF_L5(cmlog, "Reversible: %01X", path_rec->Reversible);
1883 IBTF_DPRINTF_L5(cmlog, "Numb Paths: %02d", path_rec->NumbPath);
1884 IBTF_DPRINTF_L5(cmlog, "P_Key: %04X", path_rec->P_Key);
1885 IBTF_DPRINTF_L5(cmlog, "SL: %02X", path_rec->SL);
1886 IBTF_DPRINTF_L5(cmlog, "Path MTU Selector: %01X",
1887 path_rec->MtuSelector);
1888 IBTF_DPRINTF_L5(cmlog, "Path MTU: %02X", path_rec->Mtu);
1889 IBTF_DPRINTF_L5(cmlog, "Path Rate Selector:%01X",
1890 path_rec->RateSelector);
1891 IBTF_DPRINTF_L5(cmlog, "Path Rate: %02X", path_rec->Rate);
1892 IBTF_DPRINTF_L5(cmlog, "Packet LT Selector:%01X",
1893 path_rec->PacketLifeTimeSelector);
1894 IBTF_DPRINTF_L5(cmlog, "Packet Life Time: %d (dec)",
1895 path_rec->PacketLifeTime);
1896 IBTF_DPRINTF_L5(cmlog, "Preference Bit: %02X", path_rec->Preference);
1897 }
1898
1899 /*
1900 * ibcm_dump_node_rec:
1901 * Dumps Node Records.
1902 *
1903 * Arguments:
1904 * nrec - the pointer to sa_node_record_t struct.
1905 *
1906 * Return values: NONE
1907 */
1908 void
ibcm_dump_noderec(sa_node_record_t * nrec)1909 ibcm_dump_noderec(sa_node_record_t *nrec)
1910 {
1911 IBTF_DPRINTF_L5(cmlog, "ibcm_dump_noderec: Node Info Record");
1912 IBTF_DPRINTF_L5(cmlog, "LID : %04X", nrec->LID);
1913 IBTF_DPRINTF_L5(cmlog, "Base Ver : %02X", nrec->NodeInfo.BaseVersion);
1914 IBTF_DPRINTF_L5(cmlog, "Class Ver : %02X", nrec->NodeInfo.ClassVersion);
1915 IBTF_DPRINTF_L5(cmlog, "Node Type : %02d", nrec->NodeInfo.NodeType);
1916 IBTF_DPRINTF_L5(cmlog, "Num Ports : %02X", nrec->NodeInfo.NumPorts);
1917 IBTF_DPRINTF_L5(cmlog, "SysImgGUID: %016llX",
1918 nrec->NodeInfo.SystemImageGUID);
1919 IBTF_DPRINTF_L5(cmlog, "NODE GUID : %016llX", nrec->NodeInfo.NodeGUID);
1920 IBTF_DPRINTF_L5(cmlog, "Port GUID : %016llX", nrec->NodeInfo.PortGUID);
1921 IBTF_DPRINTF_L5(cmlog, "PartionCap: %04X", nrec->NodeInfo.PartitionCap);
1922 IBTF_DPRINTF_L5(cmlog, "Device ID : %04X", nrec->NodeInfo.DeviceID);
1923 IBTF_DPRINTF_L5(cmlog, "Revision : %06X", nrec->NodeInfo.Revision);
1924 IBTF_DPRINTF_L5(cmlog, "LocalPort#: %02X", nrec->NodeInfo.LocalPortNum);
1925 IBTF_DPRINTF_L5(cmlog, "Vendor ID : %06X", nrec->NodeInfo.VendorID);
1926 IBTF_DPRINTF_L5(cmlog, "Description: %s",
1927 (char *)&nrec->NodeDescription);
1928 }
1929 #endif
1930
1931 /*
1932 * ibcm_ibtl_node_info:
1933 * Get the node record of the destination specified by lid via the HCA
1934 * and port specified.
1935 *
1936 * Arguments:
1937 * hca_guid - GUID of the local HCA.
1938 * port - port in the HCA to be used.
1939 * lid - destination LID
1940 * node_info_p - pointer to the Node Info to be returned.
1941 *
1942 * Return values:
1943 * IBT_SUCCESS : Got the node record sucessfully
1944 * IBT_FILURE : Failed to get the node record.
1945 */
1946 ibt_status_t
ibcm_ibtl_node_info(ib_guid_t hca_guid,uint8_t port,ib_lid_t lid,ibt_node_info_t * node_info_p)1947 ibcm_ibtl_node_info(ib_guid_t hca_guid, uint8_t port, ib_lid_t lid,
1948 ibt_node_info_t *node_info_p)
1949 {
1950 sa_node_record_t nr_req, *nr_resp;
1951 void *res_p;
1952 ibmf_saa_handle_t saa_handle;
1953 ibt_status_t ibt_status;
1954 ibcm_hca_info_t *hcap;
1955 uint_t num_rec;
1956 size_t len;
1957
1958 IBTF_DPRINTF_L3(cmlog, "ibcm_ibtl_node_info: ENTER: port %x "
1959 "guid %llx\n", port, hca_guid);
1960
1961 hcap = ibcm_find_hca_entry(hca_guid);
1962 if (hcap == NULL) {
1963 IBTF_DPRINTF_L2(cmlog, "ibcm_ibtl_node_info: "
1964 "HCA(%llX) info not found", hca_guid);
1965 return (IBT_FAILURE);
1966 }
1967
1968 /* Get SA Access Handle. */
1969 saa_handle = ibcm_get_saa_handle(hcap, port);
1970 if (saa_handle == NULL) {
1971 IBTF_DPRINTF_L2(cmlog, "ibcm_ibtl_node_info: "
1972 "Port %d of HCA (%llX) is NOT ACTIVE", port, hca_guid);
1973 ibcm_dec_hca_acc_cnt(hcap);
1974 return (IBT_FAILURE);
1975 }
1976
1977 /* Retrieve Node Records from SA Access. */
1978 bzero(&nr_req, sizeof (sa_node_record_t));
1979 nr_req.LID = lid;
1980
1981 ibt_status = ibcm_get_node_rec(saa_handle, &nr_req,
1982 SA_NODEINFO_COMPMASK_NODELID, &res_p, &len);
1983 if (ibt_status != IBT_SUCCESS) {
1984 IBTF_DPRINTF_L2(cmlog, "ibcm_ibtl_node_info: "
1985 "failed (%d) to get Node records", ibt_status);
1986 ibcm_dec_hca_acc_cnt(hcap);
1987 return (IBT_FAILURE);
1988 }
1989
1990 num_rec = len/sizeof (sa_node_record_t);
1991 nr_resp = (sa_node_record_t *)(uchar_t *)res_p;
1992
1993 if ((nr_resp != NULL) && (num_rec > 0)) {
1994 IBCM_DUMP_NODE_REC(nr_resp);
1995
1996 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(
1997 *node_info_p))
1998
1999 node_info_p->n_sys_img_guid =
2000 nr_resp->NodeInfo.SystemImageGUID;
2001 node_info_p->n_node_guid =
2002 nr_resp->NodeInfo.NodeGUID;
2003 node_info_p->n_port_guid =
2004 nr_resp->NodeInfo.PortGUID;
2005 node_info_p->n_dev_id =
2006 nr_resp->NodeInfo.DeviceID;
2007 node_info_p->n_revision =
2008 nr_resp->NodeInfo.Revision;
2009 node_info_p->n_vendor_id =
2010 nr_resp->NodeInfo.VendorID;
2011 node_info_p->n_num_ports =
2012 nr_resp->NodeInfo.NumPorts;
2013 node_info_p->n_port_num =
2014 nr_resp->NodeInfo.LocalPortNum;
2015 node_info_p->n_node_type =
2016 nr_resp->NodeInfo.NodeType;
2017 (void) strncpy(node_info_p->n_description,
2018 (char *)&nr_resp->NodeDescription, 64);
2019 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(
2020 *node_info_p))
2021
2022
2023 kmem_free(nr_resp, len);
2024 }
2025 ibcm_dec_hca_acc_cnt(hcap);
2026 return (IBT_SUCCESS);
2027 }
2028
2029 /*
2030 * ibcm_ibmf_analyze_error:
2031 * Checks IBMF status and determines appropriate ibt status.
2032 *
2033 * Arguments:
2034 * ibmf_status - IBMF Status
2035 *
2036 * Return values:
2037 * ibt_status_t
2038 */
2039 ibt_status_t
ibcm_ibmf_analyze_error(int ibmf_status)2040 ibcm_ibmf_analyze_error(int ibmf_status)
2041 {
2042 if (ibt_check_failure(ibmf_status, NULL) != IBT_FAILURE_STANDARD) {
2043 /*
2044 * IBMF specific failure, return special error code
2045 * to the client so that it can retrieve any associated ENA.
2046 */
2047 return (ibmf_status);
2048 } else if (ibmf_status == IBMF_TRANS_TIMEOUT) {
2049 return (IBT_IBMF_TIMEOUT);
2050 } else {
2051 /*
2052 * IBMF failed for some other reason, invalid arguments etc.
2053 * Analyze, log ENA with IBTF and obtain a special ibt_status_t
2054 * that indicates IBMF failure.
2055 */
2056 if ((ibmf_status == IBMF_BAD_CLASS) ||
2057 (ibmf_status == IBMF_BAD_HANDLE) ||
2058 (ibmf_status == IBMF_BAD_QP_HANDLE) ||
2059 (ibmf_status == IBMF_BAD_NODE) ||
2060 (ibmf_status == IBMF_BAD_PORT) ||
2061 (ibmf_status == IBMF_BAD_VERSION) ||
2062 (ibmf_status == IBMF_BAD_FLAGS) ||
2063 (ibmf_status == IBMF_BAD_SIZE) ||
2064 (ibmf_status == IBMF_INVALID_GID) ||
2065 (ibmf_status == IBMF_INVALID_ARG) ||
2066 (ibmf_status == IBMF_INVALID_FIELD) ||
2067 (ibmf_status == IBMF_UNSUPP_METHOD) ||
2068 (ibmf_status == IBMF_UNSUPP_METHOD_ATTR)) {
2069
2070 /*
2071 * These errors, we should not see...
2072 * something really bad happened!.
2073 */
2074 IBTF_DPRINTF_L2(cmlog, "ibcm_ibmf_analyze_error: "
2075 "Unexpected ERROR from IBMF - %d", ibmf_status);
2076 }
2077 return (ibt_get_module_failure(IBT_FAILURE_IBMF, 0));
2078 }
2079 }
2080