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 (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25 #include <sys/ib/mgt/ibcm/ibcm_impl.h>
26 #include <sys/callb.h>
27
28 /*
29 * ibcm_sm.c
30 * These routines implement the CM state machine (both ACTIVE and PASSIVE)
31 *
32 * Points to Note :
33 *
34 * o CM uses one ibcm_hca_info_t entry per HCA to store all the
35 * connection state data belonging to that HCA in the AVL trees, etc.,
36 *
37 * o There is one state structure per RC, referenced from three AVL trees
38 * ie. the HCA active AVL tree, and the HCA passive AVL tree and HCA
39 * passive comid tree
40 *
41 * o SIDR state structures are stored in a linked list
42 *
43 * o The term statep generally refers to RC, until explicitly mentioned
44 * in the notes below
45 *
46 * o Any thread that may access statep increments the ref_cnt. This ensures
47 * that statep is not deleted when it is still being accessed and modified
48 * by other threads
49 *
50 * o Any thread that may want to search the AVL tree(s) holds the hca state
51 * table reader lock. If it shall insert/delete a new state structure, then
52 * the lock held is writer lock.
53 *
54 * o Incrementing and Decrementing the ref_cnt can happen only after acquiring
55 * statep mutex
56 *
57 * o Deleting a statep can happen only by acquiring the hca state writer lock
58 * and statep mutex and if ref_cnt is zero.
59 *
60 * o Statep mutexes are used to decrease the hca state table lock holding
61 * times. thus increasing more number of threads that can access hca
62 * global data structures
63 *
64 * o Statep mutexes cannot be hold for long time. They are primarily used to
65 * check the state of statep, change it and exit the lock. Other threads
66 * checking this statep find statep's new state, and may exit without
67 * further processing (as the statep->state has changed).
68 *
69 * o Statep mutex must be held while setting and unsetting the timer id
70 * values and during untimeout
71 *
72 * Re-stating, the overall purpose of these various locks are:
73 * - Minimize the time state table locks are held
74 * - Writer locks are held only while inserting/deleting into trees,
75 * so multiple readers can traverse data structures in parallel
76 * - Minimize the time statep mutex held, so other threads entering the same
77 * statep mutex are not held for long
78 *
79 * The CM state machine logic ensures that the statep is valid and exists
80 * when timeout callback (ibcm_timeout_cb) is called. This is ensured by
81 * cancelling timeouts on state changes, where appropriate
82 *
83 *
84 * The timeout processing is handled in the context in which the
85 * timeout callback is invoked.
86 *
87 * The CM STATE MACHINE logic flow:
88 *
89 * On an incoming MAD:-
90 *
91 * IBMF -> ibcm_process_incoming_mad
92 * Verify and branch to one of the below connection state routines.
93 * The callback arg from ibmf has the pointer to ibcm_hca_info_t
94 *
95 * 1. INCOMING REQ MAD
96 *
97 * Acquire hca state table WRITER lock
98 * Do lookup in passive AVL tree by remote qpn and remote hca guid
99 *
100 * If (new lookup)
101 *
102 * create new statep, initialize key fields
103 * obtain new local com id, insert into hca state AVL tree
104 * release hca state table WRITER lock
105 *
106 * Initialize remaining fields
107 * If invalid service id,
108 * send a REJ reply,
109 * decr ref_cnt holding state mutex
110 * If existing peer conn, check guids, and break the tie
111 * Call the cep state transition function
112 * Send an RTU/REJ reply
113 * Check and handle for any incoming REJ's during REQ RCVD state
114 *
115 * else if (existing lookup)
116 *
117 * increment refcnt holding state mutex
118 * release hca state table WRITER lock
119 *
120 * re-acquire the statep mutex
121 * if (statep->state is REP SENT/REJ SENT/ MRA SENT)
122 * resend the mad
123 * else if established
124 * handle the stale detection
125 * else
126 * drop the mad (no processing required)
127 * decr statep->ref_cnt, release state mutex
128 *
129 *
130 * 2. INCOMING REP MAD
131 *
132 * Acquire hca state READER lock
133 * Do lookup in hca state tree by local com id
134 * Release hca state table READER lock
135 *
136 * if lookup does not exist
137 * return
138 *
139 * if look up exists
140 * incr statep->ref_cnt holding state mutex
141 *
142 * acquire the statep lock
143 * if (state == ESTABLISHED or REJ SENt or MRA REP SENT)
144 * resend the MAD
145 * release state mutex, cancel req sent timer
146 * decrement ref_cnt holding the statep lock
147 * return
148 *
149 * if (state == REQ_SENT or REP_WAIT)
150 * first, change state to REP_RCVD
151 * release statep lock
152 * cancel timers
153 * lookup in the passive tree by remote qpn and remote hca guid
154 * if entry already exists
155 * handle the stale detection
156 * else
157 * add to the passive tree
158 *
159 * Initialize fields of statep
160 * Call the qp state transition function
161 * Post RTU/REJ reply
162 * Acquire the state mutex
163 * decrement the ref cnt
164 * release the statep lock
165 *
166 * 3. INCOMING MRA
167 *
168 * Acquire hca state table READER lock
169 * Do lookup in active hca state tree by local com id
170 * Release hca state table READER lock
171 *
172 * If lookup does not exist
173 * return
174 *
175 * if look up exists
176 * incr statep->ref_cnt holding state mutex
177 *
178 * acquire state mutex
179 * if (state is REQ_SENT or REP_SENT)
180 * change state to REP WAIT or MRA REP RCVD
181 * release state mutex
182 * cancel the current timer
183 *
184 * reacquire state mutex
185 * if (state is REP_WAIT or MRA_REP_RCVD)
186 * set new timer, using service timeout for the first timeout
187 * decr ref cnt, release state mutex
188 *
189 * 4. INCOMING RTU
190 *
191 * Acquire hca state table READER lock
192 * Do lookup in active hca state tree by local com id
193 * Release hca state table READER lock
194 *
195 * If lookup does not exist
196 * return
197 *
198 * if look up exists
199 * incr statep->ref_cnt holding state mutex
200 *
201 * acquire statep mutex
202 * if (state == REP_SENT or MRA REP RCVD))
203 * change state to ESTABLISHED
204 * release statep mutex
205 * cancel timer
206 *
207 * Change QP state
208 *
209 * acquire the statep mutex
210 * decrement the ref count
211 * release statep mutex
212 *
213 * 5. INCOMING REJ
214 *
215 * Acquire hca state table READER lock
216 * Do lookup in active hca state tree by local com id
217 * Release hca state table READER lock
218 *
219 * If lookup does not exist
220 * return
221 *
222 * if look up exists
223 * incr statep->ref_cnt holding state mutex
224 *
225 * if (state == REQ RCVD or REP RCVD MRA_SENT or MRA_REP_SNET)
226 * set statep->delete = true
227 * decrement the ref_cnt
228 * release statep mutex;
229 *
230 * else if (state == REQ_SENT or REP SENT or MRA REP Rcvd)
231 * state = IBCM_STATE_DELETE
232 * Cancel running timers
233 * decrement the ref_cnt
234 * release state mutex
235 * Call the client QP handler
236 * delete the state data
237 *
238 * 6. INCOMING DREQ
239 *
240 * Acquire hca state table READER lock
241 * Do lookup in active hca state tree by local com id
242 * Release hca state table READER lock
243 *
244 * If lookup does not exist
245 * return
246 *
247 * if look up exists
248 * incr statep->ref_cnt holding state mutex
249 *
250 * acquire state mutex
251 * if (state is ESTABLISHED/DREQ SENT/TIMEWAIT)
252 * if state is ESTABLISHED/DREQ SENT,
253 * change state to DREQ RECVD
254 * start timers
255 *
256 * send DREP reply
257 * decr ref_cnt
258 * release state mutex
259 *
260 * 7. Incoming DREP
261 *
262 * Acquire hca state table READER lock
263 * Do lookup in active hca state tree by local com id
264 * Release hca state table READER lock
265 *
266 * If lookup does not exist
267 * return
268 *
269 * if look up exists
270 * incr statep->ref_cnt holding state mutex
271 *
272 * acquire state mutex
273 * if state is DREQ_SENT
274 * change state to DREP_RCVD
275 * cancel timer
276 * change state to TIMEWAIT
277 * set timewait timer
278 * decr ref_cnt
279 * release state mutex
280 *
281 * 8. Timeout handler
282 *
283 * (for states REQ SENT/REP SENT/REJ SENT/DREQ SENT/DREP SENT/TIMEWAIT)
284 *
285 * acquire the statep mutex
286 *
287 * if (set state != stored_state)
288 * The thread that changed the state is responsible for any cleanup
289 * decrement ref cnt
290 * release statep mutex
291 * return
292 * else if (statep's state == REJ SENT)
293 * change state to DELETE
294 * decrement ref cnt
295 * release statep mutex
296 * delete statep
297 * return
298 * else if (state == TIME WAIT)
299 * do the time wait state processing
300 * decrement ref cnt
301 * change state to DELETE
302 * release statep mutex
303 * delete statep, and also QP
304 * else if (remaining retry cnt > 0)
305 * resend the mad
306 * decrement ref cnt
307 * release statep mutex
308 * else if (state == rep sent or req sent or mra rep rcvd or rep wait)
309 * (retry counter expired)
310 * change state to REJ SENT (No one shall delete in REJ SENT)
311 * decrement the ref_cnt
312 * release the statep mutex
313 * Post REJ MAD
314 * cv_signal anyone blocking
315 * Invoke client handler
316 * else if state == DREQ_SENT
317 * change state to TIME WAIT
318 * decrement the ref cnt
319 * set a timer for time wait time
320 * release the statep mutex
321 *
322 *
323 * SIDR processing
324 *
325 * 9. INCOMING SIDR_REQ MAD
326 *
327 * Figure out LID/GID
328 * Do lookup in SIDR LIST based on LID, GID, grh_exists and req_id
329 * increment ud_statep->ud_ref_cnt
330 *
331 * If (new lookup)
332 *
333 * validate service id, and the create new statep,
334 * initialize key fields
335 * do a lookup based on service id
336 * if service_id_lookup returns exists
337 * set sidr_status to QPN_VALID
338 * else
339 * set sidr_status to SID_INVALID
340 * post SIDR_REP mad
341 * decr ud_statep->ud_ref_cnt, release ud_state_mutex
342 *
343 * else if (existing lookup)
344 *
345 * if (ud_statep->ud_state is SIDR_REP_SENT)
346 * resend the mad
347 *
348 * decr ud_statep->ud_ref_cnt, release ud_state_mutex
349 *
350 *
351 * 10. INCOMING SIDR_REP MAD
352 *
353 * Figure out LID/GID
354 * Do lookup in SIDR LIST based on LID, GID, grh_exists and req_id
355 * increment ud_statep->ud_ref_cnt
356 *
357 * if look up doesn't exists
358 * return
359 *
360 * if (state == SIDR_REQ_SENT)
361 * first, change state to SIDR_REP_RCVD
362 * release statep lock
363 * cancel timers
364 * cv_signal anyone blocking
365 * release the statep lock
366 * extract return args
367 * destroy the statep
368 *
369 * 11. Timeout handler
370 *
371 * (for states SIDR_REQ_SENT/SIDR_REP_SENT)
372 *
373 * acquire the statep mutex
374 *
375 * if (statep's state == SIDR_REP_SENT SENT)
376 * change state to DELETE
377 * decrement ref cnt
378 * release statep mutex
379 * delete statep
380 * return
381 * else if (remaining retry cnt > 0 and state is SIDR_REQ_SENT)
382 * resend the mad
383 * decrement ref cnt
384 * release statep mutex
385 * else if (state == SIDR_REQ_SENT)
386 * (retry counter expired)
387 * change state to DELETE
388 * decrement the ref_cnt
389 * the statep mutex
390 * cv_signal anyone blocking
391 * Invoke client handler
392 * delete statep
393 */
394
395 /* Function prototypes */
396 static void ibcm_set_primary_adds_vect(ibcm_state_data_t *,
397 ibt_adds_vect_t *, ibcm_req_msg_t *);
398 static void ibcm_set_alt_adds_vect(ibcm_state_data_t *,
399 ibt_adds_vect_t *, ibcm_req_msg_t *);
400 static ibt_status_t ibcm_set_primary_cep_path(ibcm_state_data_t *,
401 ibt_cep_path_t *, ibcm_req_msg_t *);
402 static ibt_status_t ibcm_set_alt_cep_path(ibcm_state_data_t *,
403 ibt_cep_path_t *, ibcm_req_msg_t *);
404 static ibt_status_t ibcm_invoke_qp_modify(ibcm_state_data_t *,
405 ibcm_req_msg_t *, ibcm_rep_msg_t *);
406 static ibt_status_t ibcm_invoke_rtu_qp_modify(ibcm_state_data_t *,
407 ib_time_t, ibcm_rep_msg_t *);
408 static ibcm_status_t ibcm_sidr_req_ud_handler(ibcm_ud_state_data_t *,
409 ibcm_sidr_req_msg_t *, ibcm_mad_addr_t *,
410 ibt_sidr_status_t *);
411 static void ibcm_sidr_rep_ud_handler(ibcm_ud_state_data_t *,
412 ibcm_sidr_rep_msg_t *);
413 static void ibcm_handler_conn_fail(ibcm_state_data_t *,
414 uint8_t cf_code, uint8_t cf_msg,
415 ibt_cm_reason_t rej_reason, uint8_t *,
416 ibt_priv_data_len_t);
417 static void ibcm_build_n_post_rej_mad(uint8_t *input_madp,
418 ib_com_id_t, ibcm_mad_addr_t *, int, uint16_t);
419 static void ibcm_post_drep_mad(ibcm_state_data_t *);
420
421 static ibcm_status_t ibcm_verify_req_gids_and_svcid(
422 ibcm_state_data_t *statep,
423 ibcm_req_msg_t *cm_req_msgp);
424
425 static void ibcm_timeout_client_cb(ibcm_state_data_t *statep);
426 static void ibcm_ud_timeout_client_cb(
427 ibcm_ud_state_data_t *ud_statep);
428
429 static void ibcm_process_dreq_timeout(ibcm_state_data_t *statep);
430
431 static void ibcm_fill_adds_from_lap(ibt_adds_vect_t *adds,
432 ibcm_lap_msg_t *lap_msg, ibcm_mode_t mode);
433
434 static void ibcm_post_stored_apr_mad(ibcm_state_data_t *statep,
435 uint8_t *input_madp);
436
437 static ibcm_status_t ibcm_set_qp_from_apr(ibcm_state_data_t *statep,
438 ibcm_lap_msg_t *lap_msg);
439
440 static boolean_t ibcm_compare_prim_alt_paths(ibt_adds_vect_t *prim,
441 ibt_adds_vect_t *alt);
442
443 static void ibcm_process_get_classport_info(ibcm_hca_info_t *hcap,
444 uint8_t *input_madp, ibcm_mad_addr_t *cm_mad_addr);
445
446 static void ibcm_decode_classport_info(ibcm_hca_info_t *hcap,
447 uint8_t *input_madp, ibcm_mad_addr_t *cm_mad_addr);
448
449 static void ibcm_post_rej_ver_mismatch(uint8_t *input_madp,
450 ibcm_mad_addr_t *cm_mad_addr);
451
452 static void ibcm_init_clp_to_mad(ibcm_classportinfo_msg_t *clp,
453 ibt_redirect_info_t *rinfo);
454
455 static void ibcm_init_clp_from_mad(ibcm_classportinfo_msg_t *clp,
456 ibt_redirect_info_t *rinfo);
457
458 static void ibcm_copy_addl_rej(ibcm_state_data_t *statep,
459 ibcm_rej_msg_t *rej_msgp,
460 ibt_cm_conn_failed_t *failed);
461
462 static void ibcm_return_open_data(ibcm_state_data_t *statep,
463 ibcm_rep_msg_t *rep_msgp,
464 ibt_cm_reason_t reject_reason);
465
466 /* limit the number of taskq threads to handle received MADs. */
467 int ibcm_recv_tasks = 0;
468 int ibcm_max_recv_tasks = 24;
469 int ibcm_recv_timeouts = 0;
470
471 /*
472 * Tunable MAX MRA Service Timeout value in MicroSECONDS.
473 * 0 - Tunable parameter not used.
474 *
475 * Ex: 60000000 - Max MRA Service Delay is 60 Seconds.
476 */
477 clock_t ibcm_mra_service_timeout_max = 0;
478
479 #ifdef DEBUG
480
481 static void print_modify_qp(char *prefix,
482 ibt_qp_hdl_t ibt_qp,
483 ibt_cep_modify_flags_t flags,
484 ibt_qp_info_t *qp_attr);
485 #endif
486
487 /* Warlock annotations */
488
_NOTE(READ_ONLY_DATA (ibt_arej_info_u))489 _NOTE(READ_ONLY_DATA(ibt_arej_info_u))
490
491 /*
492 * ibcm_process_incoming_mad:
493 * The CM callback that is invoked by IBMF, when a valid CM MAD arrives
494 * on any of the registered ibmf handles by CM.
495 *
496 * It is assumed that the incoming MAD (except for incoming REQ) belongs
497 * to a connection on the HCA, on which the MAD is received.
498 * The IBMF callback arg specifies ibcm_hca_info_t
499 *
500 * NOTE: IBMF always invokes ibcm_recv_cb() in a taskq. CM does some memory
501 * allocations and invoke ibcm_sm_funcs_tbl[i]() in the same taskq.
502 *
503 * INPUTS:
504 * ibmf_handle - IBMF Handle
505 * args - from IBMF. Is a ptr to ibcm_hca_info_t
506 * status - Callback status. Is mostly IBMF_SUCCESS
507 * madbuf - IBMF allocated MAD buffer (CM should free it)
508 * madaddr - IBMF MAD's address
509 * grhvalid - If GRH is valid or not
510 *
511 * RETURN VALUES: NONE
512 */
513 void
514 ibcm_process_incoming_mad(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
515 void *args)
516 {
517 uint8_t method; /* Method type in MAD hdr */
518 ib_mad_hdr_t *in_mad_hdr; /* Incoming MAD's header */
519 ibcm_hca_info_t *hcap; /* pointer to HCA entry */
520 ibcm_port_info_t *portp;
521 ibcm_mad_addr_t *cm_mad_addr; /* MAD address information */
522 ibcm_event_type_t attr_id; /* Attribute ID in MAD hdr */
523 ibcm_mad_addr_t loc_mad_addr; /* MAD address information */
524 ibcm_qp_list_t *cm_qp_entry;
525 int ibmf_status;
526
527
528 /* Noticed that IBMF always calls with IBMF_SUCCESS, but still check */
529 if (msgp->im_msg_status != IBMF_SUCCESS) {
530 IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: "
531 "bad status %x", msgp->im_msg_status);
532 /* IBMF allocates Input MAD, so free it here */
533 if ((ibmf_status = ibmf_free_msg(ibmf_handle, &msgp)) !=
534 IBMF_SUCCESS)
535 IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: "
536 "ibmf_free_msg failed %d", ibmf_status);
537 return;
538 }
539
540 /* Get the HCA entry pointer */
541 cm_qp_entry = (ibcm_qp_list_t *)args;
542
543 IBTF_DPRINTF_L5(cmlog, "ibcm_process_incoming_mad: ibmf_hdl %p "
544 "msg %p args %p", ibmf_handle, msgp, args);
545
546 #ifdef DEBUG
547 if (ibcm_test_mode > 1)
548 ibcm_query_qp(ibmf_handle, cm_qp_entry->qp_cm);
549 #endif
550
551 portp = cm_qp_entry->qp_port;
552 hcap = portp->port_hcap;
553
554 IBTF_DPRINTF_L4(cmlog, "ibcm_process_incoming_mad: CM MAD on "
555 "port %d", portp->port_num);
556
557 /* Increment hca ref cnt, if HCA is in attached state, else fail */
558 if (ibcm_inc_hca_acc_cnt(hcap) != IBCM_SUCCESS) {
559 IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: "
560 "hca not in attach state");
561 /* IBMF allocates Input MAD, and ibcm free's it */
562 if ((ibmf_status = ibmf_free_msg(ibmf_handle, &msgp)) !=
563 IBMF_SUCCESS)
564 IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: "
565 "ibmf_free_msg failed %d", ibmf_status);
566 return;
567 }
568
569 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cm_mad_addr))
570
571 /* allocate memory for internal MAD address buffer */
572 cm_mad_addr = &loc_mad_addr;
573 bzero(cm_mad_addr, sizeof (ibcm_mad_addr_t));
574
575 cm_mad_addr->port_num = portp->port_num;
576
577 /* initialize cm_mad_addr field(s) */
578 in_mad_hdr = msgp->im_msgbufs_recv.im_bufs_mad_hdr;
579
580 if (in_mad_hdr->MgmtClass != MAD_MGMT_CLASS_COMM_MGT) {
581 IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: "
582 "bad mgmt class %x", in_mad_hdr->MgmtClass);
583 if ((ibmf_status = ibmf_free_msg(ibmf_handle, &msgp)) !=
584 IBMF_SUCCESS)
585 IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: "
586 "ibmf_free_msg failed %d", ibmf_status);
587 ibcm_dec_hca_acc_cnt(hcap);
588 return;
589 }
590
591 cm_mad_addr->rcvd_addr = msgp->im_local_addr;
592 if (msgp->im_msg_flags & IBMF_MSG_FLAGS_GLOBAL_ADDRESS) {
593 cm_mad_addr->grh_hdr = msgp->im_global_addr;
594 cm_mad_addr->grh_exists = B_TRUE;
595 IBTF_DPRINTF_L3(cmlog, "ibcm_process_incoming_mad: "
596 "CM recv GID GUID %llX sender GID GUID %llX",
597 msgp->im_global_addr.ig_recver_gid.gid_guid,
598 msgp->im_global_addr.ig_sender_gid.gid_guid);
599 }
600
601 /* Save IBMF handle and ibmf qp related information */
602 cm_mad_addr->ibmf_hdl = ibmf_handle;
603 cm_mad_addr->cm_qp_entry = cm_qp_entry;
604
605 /* IBMF does not initialize ia_p_key for non-QP1's */
606 if (cm_qp_entry->qp_cm != IBMF_QP_HANDLE_DEFAULT)
607 cm_mad_addr->rcvd_addr.ia_p_key = cm_qp_entry->qp_pkey;
608
609 if (cm_mad_addr->rcvd_addr.ia_p_key & 0x8000)
610 IBTF_DPRINTF_L5(cmlog, "ibcm_process_incoming_mad: PKEY %x",
611 cm_mad_addr->rcvd_addr.ia_p_key);
612 else
613 IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: CM MAD "
614 "arrived from limited PKEY %x",
615 cm_mad_addr->rcvd_addr.ia_p_key);
616
617 /* Retrieve the method and Attr-Id from generic mad header */
618 method = in_mad_hdr->R_Method;
619 attr_id = b2h16(in_mad_hdr->AttributeID);
620
621 IBTF_DPRINTF_L4(cmlog, "ibcm_process_incoming_mad: "
622 "Method %x Attribute %x", method, attr_id);
623
624 if (in_mad_hdr->ClassVersion != IBCM_MAD_CLASS_VERSION) {
625
626 IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: "
627 "unsupported ibcm class version %x",
628 in_mad_hdr->ClassVersion);
629
630 if (attr_id == (IBCM_INCOMING_REQ + IBCM_ATTR_BASE_ID))
631 ibcm_post_rej_ver_mismatch(
632 (uint8_t *)IBCM_IN_HDRP(msgp), cm_mad_addr);
633
634 if ((ibmf_status = ibmf_free_msg(ibmf_handle, &msgp)) !=
635 IBMF_SUCCESS)
636 IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: "
637 "ibmf_free_msg failed %d", ibmf_status);
638 ibcm_dec_hca_acc_cnt(hcap);
639 return;
640 }
641
642 IBTF_DPRINTF_L4(cmlog, "ibcm_process_incoming_mad: "
643 "Transaction Id 0x%llX", b2h64(in_mad_hdr->TransactionID));
644
645 #ifdef DEBUG
646 ibcm_decode_tranid(b2h64(in_mad_hdr->TransactionID), NULL);
647 #endif
648
649 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*cm_mad_addr))
650
651 /*
652 * The following are valid combination of Method type
653 * and attribute id in the received MAD :-
654 * o ClassPortInfo with Get method
655 * o CM messages with Send method
656 */
657 if ((attr_id == MAD_ATTR_ID_CLASSPORTINFO) &&
658 ((method == MAD_METHOD_GET) ||
659 (method == MAD_METHOD_GET_RESPONSE))) {
660 if (method == MAD_METHOD_GET)
661 ibcm_process_get_classport_info(hcap,
662 (uint8_t *)IBCM_IN_HDRP(msgp), cm_mad_addr);
663 else if (method == MAD_METHOD_GET_RESPONSE)
664 ibcm_decode_classport_info(hcap,
665 (uint8_t *)IBCM_IN_HDRP(msgp), cm_mad_addr);
666 } else if ((attr_id >= IBCM_ATTR_BASE_ID) &&
667 (attr_id < (IBCM_ATTR_BASE_ID + IBCM_MAX_EVENTS)) &&
668 (method == MAD_METHOD_SEND)) {
669
670 attr_id -= IBCM_ATTR_BASE_ID; /* figure out CM message id */
671
672 ASSERT(msgp->im_msgbufs_recv.im_bufs_mad_hdr != NULL);
673
674 /* Call the CM process connection state function */
675 ibcm_sm_funcs_tbl[attr_id](hcap,
676 (uint8_t *)IBCM_IN_HDRP(msgp), cm_mad_addr);
677 } else {
678 /*
679 * Any other combination of method and attribute are invalid,
680 * hence drop the MAD
681 */
682 IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: "
683 "unknown Method %x or Attribute %x", method, attr_id);
684 }
685
686 /* decrement the hcap access reference count */
687 ibcm_dec_hca_acc_cnt(hcap);
688
689 /* ASSERT(NO_LOCKS_HELD); */
690
691 /* free up ibmf msgp */
692 if ((ibmf_status = ibmf_free_msg(ibmf_handle, &msgp)) != IBMF_SUCCESS)
693 IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: "
694 "ibmf_free_msg failed %d", ibmf_status);
695 }
696
697 /*
698 * Structure to carry the arguments from ibcm_recv_cb() to
699 * ibcm_recv_incoming_mad() via taskq_dispatch
700 */
701 typedef struct ibcm_taskq_args_s {
702 ibmf_handle_t tq_ibmf_handle;
703 ibmf_msg_t *tq_ibmf_msgp;
704 void *tq_args;
705 } ibcm_taskq_args_t;
706
707 #define IBCM_RECV_MAX 128
708 ibcm_taskq_args_t ibcm_recv_array[IBCM_RECV_MAX + 1];
709 int ibcm_get, ibcm_put;
710 int ibcm_recv_total;
711 int ibcm_recv_queued;
712
_NOTE(READ_ONLY_DATA (ibcm_taskq_args_t))713 _NOTE(READ_ONLY_DATA(ibcm_taskq_args_t))
714
715 static int
716 ibcm_recv_dequeue(ibmf_handle_t *ibmf_handlep, ibmf_msg_t **msgpp, void **argsp)
717 {
718 ibcm_taskq_args_t *tq;
719
720 if (ibcm_put == ibcm_get)
721 return (0);
722
723 if (++ibcm_get >= IBCM_RECV_MAX)
724 ibcm_get = 0;
725 tq = ibcm_recv_array + ibcm_get;
726 *ibmf_handlep = tq->tq_ibmf_handle;
727 *msgpp = tq->tq_ibmf_msgp;
728 *argsp = tq->tq_args;
729 return (1);
730 }
731
732 static int
ibcm_recv_enqueue(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)733 ibcm_recv_enqueue(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, void *args)
734 {
735 int next;
736 ibcm_taskq_args_t *tq;
737
738 ASSERT(MUTEX_HELD(&ibcm_recv_mutex));
739 next = ibcm_put + 1;
740 if (next >= IBCM_RECV_MAX)
741 next = 0;
742 if (next != ibcm_get) {
743 ibcm_recv_queued++;
744 ibcm_put = next;
745 tq = ibcm_recv_array + next;
746 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*tq))
747 tq->tq_ibmf_handle = ibmf_handle;
748 tq->tq_ibmf_msgp = msgp;
749 tq->tq_args = args;
750 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*tq))
751 return (1);
752 } else {
753 return (0);
754 }
755 }
756
757 void
ibcm_drop_msg(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp)758 ibcm_drop_msg(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp)
759 {
760 int ibmf_status;
761
762 IBTF_DPRINTF_L2(cmlog, "ibcm_drop_msg: discarding MAD");
763
764 if ((ibmf_status = ibmf_free_msg(ibmf_handle, &msgp)) != IBMF_SUCCESS)
765 IBTF_DPRINTF_L2(cmlog, "ibcm_drop_msg: "
766 "ibmf_free_msg failed %d", ibmf_status);
767 }
768
769 /*
770 * Processing done in taskq thread.
771 *
772 * Calls ibcm_process_incoming_mad with all function arguments extracted
773 * from args. Afterwards, check for queued requests.
774 */
775 static void
ibcm_recv_task(void * args)776 ibcm_recv_task(void *args)
777 {
778 ibcm_taskq_args_t *taskq_args;
779 ibmf_handle_t ibmf_handle;
780 ibmf_msg_t *msgp;
781
782 taskq_args = (ibcm_taskq_args_t *)args;
783
784 IBTF_DPRINTF_L4(cmlog, "ibcm_recv_task: Processing incoming MAD"
785 " via taskq");
786
787 ibcm_process_incoming_mad(taskq_args->tq_ibmf_handle,
788 taskq_args->tq_ibmf_msgp, taskq_args->tq_args);
789
790 kmem_free(taskq_args, sizeof (ibcm_taskq_args_t));
791
792 /* process queued entries before giving up this thread */
793 mutex_enter(&ibcm_recv_mutex);
794 while (ibcm_recv_dequeue(&ibmf_handle, &msgp, &args)) {
795 mutex_exit(&ibcm_recv_mutex);
796 ibcm_process_incoming_mad(ibmf_handle, msgp, args);
797 mutex_enter(&ibcm_recv_mutex);
798 }
799 --ibcm_recv_tasks;
800 mutex_exit(&ibcm_recv_mutex);
801 }
802
803 static void
ibcm_recv_timeout_cb(void * args)804 ibcm_recv_timeout_cb(void *args)
805 {
806 ibcm_taskq_args_t *tq = (ibcm_taskq_args_t *)args;
807 int rv = 1;
808
809 mutex_enter(&ibcm_recv_mutex);
810 ibcm_recv_timeouts--;
811 if (ibcm_recv_tasks == 0) {
812 ibcm_recv_tasks++;
813 mutex_exit(&ibcm_recv_mutex);
814 if (taskq_dispatch(ibcm_taskq, ibcm_recv_task, tq,
815 TQ_NOQUEUE | TQ_NOSLEEP) == 0) {
816 mutex_enter(&ibcm_recv_mutex);
817 if (--ibcm_recv_tasks == 0) {
818 (void) timeout(ibcm_recv_timeout_cb, tq, 1);
819 ibcm_recv_timeouts++;
820 } else {
821 rv = ibcm_recv_enqueue(tq->tq_ibmf_handle,
822 tq->tq_ibmf_msgp, tq->tq_args);
823 kmem_free(tq, sizeof (*tq));
824 }
825 mutex_exit(&ibcm_recv_mutex);
826 }
827 } else {
828 /*
829 * one or more taskq threads are running now
830 * so just try to enqueue this one.
831 */
832 rv = ibcm_recv_enqueue(tq->tq_ibmf_handle,
833 tq->tq_ibmf_msgp, tq->tq_args);
834 kmem_free(tq, sizeof (*tq));
835 mutex_exit(&ibcm_recv_mutex);
836 }
837 if (rv == 0)
838 ibcm_drop_msg(tq->tq_ibmf_handle, tq->tq_ibmf_msgp);
839 }
840
841 /*
842 * Dispatch to taskq if we're not using many, else just queue it
843 * and have the taskq thread pick it up. Return 0 if we're dropping it.
844 */
845 static int
ibcm_recv_add_one(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)846 ibcm_recv_add_one(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, void *args)
847 {
848 int rv;
849 ibcm_taskq_args_t *tq;
850
851 mutex_enter(&ibcm_recv_mutex);
852 ibcm_recv_total++;
853 if (ibcm_recv_tasks >= ibcm_max_recv_tasks) { /* just queue this one */
854 rv = ibcm_recv_enqueue(ibmf_handle, msgp, args);
855 mutex_exit(&ibcm_recv_mutex);
856 return (rv);
857 } else {
858 ibcm_recv_tasks++; /* dispatch this one to a taskq thread */
859 mutex_exit(&ibcm_recv_mutex);
860 tq = kmem_alloc(sizeof (*tq), KM_NOSLEEP);
861 if (tq == NULL) {
862 mutex_enter(&ibcm_recv_mutex);
863 if (--ibcm_recv_tasks > 0)
864 rv = ibcm_recv_enqueue(ibmf_handle, msgp, args);
865 else /* don't enqueue if no threads are running */
866 rv = 0;
867 mutex_exit(&ibcm_recv_mutex);
868 return (rv);
869 }
870 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*tq))
871 tq->tq_ibmf_handle = ibmf_handle;
872 tq->tq_ibmf_msgp = msgp;
873 tq->tq_args = args;
874 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*tq))
875 if (taskq_dispatch(ibcm_taskq, ibcm_recv_task, tq,
876 TQ_NOQUEUE | TQ_NOSLEEP) == 0) { /* dispatch failed */
877 mutex_enter(&ibcm_recv_mutex);
878 if (--ibcm_recv_tasks == 0) {
879 /* try the dispatch again, after a tick */
880 (void) timeout(ibcm_recv_timeout_cb, tq, 1);
881 ibcm_recv_timeouts++;
882 rv = 1; /* indicate success */
883 } else {
884 rv = ibcm_recv_enqueue(ibmf_handle, msgp, args);
885 kmem_free(tq, sizeof (*tq));
886 }
887 mutex_exit(&ibcm_recv_mutex);
888 return (rv);
889 } else {
890 return (1);
891 }
892 }
893 }
894
895 /*
896 * ibcm_recv_cb:
897 * The CM callback that is invoked by IBMF, when a valid CM MAD arrives
898 * on any of the registered ibmf handles by CM.
899 *
900 * INPUTS:
901 * ibmf_handle - IBMF Handle
902 * msgp - IBMF msg containing the MAD (allocated by IBMF)
903 * args - Ptr to ibcm_hca_info_t
904 *
905 * RETURN VALUES: NONE
906 */
907 void
ibcm_recv_cb(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)908 ibcm_recv_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, void *args)
909 {
910 if (ibcm_recv_add_one(ibmf_handle, msgp, args) == 0)
911 ibcm_drop_msg(ibmf_handle, msgp);
912 }
913
914 /*
915 * ibcm_process_req_msg:
916 * PASSIVE SIDE CM
917 * Called from ibcm_process_incoming_mad on reception of a REQ message
918 *
919 * Description:
920 * If it a new REQ (not duplicate)
921 * creates a new state structure in passive connection mode
922 * populate state structure fields
923 * inserts state structure in hca active and passive trees
924 * validates service id
925 * validates primary and alternate lid/gid in REQ,
926 * calls QP state transition function
927 * generates REP/REJ response
928 * stores the response MAD in state structure for future re-sends
929 * initializes timers as required
930 * If a duplicate REQ, action depends upon current state in the state
931 * structure
932 *
933 * INPUTS:
934 * hcap - HCA entry ptr
935 * input_madp - CM MAD that is input to this function
936 * cm_mad_addr - Address information for the MAD
937 *
938 * RETURN VALUE:
939 * NONE
940 */
941 void
ibcm_process_req_msg(ibcm_hca_info_t * hcap,uint8_t * input_madp,ibcm_mad_addr_t * cm_mad_addr)942 ibcm_process_req_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
943 ibcm_mad_addr_t *cm_mad_addr)
944 {
945 ibt_priv_data_len_t arej_info_len = 0;
946 ib_qpn_t remote_qpn;
947 ib_guid_t remote_hca_guid;
948 ib_com_id_t remote_comid;
949 ib_com_id_t local_comid;
950 ibcm_status_t state_lookup_status;
951 ibcm_status_t comid_lookup_status;
952 ibcm_status_t response;
953 ibcm_req_msg_t *req_msgp =
954 (ibcm_req_msg_t *)&input_madp[IBCM_MAD_HDR_SIZE];
955 ibt_cm_reason_t reject_reason = IBT_CM_SUCCESS;
956 ibcm_state_data_t *statep;
957 ibcm_state_data_t *stale_statep = NULL;
958 ibcm_status_t svc_gid_check;
959 uint32_t psn24_timeout5_retry3;
960 ibt_tran_srv_t trans;
961
962 IBTF_DPRINTF_L5(cmlog, "ibcm_process_req_msg(%p, %p, %p)",
963 hcap, input_madp, cm_mad_addr);
964
965 /*
966 * Lookup for an existing state structure or create a new state struct
967 * If there is no entry, the lookup function also allocates a new
968 * state structure and inserts in the table, initializes remote qpn
969 * and hca guid from REQ
970 */
971 remote_hca_guid = b2h64(req_msgp->req_local_ca_guid);
972 remote_qpn = b2h32(req_msgp->req_local_qpn_plus) >> 8;
973 remote_comid = b2h32(req_msgp->req_local_comm_id);
974
975 IBCM_DUMP_RAW_MSG((uchar_t *)input_madp);
976
977 IBTF_DPRINTF_L4(cmlog, "ibcm_process_req_msg: remote_comid = %x"
978 " remote_qpn = %x", remote_comid, remote_qpn);
979
980 IBTF_DPRINTF_L4(cmlog, "ibcm_process_req_msg: remote_hcaguid = %llX",
981 remote_hca_guid);
982
983 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*statep))
984
985 new_req:
986 /* allocate the local_comid before proceeding */
987 if (ibcm_alloc_comid(hcap, &local_comid) != IBCM_SUCCESS) {
988 ibcm_build_n_post_rej_mad(input_madp,
989 b2h32(req_msgp->req_local_comm_id), cm_mad_addr,
990 IBT_CM_FAILURE_REQ, IBT_CM_NO_RESC);
991 return;
992 }
993
994 /* allocate ibcm_state_data_t before grabbing the WRITER lock */
995 statep = kmem_zalloc(sizeof (*statep), KM_SLEEP);
996
997 rw_enter(&hcap->hca_state_rwlock, RW_WRITER);
998
999 /* NOTE that only a writer lock is held here */
1000
1001 state_lookup_status = ibcm_lookup_msg(IBCM_INCOMING_REQ,
1002 local_comid, remote_qpn, remote_hca_guid, hcap, &statep);
1003
1004 if (state_lookup_status == IBCM_LOOKUP_NEW) {
1005 /* seeing the REQ request for the first time */
1006
1007 mutex_enter(&statep->state_mutex);
1008 /* Release the state table lock */
1009 rw_exit(&hcap->hca_state_rwlock);
1010
1011 IBTF_DPRINTF_L4(cmlog, "ibcm_process_req_msg: New statep 0x%p"
1012 " created", statep);
1013
1014 psn24_timeout5_retry3 = b2h32(req_msgp->req_starting_psn_plus);
1015
1016 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*statep))
1017
1018 /* if ibmf msg allocation fails, delete the statep */
1019 if (ibcm_alloc_out_msg(cm_mad_addr->ibmf_hdl,
1020 &statep->stored_msg, MAD_METHOD_SEND) != IBT_SUCCESS) {
1021
1022 IBCM_REF_CNT_DECR(statep);
1023 statep->state = IBCM_STATE_DELETE;
1024 mutex_exit(&statep->state_mutex);
1025 /* HCA res cnt decremented via ibcm_delete_state_data */
1026 ibcm_inc_hca_res_cnt(hcap);
1027 ibcm_delete_state_data(statep);
1028 return;
1029 }
1030
1031 /* Allocate dreq_msg buf to be used during teardown. */
1032 if (ibcm_alloc_out_msg(cm_mad_addr->ibmf_hdl,
1033 &statep->dreq_msg, MAD_METHOD_SEND) != IBT_SUCCESS) {
1034
1035 IBCM_REF_CNT_DECR(statep);
1036 statep->state = IBCM_STATE_DELETE;
1037 mutex_exit(&statep->state_mutex);
1038 IBTF_DPRINTF_L2(cmlog, "ibcm_process_req_msg: "
1039 "statep 0x%p: Failed to allocate dreq_msg", statep);
1040
1041 /* HCA res cnt decremented via ibcm_delete_state_data */
1042 ibcm_inc_hca_res_cnt(hcap);
1043 ibcm_delete_state_data(statep);
1044 return;
1045 }
1046
1047 /* initialize some "statep" fields */
1048 statep->mode = IBCM_PASSIVE_MODE;
1049 statep->hcap = hcap;
1050 statep->remote_comid = remote_comid;
1051 statep->svcid = b2h64(req_msgp->req_svc_id);
1052 statep->local_qp_rnr_cnt =
1053 req_msgp->req_mtu_plus & 0x7;
1054
1055 /*
1056 * get the remote_ack_delay, etc.
1057 */
1058 statep->remote_ack_delay =
1059 ibt_ib2usec(req_msgp->req_primary_localtime_plus >> 3);
1060 statep->cep_retry_cnt = psn24_timeout5_retry3 & 0x7;
1061
1062 /*
1063 * get the req_max_cm_retries
1064 */
1065 statep->max_cm_retries = req_msgp->req_max_cm_retries_plus >> 4;
1066 statep->remaining_retry_cnt = statep->max_cm_retries;
1067
1068 /* Approximate pkt life time for now */
1069 statep->pkt_life_time = statep->remote_ack_delay/2;
1070
1071 /* Passive side timer is set to LocalCMRespTime in REQ */
1072 statep->timer_value =
1073 ibt_ib2usec(psn24_timeout5_retry3 >> 3 & 0x1f);
1074
1075 statep->starting_psn = psn24_timeout5_retry3 >> 8;
1076
1077 IBTF_DPRINTF_L4(cmlog, "ibcm_process_req_msg: statep 0x%p "
1078 "active cep timeout(usec) = %u",
1079 statep, statep->remote_ack_delay);
1080 IBTF_DPRINTF_L4(cmlog, "ibcm_process_req_msg: "
1081 "passive timer(usec) = %u", statep->timer_value);
1082 IBTF_DPRINTF_L4(cmlog, "ibcm_process_req_msg: "
1083 "approx pkt lt(usec)= %u ", statep->pkt_life_time);
1084 IBTF_DPRINTF_L4(cmlog, "ibcm_process_req_msg: "
1085 "max cm retries %u", statep->max_cm_retries);
1086
1087 /* The reply ie., REP/REJ transaction id copied from REQ */
1088 IBCM_OUT_HDRP(statep->stored_msg)->TransactionID =
1089 ((ib_mad_hdr_t *)(input_madp))->TransactionID;
1090
1091 /*
1092 * Initialize the stale clock. Any other REQ
1093 * messages on this statep are considered as duplicate
1094 * if they arrive within stale clock
1095 * ibcm_adj_btime is used to offset for retry REQ's
1096 * arriving just after expected retry clock
1097 */
1098 statep->stale_clock = gethrtime() +
1099 (hrtime_t)(ibcm_adj_btime * 1000000000) +
1100 (hrtime_t)statep->remote_ack_delay *
1101 (statep->max_cm_retries * (1000 / 2));
1102
1103 mutex_exit(&statep->state_mutex);
1104
1105 ibcm_insert_trace(statep, IBCM_TRACE_INCOMING_REQ);
1106
1107 /* Increment the hca's resource count */
1108 ibcm_inc_hca_res_cnt(hcap);
1109
1110 ibcm_build_reply_mad_addr(cm_mad_addr,
1111 &statep->stored_reply_addr);
1112
1113 if (statep->stored_reply_addr.cm_qp_entry == NULL) {
1114
1115 IBTF_DPRINTF_L2(cmlog, "ibcm_process_req_msg: "
1116 "statep 0x%p cm_qp_entry alloc failed", statep);
1117
1118 /*
1119 * Not much choice. CM MADs cannot go on QP1, not even
1120 * REJ. Hence delete state data and go away silently.
1121 * The remote will timeout after repeated attempts
1122 */
1123 mutex_enter(&statep->state_mutex);
1124 IBCM_REF_CNT_DECR(statep);
1125 statep->state = IBCM_STATE_DELETE;
1126 mutex_exit(&statep->state_mutex);
1127
1128 ibcm_delete_state_data(statep);
1129 return;
1130 }
1131
1132 stale_statep = statep;
1133 rw_enter(&hcap->hca_state_rwlock, RW_WRITER);
1134 comid_lookup_status = ibcm_lookup_msg(IBCM_INCOMING_REQ_STALE,
1135 remote_comid, 0, remote_hca_guid, hcap, &stale_statep);
1136 rw_exit(&hcap->hca_state_rwlock);
1137
1138 if (comid_lookup_status == IBCM_LOOKUP_EXISTS) {
1139
1140 IBTF_DPRINTF_L2(cmlog, "ibcm_process_req_msg: "
1141 "dup comid %x stale_statep 0x%p statep 0x%p",
1142 remote_comid, stale_statep, statep);
1143
1144 ibcm_insert_trace(stale_statep,
1145 IBCM_TRACE_STALE_DETECT);
1146
1147 /* Send a REJ with duplicate com id */
1148 ibcm_post_rej_mad(statep, IBT_CM_DUP_COM_ID,
1149 IBT_CM_FAILURE_REQ, NULL, 0);
1150
1151 /*
1152 * Don't free the ibmf msg, if stale_statep is not in
1153 * ESTABLISHED state, because probability is very less.
1154 * ibmf msg shall be deleted along with statep
1155 */
1156
1157 /*
1158 * if stale_statep is in established state, process
1159 * stale connection handling on stale_statep
1160 */
1161 mutex_enter(&stale_statep->state_mutex);
1162 if (stale_statep->state == IBCM_STATE_ESTABLISHED) {
1163
1164 stale_statep->state =
1165 IBCM_STATE_TRANSIENT_DREQ_SENT;
1166 stale_statep->stale = B_TRUE;
1167
1168 /* Cancel pending ibt_set_alt_path */
1169 ibcm_sync_lapr_idle(stale_statep);
1170 /* The above call releases the state mutex */
1171
1172 if (stale_statep->dreq_msg == NULL)
1173 (void) ibcm_alloc_out_msg(stale_statep->
1174 stored_reply_addr.ibmf_hdl,
1175 &stale_statep->dreq_msg,
1176 MAD_METHOD_SEND);
1177
1178 /*
1179 * Spec says, post DREQ MAD on the stale
1180 * channel. This moves channel into timewait
1181 */
1182 if (stale_statep->dreq_msg != NULL) {
1183 ibcm_post_dreq_mad(stale_statep);
1184 mutex_enter(&stale_statep->state_mutex);
1185 } else {
1186 mutex_enter(&stale_statep->state_mutex);
1187 /* Set it back to original state. */
1188 stale_statep->state =
1189 IBCM_STATE_ESTABLISHED;
1190 cv_broadcast(
1191 &stale_statep->block_mad_cv);
1192 }
1193 }
1194
1195 IBCM_REF_CNT_DECR(stale_statep);
1196 mutex_exit(&stale_statep->state_mutex);
1197
1198 mutex_enter(&statep->state_mutex);
1199 IBCM_REF_CNT_DECR(statep);
1200 mutex_exit(&statep->state_mutex);
1201 return;
1202 }
1203
1204 /* If unknown service type, just post a REJ */
1205 trans = ((uint8_t *)&req_msgp->req_remote_eecn_plus)[3] >> 1 &
1206 0x3;
1207 if ((trans != IBT_RC_SRV) && (trans != IBT_UC_SRV) &&
1208 (trans != IBT_RD_SRV)) {
1209
1210 IBTF_DPRINTF_L2(cmlog, "ibcm_process_req_msg: "
1211 "statep 0x%p invalid transport type %x", statep,
1212 trans);
1213
1214 /* Send a REJ with invalid transport type */
1215 ibcm_post_rej_mad(statep, IBT_CM_INVALID_SRV_TYPE,
1216 IBT_CM_FAILURE_REQ, NULL, 0);
1217
1218 mutex_enter(&statep->state_mutex);
1219 IBCM_REF_CNT_DECR(statep);
1220 mutex_exit(&statep->state_mutex);
1221 return;
1222 }
1223
1224 /* Validate the gids, lids and service id */
1225 svc_gid_check = ibcm_verify_req_gids_and_svcid(statep,
1226 req_msgp);
1227
1228 if (svc_gid_check == IBCM_FAILURE) {
1229
1230 IBTF_DPRINTF_L3(cmlog, "ibcm_process_req_msg: Either "
1231 "gid or sid invalid for statep 0x%p", statep);
1232 mutex_enter(&statep->state_mutex);
1233 IBCM_REF_CNT_DECR(statep);
1234 mutex_exit(&statep->state_mutex);
1235
1236 /* REJ posted from ibcm_verify_req_gids_and_svcid */
1237 return;
1238 }
1239
1240 /* Call the QP state transition processing function */
1241 response = ibcm_cep_state_req(statep, req_msgp,
1242 &reject_reason, &arej_info_len);
1243
1244 /* If defer, return holding the statep ref cnt */
1245 if (response == IBCM_DEFER) {
1246 IBTF_DPRINTF_L4(cmlog, "ibcm_process_req_msg: "
1247 "statep %0xp client returned DEFER response",
1248 statep);
1249 return;
1250 }
1251
1252 /* statep ref cnt decremented in the func below */
1253 ibcm_handle_cep_req_response(statep, response,
1254 reject_reason, arej_info_len);
1255
1256 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*statep))
1257
1258 return;
1259
1260 } else {
1261 rw_exit(&hcap->hca_state_rwlock);
1262 ibcm_free_comid(hcap, local_comid);
1263 }
1264
1265 if (state_lookup_status == IBCM_LOOKUP_EXISTS) {
1266 hrtime_t cur_time;
1267
1268 mutex_enter(&statep->state_mutex);
1269
1270 /*
1271 * There is an existing state structure entry
1272 * with the same active comid
1273 * Resending REP MAD is necessary only for REP/REJ/MRA Sent
1274 * states
1275 * Any other state implies the active has already received
1276 * the REP/REJ response, and this REQ is an old MAD popping
1277 * out of the fabric, hence no resend is required
1278 */
1279 cur_time = gethrtime();
1280
1281 if ((remote_comid == statep->remote_comid) &&
1282 (IBCM_OUT_HDRP(statep->stored_msg)->TransactionID ==
1283 ((ib_mad_hdr_t *)(input_madp))->TransactionID) &&
1284 (cur_time <= statep->stale_clock)) {
1285
1286 ibcm_insert_trace(statep, IBCM_TRACE_INCOMING_REQ);
1287
1288 if (statep->state == IBCM_STATE_REP_SENT)
1289 ibcm_resend_rep_mad(statep);
1290 else if (statep->state == IBCM_STATE_REJ_SENT)
1291 ibcm_resend_rej_mad(statep);
1292 else if (statep->state == IBCM_STATE_MRA_SENT)
1293 ibcm_resend_mra_mad(statep);
1294
1295 /* decrementing ref cnt and returning from below */
1296
1297 } else if ((statep->state == IBCM_STATE_REJ_SENT) &&
1298 remote_comid != statep->remote_comid) {
1299 timeout_id_t timer_val;
1300
1301 IBTF_DPRINTF_L2(cmlog, "ibcm_process_req_msg: "
1302 "statep 0x%p being retired, REMOTE_QPN %x",
1303 statep, remote_qpn);
1304 /*
1305 * OK, this is reuse of the QPN on the active side
1306 * that was not connected last time. This REQ is
1307 * considered NEW. We delete the statep here,
1308 * then start over from the top.
1309 */
1310 statep->state = IBCM_STATE_DELETE;
1311 timer_val = statep->timerid;
1312 statep->timerid = 0;
1313 mutex_exit(&statep->state_mutex);
1314 if (timer_val)
1315 (void) untimeout(timer_val);
1316 IBCM_REF_CNT_DECR(statep);
1317 ibcm_delete_state_data(statep);
1318 goto new_req;
1319
1320 /*
1321 * The statep is stale in the following cases :-
1322 * 1) if incoming REQ's comid's doesn't match with what is
1323 * stored in statep
1324 * 2) incoming REQ's local comid matches with statep's
1325 * remote comid, but the REQ is for a new connection.
1326 * This is verified that by comparing the current time
1327 * with stale clock in statep
1328 */
1329 } else {
1330 /* This is a stale connection on passive side */
1331
1332 ibcm_insert_trace(statep, IBCM_TRACE_STALE_DETECT);
1333
1334 IBTF_DPRINTF_L2(cmlog, "ibcm_process_req_msg: "
1335 "stale detected statep %p state %x",
1336 statep, statep->state);
1337
1338 IBTF_DPRINTF_L4(cmlog, "ibcm_process_req_msg: "
1339 "cur_time 0x%llX stale_clock 0x%llX", cur_time,
1340 statep->stale_clock);
1341
1342 if (statep->state == IBCM_STATE_ESTABLISHED) {
1343
1344 statep->state = IBCM_STATE_TRANSIENT_DREQ_SENT;
1345 statep->stale = B_TRUE;
1346
1347 /* Cancel pending ibt_set_alt_path */
1348 ibcm_sync_lapr_idle(statep);
1349 /* The above call releases the state mutex */
1350
1351 if (statep->dreq_msg == NULL)
1352 (void) ibcm_alloc_out_msg(
1353 statep->stored_reply_addr.ibmf_hdl,
1354 &statep->dreq_msg, MAD_METHOD_SEND);
1355
1356 /*
1357 * Spec says, post DREQ MAD on the stale
1358 * channel. This moves channel into timewait
1359 */
1360 if (statep->dreq_msg != NULL)
1361 ibcm_post_dreq_mad(statep);
1362 else {
1363 mutex_enter(&statep->state_mutex);
1364 statep->state = IBCM_STATE_ESTABLISHED;
1365 cv_broadcast(&statep->block_mad_cv);
1366 mutex_exit(&statep->state_mutex);
1367 }
1368 } else {
1369 /*
1370 * If not in established state, the CM
1371 * protocol would timeout and delete the
1372 * statep that is stale, eventually
1373 */
1374 mutex_exit(&statep->state_mutex);
1375 }
1376
1377 /* Post a REJ MAD to the incoming REQ's sender */
1378 ibcm_build_n_post_rej_mad(input_madp,
1379 b2h32(req_msgp->req_local_comm_id),
1380 cm_mad_addr, IBT_CM_FAILURE_REQ, IBT_CM_CONN_STALE);
1381
1382 mutex_enter(&statep->state_mutex);
1383 }
1384 IBCM_REF_CNT_DECR(statep); /* decrement the ref count */
1385 mutex_exit(&statep->state_mutex);
1386 }
1387 }
1388
1389 /*
1390 * ibcm_handle_cep_req_response:
1391 * Processes the response from ibcm_cep_state_req. Called holding a
1392 * statep ref cnt. The statep ref cnt is decremented before returning.
1393 */
1394 void
ibcm_handle_cep_req_response(ibcm_state_data_t * statep,ibcm_status_t response,ibt_cm_reason_t reject_reason,uint8_t arej_info_len)1395 ibcm_handle_cep_req_response(ibcm_state_data_t *statep, ibcm_status_t response,
1396 ibt_cm_reason_t reject_reason, uint8_t arej_info_len)
1397 {
1398 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*statep))
1399
1400 if (response == IBCM_SEND_REP)
1401 ibcm_post_rep_mad(statep);
1402 else {
1403 ASSERT(response == IBCM_SEND_REJ);
1404 IBTF_DPRINTF_L4(cmlog, "ibcm_handle_cep_req_response: statep %p"
1405 " posting REJ reject_reason = %d", statep, reject_reason);
1406
1407 ibcm_post_rej_mad(statep,
1408 reject_reason, IBT_CM_FAILURE_REQ,
1409 NULL, arej_info_len);
1410 }
1411
1412 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*statep))
1413
1414 mutex_enter(&statep->state_mutex);
1415 IBCM_REF_CNT_DECR(statep);
1416 mutex_exit(&statep->state_mutex);
1417 }
1418
1419
1420 /*
1421 * ibcm_process_rep_msg:
1422 * ACTIVE SIDE CM
1423 * Called from ibcm_process_incoming_mad on reception of a REP message
1424 *
1425 * INPUTS:
1426 * hcap - HCA entry pointer
1427 * input_madp - CM MAD that is input to this function
1428 * cm_mad_addr - Address information for the MAD
1429 *
1430 * RETURN VALUE: NONE
1431 */
1432 void
ibcm_process_rep_msg(ibcm_hca_info_t * hcap,uint8_t * input_madp,ibcm_mad_addr_t * cm_mad_addr)1433 ibcm_process_rep_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
1434 ibcm_mad_addr_t *cm_mad_addr)
1435 {
1436 ibt_priv_data_len_t arej_info_len = 0;
1437 ib_com_id_t local_comid;
1438 timeout_id_t timer_val;
1439 ibcm_status_t lookup_status; /* state lookup status */
1440 ibcm_status_t stale_lookup_status;
1441 ibcm_status_t stale_comid_lookup_status;
1442 ibcm_status_t response;
1443 ibcm_rep_msg_t *rep_msgp; /* Response REP mesg */
1444 ibt_cm_reason_t reject_reason;
1445 ibcm_state_data_t *statep = NULL;
1446 ibcm_state_data_t *stale_qpn = NULL;
1447 ibcm_state_data_t *stale_comid = NULL;
1448 ib_guid_t remote_ca_guid;
1449
1450 IBTF_DPRINTF_L3(cmlog, "ibcm_process_rep_msg:");
1451
1452 /* Lookup for an existing state structure */
1453 rep_msgp = (ibcm_rep_msg_t *)(&input_madp[IBCM_MAD_HDR_SIZE]);
1454
1455 IBCM_DUMP_RAW_MSG((uchar_t *)input_madp);
1456
1457 IBTF_DPRINTF_L5(cmlog, "ibcm_process_rep_msg: active comid: %x",
1458 rep_msgp->rep_remote_comm_id);
1459
1460 local_comid = b2h32(rep_msgp->rep_remote_comm_id);
1461
1462 /* lookup message holding a reader lock */
1463 rw_enter(&hcap->hca_state_rwlock, RW_READER);
1464 lookup_status = ibcm_lookup_msg(IBCM_INCOMING_REP, local_comid, 0, 0,
1465 hcap, &statep);
1466 rw_exit(&hcap->hca_state_rwlock);
1467
1468 IBTF_DPRINTF_L4(cmlog, "ibcm_process_rep_msg: lkup status %x, "
1469 "statep 0x%p active comid %x", lookup_status, statep, local_comid);
1470
1471 if (lookup_status == IBCM_LOOKUP_FAIL) {
1472 ibcm_build_n_post_rej_mad(input_madp,
1473 b2h32(rep_msgp->rep_local_comm_id), cm_mad_addr,
1474 IBT_CM_FAILURE_REP, IBT_CM_INVALID_CID);
1475
1476 return;
1477 }
1478
1479 /* if transaction id is not as expected, drop the REP mad */
1480 if (IBCM_OUT_HDRP(statep->stored_msg)->TransactionID !=
1481 ((ib_mad_hdr_t *)(input_madp))->TransactionID) {
1482
1483 IBTF_DPRINTF_L3(cmlog, "ibcm_process_rep_msg: statep 0x%p, "
1484 "An REP MAD with tid expected 0x%llX tid found 0x%llX ",
1485 statep,
1486 b2h64(IBCM_OUT_HDRP(statep->stored_msg)->TransactionID),
1487 b2h64(((ib_mad_hdr_t *)(input_madp))->TransactionID));
1488
1489 mutex_enter(&statep->state_mutex);
1490 IBCM_REF_CNT_DECR(statep);
1491 mutex_exit(&statep->state_mutex);
1492 return;
1493 }
1494
1495 ibcm_insert_trace(statep, IBCM_TRACE_INCOMING_REP);
1496
1497 /* grab mutex first */
1498 mutex_enter(&statep->state_mutex);
1499
1500 /*
1501 * There is a state structure entry with active comid
1502 * First, handle the re-send cases
1503 * The resend routines below release the state mutex
1504 */
1505 if (statep->state == IBCM_STATE_ESTABLISHED ||
1506 statep->state == IBCM_STATE_DREQ_SENT)
1507 ibcm_resend_rtu_mad(statep);
1508 else if (statep->state == IBCM_STATE_REJ_SENT)
1509 ibcm_resend_rej_mad(statep);
1510 else if (statep->state == IBCM_STATE_MRA_REP_SENT)
1511 ibcm_resend_mra_mad(statep);
1512 else if ((statep->state == IBCM_STATE_REQ_SENT) ||
1513 (statep->state == IBCM_STATE_REP_WAIT)) {
1514
1515 /* change state */
1516 statep->state = IBCM_STATE_REP_RCVD;
1517 statep->clnt_proceed = IBCM_BLOCK;
1518 statep->local_qp_rnr_cnt =
1519 rep_msgp->rep_rnr_retry_cnt_plus >> 5;
1520
1521 /* cancel the REQ timer */
1522 if (statep->timerid != 0) {
1523 timer_val = statep->timerid;
1524 statep->timerid = 0;
1525 mutex_exit(&statep->state_mutex);
1526 (void) untimeout(timer_val);
1527 } else {
1528 mutex_exit(&statep->state_mutex);
1529 }
1530
1531 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*statep))
1532
1533 /* Initialize the remote destination QPN for further MADs */
1534 statep->stored_reply_addr.rcvd_addr.ia_remote_qno =
1535 cm_mad_addr->rcvd_addr.ia_remote_qno;
1536 statep->remote_qpn = b2h32(rep_msgp->rep_local_qpn_plus) >> 8;
1537 statep->remote_comid = b2h32(rep_msgp->rep_local_comm_id);
1538 bcopy(rep_msgp->rep_local_ca_guid, &remote_ca_guid,
1539 sizeof (ib_guid_t));
1540 statep->remote_hca_guid = b2h64(remote_ca_guid);
1541
1542 IBTF_DPRINTF_L4(cmlog, "ibcm_process_rep_msg: statep 0x%p "
1543 "passive cid = %x passive qpn = %x", statep,
1544 statep->remote_comid, statep->remote_qpn);
1545
1546 IBTF_DPRINTF_L4(cmlog, "ibcm_process_rep_msg: statep 0x%p "
1547 "passive hcaguid = %llX", statep, statep->remote_hca_guid);
1548
1549 stale_qpn = statep;
1550 stale_comid = statep;
1551
1552 /* Handle stale connection detection on active side */
1553 rw_enter(&hcap->hca_state_rwlock, RW_WRITER);
1554
1555 stale_lookup_status = ibcm_lookup_msg(IBCM_INCOMING_REP_STALE,
1556 0, statep->remote_qpn, statep->remote_hca_guid, hcap,
1557 &stale_qpn);
1558
1559 stale_comid_lookup_status = ibcm_lookup_msg(
1560 IBCM_INCOMING_REQ_STALE, statep->remote_comid, 0,
1561 statep->remote_hca_guid, hcap, &stale_comid);
1562
1563 rw_exit(&hcap->hca_state_rwlock);
1564
1565 /*
1566 * Check for other side reusing QPN that was attempted
1567 * to be used, but somehow we sent a REJ.
1568 */
1569 mutex_enter(&stale_qpn->state_mutex);
1570 if ((stale_lookup_status == IBCM_LOOKUP_EXISTS) &&
1571 (stale_comid_lookup_status != IBCM_LOOKUP_EXISTS) &&
1572 (stale_qpn->state == IBCM_STATE_REJ_SENT)) {
1573
1574 timeout_id_t timer_val;
1575
1576 IBTF_DPRINTF_L3(cmlog, "ibcm_process_rep_msg: "
1577 "statep 0x%p being retired, REMOTE_QPN %x",
1578 stale_qpn, statep->remote_qpn);
1579 /*
1580 * OK, this is reuse of the QPN on the active side
1581 * that was not connected last time. This REQ is
1582 * considered NEW. We delete the statep here,
1583 * then start over from the top.
1584 */
1585 stale_qpn->state = IBCM_STATE_DELETE;
1586 timer_val = stale_qpn->timerid;
1587 stale_qpn->timerid = 0;
1588 mutex_exit(&stale_qpn->state_mutex);
1589 if (timer_val)
1590 (void) untimeout(timer_val);
1591 IBCM_REF_CNT_DECR(stale_qpn);
1592 ibcm_delete_state_data(stale_qpn);
1593 stale_qpn = statep;
1594 rw_enter(&hcap->hca_state_rwlock, RW_WRITER);
1595 stale_lookup_status = ibcm_lookup_msg(
1596 IBCM_INCOMING_REP_STALE, 0, statep->remote_qpn,
1597 statep->remote_hca_guid, hcap, &stale_qpn);
1598 rw_exit(&hcap->hca_state_rwlock);
1599 /* OK to continue now */
1600 } else
1601 mutex_exit(&stale_qpn->state_mutex);
1602
1603 /*
1604 * lookup exists implies that there is already an entry with
1605 * the remote qpn/comid and remote hca guid
1606 */
1607 if ((stale_lookup_status == IBCM_LOOKUP_EXISTS) ||
1608 (stale_comid_lookup_status == IBCM_LOOKUP_EXISTS)) {
1609
1610 IBTF_DPRINTF_L2(cmlog, "ibcm_process_rep_msg: "
1611 "statep 0x%p stale detected "
1612 "qpn_lkup %d comid_lkup %d", statep,
1613 stale_lookup_status, stale_comid_lookup_status);
1614
1615 /* Disassociate statep and QP */
1616 IBCM_SET_CHAN_PRIVATE(statep->channel, NULL);
1617
1618 if (stale_lookup_status == IBCM_LOOKUP_EXISTS)
1619 reject_reason = IBT_CM_CONN_STALE;
1620 else
1621 reject_reason = IBT_CM_DUP_COM_ID;
1622
1623 ibcm_handler_conn_fail(statep,
1624 IBT_CM_FAILURE_REJ_SENT, IBT_CM_FAILURE_REP,
1625 reject_reason,
1626 IBCM_REJ_PRIV(statep->stored_msg),
1627 IBT_REJ_PRIV_DATA_SZ);
1628
1629 /* Send a REJ with stale reason for statep */
1630 ibcm_post_rej_mad(statep, reject_reason,
1631 IBT_CM_FAILURE_REP, NULL, 0);
1632
1633 /* Now let's handle the logic for stale connections */
1634 /* If in established state, stale_statep is stale */
1635 if (stale_lookup_status == IBCM_LOOKUP_EXISTS) {
1636
1637 IBTF_DPRINTF_L2(cmlog, "ibcm_process_rep_msg: "
1638 "state_qpn 0x%p stale QPN detected "
1639 "state %X", stale_qpn, stale_qpn->state);
1640
1641 ibcm_insert_trace(stale_qpn,
1642 IBCM_TRACE_STALE_DETECT);
1643
1644 mutex_enter(&stale_qpn->state_mutex);
1645 if (stale_qpn->state ==
1646 IBCM_STATE_ESTABLISHED) {
1647 /* change state to DREQ sent */
1648 stale_qpn->state =
1649 IBCM_STATE_TRANSIENT_DREQ_SENT;
1650 stale_qpn->stale = B_TRUE;
1651
1652 /* wait for/cancel pending LAP/APR */
1653 ibcm_sync_lapr_idle(stale_qpn);
1654 /* above call releases state mutex */
1655
1656 if (stale_qpn->dreq_msg == NULL)
1657 (void) ibcm_alloc_out_msg(
1658 stale_qpn->
1659 stored_reply_addr.ibmf_hdl,
1660 &stale_qpn->dreq_msg,
1661 MAD_METHOD_SEND);
1662
1663 if (stale_qpn->dreq_msg != NULL) {
1664 ibcm_post_dreq_mad(stale_qpn);
1665 mutex_enter(
1666 &stale_qpn->state_mutex);
1667 } else {
1668 mutex_enter(
1669 &stale_qpn->state_mutex);
1670 stale_qpn->state =
1671 IBCM_STATE_ESTABLISHED;
1672 cv_broadcast(
1673 &stale_qpn->block_mad_cv);
1674 }
1675 }
1676 IBCM_REF_CNT_DECR(stale_qpn);
1677 mutex_exit(&stale_qpn->state_mutex);
1678 }
1679
1680 if (stale_comid_lookup_status == IBCM_LOOKUP_EXISTS) {
1681
1682 IBTF_DPRINTF_L2(cmlog, "ibcm_process_rep_msg: "
1683 "state_comid 0x%p stale COMID detected "
1684 "state %X", stale_comid,
1685 stale_comid->state);
1686
1687 mutex_enter(&stale_comid->state_mutex);
1688 if (!((stale_lookup_status ==
1689 IBCM_LOOKUP_EXISTS) &&
1690 (stale_qpn == stale_comid)) &&
1691 (stale_comid->state ==
1692 IBCM_STATE_ESTABLISHED)) {
1693
1694 ibcm_insert_trace(stale_comid,
1695 IBCM_TRACE_STALE_DETECT);
1696
1697 /* change state to DREQ sent */
1698 stale_comid->state =
1699 IBCM_STATE_TRANSIENT_DREQ_SENT;
1700 stale_comid->stale = B_TRUE;
1701
1702 /* wait for/cancel pending LAP/APR */
1703 ibcm_sync_lapr_idle(stale_comid);
1704
1705 /* above call releases state mutex */
1706
1707 if (stale_comid->dreq_msg == NULL)
1708 (void) ibcm_alloc_out_msg(
1709 stale_comid->
1710 stored_reply_addr.ibmf_hdl,
1711 &stale_comid->dreq_msg,
1712 MAD_METHOD_SEND);
1713
1714 if (stale_comid->dreq_msg != NULL) {
1715 ibcm_post_dreq_mad(stale_comid);
1716 mutex_enter(
1717 &stale_comid->state_mutex);
1718 } else {
1719 mutex_enter(
1720 &stale_comid->state_mutex);
1721 stale_comid->state =
1722 IBCM_STATE_ESTABLISHED;
1723 cv_broadcast(
1724 &stale_comid->block_mad_cv);
1725 }
1726 }
1727 IBCM_REF_CNT_DECR(stale_comid);
1728 mutex_exit(&stale_comid->state_mutex);
1729 }
1730 ibcm_return_open_data(statep, rep_msgp, reject_reason);
1731 return;
1732 }
1733
1734 /*
1735 * No need to handle out of memory conditions as we called
1736 * ibcm_lookup_msg() with IBT_CHAN_BLOCKING flags.
1737 */
1738 ASSERT(stale_lookup_status == IBCM_LOOKUP_NEW);
1739
1740 /* Initialize the remote ack delay */
1741 statep->remote_ack_delay =
1742 ibt_ib2usec(rep_msgp->rep_target_delay_plus >> 3);
1743
1744 IBTF_DPRINTF_L4(cmlog, "ibcm_process_rep_msg: statep 0x%p"
1745 " passive hca_ack_delay= %x ", statep,
1746 statep->remote_ack_delay);
1747
1748 response = ibcm_cep_state_rep(statep, rep_msgp,
1749 &reject_reason, &arej_info_len);
1750
1751 if (response == IBCM_DEFER) {
1752 IBTF_DPRINTF_L4(cmlog, "ibcm_process_rep_msg: "
1753 "statep 0x%p client returned DEFER response",
1754 statep);
1755 return;
1756 }
1757 ibcm_handle_cep_rep_response(statep, response,
1758 reject_reason, arej_info_len, rep_msgp);
1759
1760 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*statep))
1761
1762 return;
1763
1764 } else if (statep->state == IBCM_STATE_DELETE) {
1765
1766 mutex_exit(&statep->state_mutex);
1767 ibcm_build_n_post_rej_mad(input_madp,
1768 b2h32(rep_msgp->rep_local_comm_id), cm_mad_addr,
1769 IBT_CM_FAILURE_REP, IBT_CM_INVALID_CID);
1770 mutex_enter(&statep->state_mutex);
1771 } else {
1772
1773 #ifdef DEBUG
1774 if (ibcm_test_mode > 0)
1775 if (statep->state == IBCM_STATE_REP_RCVD)
1776 IBTF_DPRINTF_L2(cmlog, "ibcm_process_rep_msg: "
1777 "REP re-send from passive for statep 0x%p"
1778 " in state %d", statep, statep->state);
1779 else
1780 IBTF_DPRINTF_L2(cmlog, "ibcm_process_rep_msg: "
1781 "Unexpected REP for statep 0x%p in "
1782 "state %d", statep, statep->state);
1783 #endif
1784 }
1785 /* decrement ref count and return for LOOKUP_EXISTS */
1786 IBCM_REF_CNT_DECR(statep);
1787 mutex_exit(&statep->state_mutex);
1788
1789 }
1790
1791 /*
1792 * ibcm_handle_cep_req_response:
1793 * Processes the response from ibcm_cep_state_rep. Called holding a
1794 * statep ref cnt. The statep ref cnt is decremented before returning.
1795 */
1796 void
ibcm_handle_cep_rep_response(ibcm_state_data_t * statep,ibcm_status_t response,ibt_cm_reason_t reject_reason,uint8_t arej_info_len,ibcm_rep_msg_t * rep_msgp)1797 ibcm_handle_cep_rep_response(ibcm_state_data_t *statep, ibcm_status_t response,
1798 ibt_cm_reason_t reject_reason, uint8_t arej_info_len,
1799 ibcm_rep_msg_t *rep_msgp)
1800 {
1801 /* wait until the send completion callback is invoked for REQ post */
1802 mutex_enter(&statep->state_mutex);
1803 while (statep->send_mad_flags & IBCM_REQ_POST_BUSY)
1804 cv_wait(&statep->block_mad_cv, &statep->state_mutex);
1805 mutex_exit(&statep->state_mutex);
1806
1807 if (response == IBCM_SEND_RTU) {
1808 /* if connection aborted, return */
1809 if (ibcm_post_rtu_mad(statep) != IBCM_SUCCESS) {
1810 mutex_enter(&statep->state_mutex);
1811 IBCM_REF_CNT_DECR(statep);
1812 mutex_exit(&statep->state_mutex);
1813 return;
1814 }
1815
1816 /*
1817 * Call client handler with cm event IBT_CM_EVENT_CONN_EST to
1818 * indicate RTU posted
1819 */
1820 ibcm_cep_send_rtu(statep);
1821 } else {
1822 IBTF_DPRINTF_L4(cmlog, "ibcm_handle_cep_rep_response: statep %p"
1823 " posting REJ reject_reason = %d", statep, reject_reason);
1824
1825 ASSERT(response == IBCM_SEND_REJ);
1826 ibcm_post_rej_mad(statep, reject_reason, IBT_CM_FAILURE_REP,
1827 NULL, arej_info_len);
1828 }
1829
1830 ibcm_return_open_data(statep, rep_msgp, reject_reason);
1831 }
1832
1833 /*
1834 * ibcm_return_open_data:
1835 * Initializes the ibt_open_rc_channel return data. The statep ref cnt is
1836 * decremented before returning.
1837 */
1838 static void
ibcm_return_open_data(ibcm_state_data_t * statep,ibcm_rep_msg_t * rep_msgp,ibt_cm_reason_t reject_reason)1839 ibcm_return_open_data(ibcm_state_data_t *statep, ibcm_rep_msg_t *rep_msgp,
1840 ibt_cm_reason_t reject_reason)
1841 {
1842 /* signal waiting CV - blocking in ibt_open_channel() */
1843 if (statep->open_return_data != NULL) {
1844 if (statep->open_return_data->rc_priv_data_len > 0)
1845 bcopy(rep_msgp->rep_private_data,
1846 statep->open_return_data->rc_priv_data,
1847 statep->open_return_data->rc_priv_data_len);
1848 statep->open_return_data->rc_rdma_ra_in =
1849 rep_msgp->rep_initiator_depth;
1850 statep->open_return_data->rc_rdma_ra_out =
1851 rep_msgp->rep_resp_resources;
1852 statep->open_return_data->rc_failover_status =
1853 rep_msgp->rep_target_delay_plus >> 1 & 3;
1854 statep->open_return_data->rc_status = reject_reason;
1855
1856 mutex_enter(&statep->state_mutex);
1857 statep->open_done = B_TRUE;
1858 cv_broadcast(&statep->block_client_cv);
1859 } else mutex_enter(&statep->state_mutex);
1860
1861 /* decrement ref count and return for LOOKUP_EXISTS */
1862 IBCM_REF_CNT_DECR(statep);
1863 mutex_exit(&statep->state_mutex);
1864 }
1865
1866
1867 /*
1868 * ibcm_process_mra_msg:
1869 * Called from ibcm_process_incoming_mad on reception of a MRA message
1870 *
1871 * Cancels existing timer, and sets a new timer based on timeout
1872 * value from MRA message. The remaining retry count of statep is
1873 * not changed, and timer value for the remaining retry timers is
1874 * also not changed
1875 *
1876 * INPUTS:
1877 * hcap - HCA entry pointer
1878 * input_madp - CM MAD that is input to this function
1879 * cm_mad_addr - Address information for the MAD
1880 *
1881 * RETURN VALUE: NONE
1882 */
1883 void
ibcm_process_mra_msg(ibcm_hca_info_t * hcap,uint8_t * input_madp,ibcm_mad_addr_t * cm_mad_addr)1884 ibcm_process_mra_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
1885 ibcm_mad_addr_t *cm_mad_addr)
1886 {
1887 ibcm_status_t state_lookup_status;
1888 ibcm_mra_msg_t *mra_msgp =
1889 (ibcm_mra_msg_t *)(&input_madp[IBCM_MAD_HDR_SIZE]);
1890 ibcm_state_data_t *statep = NULL;
1891 uint8_t mra_msg;
1892
1893 IBTF_DPRINTF_L4(cmlog, "ibcm_process_mra_msg:");
1894
1895 /* Lookup for an existing state structure (as a READER) */
1896 rw_enter(&hcap->hca_state_rwlock, RW_READER);
1897 state_lookup_status = ibcm_lookup_msg(IBCM_INCOMING_MRA,
1898 b2h32(mra_msgp->mra_remote_comm_id), 0, 0, hcap, &statep);
1899 rw_exit(&hcap->hca_state_rwlock);
1900
1901 /* if state doesn't exist just return */
1902 if (state_lookup_status != IBCM_LOOKUP_EXISTS) {
1903 ibcm_build_n_post_rej_mad(input_madp,
1904 b2h32(mra_msgp->mra_local_comm_id), cm_mad_addr,
1905 IBT_CM_FAILURE_UNKNOWN, IBT_CM_INVALID_CID);
1906 return;
1907 }
1908
1909 if (IBCM_OUT_HDRP(statep->stored_msg)->TransactionID !=
1910 ((ib_mad_hdr_t *)(input_madp))->TransactionID) {
1911 mutex_enter(&statep->state_mutex);
1912 IBCM_REF_CNT_DECR(statep);
1913 mutex_exit(&statep->state_mutex);
1914 IBTF_DPRINTF_L3(cmlog, "ibcm_process_mra_msg: statep 0x%p "
1915 "MRA MAD with tid expected 0x%llX tid found 0x%llX "
1916 "com id 0x%x arrived", statep,
1917 b2h64(IBCM_OUT_HDRP(statep->stored_msg)->TransactionID),
1918 b2h64(((ib_mad_hdr_t *)(input_madp))->TransactionID),
1919 b2h32(mra_msgp->mra_local_comm_id));
1920 return;
1921 }
1922
1923 ibcm_insert_trace(statep, IBCM_TRACE_INCOMING_MRA);
1924
1925 mutex_enter(&statep->state_mutex);
1926
1927 /*
1928 * Only allow for REQ/REP "mra_msg_typ" ONLY
1929 * (to validate MRA message received)?
1930 */
1931 mra_msg = mra_msgp->mra_message_type_plus >> 6;
1932 if ((mra_msg != IBT_CM_MRA_TYPE_REQ) &&
1933 (mra_msg != IBT_CM_MRA_TYPE_REP) &&
1934 (mra_msg != IBT_CM_MRA_TYPE_LAP)) {
1935
1936 IBTF_DPRINTF_L2(cmlog, "ibcm_process_mra_msg: statep 0x%p "
1937 "Unexpected MRA MSG Type %x", statep, mra_msg);
1938 IBCM_REF_CNT_DECR(statep);
1939 mutex_exit(&statep->state_mutex);
1940 return;
1941 }
1942
1943 if ((statep->state == IBCM_STATE_REQ_SENT) ||
1944 (statep->state == IBCM_STATE_REP_SENT) ||
1945 ((statep->state == IBCM_STATE_ESTABLISHED) &&
1946 (statep->ap_state == IBCM_AP_STATE_LAP_SENT))) {
1947 timeout_id_t timer_val = statep->timerid;
1948 clock_t service_timeout;
1949
1950 if (statep->state == IBCM_STATE_REQ_SENT) {
1951 mra_msg = IBT_CM_MRA_TYPE_REQ;
1952 statep->state = IBCM_STATE_REP_WAIT;
1953 } else if (statep->state == IBCM_STATE_REP_SENT) {
1954 mra_msg = IBT_CM_MRA_TYPE_REP;
1955 statep->state = IBCM_STATE_MRA_REP_RCVD;
1956 } else { /* statep->state == IBCM_STATE_LAP_SENT */
1957 mra_msg = IBT_CM_MRA_TYPE_LAP;
1958 statep->ap_state = IBCM_AP_STATE_MRA_LAP_RCVD;
1959 }
1960
1961 /* cancel the timer */
1962 statep->timerid = 0;
1963 mutex_exit(&statep->state_mutex);
1964
1965 (void) untimeout(timer_val);
1966
1967 service_timeout =
1968 ibt_ib2usec(mra_msgp->mra_service_timeout_plus >> 3);
1969
1970 /*
1971 * If tunable MAX MRA Service Timeout parameter is set, then
1972 * verify whether the requested timer value exceeds the MAX
1973 * value and reset the timer value to the MAX value.
1974 */
1975 if (ibcm_mra_service_timeout_max &&
1976 ibcm_mra_service_timeout_max < service_timeout) {
1977 IBTF_DPRINTF_L2(cmlog, "ibcm_process_mra_msg: "
1978 "Unexpected MRA Service Timeout value (%ld), Max "
1979 "allowed is (%ld)", service_timeout,
1980 ibcm_mra_service_timeout_max);
1981 service_timeout = ibcm_mra_service_timeout_max;
1982 }
1983
1984 /*
1985 * Invoke client handler to pass the MRA private data
1986 */
1987 if (statep->cm_handler != NULL) {
1988 ibt_cm_event_t event;
1989
1990 bzero(&event, sizeof (event));
1991
1992 event.cm_type = IBT_CM_EVENT_MRA_RCV;
1993 event.cm_channel = statep->channel;
1994 event.cm_session_id = NULL;
1995 event.cm_priv_data = mra_msgp->mra_private_data;
1996 event.cm_priv_data_len = IBT_MRA_PRIV_DATA_SZ;
1997
1998 event.cm_event.mra.mra_msg_type = mra_msg;
1999
2000 event.cm_event.mra.mra_service_time = service_timeout;
2001
2002 /* Client cannot return private data */
2003 (void) statep->cm_handler(statep->state_cm_private,
2004 &event, NULL, NULL, 0);
2005 }
2006
2007 /*
2008 * Must re-check state, as an RTU could have come
2009 * after the above mutex_exit and mutex_enter below
2010 */
2011 mutex_enter(&statep->state_mutex);
2012 if ((statep->state == IBCM_STATE_REP_WAIT) ||
2013 (statep->state == IBCM_STATE_MRA_REP_RCVD) ||
2014 (statep->ap_state == IBCM_AP_STATE_MRA_LAP_RCVD)) {
2015
2016 statep->remaining_retry_cnt = statep->max_cm_retries;
2017
2018 /*
2019 * The timeout interval is changed only for the first
2020 * retry. The later retries use the timeout from
2021 * statep->timer_value
2022 */
2023 statep->timer_stored_state = statep->state;
2024 statep->timer_value = statep->pkt_life_time +
2025 service_timeout;
2026 statep->timerid = IBCM_TIMEOUT(statep,
2027 statep->timer_value);
2028 }
2029
2030 } else if (statep->state == IBCM_STATE_DELETE) {
2031
2032 mutex_exit(&statep->state_mutex);
2033 ibcm_build_n_post_rej_mad(input_madp,
2034 b2h32(mra_msgp->mra_local_comm_id), cm_mad_addr,
2035 IBT_CM_FAILURE_UNKNOWN, IBT_CM_INVALID_CID);
2036 mutex_enter(&statep->state_mutex);
2037 } else {
2038
2039 #ifdef DEBUG
2040 if (ibcm_test_mode > 0)
2041 IBTF_DPRINTF_L2(cmlog, "ibcm_process_mra_msg: "
2042 "Unexpected mra for statep 0x%p in state %d",
2043 statep, statep->state);
2044 #endif
2045 }
2046
2047 IBCM_REF_CNT_DECR(statep);
2048 mutex_exit(&statep->state_mutex);
2049 }
2050
2051
2052 /*
2053 * ibcm_process_rtu_msg:
2054 * Called from ibcm_process_incoming_mad on reception of a RTU message
2055 *
2056 * Changes connection state to established if in REP SENT state
2057 *
2058 * INPUTS:
2059 * hcap - HCA entry pointer
2060 * input_madp - CM MAD that is input to this function
2061 * cm_mad_addr - Address information for the MAD
2062 *
2063 * RETURN VALUE: NONE
2064 */
2065 void
ibcm_process_rtu_msg(ibcm_hca_info_t * hcap,uint8_t * input_madp,ibcm_mad_addr_t * cm_mad_addr)2066 ibcm_process_rtu_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
2067 ibcm_mad_addr_t *cm_mad_addr)
2068 {
2069 timeout_id_t timer_val;
2070 ibcm_status_t status;
2071 ibcm_rtu_msg_t *rtu_msg =
2072 (ibcm_rtu_msg_t *)(&input_madp[IBCM_MAD_HDR_SIZE]);
2073 ibcm_state_data_t *statep = NULL;
2074
2075 IBTF_DPRINTF_L4(cmlog, "ibcm_process_rtu_msg:");
2076
2077 /* Lookup for an existing state structure - using a reader lock */
2078 rw_enter(&hcap->hca_state_rwlock, RW_READER);
2079 status = ibcm_lookup_msg(IBCM_INCOMING_RTU,
2080 b2h32(rtu_msg->rtu_remote_comm_id), 0, 0, hcap, &statep);
2081 rw_exit(&hcap->hca_state_rwlock);
2082
2083 /* if state doesn't exist just return */
2084 if (status != IBCM_LOOKUP_EXISTS) {
2085 ibcm_build_n_post_rej_mad(input_madp,
2086 b2h32(rtu_msg->rtu_local_comm_id), cm_mad_addr,
2087 IBT_CM_FAILURE_UNKNOWN, IBT_CM_INVALID_CID);
2088 return;
2089 }
2090
2091 if (IBCM_OUT_HDRP(statep->stored_msg)->TransactionID !=
2092 ((ib_mad_hdr_t *)(input_madp))->TransactionID) {
2093 mutex_enter(&statep->state_mutex);
2094 IBCM_REF_CNT_DECR(statep);
2095 mutex_exit(&statep->state_mutex);
2096 IBTF_DPRINTF_L3(cmlog, "ibcm_process_rtu_msg: statep 0x%p "
2097 "An RTU MAD with tid expected 0x%llX tid found 0x%llX "
2098 "com id 0x%x arrived", statep,
2099 b2h64(IBCM_OUT_HDRP(statep->stored_msg)->TransactionID),
2100 b2h64(((ib_mad_hdr_t *)(input_madp))->TransactionID),
2101 b2h32(rtu_msg->rtu_remote_comm_id));
2102 return;
2103 }
2104
2105 ibcm_insert_trace(statep, IBCM_TRACE_INCOMING_RTU);
2106
2107 mutex_enter(&statep->state_mutex);
2108
2109 if ((statep->state == IBCM_STATE_REP_SENT) ||
2110 (statep->state == IBCM_STATE_MRA_REP_RCVD)) {
2111
2112 /* transient until ibt_modify_qp succeeds to RTS */
2113 statep->state = IBCM_STATE_TRANSIENT_ESTABLISHED;
2114
2115 timer_val = statep->timerid;
2116 statep->timerid = 0;
2117 mutex_exit(&statep->state_mutex);
2118
2119 (void) untimeout(timer_val);
2120
2121 ibcm_cep_state_rtu(statep, rtu_msg);
2122
2123 mutex_enter(&statep->state_mutex);
2124
2125 } else if (statep->state == IBCM_STATE_REJ_SENT) {
2126 ibcm_resend_rej_mad(statep);
2127 } else if (statep->state == IBCM_STATE_DELETE) {
2128
2129 mutex_exit(&statep->state_mutex);
2130 ibcm_build_n_post_rej_mad(input_madp,
2131 b2h32(rtu_msg->rtu_local_comm_id), cm_mad_addr,
2132 IBT_CM_FAILURE_UNKNOWN, IBT_CM_INVALID_CID);
2133 mutex_enter(&statep->state_mutex);
2134 } else {
2135
2136 #ifdef DEBUG
2137 if ((ibcm_test_mode > 0) &&
2138 (statep->state != IBCM_STATE_ESTABLISHED))
2139 IBTF_DPRINTF_L2(cmlog, "ibcm_process_rtu_msg: "
2140 "Unexpected rtu for statep 0x%p in state %d",
2141 statep, statep->state);
2142 #endif
2143 }
2144
2145 IBCM_REF_CNT_DECR(statep);
2146 mutex_exit(&statep->state_mutex);
2147 }
2148
2149
2150 /*
2151 * ibcm_process_rej_msg:
2152 * Called from ibcm_process_incoming_mad on reception of a REJ message.
2153 *
2154 * INPUTS:
2155 * hcap - HCA entry pointer
2156 * input_madp - CM MAD that is input to this function
2157 * cm_mad_addr - Address information for the MAD
2158 *
2159 * RETURN VALUE: NONE
2160 */
2161 /* ARGSUSED */
2162 void
ibcm_process_rej_msg(ibcm_hca_info_t * hcap,uint8_t * input_madp,ibcm_mad_addr_t * cm_mad_addr)2163 ibcm_process_rej_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
2164 ibcm_mad_addr_t *cm_mad_addr)
2165 {
2166 ibcm_status_t state_lookup_status;
2167 ibcm_rej_msg_t *rej_msg =
2168 (ibcm_rej_msg_t *)(&input_madp[IBCM_MAD_HDR_SIZE]);
2169 ibcm_state_data_t *statep = NULL;
2170 ib_guid_t remote_hca_guid;
2171 ibcm_conn_state_t rej_state;
2172
2173 IBTF_DPRINTF_L4(cmlog, "ibcm_process_rej_msg:");
2174
2175 /* Lookup for an existing state structure */
2176 rw_enter(&hcap->hca_state_rwlock, RW_READER); /* grab READER lock */
2177
2178 if ((b2h32(rej_msg->rej_remote_comm_id) == 0) &&
2179 ((rej_msg->rej_reject_info_len_plus >> 1) >= sizeof (ib_guid_t)) &&
2180 (b2h16(rej_msg->rej_rejection_reason) == IBT_CM_TIMEOUT)) {
2181 bcopy(rej_msg->rej_addl_rej_info, &remote_hca_guid,
2182 sizeof (ib_guid_t));
2183 remote_hca_guid = b2h64(remote_hca_guid);
2184
2185 IBTF_DPRINTF_L4(cmlog, "ibcm_process_rej_msg: "
2186 "hca guid in REJ's ARI = %llX", remote_hca_guid);
2187
2188 state_lookup_status = ibcm_lookup_msg(IBCM_INCOMING_REJ_RCOMID,
2189 b2h32(rej_msg->rej_local_comm_id), 0, remote_hca_guid,
2190 hcap, &statep);
2191 } else
2192 state_lookup_status = ibcm_lookup_msg(IBCM_INCOMING_REJ,
2193 b2h32(rej_msg->rej_remote_comm_id), 0, 0, hcap, &statep);
2194
2195 rw_exit(&hcap->hca_state_rwlock);
2196
2197
2198 /* if state doesn't exist just return */
2199 if (state_lookup_status != IBCM_LOOKUP_EXISTS) {
2200
2201 IBTF_DPRINTF_L2(cmlog, "ibcm_process_rej_msg: no statep with "
2202 "local com id %x remote com id %x reason %d",
2203 b2h32(rej_msg->rej_remote_comm_id),
2204 b2h32(rej_msg->rej_local_comm_id),
2205 b2h16(rej_msg->rej_rejection_reason));
2206
2207 /* Do NOT respond with invalid comid REJ */
2208 return;
2209 }
2210
2211 IBTF_DPRINTF_L2(cmlog, "ibcm_process_rej_msg: statep 0x%p INCOMING_REJ",
2212 statep);
2213 ibcm_insert_trace(statep, IBCM_TRACE_INCOMING_REJ);
2214 if (ibcm_enable_trace & 2)
2215 ibcm_dump_conn_trace(statep);
2216
2217 mutex_enter(&statep->state_mutex);
2218
2219 rej_state = statep->state;
2220
2221 if ((statep->state == IBCM_STATE_REP_SENT) ||
2222 (statep->state == IBCM_STATE_REQ_SENT) ||
2223 (statep->state == IBCM_STATE_REP_WAIT) ||
2224 (statep->state == IBCM_STATE_MRA_REP_RCVD)) {
2225 timeout_id_t timer_val = statep->timerid;
2226
2227 statep->state = IBCM_STATE_DELETE;
2228
2229 /* cancel the REQ/REP timer */
2230 if (timer_val != 0) {
2231 statep->timerid = 0;
2232 mutex_exit(&statep->state_mutex);
2233
2234 (void) untimeout(timer_val);
2235 } else {
2236 mutex_exit(&statep->state_mutex);
2237 }
2238
2239 /*
2240 * Call the QP state transition processing function
2241 * NOTE: Input MAD is the REJ received, there is no output MAD
2242 */
2243 ibcm_cep_state_rej(statep, rej_msg, rej_state);
2244
2245 /* signal waiting CV - blocking in ibt_open_channel() */
2246 if (statep->open_return_data != NULL) {
2247 statep->open_return_data->rc_status =
2248 b2h16(rej_msg->rej_rejection_reason);
2249
2250 if (statep->open_return_data->rc_priv_data_len > 0)
2251 bcopy(rej_msg->rej_private_data,
2252 statep->open_return_data->rc_priv_data,
2253 min(
2254 statep->open_return_data->rc_priv_data_len,
2255 IBT_REJ_PRIV_DATA_SZ));
2256 mutex_enter(&statep->state_mutex);
2257 statep->open_done = B_TRUE;
2258 cv_broadcast(&statep->block_client_cv);
2259 } else {
2260 mutex_enter(&statep->state_mutex);
2261 }
2262
2263 IBCM_REF_CNT_DECR(statep);
2264 mutex_exit(&statep->state_mutex);
2265
2266 /* Now delete the statep */
2267 ibcm_delete_state_data(statep);
2268
2269 } else if ((statep->state == IBCM_STATE_ESTABLISHED) &&
2270 (statep->mode == IBCM_ACTIVE_MODE)) {
2271
2272 IBTF_DPRINTF_L4(cmlog, "ibcm_process_rej_msg: statep 0x%p "
2273 "REJ in established state", statep);
2274
2275 statep->state = IBCM_STATE_TIMEWAIT;
2276
2277 /* wait for/cancel pending LAP/APR, release state mutex */
2278 ibcm_sync_lapr_idle(statep);
2279
2280 /* wait until client is informed CONN EST event */
2281 mutex_enter(&statep->state_mutex);
2282 while (statep->cep_in_rts == IBCM_BLOCK)
2283 cv_wait(&statep->block_mad_cv, &statep->state_mutex);
2284 mutex_exit(&statep->state_mutex);
2285
2286 /*
2287 * Call the QP state transition processing function
2288 * NOTE: Input MAD is the REJ received, there is no output MAD
2289 */
2290 ibcm_cep_state_rej_est(statep);
2291
2292 /*
2293 * Start the timewait state timer, as connection is in
2294 * established state
2295 */
2296
2297 /*
2298 * For passive side CM set it to remote_ack_delay
2299 * For active side CM add the pkt_life_time * 2
2300 */
2301 mutex_enter(&statep->state_mutex);
2302 statep->timer_value = statep->remote_ack_delay;
2303 /* statep->mode == IBCM_ACTIVE_MODE) */
2304 statep->timer_value += (2 * statep->pkt_life_time);
2305
2306 statep->remaining_retry_cnt = 0;
2307 statep->timer_stored_state = statep->state;
2308
2309 statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
2310
2311 IBCM_REF_CNT_DECR(statep);
2312 mutex_exit(&statep->state_mutex);
2313
2314 } else if (((statep->state == IBCM_STATE_REQ_RCVD) ||
2315 (statep->state == IBCM_STATE_REP_RCVD) ||
2316 (statep->state == IBCM_STATE_MRA_SENT) ||
2317 (statep->state == IBCM_STATE_MRA_REP_SENT)) &&
2318 (b2h16(rej_msg->rej_rejection_reason) == IBT_CM_TIMEOUT)) {
2319
2320 if (statep->abort_flag == IBCM_ABORT_INIT)
2321 statep->abort_flag = IBCM_ABORT_REJ;
2322
2323 IBCM_REF_CNT_DECR(statep);
2324 mutex_exit(&statep->state_mutex);
2325 } else {
2326
2327 #ifdef DEBUG
2328 if ((ibcm_test_mode > 0) &&
2329 (statep->state != IBCM_STATE_DELETE))
2330 IBTF_DPRINTF_L2(cmlog, "ibcm_process_rej_msg: "
2331 "Unexpected rej for statep 0x%p in state %d",
2332 statep, statep->state);
2333 #endif
2334 IBCM_REF_CNT_DECR(statep);
2335 mutex_exit(&statep->state_mutex);
2336 }
2337 }
2338
2339
2340 /*
2341 * ibcm_process_dreq_msg:
2342 * Processes incoming DREQ message on active/passive side
2343 *
2344 * INPUTS:
2345 * hcap - HCA entry pointer
2346 * input_madp - CM MAD that is input to this function
2347 * cm_mad_addr - Address information for the MAD
2348 *
2349 * RETURN VALUE: NONE
2350 */
2351 /*ARGSUSED*/
2352 void
ibcm_process_dreq_msg(ibcm_hca_info_t * hcap,uint8_t * input_madp,ibcm_mad_addr_t * cm_mad_addr)2353 ibcm_process_dreq_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
2354 ibcm_mad_addr_t *cm_mad_addr)
2355 {
2356 void *priv_data = NULL;
2357 ibcm_status_t state_lookup_status;
2358 ib_qpn_t local_qpn;
2359 ibcm_dreq_msg_t *dreq_msgp =
2360 (ibcm_dreq_msg_t *)(&input_madp[IBCM_MAD_HDR_SIZE]);
2361 ibcm_state_data_t *statep = NULL;
2362 uint8_t close_event_type;
2363 ibt_cm_status_t cb_status;
2364
2365 IBTF_DPRINTF_L4(cmlog, "ibcm_process_dreq_msg:");
2366
2367 /* Lookup for an existing state structure */
2368 rw_enter(&hcap->hca_state_rwlock, RW_READER);
2369
2370 state_lookup_status = ibcm_lookup_msg(IBCM_INCOMING_DREQ,
2371 b2h32(dreq_msgp->dreq_remote_comm_id), 0, 0, hcap, &statep);
2372 rw_exit(&hcap->hca_state_rwlock);
2373
2374 local_qpn = b2h32(dreq_msgp->dreq_remote_qpn_eecn_plus) >> 8;
2375
2376 if (state_lookup_status != IBCM_LOOKUP_EXISTS) {
2377 IBTF_DPRINTF_L3(cmlog, "ibcm_process_dreq_msg: no statep with"
2378 "com id %x", b2h32(dreq_msgp->dreq_remote_comm_id));
2379 /* implies a bogus message */
2380 return;
2381 }
2382
2383 IBTF_DPRINTF_L4(cmlog, "ibcm_process_dreq_msg: statep 0x%p "
2384 "lookup status %x dreq qpn = %x", statep, state_lookup_status,
2385 local_qpn);
2386
2387 /*
2388 * Local QPN check is necessary. There could be a DREQ from
2389 * a remote stale connection processing with the same com id, but
2390 * not intended for this statep
2391 */
2392 mutex_enter(&statep->state_mutex);
2393 if ((statep->local_qpn != local_qpn) ||
2394 (statep->remote_comid != b2h32(dreq_msgp->dreq_local_comm_id))) {
2395
2396 IBTF_DPRINTF_L3(cmlog, "ibcm_process_dreq_msg:"
2397 "statep->local_qpn = %x qpn in dreq = %x"
2398 "statep->remote_comid = %x local comid in dreq = %x",
2399 statep->local_qpn, local_qpn, statep->remote_comid,
2400 b2h32(dreq_msgp->dreq_local_comm_id));
2401
2402 IBCM_REF_CNT_DECR(statep);
2403 mutex_exit(&statep->state_mutex);
2404 return;
2405 }
2406 /*
2407 * If another thread is processing a copy of this same DREQ,
2408 * bail out here.
2409 */
2410 if (statep->state == IBCM_STATE_TRANSIENT_DREQ_SENT ||
2411 statep->drep_in_progress) {
2412 IBCM_REF_CNT_DECR(statep);
2413 mutex_exit(&statep->state_mutex);
2414 return;
2415 }
2416 switch (statep->state) {
2417 case IBCM_STATE_ESTABLISHED:
2418 case IBCM_STATE_DREQ_SENT:
2419 case IBCM_STATE_TIMEWAIT:
2420 break;
2421 default:
2422 /* All other states ignore DREQ */
2423 IBCM_REF_CNT_DECR(statep);
2424 mutex_exit(&statep->state_mutex);
2425 return;
2426 }
2427 statep->drep_in_progress = 1;
2428
2429 /*
2430 * If drep msg wasn't really required, it shall be deleted finally
2431 * when statep goes away
2432 */
2433 if (statep->drep_msg == NULL) {
2434 mutex_exit(&statep->state_mutex);
2435 if (ibcm_alloc_out_msg(statep->stored_reply_addr.ibmf_hdl,
2436 &statep->drep_msg, MAD_METHOD_SEND) != IBT_SUCCESS) {
2437 IBTF_DPRINTF_L2(cmlog, "ibcm_process_dreq_msg: "
2438 "statep 0x%p ibcm_alloc_out_msg failed", statep);
2439 mutex_enter(&statep->state_mutex);
2440 statep->drep_in_progress = 0;
2441 IBCM_REF_CNT_DECR(statep);
2442 mutex_exit(&statep->state_mutex);
2443 return;
2444 }
2445 mutex_enter(&statep->state_mutex);
2446 }
2447
2448 if (statep->state == IBCM_STATE_TRANSIENT_DREQ_SENT) {
2449 IBCM_REF_CNT_DECR(statep);
2450 statep->drep_in_progress = 0;
2451 mutex_exit(&statep->state_mutex);
2452 return;
2453 }
2454
2455 /*
2456 * Need to generate drep, as time wait can be reached either by an
2457 * outgoing dreq or an incoming dreq
2458 */
2459 if ((statep->state == IBCM_STATE_ESTABLISHED) ||
2460 (statep->state == IBCM_STATE_DREQ_SENT)) {
2461 timeout_id_t timer_val = statep->timerid;
2462
2463 if (statep->state == IBCM_STATE_DREQ_SENT) {
2464 statep->state = IBCM_STATE_DREQ_RCVD;
2465 statep->timerid = 0;
2466 ibcm_close_done(statep, 0);
2467 mutex_exit(&statep->state_mutex);
2468
2469 close_event_type = IBT_CM_CLOSED_DUP;
2470 if (timer_val != 0) {
2471 /* Cancel the timer set for DREP reception */
2472 (void) untimeout(timer_val);
2473 }
2474 } else { /* In ESTABLISHED State */
2475 boolean_t is_ofuv = statep->is_this_ofuv_chan;
2476
2477 statep->state = IBCM_STATE_DREQ_RCVD;
2478 statep->clnt_proceed = IBCM_BLOCK;
2479
2480 /* Cancel or wait for LAP/APR to complete */
2481 ibcm_sync_lapr_idle(statep);
2482 /* The above function releases the state mutex */
2483
2484 /* wait until client knows CONN EST event */
2485 mutex_enter(&statep->state_mutex);
2486 while (statep->cep_in_rts == IBCM_BLOCK)
2487 cv_wait(&statep->block_mad_cv,
2488 &statep->state_mutex);
2489 mutex_exit(&statep->state_mutex);
2490
2491 close_event_type = IBT_CM_CLOSED_DREQ_RCVD;
2492 /* Move CEP to error state */
2493 if (is_ofuv == B_FALSE) /* Skip for OFUV channel */
2494 (void) ibcm_cep_to_error_state(statep);
2495 }
2496 mutex_enter(&statep->state_mutex);
2497 statep->drep_in_progress = 0;
2498
2499 IBCM_OUT_HDRP(statep->drep_msg)->TransactionID =
2500 ((ib_mad_hdr_t *)(input_madp))->TransactionID;
2501
2502 priv_data = &(((ibcm_drep_msg_t *)
2503 IBCM_OUT_MSGP(statep->drep_msg))->drep_private_data[0]);
2504
2505 if (statep->close_ret_status)
2506 *statep->close_ret_status = close_event_type;
2507
2508 if (statep->close_nocb_state != IBCM_FAIL) {
2509 ibtl_cm_chan_is_closing(statep->channel);
2510 statep->close_nocb_state = IBCM_BLOCK;
2511 }
2512 mutex_exit(&statep->state_mutex);
2513
2514 /*
2515 * if close_nocb_state is IBCM_FAIL, then cm_handler is NULL
2516 * if close_nocb_state is IBCM_BLOCK, client cannot go away
2517 */
2518 if (statep->cm_handler != NULL) {
2519 ibt_cm_event_t event;
2520 ibt_cm_return_args_t ret_args;
2521
2522 bzero(&event, sizeof (event));
2523 bzero(&ret_args, sizeof (ret_args));
2524
2525 event.cm_type = IBT_CM_EVENT_CONN_CLOSED;
2526 event.cm_channel = statep->channel;
2527 event.cm_session_id = statep;
2528 event.cm_priv_data = dreq_msgp->dreq_private_data;
2529 event.cm_priv_data_len = IBT_DREQ_PRIV_DATA_SZ;
2530 event.cm_event.closed = close_event_type;
2531
2532 ibcm_insert_trace(statep,
2533 IBCM_TRACE_CALLED_CONN_CLOSE_EVENT);
2534
2535 cb_status = statep->cm_handler(statep->state_cm_private,
2536 &event, &ret_args, priv_data,
2537 IBT_DREP_PRIV_DATA_SZ);
2538
2539 ibcm_insert_trace(statep,
2540 IBCM_TRACE_RET_CONN_CLOSE_EVENT);
2541
2542 if (cb_status == IBT_CM_DEFER) {
2543 mutex_enter(&statep->state_mutex);
2544 statep->clnt_proceed =
2545 IBCM_UNBLOCK;
2546 cv_broadcast(&statep->block_client_cv);
2547 mutex_exit(&statep->state_mutex);
2548
2549 IBTF_DPRINTF_L4(cmlog, "ibcm_process_dreq_msg:"
2550 " statep 0x%p client returned DEFER "
2551 "response", statep);
2552 return;
2553 }
2554 }
2555
2556 /* fail/resume any blocked cm api call */
2557 mutex_enter(&statep->state_mutex);
2558
2559 /* Signal for cm proceed api */
2560 statep->clnt_proceed = IBCM_FAIL;
2561
2562 /* Signal for close with no callbacks */
2563 statep->close_nocb_state = IBCM_FAIL;
2564
2565 /* Signal any waiting close channel thread */
2566 statep->close_done = B_TRUE;
2567
2568 cv_broadcast(&statep->block_client_cv);
2569 mutex_exit(&statep->state_mutex);
2570
2571 ibcm_handle_cep_dreq_response(statep, NULL, 0);
2572
2573 } else if (statep->state == IBCM_STATE_TIMEWAIT) {
2574 statep->drep_in_progress = 0;
2575 if (statep->send_mad_flags & IBCM_DREP_POST_BUSY) {
2576 IBCM_REF_CNT_DECR(statep);
2577 mutex_exit(&statep->state_mutex);
2578 return;
2579 }
2580 statep->send_mad_flags |= IBCM_DREP_POST_BUSY;
2581
2582 /* Release statep mutex before posting the MAD */
2583 mutex_exit(&statep->state_mutex);
2584
2585 IBCM_OUT_HDRP(statep->drep_msg)->TransactionID =
2586 ((ib_mad_hdr_t *)(input_madp))->TransactionID;
2587
2588 ibcm_post_drep_mad(statep);
2589 /* ref cnt decremented in ibcm_post_drep_complete */
2590 } else {
2591 #ifdef DEBUG
2592 if ((ibcm_test_mode > 0) &&
2593 (statep->state != IBCM_STATE_DELETE))
2594 IBTF_DPRINTF_L2(cmlog, "ibcm_process_dreq_msg: "
2595 "Unexpected dreq for statep 0x%p in state %d",
2596 statep, statep->state);
2597 #endif
2598 IBCM_REF_CNT_DECR(statep);
2599 statep->drep_in_progress = 0;
2600 mutex_exit(&statep->state_mutex);
2601 }
2602 }
2603
2604 /*
2605 * ibcm_handle_cep_dreq_response:
2606 * Processes the response from client handler for an incoming DREQ.
2607 * The statep ref cnt is decremented before returning.
2608 */
2609 void
ibcm_handle_cep_dreq_response(ibcm_state_data_t * statep,void * priv_data,ibt_priv_data_len_t priv_data_len)2610 ibcm_handle_cep_dreq_response(ibcm_state_data_t *statep, void *priv_data,
2611 ibt_priv_data_len_t priv_data_len)
2612 {
2613 if ((priv_data != NULL) && (priv_data_len > 0))
2614 bcopy(priv_data,
2615 &(((ibcm_drep_msg_t *)
2616 IBCM_OUT_MSGP(statep->drep_msg))->drep_private_data[0]),
2617 min(priv_data_len, IBT_DREP_PRIV_DATA_SZ));
2618
2619 ibcm_post_drep_mad(statep);
2620 }
2621
2622
2623 /*
2624 * ibcm_post_dreq_mad:
2625 * Posts a DREQ MAD
2626 * Post DREQ now for TIMEWAIT state and DREQ_RCVD
2627 *
2628 * INPUTS:
2629 * statep - state pointer
2630 *
2631 * RETURN VALUE:
2632 * NONE
2633 */
2634 void
ibcm_post_dreq_mad(void * vstatep)2635 ibcm_post_dreq_mad(void *vstatep)
2636 {
2637 ibcm_state_data_t *statep = vstatep;
2638 ibcm_dreq_msg_t *dreq_msgp;
2639
2640 ASSERT(statep->dreq_msg != NULL);
2641
2642 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dreq_msgp))
2643
2644 /* Fill in the DREQ message */
2645 dreq_msgp = (ibcm_dreq_msg_t *)IBCM_OUT_MSGP(statep->dreq_msg);
2646 dreq_msgp->dreq_local_comm_id = h2b32(statep->local_comid);
2647 dreq_msgp->dreq_remote_comm_id = h2b32(statep->remote_comid);
2648 dreq_msgp->dreq_remote_qpn_eecn_plus = h2b32(statep->remote_qpn << 8);
2649
2650 IBCM_OUT_HDRP(statep->dreq_msg)->AttributeID =
2651 h2b16(IBCM_INCOMING_DREQ + IBCM_ATTR_BASE_ID);
2652
2653 /* wait until client knows CONN EST event */
2654 mutex_enter(&statep->state_mutex);
2655 while (statep->cep_in_rts == IBCM_BLOCK)
2656 cv_wait(&statep->block_mad_cv, &statep->state_mutex);
2657 mutex_exit(&statep->state_mutex);
2658
2659 /* Transition QP/EEC state to ERROR state */
2660 (void) ibcm_cep_to_error_state(statep);
2661
2662 IBCM_OUT_HDRP(statep->dreq_msg)->TransactionID =
2663 h2b64(ibcm_generate_tranid(IBCM_INCOMING_DREQ, statep->local_comid,
2664 0));
2665
2666 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*dreq_msgp))
2667
2668 /* post the first DREQ via timeout callback */
2669 mutex_enter(&statep->state_mutex);
2670
2671 statep->state = IBCM_STATE_DREQ_SENT;
2672 cv_broadcast(&statep->block_mad_cv);
2673
2674 statep->timer_stored_state = statep->state;
2675 /* client cannot specify more than 16 retries */
2676 statep->timer_value = statep->remote_ack_delay;
2677 if (statep->mode == IBCM_ACTIVE_MODE) {
2678 statep->timer_value += (2 * statep->pkt_life_time);
2679 }
2680 statep->remaining_retry_cnt = statep->max_cm_retries + 1;
2681 statep->timerid = IBCM_TIMEOUT(statep, 0);
2682 mutex_exit(&statep->state_mutex);
2683 }
2684
2685 /*
2686 * ibcm_post_drep_mad:
2687 * Posts a DREP MAD
2688 * Post DREP now for TIMEWAIT state and DREQ_RCVD
2689 *
2690 * INPUTS:
2691 * statep - state pointer
2692 *
2693 * RETURN VALUE:
2694 * NONE
2695 */
2696 static void
ibcm_post_drep_mad(ibcm_state_data_t * statep)2697 ibcm_post_drep_mad(ibcm_state_data_t *statep)
2698 {
2699 ibcm_drep_msg_t *drep_msgp;
2700
2701 drep_msgp = (ibcm_drep_msg_t *)IBCM_OUT_MSGP(statep->drep_msg);
2702
2703 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*drep_msgp))
2704
2705 IBTF_DPRINTF_L4(cmlog, "ibcm_post_drep_mad:");
2706
2707 /* Fill up DREP fields */
2708 drep_msgp->drep_local_comm_id = h2b32(statep->local_comid);
2709 drep_msgp->drep_remote_comm_id = h2b32(statep->remote_comid);
2710 IBCM_OUT_HDRP(statep->drep_msg)->AttributeID =
2711 h2b16(IBCM_INCOMING_DREP + IBCM_ATTR_BASE_ID);
2712
2713 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*drep_msgp))
2714
2715 ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_DREP);
2716
2717 /* Post the DREP MAD now. */
2718 ibcm_post_rc_mad(statep, statep->drep_msg, ibcm_post_drep_complete,
2719 statep);
2720 }
2721
2722 /*
2723 * ibcm_process_drep_msg:
2724 * Processes incoming DREP message on active/passive side
2725 *
2726 * INPUTS:
2727 * hcap - HCA entry pointer
2728 * input_madp - CM MAD that is input to this function
2729 * cm_mad_addr - Address information for the MAD
2730 *
2731 * RETURN VALUE: NONE
2732 */
2733 /* ARGSUSED */
2734 void
ibcm_process_drep_msg(ibcm_hca_info_t * hcap,uint8_t * input_madp,ibcm_mad_addr_t * cm_mad_addr)2735 ibcm_process_drep_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
2736 ibcm_mad_addr_t *cm_mad_addr)
2737 {
2738 ibcm_status_t state_lookup_status;
2739 ibcm_drep_msg_t *drep_msgp =
2740 (ibcm_drep_msg_t *)(&input_madp[IBCM_MAD_HDR_SIZE]);
2741 ibcm_state_data_t *statep = NULL;
2742
2743 IBTF_DPRINTF_L4(cmlog, "ibcm_process_drep_msg:");
2744
2745 /* Lookup for an existing state structure */
2746 rw_enter(&hcap->hca_state_rwlock, RW_READER);
2747
2748 state_lookup_status = ibcm_lookup_msg(IBCM_INCOMING_DREP,
2749 b2h32(drep_msgp->drep_remote_comm_id), 0, 0, hcap, &statep);
2750 rw_exit(&hcap->hca_state_rwlock);
2751
2752 if (state_lookup_status != IBCM_LOOKUP_EXISTS) {
2753 IBTF_DPRINTF_L3(cmlog, "ibcm_process_drep_msg: no statep with"
2754 "com id %x", b2h32(drep_msgp->drep_remote_comm_id));
2755 return;
2756 }
2757
2758 /* if transaction id is not as expected, drop the DREP mad */
2759 if (IBCM_OUT_HDRP(statep->dreq_msg)->TransactionID !=
2760 ((ib_mad_hdr_t *)(input_madp))->TransactionID) {
2761 mutex_enter(&statep->state_mutex);
2762 IBCM_REF_CNT_DECR(statep);
2763 mutex_exit(&statep->state_mutex);
2764 IBTF_DPRINTF_L3(cmlog, "ibcm_process_drep_msg: statep 0x%p "
2765 "DREP with tid expected 0x%llX tid found 0x%llX", statep,
2766 b2h64(IBCM_OUT_HDRP(statep->dreq_msg)->TransactionID),
2767 b2h64(((ib_mad_hdr_t *)(input_madp))->TransactionID));
2768 return;
2769 }
2770
2771 ibcm_insert_trace(statep, IBCM_TRACE_INCOMING_DREP);
2772
2773 mutex_enter(&statep->state_mutex);
2774
2775 if (statep->state == IBCM_STATE_DREQ_SENT) {
2776 timeout_id_t timer_val = statep->timerid;
2777
2778 statep->state = IBCM_STATE_DREP_RCVD;
2779
2780 statep->timerid = 0;
2781 mutex_exit(&statep->state_mutex);
2782 (void) untimeout(timer_val);
2783
2784 if (statep->stale == B_TRUE)
2785 IBTF_DPRINTF_L2(cmlog, "ibcm_process_drep_msg: "
2786 "statep 0x%p Unexpected DREP received for a stale "
2787 "DREQ sent", statep);
2788
2789 mutex_enter(&statep->state_mutex);
2790 /* allow free qp, if close channel with NOCALLBACKS didn't */
2791 if (statep->close_nocb_state != IBCM_FAIL) {
2792 ibtl_cm_chan_is_closing(statep->channel);
2793 statep->close_nocb_state = IBCM_BLOCK;
2794 }
2795 mutex_exit(&statep->state_mutex);
2796
2797 /* if close_nocb_state is IBCM_FAIL, then cm_handler is NULL */
2798 if (statep->cm_handler != NULL) {
2799 ibt_cm_event_t event;
2800 ibt_cm_return_args_t ret_args;
2801
2802 bzero(&event, sizeof (event));
2803 bzero(&ret_args, sizeof (ret_args));
2804
2805 event.cm_type = IBT_CM_EVENT_CONN_CLOSED;
2806 event.cm_channel = statep->channel;
2807 event.cm_session_id = NULL;
2808
2809 if (statep->stale == B_TRUE) {
2810 event.cm_event.closed = IBT_CM_CLOSED_STALE;
2811 event.cm_priv_data = NULL;
2812 event.cm_priv_data_len = 0;
2813 } else {
2814 event.cm_event.closed = IBT_CM_CLOSED_DREP_RCVD;
2815 event.cm_priv_data =
2816 drep_msgp->drep_private_data;
2817 event.cm_priv_data_len = IBT_DREP_PRIV_DATA_SZ;
2818 }
2819
2820 ibcm_insert_trace(statep,
2821 IBCM_TRACE_CALLED_CONN_CLOSE_EVENT);
2822
2823 (void) statep->cm_handler(statep->state_cm_private,
2824 &event, &ret_args, NULL, 0);
2825
2826 ibcm_insert_trace(statep,
2827 IBCM_TRACE_RET_CONN_CLOSE_EVENT);
2828 }
2829
2830 /* copy the private to close channel, if specified */
2831 if ((statep->close_ret_priv_data != NULL) &&
2832 (statep->close_ret_priv_data_len != NULL) &&
2833 (*statep->close_ret_priv_data_len > 0)) {
2834 bcopy(drep_msgp->drep_private_data,
2835 statep->close_ret_priv_data,
2836 min(*statep->close_ret_priv_data_len,
2837 IBT_DREP_PRIV_DATA_SZ));
2838 }
2839
2840 mutex_enter(&statep->state_mutex);
2841 if (statep->close_ret_status)
2842 *statep->close_ret_status = IBT_CM_CLOSED_DREP_RCVD;
2843 /* signal waiting CV - blocking in ibt_close_channel() */
2844 statep->close_done = B_TRUE;
2845
2846 /* signal any blocked close channels with no callbacks */
2847 statep->close_nocb_state = IBCM_FAIL;
2848
2849 cv_broadcast(&statep->block_client_cv);
2850
2851 /* Set the timer wait state timer */
2852 statep->state = statep->timer_stored_state =
2853 IBCM_STATE_TIMEWAIT;
2854 ibcm_close_done(statep, 0);
2855
2856 statep->remaining_retry_cnt = 0;
2857 /*
2858 * For passive side CM set it to remote_ack_delay
2859 * For active side CM add the pkt_life_time * 2
2860 */
2861 statep->timer_value = statep->remote_ack_delay;
2862 if (statep->mode == IBCM_ACTIVE_MODE) {
2863 statep->timer_value += (2 * statep->pkt_life_time);
2864 }
2865
2866 /* start TIMEWAIT processing */
2867 statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
2868 }
2869
2870 /* There is no processing required for other states */
2871 IBCM_REF_CNT_DECR(statep);
2872 mutex_exit(&statep->state_mutex);
2873 }
2874
2875 /*
2876 * Following are the routines used to resend various CM MADs as a response to
2877 * incoming MADs
2878 */
2879 void
ibcm_resend_rtu_mad(ibcm_state_data_t * statep)2880 ibcm_resend_rtu_mad(ibcm_state_data_t *statep)
2881 {
2882 ASSERT(MUTEX_HELD(&statep->state_mutex));
2883
2884 IBTF_DPRINTF_L3(cmlog, "ibcm_resend_rtu_mad statep %p ", statep);
2885
2886 /* don't care, if timer is running or not. Timer may be from LAP */
2887
2888 if (!(statep->send_mad_flags & IBCM_RTU_POST_BUSY)) {
2889 statep->send_mad_flags |= IBCM_RTU_POST_BUSY;
2890 IBCM_REF_CNT_INCR(statep); /* for non-blocking RTU post */
2891 mutex_exit(&statep->state_mutex);
2892
2893 ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_RTU);
2894
2895 ibcm_post_rc_mad(statep, statep->stored_msg,
2896 ibcm_post_rtu_complete, statep);
2897 mutex_enter(&statep->state_mutex);
2898 }
2899 /* ref cnt is decremented in ibcm_post_rtu_complete */
2900 }
2901
2902 void
ibcm_resend_rej_mad(ibcm_state_data_t * statep)2903 ibcm_resend_rej_mad(ibcm_state_data_t *statep)
2904 {
2905 timeout_id_t timer_val = statep->timerid;
2906
2907 ASSERT(MUTEX_HELD(&statep->state_mutex));
2908
2909 IBTF_DPRINTF_L3(cmlog, "ibcm_resend_rej_mad statep %p ", statep);
2910
2911 /* It's a too fast of a REQ or REP */
2912 if (timer_val == 0)
2913 return;
2914
2915 statep->timerid = 0;
2916 if (!(statep->send_mad_flags & IBCM_REJ_POST_BUSY)) {
2917 statep->send_mad_flags |= IBCM_REJ_POST_BUSY;
2918 IBCM_REF_CNT_INCR(statep); /* for nonblocking REJ post */
2919 mutex_exit(&statep->state_mutex);
2920 (void) untimeout(timer_val);
2921
2922 ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_REJ);
2923 if (ibcm_enable_trace & 2)
2924 ibcm_dump_conn_trace(statep);
2925 else
2926 IBTF_DPRINTF_L2(cmlog, "ibcm_resend_rej_mad statep %p "
2927 "OUTGOING_REJ", statep);
2928
2929 ibcm_post_rc_mad(statep, statep->stored_msg,
2930 ibcm_post_rej_complete, statep);
2931 mutex_enter(&statep->state_mutex);
2932 }
2933 /* return, holding the state mutex */
2934 }
2935
2936 void
ibcm_resend_rep_mad(ibcm_state_data_t * statep)2937 ibcm_resend_rep_mad(ibcm_state_data_t *statep)
2938 {
2939 timeout_id_t timer_val = statep->timerid;
2940
2941 ASSERT(MUTEX_HELD(&statep->state_mutex));
2942
2943 IBTF_DPRINTF_L3(cmlog, "ibcm_resend_rep_mad statep %p ", statep);
2944
2945 /* REP timer that is set by ibcm_post_rep_mad */
2946 if (timer_val != 0) {
2947 /* Re-start REP timeout */
2948 statep->remaining_retry_cnt = statep->max_cm_retries;
2949 if (!(statep->send_mad_flags & IBCM_REP_POST_BUSY)) {
2950 statep->send_mad_flags |= IBCM_REP_POST_BUSY;
2951 /* for nonblocking REP post */
2952 IBCM_REF_CNT_INCR(statep);
2953 mutex_exit(&statep->state_mutex);
2954
2955 ibcm_insert_trace(statep, IBCM_TRACE_OUT_REP_RETRY);
2956
2957 ibcm_post_rc_mad(statep, statep->stored_msg,
2958 ibcm_resend_post_rep_complete, statep);
2959 mutex_enter(&statep->state_mutex);
2960 }
2961 }
2962
2963 /*
2964 * else, timer is not yet set by ibcm_post_rep_mad. This is too fast
2965 * of a REQ being re-transmitted.
2966 */
2967 }
2968
2969 void
ibcm_resend_mra_mad(ibcm_state_data_t * statep)2970 ibcm_resend_mra_mad(ibcm_state_data_t *statep)
2971 {
2972 ASSERT(MUTEX_HELD(&statep->state_mutex));
2973
2974 IBTF_DPRINTF_L3(cmlog, "ibcm_resend_mra_mad statep %p ", statep);
2975
2976 if (statep->send_mad_flags & IBCM_MRA_POST_BUSY)
2977 return;
2978
2979 statep->send_mad_flags |= IBCM_MRA_POST_BUSY;
2980
2981 statep->mra_time = gethrtime();
2982 IBCM_REF_CNT_INCR(statep); /* for non-blocking MRA post */
2983 /* Exit the statep mutex, before sending the MAD */
2984 mutex_exit(&statep->state_mutex);
2985
2986 ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_MRA);
2987
2988 /* Always resend the response MAD to the original reply destination */
2989 ibcm_post_rc_mad(statep, statep->mra_msg, ibcm_post_mra_complete,
2990 statep);
2991
2992 mutex_enter(&statep->state_mutex);
2993
2994 /* return, holding the state mutex */
2995 }
2996
2997
2998 /*
2999 * ibcm_post_rej_mad:
3000 * Posts a REJ MAD and starts timer
3001 *
3002 * INPUTS:
3003 * statep - state pointer
3004 * which_msg - which message is being MRAed
3005 * reject_reason - Rejection reason See Section 12.6.7.2 rev1.0a IB Spec
3006 * addl_rej_info - Additional rej Information
3007 * arej_info_len - Additional rej Info length
3008 *
3009 * RETURN VALUE:
3010 * NONE
3011 * Notes
3012 * There is no need to hold the statep->mutex and call ibcm_post_rej_mad
3013 * REJ can be posted either in IBCM_STATE_REQ_RCVD or IBCM_STATE_REP_RCVD
3014 * In these states, there is no timer active, and an incoming REJ shall
3015 * not modify the state or cancel timers
3016 * An incoming REJ doesn't affect statep in state = IBCM_STATE_REJ_SENT/BUSY
3017 */
3018 void
ibcm_post_rej_mad(ibcm_state_data_t * statep,ibt_cm_reason_t reject_reason,int which_msg,void * addl_rej_info,ibt_priv_data_len_t arej_info_len)3019 ibcm_post_rej_mad(ibcm_state_data_t *statep, ibt_cm_reason_t reject_reason,
3020 int which_msg, void *addl_rej_info, ibt_priv_data_len_t arej_info_len)
3021 {
3022 ibcm_rej_msg_t *rej_msg =
3023 (ibcm_rej_msg_t *)IBCM_OUT_MSGP(statep->stored_msg);
3024
3025 /* Message printed if connection gets REJed */
3026 IBTF_DPRINTF_L3(cmlog, "ibcm_post_rej_mad: "
3027 "statep = %p, reject_reason = %d", statep, reject_reason);
3028
3029 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rej_msg))
3030
3031 /* Initialize rej_msg fields */
3032 rej_msg->rej_local_comm_id = h2b32(statep->local_comid);
3033 rej_msg->rej_remote_comm_id = h2b32(statep->remote_comid);
3034 rej_msg->rej_msg_type_plus = (which_msg & 0x3) << 6;
3035 rej_msg->rej_reject_info_len_plus = arej_info_len << 1;
3036 rej_msg->rej_rejection_reason = h2b16((uint16_t)reject_reason);
3037
3038 if ((arej_info_len != 0) && (addl_rej_info != NULL))
3039 bcopy(addl_rej_info, rej_msg->rej_addl_rej_info, arej_info_len);
3040
3041 IBCM_OUT_HDRP(statep->stored_msg)->AttributeID =
3042 h2b16(IBCM_INCOMING_REJ + IBCM_ATTR_BASE_ID);
3043
3044 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*rej_msg))
3045
3046 mutex_enter(&statep->state_mutex);
3047
3048 /* signal any waiting close channels with blocking or no callbacks */
3049 statep->close_done = B_TRUE;
3050 statep->close_nocb_state = IBCM_FAIL;
3051
3052 cv_signal(&statep->block_client_cv);
3053
3054 statep->timer_stored_state = statep->state = IBCM_STATE_REJ_SENT;
3055 statep->send_mad_flags |= IBCM_REJ_POST_BUSY;
3056
3057 IBCM_REF_CNT_INCR(statep); /* for non-blocking post */
3058 mutex_exit(&statep->state_mutex);
3059
3060 ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_REJ);
3061 if (ibcm_enable_trace & 2)
3062 ibcm_dump_conn_trace(statep);
3063 else
3064 IBTF_DPRINTF_L2(cmlog, "ibcm_post_rej_mad statep %p "
3065 "OUTGOING_REJ", statep);
3066
3067 ibcm_post_rc_mad(statep, statep->stored_msg, ibcm_post_rej_complete,
3068 statep);
3069 }
3070
3071
3072 /*
3073 * ibcm_build_n_post_rej_mad:
3074 * Builds and posts a REJ MAD for "reject_reason"
3075 * Doesn't set a timer, and doesn't need statep
3076 *
3077 * INPUTS:
3078 * input_madp - Incoming MAD
3079 * remote_comid - Local comid in the message being rejected
3080 * cm_mad_addr - Address information for the MAD to be posted
3081 * which_msg - REJ message type ie., REJ for REQ/REP
3082 *
3083 * RETURN VALUE:
3084 * NONE
3085 */
3086 static void
ibcm_build_n_post_rej_mad(uint8_t * input_madp,ib_com_id_t remote_comid,ibcm_mad_addr_t * cm_mad_addr,int which_msg,uint16_t reject_reason)3087 ibcm_build_n_post_rej_mad(uint8_t *input_madp, ib_com_id_t remote_comid,
3088 ibcm_mad_addr_t *cm_mad_addr, int which_msg, uint16_t reject_reason)
3089 {
3090 ibcm_rej_msg_t *rej_msg;
3091 ibmf_msg_t *cm_rej_msg;
3092 ibcm_mad_addr_t rej_reply_addr;
3093
3094 IBTF_DPRINTF_L3(cmlog, "ibcm_build_n_post_rej_mad: "
3095 "remote_comid: %x reject_reason %d", remote_comid, reject_reason);
3096
3097 if (ibcm_alloc_out_msg(cm_mad_addr->ibmf_hdl, &cm_rej_msg,
3098 MAD_METHOD_SEND) != IBT_SUCCESS) {
3099 IBTF_DPRINTF_L2(cmlog, "ibcm_build_n_post_rej_mad: "
3100 "ibcm_alloc_out_msg failed");
3101 return;
3102 }
3103
3104 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rej_msg))
3105
3106 IBCM_OUT_HDRP(cm_rej_msg)->TransactionID =
3107 ((ib_mad_hdr_t *)(input_madp))->TransactionID;
3108
3109 /* Initialize rej_msg fields */
3110 rej_msg = (ibcm_rej_msg_t *)IBCM_OUT_MSGP(cm_rej_msg);
3111 rej_msg->rej_local_comm_id = 0;
3112 rej_msg->rej_remote_comm_id = h2b32(remote_comid);
3113 rej_msg->rej_msg_type_plus = (which_msg & 0x3) << 6;
3114 rej_msg->rej_reject_info_len_plus = 0;
3115 rej_msg->rej_rejection_reason = h2b16(reject_reason);
3116
3117 IBCM_OUT_HDRP(cm_rej_msg)->AttributeID =
3118 h2b16(IBCM_INCOMING_REJ + IBCM_ATTR_BASE_ID);
3119
3120 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*rej_msg))
3121
3122 ibcm_build_reply_mad_addr(cm_mad_addr, &rej_reply_addr);
3123
3124 if (rej_reply_addr.cm_qp_entry != NULL) {
3125 (void) ibcm_post_mad(cm_rej_msg, &rej_reply_addr, NULL, NULL);
3126 ibcm_release_qp(rej_reply_addr.cm_qp_entry);
3127 }
3128
3129 (void) ibcm_free_out_msg(cm_mad_addr->ibmf_hdl, &cm_rej_msg);
3130 }
3131
3132 /* posts a REJ for an incoming REQ with unsupported class version */
3133
3134 static void
ibcm_post_rej_ver_mismatch(uint8_t * input_madp,ibcm_mad_addr_t * cm_mad_addr)3135 ibcm_post_rej_ver_mismatch(uint8_t *input_madp, ibcm_mad_addr_t *cm_mad_addr)
3136 {
3137 ibcm_req_msg_t *req_msgp =
3138 (ibcm_req_msg_t *)&input_madp[IBCM_MAD_HDR_SIZE];
3139 ibcm_rej_msg_t *rej_msg;
3140 ibmf_msg_t *cm_rej_msg;
3141 ibcm_mad_addr_t rej_reply_addr;
3142
3143 IBTF_DPRINTF_L3(cmlog, "ibcm_post_rej_ver_mismatch: remote comid %x",
3144 b2h32(req_msgp->req_local_comm_id));
3145
3146 if (ibcm_alloc_out_msg(cm_mad_addr->ibmf_hdl, &cm_rej_msg,
3147 MAD_METHOD_SEND) != IBT_SUCCESS) {
3148 IBTF_DPRINTF_L2(cmlog, "ibcm_post_rej_ver_mismatch: "
3149 "ibcm_alloc_out_msg failed");
3150 return;
3151 }
3152
3153 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rej_msg))
3154
3155 IBCM_OUT_HDRP(cm_rej_msg)->TransactionID =
3156 ((ib_mad_hdr_t *)(input_madp))->TransactionID;
3157
3158 /* Initialize rej_msg fields */
3159 rej_msg = (ibcm_rej_msg_t *)IBCM_OUT_MSGP(cm_rej_msg);
3160 rej_msg->rej_local_comm_id = 0;
3161 rej_msg->rej_remote_comm_id = req_msgp->req_local_comm_id;
3162 rej_msg->rej_msg_type_plus = IBT_CM_FAILURE_REQ << 6;
3163 rej_msg->rej_rejection_reason = h2b16(IBT_CM_CLASS_NO_SUPPORT);
3164 rej_msg->rej_reject_info_len_plus = 1 << 1;
3165 rej_msg->rej_addl_rej_info[0] = IBCM_MAD_CLASS_VERSION;
3166
3167 IBCM_OUT_HDRP(cm_rej_msg)->AttributeID =
3168 h2b16(IBCM_INCOMING_REJ + IBCM_ATTR_BASE_ID);
3169 IBCM_OUT_HDRP(cm_rej_msg)->Status = h2b16(MAD_STATUS_BAD_VERSION);
3170
3171 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*rej_msg))
3172
3173 ibcm_build_reply_mad_addr(cm_mad_addr, &rej_reply_addr);
3174 if (rej_reply_addr.cm_qp_entry != NULL) {
3175 (void) ibcm_post_mad(cm_rej_msg, &rej_reply_addr, NULL, NULL);
3176 ibcm_release_qp(rej_reply_addr.cm_qp_entry);
3177 }
3178 (void) ibcm_free_out_msg(cm_mad_addr->ibmf_hdl, &cm_rej_msg);
3179 }
3180
3181
3182 /*
3183 * ibcm_post_rep_mad:
3184 * Posts a REP MAD and starts timer
3185 *
3186 * INPUTS:
3187 * statep - state pointer
3188 *
3189 * RETURN VALUE:
3190 * NONE
3191 */
3192 void
ibcm_post_rep_mad(ibcm_state_data_t * statep)3193 ibcm_post_rep_mad(ibcm_state_data_t *statep)
3194 {
3195 ibcm_rep_msg_t *rep_msgp =
3196 (ibcm_rep_msg_t *)IBCM_OUT_MSGP(statep->stored_msg);
3197 ibmf_msg_t *mra_msg = NULL;
3198 boolean_t ret = B_FALSE;
3199
3200 IBTF_DPRINTF_L4(cmlog, "ibcm_post_rep_mad: statep 0x%p", statep);
3201
3202 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rep_msgp))
3203
3204 /*
3205 * All other REP fields, other that the 2 below, are filled in
3206 * the ibcm_cep_state_req() function.
3207 */
3208 rep_msgp->rep_local_comm_id = h2b32(statep->local_comid);
3209 rep_msgp->rep_remote_comm_id = h2b32(statep->remote_comid);
3210 IBCM_OUT_HDRP(statep->stored_msg)->AttributeID =
3211 h2b16(IBCM_INCOMING_REP + IBCM_ATTR_BASE_ID);
3212
3213 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*rep_msgp))
3214
3215 /*
3216 * Changing state and attempt to delete the mra msg must be done
3217 * together holding the state_mutex
3218 */
3219 mutex_enter(&statep->state_mutex);
3220
3221 /* Now, attempt to delete the mra_msg, if there is one allocated */
3222 if (statep->mra_msg != NULL) {
3223 if (!(statep->send_mad_flags & IBCM_MRA_POST_BUSY)) {
3224 mra_msg = statep->mra_msg;
3225 statep->mra_msg = NULL;
3226 } else statep->delete_mra_msg = B_TRUE;
3227 }
3228
3229 if (statep->abort_flag == IBCM_ABORT_CLIENT) {
3230 statep->state = IBCM_STATE_ABORTED;
3231 mutex_exit(&statep->state_mutex);
3232 ibcm_process_abort(statep);
3233
3234 /* Now post a REJ MAD, rej reason consumer abort */
3235 ibcm_post_rej_mad(statep, IBT_CM_CONSUMER, IBT_CM_FAILURE_REQ,
3236 NULL, 0);
3237 ret = B_TRUE;
3238 } else if (statep->abort_flag & IBCM_ABORT_REJ) {
3239
3240 statep->state = IBCM_STATE_DELETE;
3241 mutex_exit(&statep->state_mutex);
3242
3243 ibcm_process_abort(statep);
3244 ibcm_delete_state_data(statep);
3245 ret = B_TRUE;
3246 } else {
3247
3248 statep->state = statep->timer_stored_state =
3249 IBCM_STATE_REP_SENT;
3250 statep->remaining_retry_cnt = statep->max_cm_retries;
3251 statep->send_mad_flags |= IBCM_REP_POST_BUSY;
3252 IBCM_REF_CNT_INCR(statep); /* for nonblocking REP Post */
3253 mutex_exit(&statep->state_mutex);
3254 }
3255
3256 if (mra_msg != NULL)
3257 (void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl,
3258 &mra_msg);
3259 if (ret == B_TRUE)
3260 return;
3261
3262 ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_REP);
3263
3264 ibcm_post_rc_mad(statep, statep->stored_msg, ibcm_post_rep_complete,
3265 statep);
3266 }
3267
3268
3269 /*
3270 * ibcm_post_rtu_mad:
3271 * From active side post RTU MAD
3272 *
3273 * INPUTS:
3274 * statep - state pointer
3275 *
3276 * RETURN VALUE: NONE
3277 *
3278 * NOTE: No timer set after posting RTU
3279 */
3280 ibcm_status_t
ibcm_post_rtu_mad(ibcm_state_data_t * statep)3281 ibcm_post_rtu_mad(ibcm_state_data_t *statep)
3282 {
3283 ibcm_rtu_msg_t *rtu_msg;
3284 ibmf_msg_t *mra_msg = NULL;
3285 boolean_t ret = B_FALSE;
3286
3287 IBTF_DPRINTF_L4(cmlog, "ibcm_post_rtu_mad: statep 0x%p", statep);
3288
3289 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rtu_msg))
3290
3291 rtu_msg = (ibcm_rtu_msg_t *)IBCM_OUT_MSGP(statep->stored_msg);
3292
3293 rtu_msg->rtu_local_comm_id = h2b32(statep->local_comid);
3294 rtu_msg->rtu_remote_comm_id = h2b32(statep->remote_comid);
3295 IBCM_OUT_HDRP(statep->stored_msg)->AttributeID =
3296 h2b16(IBCM_INCOMING_RTU + IBCM_ATTR_BASE_ID);
3297
3298 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*rtu_msg))
3299
3300 mutex_enter(&statep->state_mutex);
3301
3302 /* Now, attempt to delete the mra_msg, if there is one allocated */
3303 if (statep->mra_msg != NULL) {
3304 if (!(statep->send_mad_flags & IBCM_MRA_POST_BUSY)) {
3305 mra_msg = statep->mra_msg;
3306 statep->mra_msg = NULL;
3307 } else statep->delete_mra_msg = B_TRUE;
3308 }
3309
3310 if (statep->abort_flag == IBCM_ABORT_CLIENT) {
3311 statep->state = IBCM_STATE_ABORTED;
3312 mutex_exit(&statep->state_mutex);
3313
3314 ibcm_process_abort(statep);
3315
3316 /* Now post a REJ MAD */
3317 ibcm_post_rej_mad(statep, IBT_CM_CONSUMER, IBT_CM_FAILURE_REP,
3318 NULL, 0);
3319 ret = B_TRUE;
3320 } else if (statep->abort_flag & IBCM_ABORT_REJ) {
3321 statep->state = IBCM_STATE_DELETE;
3322 mutex_exit(&statep->state_mutex);
3323
3324 ibcm_process_abort(statep);
3325 ibcm_delete_state_data(statep);
3326 ret = B_TRUE;
3327 } else {
3328 statep->state = IBCM_STATE_ESTABLISHED;
3329 ibtl_cm_chan_is_open(statep->channel);
3330 statep->send_mad_flags |= IBCM_RTU_POST_BUSY;
3331 IBCM_REF_CNT_INCR(statep); /* for nonblocking RTU post */
3332 mutex_exit(&statep->state_mutex);
3333 }
3334
3335 if (mra_msg != NULL)
3336 (void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl,
3337 &mra_msg);
3338
3339 if (ret == B_TRUE) /* Abort case, no RTU posted */
3340 return (IBCM_FAILURE);
3341
3342 ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_RTU);
3343
3344 ibcm_post_rc_mad(statep, statep->stored_msg, ibcm_post_rtu_complete,
3345 statep);
3346 return (IBCM_SUCCESS);
3347 }
3348
3349
3350 /*
3351 * ibcm_process_abort:
3352 * Processes abort, if client requested abort connection attempt
3353 *
3354 * INPUTS:
3355 * statep - pointer to ibcm_state_data_t is passed
3356 *
3357 * RETURN VALUES: None
3358 */
3359 void
ibcm_process_abort(ibcm_state_data_t * statep)3360 ibcm_process_abort(ibcm_state_data_t *statep)
3361 {
3362 IBTF_DPRINTF_L3(cmlog, "ibcm_process_abort: statep 0x%p", statep);
3363
3364 /* move CEP to error state, before calling client handler */
3365 (void) ibcm_cep_to_error_state(statep);
3366
3367 /* Now disassociate the link between statep and qp */
3368 IBCM_SET_CHAN_PRIVATE(statep->channel, NULL);
3369
3370 /* invoke cm handler, for non-blocking open/close rc channel calls */
3371 if (statep->cm_handler) { /* cannot be NULL, but still .. */
3372 ibt_cm_event_t event;
3373 ibt_cm_return_args_t ret_args;
3374
3375 bzero(&event, sizeof (event));
3376 bzero(&ret_args, sizeof (ret_args));
3377
3378 if (statep->abort_flag & IBCM_ABORT_REJ)
3379 ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_RCV,
3380 IBT_CM_FAILURE_UNKNOWN, IBT_CM_TIMEOUT, NULL, 0);
3381 else {
3382 ibcm_path_cache_purge();
3383
3384 event.cm_type = IBT_CM_EVENT_CONN_CLOSED;
3385 event.cm_channel = statep->channel;
3386 event.cm_event.closed = IBT_CM_CLOSED_ABORT;
3387
3388 ibcm_insert_trace(statep,
3389 IBCM_TRACE_CALLED_CONN_CLOSE_EVENT);
3390
3391 if (statep->channel)
3392 ibtl_cm_chan_open_is_aborted(statep->channel);
3393
3394 (void) statep->cm_handler(statep->state_cm_private,
3395 &event, &ret_args, NULL, 0);
3396
3397 ibcm_insert_trace(statep,
3398 IBCM_TRACE_RET_CONN_CLOSE_EVENT);
3399
3400 mutex_enter(&statep->state_mutex);
3401 ibcm_open_done(statep);
3402 mutex_exit(&statep->state_mutex);
3403 }
3404 }
3405
3406 /*
3407 * Unblock an ibt_open_rc_channel called in a blocking mode, though
3408 * it is an unlikely scenario
3409 */
3410 mutex_enter(&statep->state_mutex);
3411
3412 statep->cm_retries++; /* cause connection trace to be printed */
3413 statep->open_done = B_TRUE;
3414 statep->close_done = B_TRUE;
3415 statep->close_nocb_state = IBCM_FAIL; /* sanity sake */
3416
3417 if (statep->open_return_data != NULL) {
3418 /* REJ came first, and then client aborted connection */
3419 if (statep->abort_flag & IBCM_ABORT_REJ)
3420 statep->open_return_data->rc_status = IBT_CM_TIMEOUT;
3421 else statep->open_return_data->rc_status = IBT_CM_ABORT;
3422 }
3423
3424 cv_broadcast(&statep->block_client_cv);
3425 mutex_exit(&statep->state_mutex);
3426 if (ibcm_enable_trace != 0)
3427 ibcm_dump_conn_trace(statep);
3428 }
3429
3430 /*
3431 * ibcm_timeout_cb:
3432 * Called when the timer expires
3433 *
3434 * INPUTS:
3435 * arg - ibcm_state_data_t is passed
3436 *
3437 * RETURN VALUES: NONE
3438 */
3439 void
ibcm_timeout_cb(void * arg)3440 ibcm_timeout_cb(void *arg)
3441 {
3442 ibcm_state_data_t *statep = (ibcm_state_data_t *)arg;
3443
3444 mutex_enter(&statep->state_mutex);
3445
3446 /*
3447 * The blocking operations are handled in a separate thread.
3448 * All other non-blocking operations, including ibmf non-blocking
3449 * posts are done from timeout context
3450 */
3451
3452 if ((statep->timer_stored_state != statep->state) ||
3453 ((statep->timer_stored_state == IBCM_STATE_ESTABLISHED) &&
3454 (statep->ap_state != statep->timer_stored_ap_state))) {
3455 mutex_exit(&statep->state_mutex);
3456 return;
3457 }
3458
3459 IBTF_DPRINTF_L3(cmlog, "ibcm_timeout_cb: statep 0x%p state %x "
3460 "ap_state %x", statep, statep->state, statep->ap_state);
3461
3462 /* Processing depends upon current state */
3463
3464 if (statep->state == IBCM_STATE_REJ_SENT) {
3465 statep->state = IBCM_STATE_DELETE;
3466 mutex_exit(&statep->state_mutex);
3467
3468 /* Deallocate the CM state structure */
3469 ibcm_delete_state_data(statep);
3470 return;
3471
3472 } else if (statep->state == IBCM_STATE_TIMEWAIT) {
3473 statep->state = IBCM_STATE_DELETE;
3474
3475 /* TIME_WAIT timer expired, so cleanup */
3476 mutex_exit(&statep->state_mutex);
3477
3478 if (statep->channel)
3479 ibtl_cm_chan_is_closed(statep->channel);
3480
3481 if (statep->recycle_arg) {
3482 struct ibcm_taskq_recycle_arg_s *recycle_arg;
3483
3484 recycle_arg = statep->recycle_arg;
3485
3486 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(
3487 statep->recycle_arg))
3488 statep->recycle_arg = NULL;
3489 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(statep->recycle_arg))
3490
3491 /* if possible, do not slow down calling recycle func */
3492 if (taskq_dispatch(ibcm_taskq, ibcm_process_rc_recycle,
3493 recycle_arg, TQ_NOQUEUE | TQ_NOSLEEP) == 0) {
3494
3495 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(
3496 statep->recycle_arg))
3497 statep->recycle_arg = recycle_arg;
3498 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(
3499 statep->recycle_arg))
3500 ibcm_add_tlist(statep);
3501 return;
3502 }
3503 }
3504
3505 ibcm_delete_state_data(statep);
3506 return;
3507 } else if (statep->remaining_retry_cnt > 0) {
3508 ibcm_conn_state_t stored_state;
3509 ibcm_ap_state_t stored_ap_state;
3510
3511 statep->remaining_retry_cnt--;
3512 IBTF_DPRINTF_L3(cmlog, "ibcm_timeout_cb: statep 0x%p "
3513 "attr-id= 0x%x, retries remaining = 0x%x", statep,
3514 b2h16(IBCM_OUT_HDRP(statep->stored_msg)->AttributeID),
3515 statep->remaining_retry_cnt);
3516
3517 /*
3518 * REP could be resent, either because of timeout or an
3519 * incoming REQ. Any other MAD below can be resent, because
3520 * of timeout only, hence send_mad_flag manipulation not
3521 * required for those cases.
3522 * If REP is already being retransmitted, then just set the
3523 * timer and return. Else post REP in non-blocking mode
3524 */
3525 if (statep->timer_stored_state == IBCM_STATE_REP_SENT) {
3526 if (statep->send_mad_flags & IBCM_REP_POST_BUSY) {
3527 statep->timerid = IBCM_TIMEOUT(statep,
3528 statep->timer_value);
3529 mutex_exit(&statep->state_mutex);
3530 ibcm_insert_trace(statep,
3531 IBCM_TRACE_TIMEOUT_REP);
3532 return;
3533 }
3534
3535 /*
3536 * Set REP busy flag, so any incoming REQ's will not
3537 * initiate new REP transmissions
3538 */
3539 statep->send_mad_flags |= IBCM_REP_POST_BUSY;
3540
3541 /* Since REQ/RTU/REJ on active side use same MAD, synchronize */
3542 } else if (statep->timer_stored_state == IBCM_STATE_REQ_SENT) {
3543 ASSERT((statep->send_mad_flags & IBCM_REQ_POST_BUSY)
3544 == 0);
3545 statep->send_mad_flags |= IBCM_REQ_POST_BUSY;
3546 }
3547
3548 IBCM_REF_CNT_INCR(statep); /* for non-blocking post */
3549 stored_state = statep->timer_stored_state;
3550 stored_ap_state = statep->timer_stored_ap_state;
3551 mutex_exit(&statep->state_mutex);
3552
3553 /* Post REQ MAD in non-blocking mode */
3554 if (stored_state == IBCM_STATE_REQ_SENT) {
3555 ibcm_insert_trace(statep, IBCM_TRACE_OUT_REQ_RETRY);
3556 ibcm_post_rc_mad(statep, statep->stored_msg,
3557 ibcm_post_req_complete, statep);
3558 /* Post REQ MAD in non-blocking mode */
3559 } else if (stored_state == IBCM_STATE_REP_WAIT) {
3560 ibcm_insert_trace(statep, IBCM_TRACE_OUT_REQ_RETRY);
3561 ibcm_post_rc_mad(statep, statep->stored_msg,
3562 ibcm_post_rep_wait_complete, statep);
3563 /* Post REP MAD in non-blocking mode */
3564 } else if (stored_state == IBCM_STATE_REP_SENT) {
3565 ibcm_insert_trace(statep, IBCM_TRACE_OUT_REP_RETRY);
3566 ibcm_post_rc_mad(statep, statep->stored_msg,
3567 ibcm_post_rep_complete, statep);
3568 /* Post REP MAD in non-blocking mode */
3569 } else if (stored_state == IBCM_STATE_MRA_REP_RCVD) {
3570 ibcm_insert_trace(statep, IBCM_TRACE_OUT_REP_RETRY);
3571 mutex_enter(&statep->state_mutex);
3572 statep->mra_time = gethrtime();
3573 mutex_exit(&statep->state_mutex);
3574 ibcm_post_rc_mad(statep, statep->stored_msg,
3575 ibcm_post_mra_rep_complete, statep);
3576 /* Post DREQ MAD in non-blocking mode */
3577 } else if (stored_state == IBCM_STATE_DREQ_SENT) {
3578 mutex_enter(&statep->state_mutex);
3579 if (statep->remaining_retry_cnt ==
3580 statep->max_cm_retries)
3581 ibcm_insert_trace(statep,
3582 IBCM_TRACE_OUTGOING_DREQ);
3583 else {
3584 ibcm_insert_trace(statep,
3585 IBCM_TRACE_OUT_DREQ_RETRY);
3586 statep->cm_retries++;
3587 ibcm_close_done(statep, 0);
3588 }
3589 mutex_exit(&statep->state_mutex);
3590 ibcm_post_rc_mad(statep, statep->dreq_msg,
3591 ibcm_post_dreq_complete, statep);
3592 /* post LAP MAD in non-blocking mode */
3593 } else if (stored_ap_state == IBCM_AP_STATE_LAP_SENT) {
3594 ibcm_insert_trace(statep, IBCM_TRACE_OUT_LAP_RETRY);
3595 ibcm_post_rc_mad(statep, statep->lapr_msg,
3596 ibcm_post_lap_complete, statep);
3597 /* post LAP MAD in non-blocking mode */
3598 } else if (stored_ap_state == IBCM_AP_STATE_MRA_LAP_RCVD) {
3599 ibcm_insert_trace(statep, IBCM_TRACE_OUT_LAP_RETRY);
3600 mutex_enter(&statep->state_mutex);
3601 statep->mra_time = gethrtime();
3602 mutex_exit(&statep->state_mutex);
3603 ibcm_post_rc_mad(statep, statep->lapr_msg,
3604 ibcm_post_mra_lap_complete, statep);
3605 }
3606 return;
3607
3608 } else if ((statep->state == IBCM_STATE_REQ_SENT) ||
3609 (statep->state == IBCM_STATE_REP_SENT) ||
3610 (statep->state == IBCM_STATE_MRA_REP_RCVD) ||
3611 (statep->state == IBCM_STATE_REP_WAIT)) {
3612
3613 /*
3614 * MAX retries reached, send a REJ to the remote,
3615 * and close the connection
3616 */
3617 statep->timedout_state = statep->state;
3618 statep->state = IBCM_STATE_TIMED_OUT;
3619
3620 IBTF_DPRINTF_L3(cmlog, "ibcm_timeout_cb: "
3621 "max retries done for statep 0x%p", statep);
3622 statep->cm_retries++; /* cause conn trace to print */
3623 mutex_exit(&statep->state_mutex);
3624
3625 if ((statep->timedout_state == IBCM_STATE_REP_SENT) ||
3626 (statep->timedout_state == IBCM_STATE_MRA_REP_RCVD))
3627 (void) ibcm_cep_to_error_state(statep);
3628
3629 /* Disassociate statep from QP */
3630 IBCM_SET_CHAN_PRIVATE(statep->channel, NULL);
3631
3632 /*
3633 * statep is in REJ SENT state, the only way to get deleted is
3634 * the timeout callback that is set after posting REJ
3635 * The thread processing is required where cm handler is
3636 * specified
3637 */
3638
3639 if (statep->cm_handler != NULL) {
3640 /* Attach the statep to timeout list */
3641 ibcm_add_tlist(statep);
3642 } else {
3643 ib_guid_t local_hca_guid;
3644
3645 mutex_enter(&statep->state_mutex);
3646
3647 /*
3648 * statep->open_return_data is set for blocking
3649 * No handler specified, hence signal blocked
3650 * ibt_open_rc_channel from here
3651 */
3652 if (statep->open_return_data != NULL) {
3653 statep->open_return_data->rc_status =
3654 IBT_CM_TIMEOUT;
3655 statep->open_done = B_TRUE;
3656 cv_broadcast(&statep->block_client_cv);
3657 }
3658
3659 mutex_exit(&statep->state_mutex);
3660
3661 local_hca_guid = h2b64(statep->local_hca_guid);
3662 ibcm_post_rej_mad(statep, IBT_CM_TIMEOUT,
3663 (statep->timedout_state == IBCM_STATE_REP_SENT ||
3664 statep->timedout_state == IBCM_STATE_MRA_REP_RCVD) ?
3665 IBT_CM_FAILURE_REP: IBT_CM_FAILURE_REQ,
3666 &local_hca_guid, sizeof (ib_guid_t));
3667 }
3668
3669 } else if ((statep->ap_state == IBCM_AP_STATE_LAP_SENT) ||
3670 (statep->ap_state == IBCM_AP_STATE_MRA_LAP_RCVD)) {
3671
3672 IBTF_DPRINTF_L4(cmlog, "ibcm_timeout_cb: statep 0x%p "
3673 "LAP timed out", statep);
3674 statep->timedout_state = statep->state;
3675 /*
3676 * This state setting ensures that the processing of DREQ is
3677 * sequentialized, once this ap_state is set. If statep is
3678 * attached to timeout list, it cannot be re-attached as long
3679 * as in this state
3680 */
3681 statep->ap_state = IBCM_AP_STATE_TIMED_OUT;
3682 ibcm_open_done(statep);
3683
3684 if (statep->cm_handler != NULL) {
3685 /* Attach statep to timeout list - thread handling */
3686 ibcm_add_tlist(statep);
3687 } else if (statep->ap_return_data != NULL) {
3688 /*
3689 * statep->ap_return_data is initialized for blocking in
3690 * ibt_set_alt_path(), signal the waiting CV
3691 */
3692 statep->ap_return_data->ap_status = IBT_CM_AP_TIMEOUT;
3693 statep->ap_done = B_TRUE;
3694 cv_broadcast(&statep->block_client_cv);
3695
3696 statep->ap_state = IBCM_AP_STATE_IDLE;
3697 /* Wake up threads waiting for LAP/APR to complete */
3698 cv_broadcast(&statep->block_mad_cv);
3699 }
3700 mutex_exit(&statep->state_mutex);
3701
3702 } else if (statep->state == IBCM_STATE_DREQ_SENT) {
3703
3704 statep->timedout_state = statep->state;
3705 statep->state = IBCM_STATE_TIMED_OUT;
3706
3707 /*
3708 * The logic below is necessary, for a race situation between
3709 * ibt_close_rc_channel with no callbacks option and CM's
3710 * internal stale connection handling on the same connection
3711 */
3712 if (statep->close_nocb_state != IBCM_FAIL) {
3713 ASSERT(statep->close_nocb_state == IBCM_UNBLOCK);
3714 ibtl_cm_chan_is_closing(statep->channel);
3715 statep->close_nocb_state = IBCM_BLOCK;
3716 }
3717
3718 mutex_exit(&statep->state_mutex);
3719
3720 /*
3721 * If cm handler is specified, then invoke handler for
3722 * the DREQ timeout
3723 */
3724 if (statep->cm_handler != NULL) {
3725 ibcm_add_tlist(statep);
3726 return;
3727 }
3728
3729 ibcm_process_dreq_timeout(statep);
3730 } else {
3731
3732 #ifdef DEBUG
3733 if (ibcm_test_mode > 0)
3734 IBTF_DPRINTF_L2(cmlog, "ibcm_timeout_cb: "
3735 "Unexpected unhandled timeout for statep 0x%p "
3736 "state %d", statep, statep->state);
3737 #endif
3738 mutex_exit(&statep->state_mutex);
3739 }
3740 }
3741
3742 /*
3743 * Following are set of ibmf send callback routines that are used when posting
3744 * various CM MADs in non-blocking post mode
3745 */
3746
3747 /*ARGSUSED*/
3748 void
ibcm_post_req_complete(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)3749 ibcm_post_req_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, void *args)
3750 {
3751 ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
3752
3753 IBTF_DPRINTF_L4(cmlog, "ibcm_post_req_complete statep %p ", statep);
3754
3755 mutex_enter(&statep->state_mutex);
3756 ibcm_flow_dec(statep->post_time, "REQ");
3757 ibcm_insert_trace(statep, IBCM_TRACE_REQ_POST_COMPLETE);
3758
3759 statep->send_mad_flags &= ~IBCM_REQ_POST_BUSY;
3760
3761 /* signal any waiting threads for REQ MAD to become available */
3762 cv_signal(&statep->block_mad_cv);
3763
3764 if (statep->state == IBCM_STATE_REQ_SENT)
3765 statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
3766
3767 IBCM_REF_CNT_DECR(statep);
3768 mutex_exit(&statep->state_mutex);
3769 }
3770
3771 /*ARGSUSED*/
3772 void
ibcm_post_rep_wait_complete(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)3773 ibcm_post_rep_wait_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
3774 void *args)
3775 {
3776 ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
3777
3778 IBTF_DPRINTF_L4(cmlog, "ibcm_post_rep_wait_complete statep %p", statep);
3779
3780 mutex_enter(&statep->state_mutex);
3781 ibcm_flow_dec(statep->post_time, "REQ_RETRY");
3782 ibcm_insert_trace(statep, IBCM_TRACE_REQ_POST_COMPLETE);
3783 if (statep->state == IBCM_STATE_REP_WAIT)
3784 statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
3785 IBCM_REF_CNT_DECR(statep);
3786 mutex_exit(&statep->state_mutex);
3787 }
3788
3789 /*ARGSUSED*/
3790 void
ibcm_post_rep_complete(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)3791 ibcm_post_rep_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, void *args)
3792 {
3793 ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
3794
3795 IBTF_DPRINTF_L4(cmlog, "ibcm_post_rep_complete statep %p", statep);
3796
3797 mutex_enter(&statep->state_mutex);
3798 ibcm_flow_dec(statep->post_time, "REP");
3799 ibcm_insert_trace(statep, IBCM_TRACE_REP_POST_COMPLETE);
3800 statep->send_mad_flags &= ~IBCM_REP_POST_BUSY;
3801 if (statep->state == IBCM_STATE_REP_SENT)
3802 statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
3803 IBCM_REF_CNT_DECR(statep);
3804 mutex_exit(&statep->state_mutex);
3805 }
3806
3807 /*ARGSUSED*/
3808 void
ibcm_resend_post_rep_complete(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)3809 ibcm_resend_post_rep_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
3810 void *args)
3811 {
3812 ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
3813
3814 IBTF_DPRINTF_L4(cmlog, "ibcm_resend_post_rep_complete(%p)", statep);
3815
3816 mutex_enter(&statep->state_mutex);
3817 ibcm_flow_dec(statep->post_time, "REP_RETRY");
3818 ibcm_insert_trace(statep, IBCM_TRACE_REP_POST_COMPLETE);
3819 statep->send_mad_flags &= ~IBCM_REP_POST_BUSY;
3820
3821 /* No new timeout is set for resending a REP MAD for an incoming REQ */
3822 IBCM_REF_CNT_DECR(statep);
3823 mutex_exit(&statep->state_mutex);
3824 }
3825
3826 /*ARGSUSED*/
3827 void
ibcm_post_mra_rep_complete(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)3828 ibcm_post_mra_rep_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
3829 void *args)
3830 {
3831 ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
3832
3833 IBTF_DPRINTF_L4(cmlog, "ibcm_post_mra_rep_complete statep %p", statep);
3834
3835 mutex_enter(&statep->state_mutex);
3836 ibcm_flow_dec(statep->mra_time, "MRA_REP");
3837 ibcm_insert_trace(statep, IBCM_TRACE_REP_POST_COMPLETE);
3838 if (statep->state == IBCM_STATE_MRA_REP_RCVD)
3839 statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
3840 IBCM_REF_CNT_DECR(statep);
3841 mutex_exit(&statep->state_mutex);
3842 }
3843
3844
3845 /*ARGSUSED*/
3846 void
ibcm_post_mra_complete(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)3847 ibcm_post_mra_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
3848 void *args)
3849 {
3850 ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
3851
3852 IBTF_DPRINTF_L4(cmlog, "ibcm_post_mra_complete statep %p", statep);
3853
3854 mutex_enter(&statep->state_mutex);
3855 ibcm_flow_dec(statep->mra_time, "MRA");
3856 ibcm_insert_trace(statep, IBCM_TRACE_MRA_POST_COMPLETE);
3857
3858 if (statep->delete_mra_msg == B_TRUE) {
3859 ibmf_msg_t *mra_msg;
3860
3861 mra_msg = statep->mra_msg;
3862 statep->mra_msg = NULL;
3863 mutex_exit(&statep->state_mutex);
3864 (void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl,
3865 &mra_msg);
3866 mutex_enter(&statep->state_mutex);
3867 }
3868 statep->send_mad_flags &= ~IBCM_MRA_POST_BUSY;
3869 IBCM_REF_CNT_DECR(statep);
3870 mutex_exit(&statep->state_mutex);
3871 }
3872
3873 /*ARGSUSED*/
3874 void
ibcm_post_dreq_complete(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)3875 ibcm_post_dreq_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, void *args)
3876 {
3877 ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
3878
3879 IBTF_DPRINTF_L4(cmlog, "ibcm_post_dreq_complete statep %p", statep);
3880
3881 mutex_enter(&statep->state_mutex);
3882 ibcm_flow_dec(statep->post_time, "DREQ");
3883 ibcm_insert_trace(statep, IBCM_TRACE_DREQ_POST_COMPLETE);
3884 if (statep->state == IBCM_STATE_DREQ_SENT)
3885 statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
3886 ibcm_close_done(statep, 1);
3887 IBCM_REF_CNT_DECR(statep);
3888 mutex_exit(&statep->state_mutex);
3889 }
3890
3891 /*ARGSUSED*/
3892 void
ibcm_post_lap_complete(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)3893 ibcm_post_lap_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, void *args)
3894 {
3895 ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
3896
3897 IBTF_DPRINTF_L4(cmlog, "ibcm_post_lap_complete statep %p", statep);
3898
3899 mutex_enter(&statep->state_mutex);
3900 ibcm_flow_dec(statep->post_time, "LAP");
3901 ibcm_insert_trace(statep, IBCM_TRACE_LAP_POST_COMPLETE);
3902 if (statep->ap_state == IBCM_AP_STATE_LAP_SENT)
3903 statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
3904 IBCM_REF_CNT_DECR(statep);
3905 mutex_exit(&statep->state_mutex);
3906 }
3907
3908 /*ARGSUSED*/
3909 void
ibcm_post_mra_lap_complete(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)3910 ibcm_post_mra_lap_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
3911 void *args)
3912 {
3913 ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
3914
3915 IBTF_DPRINTF_L4(cmlog, "ibcm_post_mra_lap_complete statep %p", statep);
3916
3917 mutex_enter(&statep->state_mutex);
3918 ibcm_flow_dec(statep->mra_time, "MRA_LAP");
3919 ibcm_insert_trace(statep, IBCM_TRACE_LAP_POST_COMPLETE);
3920 if (statep->ap_state == IBCM_AP_STATE_MRA_LAP_RCVD)
3921 statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
3922 IBCM_REF_CNT_DECR(statep);
3923 mutex_exit(&statep->state_mutex);
3924 }
3925
3926 /*ARGSUSED*/
3927 void
ibcm_post_rej_complete(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)3928 ibcm_post_rej_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
3929 void *args)
3930 {
3931 ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
3932
3933 IBTF_DPRINTF_L4(cmlog, "ibcm_post_rej_complete statep %p", statep);
3934
3935 mutex_enter(&statep->state_mutex);
3936 ibcm_flow_dec(statep->post_time, "REJ");
3937 ibcm_insert_trace(statep, IBCM_TRACE_REJ_POST_COMPLETE);
3938 statep->send_mad_flags &= ~IBCM_REJ_POST_BUSY;
3939 if (statep->state == IBCM_STATE_REJ_SENT) {
3940 statep->remaining_retry_cnt = 0;
3941
3942 /* wait until all possible retransmits of REQ/REP happened */
3943 statep->timerid = IBCM_TIMEOUT(statep,
3944 statep->timer_value * statep->max_cm_retries);
3945 }
3946
3947 IBCM_REF_CNT_DECR(statep);
3948 mutex_exit(&statep->state_mutex);
3949 }
3950
3951 /*ARGSUSED*/
3952 void
ibcm_post_rtu_complete(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)3953 ibcm_post_rtu_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
3954 void *args)
3955 {
3956 ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
3957
3958 IBTF_DPRINTF_L4(cmlog, "ibcm_post_rtu_complete statep %p", statep);
3959
3960 mutex_enter(&statep->state_mutex);
3961 ibcm_flow_dec(statep->post_time, "RTU");
3962 ibcm_insert_trace(statep, IBCM_TRACE_RTU_POST_COMPLETE);
3963 statep->send_mad_flags &= ~IBCM_RTU_POST_BUSY;
3964 IBCM_REF_CNT_DECR(statep);
3965 ibcm_open_done(statep);
3966 mutex_exit(&statep->state_mutex);
3967 }
3968
3969 /*ARGSUSED*/
3970 void
ibcm_post_apr_complete(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)3971 ibcm_post_apr_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
3972 void *args)
3973 {
3974 ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
3975
3976 IBTF_DPRINTF_L4(cmlog, "ibcm_post_apr_complete statep %p", statep);
3977
3978 mutex_enter(&statep->state_mutex);
3979 ibcm_flow_dec(statep->post_time, "APR");
3980 ibcm_insert_trace(statep, IBCM_TRACE_APR_POST_COMPLETE);
3981 /* As long as one APR mad in transit, no retransmits are allowed */
3982 statep->ap_state = IBCM_AP_STATE_IDLE;
3983
3984 /* unblock any DREQ threads and close channels */
3985 cv_broadcast(&statep->block_mad_cv);
3986 IBCM_REF_CNT_DECR(statep); /* decrement the ref count */
3987 mutex_exit(&statep->state_mutex);
3988
3989 }
3990
3991 /*ARGSUSED*/
3992 void
ibcm_post_stored_apr_complete(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)3993 ibcm_post_stored_apr_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
3994 void *args)
3995 {
3996 ibmf_msg_t *ibmf_apr_msg = (ibmf_msg_t *)args;
3997
3998 IBTF_DPRINTF_L4(cmlog, "ibcm_post_stored_apr_complete args %p", args);
3999
4000 ibcm_flow_dec(0, "APR_RESEND");
4001 (void) ibcm_free_out_msg(ibmf_handle, &ibmf_apr_msg);
4002 }
4003
4004 /*ARGSUSED*/
4005 void
ibcm_post_drep_complete(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)4006 ibcm_post_drep_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
4007 void *args)
4008 {
4009 ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
4010
4011 IBTF_DPRINTF_L4(cmlog, "ibcm_post_drep_complete statep %p", statep);
4012
4013 mutex_enter(&statep->state_mutex);
4014 ibcm_flow_dec(statep->post_time, "DREP");
4015 ibcm_insert_trace(statep, IBCM_TRACE_DREP_POST_COMPLETE);
4016 statep->send_mad_flags &= ~IBCM_REJ_POST_BUSY;
4017
4018 if (statep->state == IBCM_STATE_DREQ_RCVD) {
4019
4020 ibcm_close_done(statep, 1);
4021 statep->state = IBCM_STATE_TIMEWAIT;
4022
4023 /*
4024 * For passive side CM set it to remote_ack_delay
4025 * For active side CM add the pkt_life_time * 2
4026 */
4027 statep->timer_value = statep->remote_ack_delay;
4028 if (statep->mode == IBCM_ACTIVE_MODE)
4029 statep->timer_value += (2 * statep->pkt_life_time);
4030 statep->remaining_retry_cnt = 0;
4031 statep->timer_stored_state = statep->state;
4032 statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
4033 }
4034
4035 IBCM_REF_CNT_DECR(statep);
4036 mutex_exit(&statep->state_mutex);
4037 }
4038
4039 /*ARGSUSED*/
4040 void
ibcm_post_sidr_rep_complete(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)4041 ibcm_post_sidr_rep_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
4042 void *args)
4043 {
4044 ibcm_ud_state_data_t *ud_statep = (ibcm_ud_state_data_t *)args;
4045
4046 IBTF_DPRINTF_L4(cmlog, "ibcm_post_sidr_rep_complete ud_statep %p",
4047 ud_statep);
4048
4049 ibcm_flow_dec(0, "SIDR_REP");
4050 mutex_enter(&ud_statep->ud_state_mutex);
4051 ud_statep->ud_send_mad_flags &= ~IBCM_SREP_POST_BUSY;
4052 ud_statep->ud_remaining_retry_cnt = 0;
4053 if (ud_statep->ud_state == IBCM_STATE_SIDR_REP_SENT)
4054 ud_statep->ud_timerid = IBCM_UD_TIMEOUT(ud_statep,
4055 ud_statep->ud_timer_value);
4056 IBCM_UD_REF_CNT_DECR(ud_statep);
4057 mutex_exit(&ud_statep->ud_state_mutex);
4058
4059 }
4060
4061 /*ARGSUSED*/
4062 void
ibcm_post_sidr_req_complete(ibmf_handle_t ibmf_handle,ibmf_msg_t * msgp,void * args)4063 ibcm_post_sidr_req_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
4064 void *args)
4065 {
4066 ibcm_ud_state_data_t *ud_statep = (ibcm_ud_state_data_t *)args;
4067
4068 IBTF_DPRINTF_L4(cmlog, "ibcm_post_sidr_req_complete ud_statep %p",
4069 ud_statep);
4070
4071 ibcm_flow_dec(0, "SIDR_REQ");
4072 mutex_enter(&ud_statep->ud_state_mutex);
4073 if (ud_statep->ud_state == IBCM_STATE_SIDR_REQ_SENT)
4074 ud_statep->ud_timerid = IBCM_UD_TIMEOUT(ud_statep,
4075 ud_statep->ud_timer_value);
4076 IBCM_UD_REF_CNT_DECR(ud_statep);
4077 mutex_exit(&ud_statep->ud_state_mutex);
4078
4079 }
4080
4081 /*
4082 * ibcm_process_dreq_timeout:
4083 * Called when the timer expires on DREP
4084 *
4085 * INPUTS:
4086 * arg - ibcm_state_data_t is passed
4087 *
4088 * RETURN VALUES: NONE
4089 */
4090 void
ibcm_process_dreq_timeout(ibcm_state_data_t * statep)4091 ibcm_process_dreq_timeout(ibcm_state_data_t *statep)
4092 {
4093 mutex_enter(&statep->state_mutex);
4094
4095 /* Max retries reached, move to the time wait state */
4096 statep->state = statep->timer_stored_state =
4097 IBCM_STATE_TIMEWAIT;
4098 ibcm_close_done(statep, 0);
4099
4100 /* Set the TIME_WAIT state timer value */
4101 statep->timer_value = statep->remote_ack_delay;
4102 if (statep->mode == IBCM_ACTIVE_MODE) {
4103 statep->timer_value += (2 * statep->pkt_life_time);
4104 }
4105
4106 statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
4107
4108 if (statep->close_ret_status)
4109 if (statep->stale == B_TRUE)
4110 *statep->close_ret_status = IBT_CM_CLOSED_STALE;
4111 else *statep->close_ret_status = IBT_CM_CLOSED_DREQ_TIMEOUT;
4112
4113 /* signal waiting CVs - blocking in ibt_close_channel() */
4114 statep->close_done = B_TRUE;
4115 if (statep->close_ret_priv_data_len != NULL)
4116 *statep->close_ret_priv_data_len = 0;
4117
4118 /* unblock any close channel with no callbacks option */
4119 statep->close_nocb_state = IBCM_FAIL;
4120
4121 cv_broadcast(&statep->block_client_cv);
4122 mutex_exit(&statep->state_mutex);
4123 }
4124
4125 /*
4126 * ibcm_add_tlist:
4127 * Adds the given RC statep to timeout list
4128 *
4129 * INPUTS:
4130 * arg - ibcm_state_data_t is passed
4131 *
4132 * RETURN VALUES: NONE
4133 */
4134 void
ibcm_add_tlist(ibcm_state_data_t * statep)4135 ibcm_add_tlist(ibcm_state_data_t *statep)
4136 {
4137 mutex_enter(&ibcm_timeout_list_lock);
4138
4139 statep->timeout_next = NULL;
4140 if (ibcm_timeout_list_hdr == NULL) {
4141 ibcm_timeout_list_hdr = statep;
4142 } else {
4143 ibcm_timeout_list_tail->timeout_next = statep;
4144 }
4145
4146 ibcm_timeout_list_tail = statep;
4147
4148 cv_signal(&ibcm_timeout_list_cv);
4149
4150 mutex_exit(&ibcm_timeout_list_lock);
4151 IBTF_DPRINTF_L3(cmlog, "ibcm_add_tlist: "
4152 "attached state = %p to timeout list", statep);
4153 }
4154
4155 void
ibcm_run_tlist_thread(void)4156 ibcm_run_tlist_thread(void)
4157 {
4158 mutex_enter(&ibcm_timeout_list_lock);
4159 cv_signal(&ibcm_timeout_list_cv);
4160 mutex_exit(&ibcm_timeout_list_lock);
4161 }
4162
4163 /*
4164 * ibcm_add_ud_tlist:
4165 * Adds the given UD statep to timeout list
4166 *
4167 * INPUTS:
4168 * arg - ibcm_ud_state_data_t is passed
4169 *
4170 * RETURN VALUES: NONE
4171 */
4172 void
ibcm_add_ud_tlist(ibcm_ud_state_data_t * ud_statep)4173 ibcm_add_ud_tlist(ibcm_ud_state_data_t *ud_statep)
4174 {
4175 mutex_enter(&ibcm_timeout_list_lock);
4176
4177 ud_statep->ud_timeout_next = NULL;
4178 if (ibcm_ud_timeout_list_hdr == NULL) {
4179 ibcm_ud_timeout_list_hdr = ud_statep;
4180 } else {
4181 ibcm_ud_timeout_list_tail->ud_timeout_next = ud_statep;
4182 }
4183
4184 ibcm_ud_timeout_list_tail = ud_statep;
4185
4186 cv_signal(&ibcm_timeout_list_cv);
4187
4188 mutex_exit(&ibcm_timeout_list_lock);
4189 IBTF_DPRINTF_L3(cmlog, "ibcm_add_ud_tlist: "
4190 "attached state = %p to ud timeout list", ud_statep);
4191 }
4192
4193 /*
4194 * ibcm_process_tlist:
4195 * Thread that processes all the RC and UD statep's from
4196 * the appropriate lists
4197 *
4198 * INPUTS:
4199 * NONE
4200 *
4201 * RETURN VALUES: NONE
4202 */
4203 void
ibcm_process_tlist()4204 ibcm_process_tlist()
4205 {
4206 ibcm_state_data_t *statep;
4207 ibcm_ud_state_data_t *ud_statep;
4208 callb_cpr_t cprinfo;
4209
4210 IBTF_DPRINTF_L5(cmlog, "ibcm_process_tlist: thread started");
4211
4212 mutex_enter(&ibcm_timeout_list_lock);
4213
4214 CALLB_CPR_INIT(&cprinfo, &ibcm_timeout_list_lock, callb_generic_cpr,
4215 "ibcm_process_tlist");
4216
4217 for (;;) {
4218 if (ibcm_timeout_list_flags & IBCM_TIMEOUT_THREAD_EXIT) {
4219 /* The thread needs to exit */
4220 cv_signal(&ibcm_timeout_thread_done_cv);
4221 break;
4222 }
4223 mutex_exit(&ibcm_timeout_list_lock);
4224 ibcm_check_for_opens();
4225 ibcm_check_for_async_close();
4226 mutex_enter(&ibcm_timeout_list_lock);
4227
4228 /* First, handle pending RC statep's, followed by UD's */
4229 if (ibcm_timeout_list_hdr != NULL) {
4230 statep = ibcm_timeout_list_hdr;
4231 ibcm_timeout_list_hdr = statep->timeout_next;
4232
4233 if (ibcm_timeout_list_hdr == NULL)
4234 ibcm_timeout_list_tail = NULL;
4235
4236 statep->timeout_next = NULL;
4237
4238 mutex_exit(&ibcm_timeout_list_lock);
4239 IBTF_DPRINTF_L3(cmlog, "ibcm_process_tlist: "
4240 "scheduling state = %p", statep);
4241 ibcm_timeout_client_cb(statep);
4242 mutex_enter(&ibcm_timeout_list_lock);
4243 } else if (ibcm_ud_timeout_list_hdr != NULL) {
4244 ud_statep = ibcm_ud_timeout_list_hdr;
4245 ibcm_ud_timeout_list_hdr = ud_statep->ud_timeout_next;
4246
4247 if (ibcm_ud_timeout_list_hdr == NULL)
4248 ibcm_ud_timeout_list_tail = NULL;
4249
4250 ud_statep->ud_timeout_next = NULL;
4251
4252 mutex_exit(&ibcm_timeout_list_lock);
4253 IBTF_DPRINTF_L3(cmlog, "ibcm_process_tlist: "
4254 "ud scheduling state = %p", ud_statep);
4255 ibcm_ud_timeout_client_cb(ud_statep);
4256 mutex_enter(&ibcm_timeout_list_lock);
4257 } else {
4258 CALLB_CPR_SAFE_BEGIN(&cprinfo);
4259 cv_wait(&ibcm_timeout_list_cv, &ibcm_timeout_list_lock);
4260 CALLB_CPR_SAFE_END(&cprinfo, &ibcm_timeout_list_lock);
4261 }
4262 }
4263
4264 #ifndef __lock_lint
4265 CALLB_CPR_EXIT(&cprinfo); /* mutex_exit */
4266 #endif
4267 }
4268
4269
4270 /*
4271 * ibcm_timeout_client_cb:
4272 * Called from timeout thread processing
4273 * Primary purpose is to call client handler
4274 *
4275 * INPUTS:
4276 * arg - ibcm_state_data_t is passed
4277 *
4278 * RETURN VALUES: NONE
4279 */
4280 void
ibcm_timeout_client_cb(ibcm_state_data_t * statep)4281 ibcm_timeout_client_cb(ibcm_state_data_t *statep)
4282 {
4283 mutex_enter(&statep->state_mutex);
4284
4285 if ((statep->state == IBCM_STATE_DELETE) &&
4286 (statep->recycle_arg != NULL)) {
4287 struct ibcm_taskq_recycle_arg_s *recycle_arg;
4288
4289 recycle_arg = statep->recycle_arg;
4290 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(statep->recycle_arg))
4291 statep->recycle_arg = NULL;
4292 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(statep->recycle_arg))
4293 mutex_exit(&statep->state_mutex);
4294 (void) ibcm_process_rc_recycle(recycle_arg);
4295 ibcm_delete_state_data(statep);
4296 return;
4297 }
4298
4299 if ((statep->state == IBCM_STATE_DELETE) &&
4300 (statep->delete_state_data == B_TRUE)) {
4301 mutex_exit(&statep->state_mutex);
4302 ibcm_dealloc_state_data(statep);
4303 return;
4304 }
4305
4306 /* Else, it must be in TIMEOUT state, do the necessary processing */
4307 if (statep->state == IBCM_STATE_TIMED_OUT) {
4308 void *data;
4309 uint8_t cf_msg;
4310 ib_guid_t local_hca_guid;
4311
4312 mutex_exit(&statep->state_mutex);
4313
4314 if (statep->timedout_state == IBCM_STATE_DREQ_SENT) {
4315 ibt_cm_event_t event;
4316 ibt_cm_return_args_t ret_args;
4317
4318 bzero(&event, sizeof (event));
4319 bzero(&ret_args, sizeof (ret_args));
4320
4321 event.cm_type = IBT_CM_EVENT_CONN_CLOSED;
4322 event.cm_channel = statep->channel;
4323 event.cm_session_id = NULL;
4324 event.cm_priv_data = NULL;
4325 event.cm_priv_data_len = 0;
4326
4327 if (statep->stale == B_TRUE)
4328 event.cm_event.closed = IBT_CM_CLOSED_STALE;
4329 else event.cm_event.closed = IBT_CM_CLOSED_DREQ_TIMEOUT;
4330
4331 /*
4332 * cm handler cannot be non-NULL, as that check is
4333 * already made in ibcm_timeout_cb
4334 */
4335 ibcm_insert_trace(statep,
4336 IBCM_TRACE_CALLED_CONN_CLOSE_EVENT);
4337
4338 (void) statep->cm_handler(statep->state_cm_private,
4339 &event, &ret_args, NULL, 0);
4340
4341 ibcm_insert_trace(statep,
4342 IBCM_TRACE_RET_CONN_CLOSE_EVENT);
4343
4344 ibcm_process_dreq_timeout(statep);
4345 return;
4346 }
4347
4348 data = ((ibcm_rej_msg_t *)
4349 IBCM_OUT_MSGP(statep->stored_msg))->rej_private_data;
4350
4351 if ((statep->timedout_state == IBCM_STATE_REQ_SENT) ||
4352 (statep->timedout_state == IBCM_STATE_REP_WAIT)) {
4353 cf_msg = IBT_CM_FAILURE_REQ;
4354 } else {
4355 ASSERT(
4356 (statep->timedout_state == IBCM_STATE_REP_SENT) ||
4357 (statep->timedout_state ==
4358 IBCM_STATE_MRA_REP_RCVD));
4359 cf_msg = IBT_CM_FAILURE_REP;
4360 }
4361
4362 /*
4363 * Invoke the CM handler w/ event IBT_CM_EVENT_TIMEOUT
4364 * This callback happens for only active non blocking or
4365 * passive client
4366 */
4367 ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_TIMEOUT,
4368 cf_msg, IBT_CM_TIMEOUT, data, IBT_REJ_PRIV_DATA_SZ);
4369
4370 /* signal the blocked ibt_open_rc_channel */
4371 mutex_enter(&statep->state_mutex);
4372
4373 /*
4374 * statep->open_return_data is set for blocking
4375 * signal the blocked ibt_open_rc_channel
4376 */
4377 if (statep->open_return_data != NULL) {
4378 statep->open_return_data->rc_status = IBT_CM_TIMEOUT;
4379 statep->open_done = B_TRUE;
4380 cv_broadcast(&statep->block_client_cv);
4381 }
4382
4383 mutex_exit(&statep->state_mutex);
4384
4385 local_hca_guid = h2b64(statep->local_hca_guid);
4386 ibcm_post_rej_mad(statep, IBT_CM_TIMEOUT,
4387 IBT_CM_FAILURE_UNKNOWN, &local_hca_guid,
4388 sizeof (ib_guid_t));
4389 } else if (statep->ap_state == IBCM_AP_STATE_TIMED_OUT) {
4390
4391 mutex_exit(&statep->state_mutex);
4392
4393 ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_TIMEOUT,
4394 IBT_CM_FAILURE_LAP, IBT_CM_TIMEOUT, NULL, 0);
4395
4396 /* Now wake up threads waiting for LAP/APR to complete */
4397 mutex_enter(&statep->state_mutex);
4398 /*
4399 * statep->ap_return_data is initialized for blocking in
4400 * ibt_set_alt_path(), signal the waiting CV
4401 */
4402 if (statep->ap_return_data != NULL) {
4403 statep->ap_return_data->ap_status = IBT_CM_AP_TIMEOUT;
4404 statep->ap_done = B_TRUE;
4405 cv_broadcast(&statep->block_client_cv);
4406 }
4407 statep->ap_state = IBCM_AP_STATE_IDLE;
4408 cv_broadcast(&statep->block_mad_cv);
4409 mutex_exit(&statep->state_mutex);
4410 } else {
4411 IBTF_DPRINTF_L2(cmlog, "ibcm_timeout_client_cb "
4412 "Unexpected else path statep %p state %d ap_state %d",
4413 statep, statep->state, statep->ap_state);
4414 mutex_exit(&statep->state_mutex);
4415
4416 }
4417 }
4418
4419 /*
4420 * ibcm_ud_timeout_client_cb:
4421 * Called from UD timeout thread processing
4422 * Primary purpose is to call client handler
4423 *
4424 * INPUTS:
4425 * arg - ibcm_ud_state_data_t is passed
4426 *
4427 * RETURN VALUES: NONE
4428 */
4429 void
ibcm_ud_timeout_client_cb(ibcm_ud_state_data_t * ud_statep)4430 ibcm_ud_timeout_client_cb(ibcm_ud_state_data_t *ud_statep)
4431 {
4432 ibt_cm_ud_event_t ud_event;
4433
4434 mutex_enter(&ud_statep->ud_state_mutex);
4435
4436 if ((ud_statep->ud_state == IBCM_STATE_DELETE) &&
4437 (ud_statep->ud_delete_state_data == B_TRUE)) {
4438
4439 mutex_exit(&ud_statep->ud_state_mutex);
4440 ibcm_dealloc_ud_state_data(ud_statep);
4441 return;
4442 } else
4443 mutex_exit(&ud_statep->ud_state_mutex);
4444
4445 /* Fill in ibt_cm_ud_event_t */
4446 ud_event.cm_type = IBT_CM_UD_EVENT_SIDR_REP;
4447 ud_event.cm_session_id = NULL;
4448 ud_event.cm_event.sidr_rep.srep_status = IBT_CM_SREP_TIMEOUT;
4449
4450 (void) ud_statep->ud_cm_handler(ud_statep->ud_state_cm_private,
4451 &ud_event, NULL, NULL, 0);
4452
4453 /* Delete UD state data now, finally done with it */
4454 ibcm_delete_ud_state_data(ud_statep);
4455 }
4456
4457
4458 /*
4459 * ibcm_process_sidr_req_msg:
4460 * This call processes an incoming SIDR REQ
4461 *
4462 * INPUTS:
4463 * hcap - HCA entry pointer
4464 * input_madp - Incoming CM SIDR REQ MAD
4465 * cm_mad_addr - Address information for the MAD to be posted
4466 *
4467 * RETURN VALUE:
4468 * NONE
4469 */
4470 void
ibcm_process_sidr_req_msg(ibcm_hca_info_t * hcap,uint8_t * input_madp,ibcm_mad_addr_t * cm_mad_addr)4471 ibcm_process_sidr_req_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
4472 ibcm_mad_addr_t *cm_mad_addr)
4473 {
4474 ib_gid_t gid;
4475 ib_lid_t lid;
4476 uint32_t req_id;
4477 ibcm_status_t state_lookup_status;
4478 ibcm_status_t cm_status;
4479 ibt_sidr_status_t sidr_status;
4480 ibcm_svc_info_t *svc_infop;
4481 ibcm_svc_bind_t *svc_bindp;
4482 ibcm_svc_bind_t *tmp_bindp;
4483 ibcm_sidr_req_msg_t *sidr_reqp = (ibcm_sidr_req_msg_t *)
4484 (&input_madp[IBCM_MAD_HDR_SIZE]);
4485 ibcm_ud_state_data_t *ud_statep = NULL;
4486 ibcm_sidr_srch_t srch_sidr;
4487 ib_pkey_t pkey;
4488 uint8_t port_num;
4489 ib_guid_t hca_guid;
4490
4491 IBTF_DPRINTF_L4(cmlog, "ibcm_process_sidr_req_msg:");
4492
4493 hca_guid = hcap->hca_guid;
4494 port_num = cm_mad_addr->port_num;
4495
4496 /* Figure out LID, GID, RequestId for svc_id lookup */
4497 lid = cm_mad_addr->rcvd_addr.ia_remote_lid;
4498 req_id = b2h32(sidr_reqp->sidr_req_request_id);
4499 pkey = b2h16(sidr_reqp->sidr_req_pkey);
4500 if (cm_mad_addr->grh_exists == B_TRUE)
4501 gid = cm_mad_addr->grh_hdr.ig_sender_gid;
4502 else
4503 gid.gid_prefix = gid.gid_guid = 0;
4504
4505 /*
4506 * Lookup for an existing state structure
4507 * - if lookup fails it creates a new ud_state struct
4508 * No need to hold a lock across the call to ibcm_find_sidr_entry() as
4509 * the list lock is held in that function to find the matching entry.
4510 */
4511
4512 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(srch_sidr))
4513
4514 srch_sidr.srch_lid = lid;
4515 srch_sidr.srch_gid = gid;
4516 srch_sidr.srch_grh_exists = cm_mad_addr->grh_exists;
4517 srch_sidr.srch_req_id = req_id;
4518 srch_sidr.srch_mode = IBCM_PASSIVE_MODE;
4519
4520 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(srch_sidr))
4521
4522 rw_enter(&hcap->hca_sidr_list_lock, RW_WRITER);
4523 state_lookup_status = ibcm_find_sidr_entry(&srch_sidr, hcap, &ud_statep,
4524 IBCM_FLAG_LOOKUP_AND_ADD);
4525 rw_exit(&hcap->hca_sidr_list_lock);
4526
4527 IBTF_DPRINTF_L4(cmlog, "ibcm_process_sidr_req_msg: ud_statep 0x%p "
4528 "lookup status %x", ud_statep, state_lookup_status);
4529
4530 if (state_lookup_status == IBCM_LOOKUP_NEW) {
4531
4532 /* Increment hca's resource count */
4533 ibcm_inc_hca_res_cnt(hcap);
4534
4535 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ud_statep))
4536
4537 /*
4538 * Allocate CM MAD for a response
4539 * This MAD is deallocated on state structure delete
4540 * and re-used for all outgoing MADs for this connection.
4541 * If MAD allocation fails, delete the ud statep
4542 */
4543 if (ibcm_alloc_out_msg(cm_mad_addr->ibmf_hdl,
4544 &ud_statep->ud_stored_msg, MAD_METHOD_SEND) !=
4545 IBT_SUCCESS) {
4546 mutex_enter(&ud_statep->ud_state_mutex);
4547 IBCM_UD_REF_CNT_DECR(ud_statep);
4548 mutex_exit(&ud_statep->ud_state_mutex);
4549 ibcm_delete_ud_state_data(ud_statep);
4550 return;
4551 }
4552
4553 /* Lookup for service */
4554 ud_statep->ud_svc_id = b2h64(sidr_reqp->sidr_req_service_id);
4555 ud_statep->ud_state = IBCM_STATE_SIDR_REQ_RCVD;
4556 ud_statep->ud_clnt_proceed = IBCM_BLOCK;
4557
4558 mutex_enter(&ibcm_svc_info_lock);
4559
4560 svc_infop = ibcm_find_svc_entry(ud_statep->ud_svc_id);
4561
4562 IBTF_DPRINTF_L4(cmlog, "ibcm_process_sidr_req_msg: "
4563 " ud_statep 0x%p svc_info %p", ud_statep, svc_infop);
4564
4565 /*
4566 * No need to hold the ud state mutex, as no other thread
4567 * modifies ud statep in IBCM_STATE_SIDR_REQ_RCVD state
4568 */
4569
4570 if (svc_infop != NULL) {
4571 /* find the "bind" entry that enables this port */
4572
4573 svc_bindp = NULL;
4574 tmp_bindp = svc_infop->svc_bind_list;
4575 while (tmp_bindp) {
4576 if (tmp_bindp->sbind_hcaguid == hca_guid &&
4577 tmp_bindp->sbind_port == port_num) {
4578 if (gid.gid_guid ==
4579 tmp_bindp->sbind_gid.gid_guid &&
4580 gid.gid_prefix ==
4581 tmp_bindp->sbind_gid.gid_prefix) {
4582 /* a really good match */
4583 svc_bindp = tmp_bindp;
4584 if (pkey ==
4585 tmp_bindp->sbind_pkey)
4586 /* absolute best */
4587 break;
4588 } else if (svc_bindp == NULL) {
4589 /* port match => a good match */
4590 svc_bindp = tmp_bindp;
4591 }
4592 }
4593 tmp_bindp = tmp_bindp->sbind_link;
4594 }
4595 if (svc_bindp == NULL) {
4596 svc_infop = NULL;
4597 }
4598 }
4599
4600 IBCM_OUT_HDRP(ud_statep->ud_stored_msg)->TransactionID =
4601 ((ib_mad_hdr_t *)(input_madp))->TransactionID;
4602
4603 ibcm_build_reply_mad_addr(cm_mad_addr,
4604 &ud_statep->ud_stored_reply_addr);
4605
4606 if (ud_statep->ud_stored_reply_addr.cm_qp_entry == NULL) {
4607
4608 mutex_exit(&ibcm_svc_info_lock);
4609
4610 /* Not much choice. CM MADs cannot go on QP1 */
4611 mutex_enter(&ud_statep->ud_state_mutex);
4612 IBCM_UD_REF_CNT_DECR(ud_statep);
4613 ud_statep->ud_state = IBCM_STATE_DELETE;
4614 mutex_exit(&ud_statep->ud_state_mutex);
4615
4616 ibcm_delete_ud_state_data(ud_statep);
4617 return;
4618 }
4619
4620 if (svc_infop == NULL || svc_infop->svc_ud_handler == NULL) {
4621 /*
4622 * Don't have a record of Service ID in CM's
4623 * internal list registered at this gid/lid.
4624 * So, send out Service ID not supported SIDR REP msg
4625 */
4626 sidr_status = IBT_CM_SREP_SID_INVALID;
4627 } else {
4628 ud_statep->ud_cm_handler = svc_infop->svc_ud_handler;
4629 ud_statep->ud_state_cm_private =
4630 svc_bindp->sbind_cm_private;
4631 IBCM_SVC_INCR(svc_infop);
4632 mutex_exit(&ibcm_svc_info_lock);
4633
4634 /* Call Client's UD handler */
4635 cm_status = ibcm_sidr_req_ud_handler(ud_statep,
4636 sidr_reqp, cm_mad_addr, &sidr_status);
4637
4638 mutex_enter(&ibcm_svc_info_lock);
4639 IBCM_SVC_DECR(svc_infop);
4640 }
4641
4642 mutex_exit(&ibcm_svc_info_lock);
4643
4644 if (cm_status == IBCM_DEFER) {
4645 IBTF_DPRINTF_L4(cmlog, "ibcm_process_sidr_req_msg: "
4646 "ud_statep 0x%p client returned DEFER response",
4647 ud_statep);
4648 return;
4649 }
4650
4651 ibcm_post_sidr_rep_mad(ud_statep, sidr_status);
4652
4653 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*ud_statep))
4654
4655 mutex_enter(&ud_statep->ud_state_mutex);
4656 IBCM_UD_REF_CNT_DECR(ud_statep);
4657 mutex_exit(&ud_statep->ud_state_mutex);
4658 } else {
4659 ASSERT(state_lookup_status == IBCM_LOOKUP_EXISTS);
4660
4661 mutex_enter(&ud_statep->ud_state_mutex);
4662
4663 if (ud_statep->ud_state == IBCM_STATE_SIDR_REP_SENT)
4664 ibcm_resend_srep_mad(ud_statep);
4665
4666 IBCM_UD_REF_CNT_DECR(ud_statep);
4667 mutex_exit(&ud_statep->ud_state_mutex);
4668 }
4669 }
4670
4671
4672 /*
4673 * ibcm_process_sidr_rep_msg:
4674 * This call processes an incoming SIDR REP
4675 *
4676 * INPUTS:
4677 * hcap - HCA entry pointer
4678 * input_madp - incoming CM SIDR REP MAD
4679 * cm_mad_addr - Address information for the MAD to be posted
4680 *
4681 * RETURN VALUE:
4682 * NONE
4683 */
4684 void
ibcm_process_sidr_rep_msg(ibcm_hca_info_t * hcap,uint8_t * input_madp,ibcm_mad_addr_t * cm_mad_addr)4685 ibcm_process_sidr_rep_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
4686 ibcm_mad_addr_t *cm_mad_addr)
4687 {
4688 ib_lid_t lid;
4689 ib_gid_t gid;
4690 ibcm_status_t status;
4691 ib_svc_id_t tmp_svc_id;
4692 ibcm_sidr_rep_msg_t *sidr_repp = (ibcm_sidr_rep_msg_t *)
4693 (&input_madp[IBCM_MAD_HDR_SIZE]);
4694 ibcm_ud_state_data_t *ud_statep = NULL;
4695 ibcm_sidr_srch_t srch_sidr;
4696
4697 IBTF_DPRINTF_L4(cmlog, "ibcm_process_sidr_rep_msg:");
4698
4699 lid = cm_mad_addr->rcvd_addr.ia_local_lid;
4700 if (cm_mad_addr->grh_exists == B_TRUE)
4701 gid = cm_mad_addr->grh_hdr.ig_recver_gid;
4702 else
4703 gid.gid_prefix = gid.gid_guid = 0;
4704
4705 IBTF_DPRINTF_L3(cmlog, "ibcm_process_sidr_rep_msg: QPN rcvd = %x",
4706 h2b32(sidr_repp->sidr_rep_qpn_plus) >> 8);
4707
4708 /*
4709 * Lookup for an existing state structure.
4710 * No need to hold a lock as ibcm_find_sidr_entry() holds the
4711 * list lock to find the matching entry.
4712 */
4713 IBTF_DPRINTF_L4(cmlog, "ibcm_process_sidr_rep: lid=%x, (%llX, %llX), "
4714 "grh = %x, id = %x", lid, gid.gid_prefix, gid.gid_guid,
4715 cm_mad_addr->grh_exists, sidr_repp->sidr_rep_request_id);
4716
4717 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(srch_sidr))
4718
4719 srch_sidr.srch_lid = lid;
4720 srch_sidr.srch_gid = gid;
4721 srch_sidr.srch_grh_exists = cm_mad_addr->grh_exists;
4722 srch_sidr.srch_req_id = b2h32(sidr_repp->sidr_rep_request_id);
4723 srch_sidr.srch_mode = IBCM_ACTIVE_MODE;
4724
4725 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(srch_sidr))
4726
4727 rw_enter(&hcap->hca_sidr_list_lock, RW_READER);
4728 status = ibcm_find_sidr_entry(&srch_sidr, hcap, &ud_statep,
4729 IBCM_FLAG_LOOKUP);
4730 rw_exit(&hcap->hca_sidr_list_lock);
4731
4732 IBTF_DPRINTF_L4(cmlog, "ibcm_process_sidr_rep_msg: ud_statep 0x%p "
4733 "find sidr entry status = %x", ud_statep, status);
4734
4735 if (status != IBCM_LOOKUP_EXISTS) {
4736 IBTF_DPRINTF_L2(cmlog, "ibcm_process_sidr_rep_msg: "
4737 "No matching ud_statep for SIDR REP");
4738 return;
4739 }
4740
4741 if (IBCM_OUT_HDRP(ud_statep->ud_stored_msg)->TransactionID !=
4742 ((ib_mad_hdr_t *)(input_madp))->TransactionID) {
4743 mutex_enter(&ud_statep->ud_state_mutex);
4744 IBCM_UD_REF_CNT_DECR(ud_statep);
4745 mutex_exit(&ud_statep->ud_state_mutex);
4746 IBTF_DPRINTF_L2(cmlog, "ibcm_process_sidr_rep_msg: "
4747 "ud_statep 0x%p. A SIDR REP MAD with tid expected 0x%llX "
4748 "tid found 0x%llX req_id %x arrived", ud_statep,
4749 b2h64(
4750 IBCM_OUT_HDRP(ud_statep->ud_stored_msg)->TransactionID),
4751 b2h64(((ib_mad_hdr_t *)(input_madp))->TransactionID),
4752 b2h32(sidr_repp->sidr_rep_request_id));
4753 return;
4754 }
4755
4756 mutex_enter(&ud_statep->ud_state_mutex);
4757
4758 /*
4759 * We need to check service ID received against the one sent?
4760 * If they don't match just return.
4761 */
4762 bcopy(sidr_repp->sidr_rep_service_id, &tmp_svc_id, sizeof (tmp_svc_id));
4763 bcopy(&tmp_svc_id, sidr_repp->sidr_rep_service_id, sizeof (tmp_svc_id));
4764 if (ud_statep->ud_svc_id != b2h64(tmp_svc_id)) {
4765 IBTF_DPRINTF_L2(cmlog, "ibcm_process_sidr_rep_msg: "
4766 "ud_statep -0x%p svcids do not match %llx %llx",
4767 ud_statep, ud_statep->ud_svc_id, b2h64(tmp_svc_id));
4768
4769 IBCM_UD_REF_CNT_DECR(ud_statep);
4770 mutex_exit(&ud_statep->ud_state_mutex);
4771 return;
4772 }
4773
4774 if (ud_statep->ud_state == IBCM_STATE_SIDR_REQ_SENT) {
4775 timeout_id_t timer_val = ud_statep->ud_timerid;
4776
4777 ud_statep->ud_state = IBCM_STATE_SIDR_REP_RCVD;
4778 ud_statep->ud_timerid = 0;
4779 mutex_exit(&ud_statep->ud_state_mutex);
4780
4781 /* Cancel timer set after sending SIDR REQ */
4782 (void) untimeout(timer_val);
4783
4784 /*
4785 * Call Client's UD handler
4786 */
4787 ibcm_sidr_rep_ud_handler(ud_statep, sidr_repp);
4788
4789 mutex_enter(&ud_statep->ud_state_mutex);
4790
4791 ud_statep->ud_state = IBCM_STATE_DELETE;
4792
4793 /*
4794 * ud_statep->ud_return_data is initialized for blocking in
4795 * ibt_ud_get_dqpn(). Initialize its fields and
4796 * signal the blocking call in ibt_ud_get_dqpn().
4797 */
4798 if (ud_statep->ud_return_data != NULL) {
4799 /* get rep_qpn and rep_status */
4800 ibt_priv_data_len_t len;
4801
4802 /* Copy the SIDR private data */
4803 len = min(ud_statep->ud_return_data->ud_priv_data_len,
4804 IBT_SIDR_REP_PRIV_DATA_SZ);
4805
4806 if ((ud_statep->ud_return_data->ud_priv_data != NULL) &&
4807 (len > 0)) {
4808 bcopy(sidr_repp->sidr_rep_private_data,
4809 ud_statep->ud_return_data->ud_priv_data,
4810 len);
4811 }
4812
4813 /* get status first */
4814 ud_statep->ud_return_data->ud_status =
4815 sidr_repp->sidr_rep_rep_status;
4816
4817 if (ud_statep->ud_return_data->ud_status ==
4818 IBT_CM_SREP_QPN_VALID) {
4819 ud_statep->ud_return_data->ud_dqpn =
4820 h2b32(sidr_repp->sidr_rep_qpn_plus) >> 8;
4821 ud_statep->ud_return_data->ud_qkey =
4822 b2h32(sidr_repp->sidr_rep_qkey);
4823 }
4824
4825 ud_statep->ud_blocking_done = B_TRUE;
4826 cv_broadcast(&ud_statep->ud_block_client_cv);
4827 }
4828
4829 IBCM_UD_REF_CNT_DECR(ud_statep);
4830 mutex_exit(&ud_statep->ud_state_mutex);
4831
4832 /* Delete UD state data now, finally done with it */
4833 ibcm_delete_ud_state_data(ud_statep);
4834 } else {
4835 IBTF_DPRINTF_L3(cmlog, "ibcm_process_sidr_rep_msg: "
4836 "ud state is = 0x%x", ud_statep->ud_state);
4837 IBCM_UD_REF_CNT_DECR(ud_statep);
4838 mutex_exit(&ud_statep->ud_state_mutex);
4839 }
4840 }
4841
4842
4843 /*
4844 * ibcm_post_sidr_rep_mad:
4845 * This call posts a SIDR REP MAD
4846 *
4847 * INPUTS:
4848 * ud_statep - pointer to ibcm_ud_state_data_t
4849 * status - Status information
4850 *
4851 * RETURN VALUE: NONE
4852 */
4853 void
ibcm_post_sidr_rep_mad(ibcm_ud_state_data_t * ud_statep,ibt_sidr_status_t status)4854 ibcm_post_sidr_rep_mad(ibcm_ud_state_data_t *ud_statep,
4855 ibt_sidr_status_t status)
4856 {
4857 ib_svc_id_t tmp_svc_id;
4858 ibcm_sidr_rep_msg_t *sidr_repp =
4859 (ibcm_sidr_rep_msg_t *)IBCM_OUT_MSGP(ud_statep->ud_stored_msg);
4860 clock_t timer_value;
4861
4862 IBTF_DPRINTF_L5(cmlog, "ibcm_post_sidr_rep_mad:");
4863
4864 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sidr_repp))
4865
4866 IBCM_OUT_HDRP(ud_statep->ud_stored_msg)->AttributeID =
4867 h2b16(IBCM_INCOMING_SIDR_REP + IBCM_ATTR_BASE_ID);
4868
4869 /*
4870 * Initialize SIDR REP message. (Other fields were
4871 * already filled up in ibcm_sidr_req_ud_handler()
4872 */
4873 sidr_repp->sidr_rep_request_id = h2b32(ud_statep->ud_req_id);
4874 tmp_svc_id = h2b64(ud_statep->ud_svc_id);
4875 bcopy(&tmp_svc_id, sidr_repp->sidr_rep_service_id, sizeof (tmp_svc_id));
4876
4877 sidr_repp->sidr_rep_rep_status = (uint8_t)status;
4878
4879 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*sidr_repp))
4880
4881 /* post the SIDR REP MAD */
4882 ibcm_post_ud_mad(ud_statep, ud_statep->ud_stored_msg, NULL, NULL);
4883
4884 timer_value = ibt_ib2usec(ibcm_max_sidr_rep_store_time);
4885 /*
4886 * Hold the statep lock, as a SIDR REQ may come in after setting state
4887 * but before timeout. This can result in a dangling timeout ie.,
4888 * the incoming SIDR REQ would be unable to cancel this timeout
4889 */
4890 mutex_enter(&ud_statep->ud_state_mutex);
4891
4892 ud_statep->ud_remaining_retry_cnt = 1;
4893 ud_statep->ud_timer_value = timer_value;
4894
4895 ud_statep->ud_timer_stored_state = ud_statep->ud_state =
4896 IBCM_STATE_SIDR_REP_SENT;
4897 ud_statep->ud_timerid = IBCM_UD_TIMEOUT(ud_statep,
4898 ud_statep->ud_timer_value);
4899
4900 mutex_exit(&ud_statep->ud_state_mutex);
4901 }
4902
4903
4904 /*
4905 * ibcm_sidr_timeout_cb:
4906 * Called when the timer expires on SIDR request
4907 *
4908 * INPUTS:
4909 * arg - ibcm_ud_state_data_t with all the info
4910 *
4911 * RETURN VALUE: NONE
4912 */
4913 void
ibcm_sidr_timeout_cb(void * arg)4914 ibcm_sidr_timeout_cb(void *arg)
4915 {
4916 ibcm_ud_state_data_t *ud_statep = (ibcm_ud_state_data_t *)arg;
4917
4918 mutex_enter(&ud_statep->ud_state_mutex);
4919 ud_statep->ud_timerid = 0;
4920
4921 IBTF_DPRINTF_L3(cmlog, "ibcm_sidr_timeout_cb: ud_statep 0x%p "
4922 "state = 0x%x", ud_statep, ud_statep->ud_state);
4923
4924 /* Processing depends upon current state */
4925 if (ud_statep->ud_state == IBCM_STATE_SIDR_REP_SENT) {
4926 ud_statep->ud_state = IBCM_STATE_DELETE;
4927
4928 mutex_exit(&ud_statep->ud_state_mutex);
4929
4930 /* Deallocate the CM state structure */
4931 ibcm_delete_ud_state_data(ud_statep);
4932
4933 } else if ((ud_statep->ud_remaining_retry_cnt > 0) &&
4934 (ud_statep->ud_state == IBCM_STATE_SIDR_REQ_SENT)) {
4935
4936 ud_statep->ud_remaining_retry_cnt--;
4937 IBCM_UD_REF_CNT_INCR(ud_statep); /* for non-blocking post */
4938 IBTF_DPRINTF_L4(cmlog, "ibcm_sidr_timeout_cb: "
4939 "ud_statep = %p, retries remaining = 0x%x",
4940 ud_statep, ud_statep->ud_remaining_retry_cnt);
4941 mutex_exit(&ud_statep->ud_state_mutex);
4942
4943 /* Post mad in non blocking mode */
4944 ibcm_post_ud_mad(ud_statep, ud_statep->ud_stored_msg,
4945 ibcm_post_sidr_req_complete, ud_statep);
4946
4947 } else if (ud_statep->ud_state == IBCM_STATE_SIDR_REQ_SENT) {
4948
4949 /* This is on SIDR REQ Sender side processing */
4950
4951 /* set state to IBCM_STATE_DELETE */
4952 ud_statep->ud_state = IBCM_STATE_DELETE;
4953
4954 /*
4955 * retry counter expired, clean up
4956 *
4957 * Invoke the client/server handler with a "status" of
4958 * IBT_CM_SREP_TIMEOUT.
4959 */
4960
4961 if (ud_statep->ud_return_data != NULL) {
4962 ud_statep->ud_return_data->ud_status =
4963 IBT_CM_SREP_TIMEOUT;
4964 ud_statep->ud_blocking_done = B_TRUE;
4965 cv_broadcast(&ud_statep->ud_block_client_cv);
4966 }
4967
4968 mutex_exit(&ud_statep->ud_state_mutex);
4969
4970 /* Invoke the client handler in a separate thread */
4971 if (ud_statep->ud_cm_handler != NULL) {
4972 /* UD state data is delete in timeout thread */
4973 ibcm_add_ud_tlist(ud_statep);
4974 return;
4975 }
4976
4977 /* Delete UD state data now, finally done with it */
4978 ibcm_delete_ud_state_data(ud_statep);
4979 } else {
4980
4981 #ifdef DEBUG
4982 if (ibcm_test_mode > 0)
4983 IBTF_DPRINTF_L2(cmlog, "ibcm_sidr_timeout_cb: "
4984 "Nop timeout for ud_statep 0x%p in ud_state %d",
4985 ud_statep, ud_statep->ud_state);
4986 #endif
4987 mutex_exit(&ud_statep->ud_state_mutex);
4988 }
4989 }
4990
4991
4992 /*
4993 * ibcm_resend_srep_mad:
4994 * Called on a duplicate incoming SIDR REQ on server side
4995 * Posts the stored MAD from ud state structure using ud_stored_reply_addr
4996 * Cancels any running timer, and then re-starts the timer
4997 * This routine must be called with state structure table lock held
4998 *
4999 * INPUTS:
5000 * ud_statep - ibcm_ud_state_data_t
5001 *
5002 * RETURN VALUE: NONE
5003 */
5004 void
ibcm_resend_srep_mad(ibcm_ud_state_data_t * ud_statep)5005 ibcm_resend_srep_mad(ibcm_ud_state_data_t *ud_statep)
5006 {
5007 timeout_id_t timer_val;
5008
5009 ASSERT(MUTEX_HELD(&ud_statep->ud_state_mutex));
5010
5011 IBTF_DPRINTF_L3(cmlog, "ibcm_resend_srep_mad: ud_statep 0x%p",
5012 ud_statep);
5013
5014 if (ud_statep->ud_send_mad_flags & IBCM_SREP_POST_BUSY)
5015 return;
5016
5017 ud_statep->ud_send_mad_flags |= IBCM_SREP_POST_BUSY;
5018
5019 /* for nonblocking SIDR REP Post */
5020 IBCM_UD_REF_CNT_INCR(ud_statep);
5021
5022 /* Cancel currently running timer */
5023 timer_val = ud_statep->ud_timerid;
5024
5025 if (ud_statep->ud_timerid != 0) {
5026 ud_statep->ud_timerid = 0;
5027 mutex_exit(&ud_statep->ud_state_mutex);
5028 (void) untimeout(timer_val);
5029 } else {
5030 mutex_exit(&ud_statep->ud_state_mutex);
5031 }
5032
5033 /* Always resend the response MAD to the original reply destination */
5034 ibcm_post_ud_mad(ud_statep, ud_statep->ud_stored_msg,
5035 ibcm_post_sidr_rep_complete, ud_statep);
5036
5037 mutex_enter(&ud_statep->ud_state_mutex);
5038 }
5039
5040
5041 /*
5042 * ibcm_build_reply_mad_addr:
5043 * Forms the reply MAD address based on "incoming mad addr" that is
5044 * supplied as an arg.
5045 *
5046 * Swaps the source and destination gids in ib_grh_t
5047 *
5048 * INPUTS:
5049 * inp_mad_addr: Address information in the incoming MAD
5050 * out_mad_addr: Derived address for the reply MAD
5051 * The reply MAD address is derived based
5052 * address information of incoming CM MAD
5053 * RETURN VALUE: NONE
5054 */
5055 void
ibcm_build_reply_mad_addr(ibcm_mad_addr_t * inp_mad_addr,ibcm_mad_addr_t * out_mad_addr)5056 ibcm_build_reply_mad_addr(ibcm_mad_addr_t *inp_mad_addr,
5057 ibcm_mad_addr_t *out_mad_addr)
5058 {
5059 IBTF_DPRINTF_L5(cmlog, "ibcm_build_reply_mad_addr:");
5060
5061 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*out_mad_addr))
5062
5063 bcopy(inp_mad_addr, out_mad_addr, sizeof (ibcm_mad_addr_t));
5064
5065 /* Swap the GIDs in the GRH */
5066 if (inp_mad_addr->grh_exists == B_TRUE) {
5067 ib_gid_t sgid = inp_mad_addr->grh_hdr.ig_sender_gid;
5068
5069 /* swap the SGID and DGID */
5070 out_mad_addr->grh_hdr.ig_sender_gid =
5071 inp_mad_addr->grh_hdr.ig_recver_gid;
5072 out_mad_addr->grh_hdr.ig_recver_gid = sgid;
5073 }
5074
5075 /*
5076 * CM posts response MAD on a new/existing internal QP on the same port
5077 * and pkey
5078 */
5079 out_mad_addr->cm_qp_entry =
5080 ibcm_find_qp(inp_mad_addr->cm_qp_entry->qp_port->port_hcap,
5081 inp_mad_addr->port_num, inp_mad_addr->rcvd_addr.ia_p_key);
5082
5083 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*out_mad_addr))
5084 }
5085
5086
5087 /*
5088 * ibcm_post_rc_mad
5089 * Posts a CM MAD associated with a RC statep
5090 *
5091 * INPUTS:
5092 * statep : RC statep associated with the post
5093 * msgp : CM MAD to be posted
5094 * post_cb : non-NULL callback address implies non-blocking post
5095 * args : Args to ibmf send callback
5096 *
5097 * RETURN VALUE: based on ibmf_send_mad
5098 */
5099 void
ibcm_post_rc_mad(ibcm_state_data_t * statep,ibmf_msg_t * msgp,ibmf_msg_cb_t post_cb,void * args)5100 ibcm_post_rc_mad(ibcm_state_data_t *statep, ibmf_msg_t *msgp,
5101 ibmf_msg_cb_t post_cb, void *args)
5102 {
5103 ibt_status_t status;
5104
5105 mutex_enter(&statep->state_mutex);
5106 statep->post_time = gethrtime();
5107 mutex_exit(&statep->state_mutex);
5108 status = ibcm_post_mad(msgp, &statep->stored_reply_addr, post_cb,
5109 args);
5110 if ((status != IBT_SUCCESS) && (post_cb != NULL))
5111 /* Call ibmf callback directly */
5112 (*post_cb)(NULL, msgp, args);
5113 }
5114
5115
5116 /*
5117 * ibcm_post_ud_mad
5118 * Posts a CM MAD associated with a UD statep
5119 *
5120 * INPUTS:
5121 * ud_statep : UD statep associated with the post
5122 * msgp : CM MAD to be posted
5123 * post_cb : non-NULL callback address implies non-blocking post
5124 * args : Args to ibmf send callback
5125 *
5126 * RETURN VALUE: based on ibmf_send_mad
5127 */
5128 void
ibcm_post_ud_mad(ibcm_ud_state_data_t * ud_statep,ibmf_msg_t * msgp,ibmf_msg_cb_t ud_post_cb,void * args)5129 ibcm_post_ud_mad(ibcm_ud_state_data_t *ud_statep, ibmf_msg_t *msgp,
5130 ibmf_msg_cb_t ud_post_cb, void *args)
5131 {
5132 ibt_status_t status;
5133 status = ibcm_post_mad(msgp, &ud_statep->ud_stored_reply_addr,
5134 ud_post_cb, args);
5135 if ((status != IBT_SUCCESS) && (ud_post_cb != NULL))
5136 /* Call ibmf callback directly */
5137 (*ud_post_cb)(NULL, msgp, args);
5138 }
5139
5140 /*
5141 * ibcm_post_mad:
5142 * Posts CM MAD using IBMF in blocking mode
5143 *
5144 * INPUTS:
5145 * msgp : CM MAD to be posted
5146 * cm_mad_addr : Address information for the MAD to be posted
5147 * post_cb : non-NULL callback address implies non-blocking post
5148 * args : Args to ibmf send callback
5149 *
5150 * RETURN VALUE: based on ibmf_send_mad
5151 */
5152 ibt_status_t
ibcm_post_mad(ibmf_msg_t * msgp,ibcm_mad_addr_t * cm_mad_addr,ibmf_msg_cb_t post_cb,void * args)5153 ibcm_post_mad(ibmf_msg_t *msgp, ibcm_mad_addr_t *cm_mad_addr,
5154 ibmf_msg_cb_t post_cb, void *args)
5155 {
5156 int post_status;
5157
5158 IBTF_DPRINTF_L5(cmlog, "ibcm_post_mad: "
5159 "ibmf_msg_t = %p, cm_madd_adr = %p", msgp, cm_mad_addr);
5160
5161 IBTF_DPRINTF_L4(cmlog, "ibcm_post_mad: dlid = %x, d_qno= %x",
5162 cm_mad_addr->rcvd_addr.ia_remote_lid,
5163 cm_mad_addr->rcvd_addr.ia_remote_qno);
5164 IBTF_DPRINTF_L4(cmlog, "ibcm_post_mad: p_key = %x, q_key = %x, "
5165 "sl = %x, grh_exists = %x",
5166 cm_mad_addr->rcvd_addr.ia_p_key, cm_mad_addr->rcvd_addr.ia_q_key,
5167 cm_mad_addr->rcvd_addr.ia_service_level, cm_mad_addr->grh_exists);
5168
5169 /* Copy local addressing info */
5170 msgp->im_local_addr = cm_mad_addr->rcvd_addr;
5171
5172 /* Copy global/GRH addressing info */
5173 if (cm_mad_addr->grh_exists == B_TRUE)
5174 msgp->im_global_addr = cm_mad_addr->grh_hdr;
5175
5176 if (post_cb)
5177 ibcm_flow_inc();
5178 post_status = ibmf_msg_transport(
5179 cm_mad_addr->ibmf_hdl, cm_mad_addr->cm_qp_entry->qp_cm, msgp,
5180 NULL, post_cb, args, 0);
5181 if (post_status != IBMF_SUCCESS) {
5182 IBTF_DPRINTF_L2(cmlog, "ibcm_post_mad: ibmf_msg_transport "
5183 "failed: status %d, cb = %p", post_status, post_cb);
5184 /* Analyze the reason for failure */
5185 return (ibcm_ibmf_analyze_error(post_status));
5186 }
5187
5188 return (IBT_SUCCESS);
5189 }
5190
5191
5192 /*
5193 * ibcm_process_get_classport_info:
5194 * Get classportinfo
5195 *
5196 * INPUTS:
5197 * hcap - HCA entry pointer
5198 * input_madp - Input MAD pointer
5199 * cm_mad_addr - Address information for the MAD to be posted
5200 *
5201 * RETURN VALUE: NONE
5202 */
5203 static void
ibcm_process_get_classport_info(ibcm_hca_info_t * hcap,uint8_t * input_madp,ibcm_mad_addr_t * cm_mad_addr)5204 ibcm_process_get_classport_info(ibcm_hca_info_t *hcap, uint8_t *input_madp,
5205 ibcm_mad_addr_t *cm_mad_addr)
5206 {
5207 ibmf_msg_t *msgp;
5208
5209 IBTF_DPRINTF_L5(cmlog, "ibcm_process_get_classport_info: (%p, %p, %p)",
5210 hcap, input_madp, cm_mad_addr);
5211
5212 if (ibcm_alloc_out_msg(cm_mad_addr->ibmf_hdl, &msgp,
5213 MAD_METHOD_GET_RESPONSE) != IBT_SUCCESS) {
5214 IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_classport_info: "
5215 "ibcm_alloc_out_msg failed");
5216 return;
5217 }
5218
5219 /* copy the transaction id from input get mad */
5220 IBCM_OUT_HDRP(msgp)->TransactionID =
5221 ((ib_mad_hdr_t *)(input_madp))->TransactionID;
5222 IBCM_OUT_HDRP(msgp)->AttributeID = h2b16(MAD_ATTR_ID_CLASSPORTINFO);
5223
5224 bcopy(&ibcm_clpinfo, IBCM_OUT_MSGP(msgp), sizeof (ibcm_clpinfo));
5225
5226 (void) ibcm_post_mad(msgp, cm_mad_addr, NULL, NULL);
5227 (void) ibcm_free_out_msg(cm_mad_addr->ibmf_hdl, &msgp);
5228
5229 IBTF_DPRINTF_L4(cmlog, "ibcm_process_get_classport_info: done");
5230 }
5231
5232 /*
5233 * ibcm_decode_classport_info:
5234 * Decode classportinfo
5235 *
5236 * INPUTS:
5237 * hcap - HCA entry pointer
5238 * cm_mad_addr - Address information for the MAD to be posted
5239 * input_madp - Input MAD pointer
5240 *
5241 * RETURN VALUE: NONE
5242 */
5243 static void
ibcm_decode_classport_info(ibcm_hca_info_t * hcap,uint8_t * input_madp,ibcm_mad_addr_t * cm_mad_addr)5244 ibcm_decode_classport_info(ibcm_hca_info_t *hcap, uint8_t *input_madp,
5245 ibcm_mad_addr_t *cm_mad_addr)
5246 {
5247 ibcm_classportinfo_msg_t *portinfop = (ibcm_classportinfo_msg_t *)
5248 (&input_madp[IBCM_MAD_HDR_SIZE]);
5249 IBTF_DPRINTF_L5(cmlog, "ibcm_decode_classport_info: (%p, %p, %p)",
5250 hcap, input_madp, cm_mad_addr);
5251
5252 /* Print various fields of received classportinfo in debuf buf */
5253
5254 IBTF_DPRINTF_L4(cmlog, "ibcm_decode_classport_info: "
5255 "Base version %d Class version %d", portinfop->BaseVersion,
5256 portinfop->ClassVersion);
5257 IBTF_DPRINTF_L4(cmlog, "ibcm_decode_classport_info: "
5258 "Cap Mask %d Resp Time %d", portinfop->CapabilityMask,
5259 portinfop->RespTimeValue_plus);
5260 }
5261
5262
5263 /*
5264 * ibcm_handler_conn_fail:
5265 * Helper function used to call client handler for Conn fail event
5266 *
5267 * INPUTS:
5268 * statep: The connection state pointer
5269 * rej_type: Message being rejected
5270 * rej_reason: Reason why CM is sending the REJ message
5271 * client_data: Private data returned by the client for REJ
5272 * client_data_len: Length of above client's private data.
5273 *
5274 * RETURN VALUE: Client Handler's return status
5275 */
5276 static void
ibcm_handler_conn_fail(ibcm_state_data_t * statep,uint8_t cf_code,uint8_t cf_msg,ibt_cm_reason_t cf_reason,uint8_t * client_data,ibt_priv_data_len_t client_data_len)5277 ibcm_handler_conn_fail(ibcm_state_data_t *statep, uint8_t cf_code,
5278 uint8_t cf_msg, ibt_cm_reason_t cf_reason, uint8_t *client_data,
5279 ibt_priv_data_len_t client_data_len)
5280 {
5281 ibt_cm_event_t event;
5282
5283 ibcm_path_cache_purge();
5284
5285 if (statep->channel)
5286 ibtl_cm_chan_open_is_aborted(statep->channel);
5287
5288 /* Invoke CM handler w/ event passed as arg */
5289 if (statep->cm_handler != NULL) {
5290 bzero(&event, sizeof (ibt_cm_event_t));
5291
5292 event.cm_type = IBT_CM_EVENT_FAILURE;
5293 event.cm_channel = statep->channel;
5294 event.cm_session_id = NULL;
5295 event.cm_priv_data = NULL;
5296 event.cm_priv_data_len = 0;
5297
5298 event.cm_event.failed.cf_code = cf_code;
5299 event.cm_event.failed.cf_msg = cf_msg;
5300 event.cm_event.failed.cf_reason = cf_reason;
5301
5302 ibcm_insert_trace(statep, IBCM_TRACE_CALLED_CONN_FAIL_EVENT);
5303
5304 (void) statep->cm_handler(statep->state_cm_private, &event,
5305 NULL, client_data, client_data_len);
5306
5307 ibcm_insert_trace(statep, IBCM_TRACE_RET_CONN_FAIL_EVENT);
5308 }
5309 if (ibcm_enable_trace != 0)
5310 ibcm_dump_conn_trace(statep);
5311 mutex_enter(&statep->state_mutex);
5312 ibcm_open_done(statep);
5313 mutex_exit(&statep->state_mutex);
5314 }
5315
5316 /*
5317 * QP State transition functions here
5318 *
5319 * The brief description of these functions :
5320 * Validate QP related attributes in the messages
5321 * Call client/server callback handlers
5322 * Change QP state
5323 * Set QP attributes (modify QP)
5324 * Fill up the response MADs
5325 */
5326
5327 /*
5328 * ibcm_set_primary_adds_vect:
5329 * Helper function used to fill up ibt_adds_vect_t PRIMARY PATH
5330 * (called from ibcm_cep_state_*() functions)
5331 *
5332 * INPUTS:
5333 * statep : The connection state pointer
5334 * adds_vectp : The ibt_adds_vect_t ptr that is being filled up
5335 * msgp : CM REQ message that is the source of information
5336 *
5337 * RETURN VALUE: NONE
5338 */
5339 static void
ibcm_set_primary_adds_vect(ibcm_state_data_t * statep,ibt_adds_vect_t * adds_vectp,ibcm_req_msg_t * msgp)5340 ibcm_set_primary_adds_vect(ibcm_state_data_t *statep,
5341 ibt_adds_vect_t *adds_vectp, ibcm_req_msg_t *msgp)
5342 {
5343 uint32_t flow_label20_res6_rate6;
5344
5345 flow_label20_res6_rate6 = b2h32(msgp->req_primary_flow_label_plus);
5346
5347 /* first setup the srvl, srate, dlid and dgid */
5348 adds_vectp->av_srvl = msgp->req_primary_sl_plus >> 4;
5349 adds_vectp->av_src_path = statep->prim_src_path_bits;
5350
5351 if (statep->mode == IBCM_PASSIVE_MODE) {
5352 adds_vectp->av_dlid = b2h16(msgp->req_primary_l_port_lid);
5353 adds_vectp->av_dgid.gid_prefix =
5354 b2h64(msgp->req_primary_l_port_gid.gid_prefix);
5355 adds_vectp->av_dgid.gid_guid =
5356 b2h64(msgp->req_primary_l_port_gid.gid_guid);
5357 adds_vectp->av_sgid.gid_prefix =
5358 b2h64(msgp->req_primary_r_port_gid.gid_prefix);
5359 adds_vectp->av_sgid.gid_guid =
5360 b2h64(msgp->req_primary_r_port_gid.gid_guid);
5361 adds_vectp->av_srate = flow_label20_res6_rate6 & 0x3f;
5362 } else {
5363 adds_vectp->av_dlid = b2h16(msgp->req_primary_r_port_lid);
5364 adds_vectp->av_dgid.gid_prefix =
5365 b2h64(msgp->req_primary_r_port_gid.gid_prefix);
5366 adds_vectp->av_dgid.gid_guid =
5367 b2h64(msgp->req_primary_r_port_gid.gid_guid);
5368 adds_vectp->av_sgid.gid_prefix =
5369 b2h64(msgp->req_primary_l_port_gid.gid_prefix);
5370 adds_vectp->av_sgid.gid_guid =
5371 b2h64(msgp->req_primary_l_port_gid.gid_guid);
5372 adds_vectp->av_srate = statep->local_srate;
5373 }
5374
5375 /* next copy off the GRH info if it exists */
5376 if ((msgp->req_primary_sl_plus & 0x8) == 0) {
5377 adds_vectp->av_send_grh = B_TRUE;
5378 adds_vectp->av_flow = flow_label20_res6_rate6 >> 12;
5379 adds_vectp->av_tclass = msgp->req_primary_traffic_class;
5380 adds_vectp->av_hop = msgp->req_primary_hop_limit;
5381 } else {
5382 adds_vectp->av_send_grh = B_FALSE;
5383 }
5384 }
5385
5386
5387 /*
5388 * ibcm_set_alt_adds_vect:
5389 * Helper function used to fill up ibt_adds_vect_t ALTERNATE PATH
5390 * (called from ibcm_cep_state_*() functions)
5391 *
5392 * INPUTS:
5393 * statep : The connection state pointer
5394 * adds_vectp : The ibt_adds_vect_t ptr that is being filled up
5395 * msgp : CM REQ message that is the source of information
5396 *
5397 * RETURN VALUE: NONE
5398 */
5399 static void
ibcm_set_alt_adds_vect(ibcm_state_data_t * statep,ibt_adds_vect_t * adds_vectp,ibcm_req_msg_t * msgp)5400 ibcm_set_alt_adds_vect(ibcm_state_data_t *statep,
5401 ibt_adds_vect_t *adds_vectp, ibcm_req_msg_t *msgp)
5402 {
5403 ib_gid_t dgid;
5404 ib_gid_t sgid;
5405 uint32_t flow_label20_res6_rate6;
5406
5407 flow_label20_res6_rate6 = b2h32(msgp->req_alt_flow_label_plus);
5408
5409 /* first setup the srvl, srate, dlid and dgid */
5410 adds_vectp->av_srvl = msgp->req_alt_sl_plus >> 4;
5411 adds_vectp->av_src_path = statep->alt_src_path_bits;
5412
5413 if (statep->mode == IBCM_PASSIVE_MODE) {
5414 adds_vectp->av_dlid = b2h16(msgp->req_alt_l_port_lid);
5415 bcopy(&msgp->req_alt_l_port_gid[0], &dgid, sizeof (ib_gid_t));
5416 bcopy(&msgp->req_alt_r_port_gid[0], &sgid, sizeof (ib_gid_t));
5417 adds_vectp->av_srate = flow_label20_res6_rate6 & 0x3f;
5418 } else {
5419 adds_vectp->av_dlid = b2h16(msgp->req_alt_r_port_lid);
5420 bcopy(&msgp->req_alt_r_port_gid[0], &dgid, sizeof (ib_gid_t));
5421 bcopy(&msgp->req_alt_l_port_gid[0], &sgid, sizeof (ib_gid_t));
5422 adds_vectp->av_srate = statep->local_alt_srate;
5423 }
5424 adds_vectp->av_dgid.gid_prefix = b2h64(dgid.gid_prefix);
5425 adds_vectp->av_dgid.gid_guid = b2h64(dgid.gid_guid);
5426 adds_vectp->av_sgid.gid_prefix = b2h64(sgid.gid_prefix);
5427 adds_vectp->av_sgid.gid_guid = b2h64(sgid.gid_guid);
5428
5429 /* next copy off the GRH info if it exists */
5430 if ((msgp->req_alt_sl_plus & 0x8) == 0) {
5431 adds_vectp->av_send_grh = B_TRUE;
5432 adds_vectp->av_flow = flow_label20_res6_rate6 >> 12;
5433 adds_vectp->av_tclass = msgp->req_alt_traffic_class;
5434 adds_vectp->av_hop = msgp->req_alt_hop_limit;
5435 } else {
5436 adds_vectp->av_send_grh = B_FALSE; /* no GRH */
5437 }
5438 }
5439
5440
5441 /*
5442 * ibcm_set_primary_cep_path:
5443 * Helper function used to fill up ibt_cep_path_t PRIMARY PATH
5444 * (called from ibcm_cep_state_*() functions)
5445 *
5446 * INPUTS:
5447 * statep : The connection state pointer
5448 * adds_vectp : The ibt_cep_path_t ptr that is being filled up
5449 * msgp : CM REQ message that is the source of information
5450 *
5451 * RETURN VALUE: NONE
5452 */
5453 static ibt_status_t
ibcm_set_primary_cep_path(ibcm_state_data_t * statep,ibt_cep_path_t * pathp,ibcm_req_msg_t * msgp)5454 ibcm_set_primary_cep_path(ibcm_state_data_t *statep, ibt_cep_path_t *pathp,
5455 ibcm_req_msg_t *msgp)
5456 {
5457 ibt_status_t status;
5458
5459 /* validate the PKEY in REQ for prim port */
5460 status = ibt_pkey2index_byguid(statep->local_hca_guid,
5461 statep->prim_port, b2h16(msgp->req_part_key), &pathp->cep_pkey_ix);
5462
5463 if (status != IBT_SUCCESS) {
5464 IBTF_DPRINTF_L2(cmlog, "ibcm_set_primary_cep_path: "
5465 "statep 0x%p pkey %x prim_port %d ", statep,
5466 b2h16(msgp->req_part_key), statep->prim_port);
5467 IBTF_DPRINTF_L2(cmlog, "ibcm_set_primary_cep_path: "
5468 "statep 0x%p Invalid PKEY on prim_port, status %d ",
5469 statep, status);
5470 return (status);
5471 }
5472 statep->pkey = b2h16(msgp->req_part_key);
5473 ibcm_set_primary_adds_vect(statep, &pathp->cep_adds_vect, msgp);
5474 return (IBT_SUCCESS);
5475 }
5476
5477
5478 /*
5479 * ibcm_set_alt_cep_path:
5480 * Helper function used to fill up ibt_cep_path_t ALTERNATE PATH
5481 * (called from ibcm_cep_state_*() functions)
5482 *
5483 * INPUTS:
5484 * statep : The connection state pointer
5485 * adds_vectp : The ibt_cep_path_t ptr that is being filled up
5486 * msgp : CM REQ message that is the source of information
5487 *
5488 * RETURN VALUE: NONE
5489 */
5490 static ibt_status_t
ibcm_set_alt_cep_path(ibcm_state_data_t * statep,ibt_cep_path_t * pathp,ibcm_req_msg_t * msgp)5491 ibcm_set_alt_cep_path(ibcm_state_data_t *statep, ibt_cep_path_t *pathp,
5492 ibcm_req_msg_t *msgp)
5493 {
5494 ibt_status_t status;
5495
5496 if (b2h16(msgp->req_alt_l_port_lid) == 0) {
5497 /* no alternate path specified */
5498 return (IBT_SUCCESS);
5499 }
5500
5501 /* validate the PKEY in REQ for alt port */
5502 status = ibt_pkey2index_byguid(statep->local_hca_guid,
5503 statep->alt_port, b2h16(msgp->req_part_key), &pathp->cep_pkey_ix);
5504
5505 if (status != IBT_SUCCESS) {
5506 IBTF_DPRINTF_L2(cmlog, "ibcm_set_alt_cep_path: "
5507 "statep 0x%p pkey %x alt_port %d ", statep,
5508 b2h16(msgp->req_part_key), statep->alt_port);
5509 IBTF_DPRINTF_L2(cmlog, "ibcm_set_alt_cep_path: "
5510 "statep 0x%p Invalid PKEY on alt_port, status %d ",
5511 statep, status);
5512 return (status);
5513 }
5514 pathp->cep_hca_port_num = statep->alt_port;
5515 ibcm_set_alt_adds_vect(statep, &pathp->cep_adds_vect, msgp);
5516 return (IBT_SUCCESS);
5517
5518 }
5519
5520 /*
5521 * ibcm_compare_prim_alt_paths:
5522 * Helper function used to find if primary and alternate paths are
5523 * identical
5524 * (called from ibcm_cep_state_req)
5525 *
5526 * INPUTS:
5527 * req: Pointer to ibt_cm_req_rcv_t, filled before invoking
5528 * the function
5529 *
5530 * RETURN VALUE: NONE
5531 */
5532
5533 static boolean_t
ibcm_compare_prim_alt_paths(ibt_adds_vect_t * prim,ibt_adds_vect_t * alt)5534 ibcm_compare_prim_alt_paths(ibt_adds_vect_t *prim, ibt_adds_vect_t *alt)
5535 {
5536
5537 if ((alt->av_dlid == prim->av_dlid) &&
5538 (alt->av_dgid.gid_prefix == prim->av_dgid.gid_prefix) &&
5539 (alt->av_dgid.gid_guid == prim->av_dgid.gid_guid) &&
5540 (alt->av_sgid.gid_prefix == prim->av_sgid.gid_prefix) &&
5541 (alt->av_sgid.gid_guid == prim->av_sgid.gid_guid) &&
5542 (alt->av_src_path == prim->av_src_path)) {
5543
5544 return (B_TRUE);
5545 }
5546 return (B_FALSE);
5547 }
5548
5549
5550 /*
5551 * ibcm_invoke_qp_modify:
5552 * Helper function used to call ibt_modify_qp()
5553 * called from ibcm_cep_state_req()/ibcm_cep_state_rep()
5554 * It sets up qp_info/eec_info
5555 *
5556 * Sets state to RTR as well.
5557 *
5558 *
5559 * INPUTS:
5560 * statep: The connection state pointer
5561 * req_msgp: The CM REQ message
5562 *
5563 * RETURN VALUE:
5564 * IBT_SUCCESS - call succeeded
5565 */
5566 static ibt_status_t
ibcm_invoke_qp_modify(ibcm_state_data_t * statep,ibcm_req_msg_t * req_msgp,ibcm_rep_msg_t * rep_msgp)5567 ibcm_invoke_qp_modify(ibcm_state_data_t *statep, ibcm_req_msg_t *req_msgp,
5568 ibcm_rep_msg_t *rep_msgp)
5569 {
5570 ibt_status_t status;
5571 ibt_qp_info_t qp_info;
5572 ibt_cep_modify_flags_t cep_flags;
5573 ibt_tran_srv_t trans;
5574
5575 cep_flags = IBT_CEP_SET_INIT_RTR | IBT_CEP_SET_PKEY_IX;
5576 trans = ((uint8_t *)&req_msgp->req_remote_eecn_plus)[3] >> 1 & 0x3;
5577
5578 ASSERT(statep->channel != NULL);
5579
5580 /*
5581 * If alternate path is present in REQ message then
5582 * OR in IBT_CEP_SET_ALT_PATH, if APM supported on hca
5583 */
5584 if (b2h16(req_msgp->req_alt_l_port_lid) != 0) {
5585
5586 if (statep->hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG)
5587 cep_flags |= IBT_CEP_SET_ALT_PATH;
5588 /* default value of rep_failover is ACCEPT */
5589 else {
5590 rep_msgp->rep_target_delay_plus |=
5591 IBT_CM_FAILOVER_REJ_NOTSUPP << 1;
5592 IBTF_DPRINTF_L3(cmlog, "ibcm_invoke_qp_modify"
5593 " Alt Path specified in REQ, but not supported");
5594 }
5595 }
5596
5597 /* If transport type is RD OR in IBC_CEP_SET_QKEY */
5598 if (trans == IBT_RD_SRV) {
5599 cep_flags |= IBT_CEP_SET_QKEY;
5600 }
5601
5602 /* Start filling up ibt_qp_info_t. */
5603 bzero(&qp_info, sizeof (qp_info));
5604 qp_info.qp_trans = trans;
5605 qp_info.qp_state = IBT_STATE_RTR;
5606 qp_info.qp_flags = IBT_CEP_NO_FLAGS;
5607
5608 switch (trans) {
5609 case IBT_RC_SRV:
5610
5611 if (statep->mode == IBCM_ACTIVE_MODE) {
5612 /* Setting PSN on RQ */
5613
5614 IBCM_QPINFO_RC(qp_info).rc_rq_psn =
5615 b2h32(req_msgp->req_starting_psn_plus) >> 8;
5616
5617 IBCM_QPINFO_RC(qp_info).rc_dst_qpn =
5618 b2h32(rep_msgp->rep_local_qpn_plus) >> 8;
5619
5620 /* RDMA resources taken from negotiated REP values */
5621 IBCM_QPINFO_RC(qp_info).rc_rdma_ra_in =
5622 rep_msgp->rep_initiator_depth;
5623
5624 } else { /* Passive side CM */
5625 /* Setting PSN on SQ and RQ */
5626 IBCM_QPINFO_RC(qp_info).rc_sq_psn =
5627 IBCM_QPINFO_RC(qp_info).rc_rq_psn =
5628 b2h32(rep_msgp->rep_starting_psn_plus) >> 8;
5629
5630 IBCM_QPINFO_RC(qp_info).rc_dst_qpn =
5631 b2h32(req_msgp->req_local_qpn_plus) >> 8;
5632
5633 /* RDMA resources taken from negotiated REP values */
5634 IBCM_QPINFO_RC(qp_info).rc_rdma_ra_in =
5635 rep_msgp->rep_resp_resources;
5636 }
5637
5638 /* XXX, Oh!, ibtl doesn't have interface for setting this */
5639 IBCM_QPINFO_RC(qp_info).rc_min_rnr_nak =
5640 ibcm_default_rnr_nak_time;
5641 IBCM_QPINFO_RC(qp_info).rc_path_mtu =
5642 req_msgp->req_mtu_plus >> 4;
5643 IBCM_QPINFO_RC(qp_info).rc_retry_cnt =
5644 ((uint8_t *)&req_msgp->req_starting_psn_plus)[3] & 0x7;
5645 IBCM_QPINFO_RC(qp_info).rc_rnr_retry_cnt =
5646 req_msgp->req_mtu_plus & 0x7;
5647
5648 if ((status = ibcm_set_primary_cep_path(statep,
5649 &IBCM_QPINFO_RC(qp_info).rc_path, req_msgp)) !=
5650 IBT_SUCCESS)
5651 return (status);
5652
5653 if ((status = ibcm_set_alt_cep_path(statep,
5654 &IBCM_QPINFO_RC(qp_info).rc_alt_path, req_msgp)) !=
5655 IBT_SUCCESS)
5656 return (status);
5657
5658 break;
5659 case IBT_RD_SRV:
5660 if (statep->mode == IBCM_ACTIVE_MODE) { /* look at REP msg */
5661 IBCM_QPINFO(qp_info).rd.rd_qkey =
5662 b2h32(rep_msgp->rep_local_qkey);
5663 } else {
5664 IBCM_QPINFO(qp_info).rd.rd_qkey =
5665 b2h32(req_msgp->req_local_qkey);
5666 }
5667
5668 break;
5669
5670 case IBT_UC_SRV:
5671 if (statep->mode == IBCM_ACTIVE_MODE) { /* look at REP msg */
5672 IBCM_QPINFO_UC(qp_info).uc_sq_psn =
5673 b2h32(req_msgp->req_starting_psn_plus) >> 8;
5674 IBCM_QPINFO_UC(qp_info).uc_dst_qpn =
5675 b2h32(rep_msgp->rep_local_qpn_plus) >> 8;
5676 } else {
5677 IBCM_QPINFO_UC(qp_info).uc_rq_psn =
5678 IBCM_QPINFO_UC(qp_info).uc_sq_psn =
5679 b2h32(rep_msgp->rep_starting_psn_plus) >> 8;
5680 IBCM_QPINFO_UC(qp_info).uc_dst_qpn =
5681 b2h32(req_msgp->req_local_qpn_plus) >> 8;
5682 }
5683 IBCM_QPINFO_UC(qp_info).uc_path_mtu =
5684 req_msgp->req_mtu_plus >> 4;
5685
5686 if ((status = ibcm_set_primary_cep_path(statep,
5687 &IBCM_QPINFO_UC(qp_info).uc_path, req_msgp)) !=
5688 IBT_SUCCESS)
5689 return (status);
5690
5691 if ((status = ibcm_set_alt_cep_path(statep,
5692 &IBCM_QPINFO_UC(qp_info).uc_alt_path, req_msgp)) !=
5693 IBT_SUCCESS)
5694 return (status);
5695
5696 break;
5697 default:
5698 IBTF_DPRINTF_L2(cmlog, "ibcm_invoke_qp_modify: "
5699 "unknown svc_type = %x", trans);
5700 break;
5701 }
5702
5703 /* Call modify_qp */
5704 status = ibt_modify_qp(statep->channel, cep_flags, &qp_info, NULL);
5705 IBTF_DPRINTF_L4(cmlog, "ibcm_invoke_qp_modify: statep 0x%p"
5706 " ibt_modify_qp() Init to RTR returned = %d", statep, status);
5707
5708 if (status == IBT_SUCCESS)
5709 ibcm_insert_trace(statep, IBCM_TRACE_INIT_RTR);
5710 else
5711 ibcm_insert_trace(statep, IBCM_TRACE_INIT_RTR_FAIL);
5712
5713 #ifdef DEBUG
5714
5715 print_modify_qp("Init to RTR", statep->channel, cep_flags, &qp_info);
5716
5717 if (statep->channel != NULL) {
5718 ibt_qp_query_attr_t qp_attrs;
5719
5720 (void) ibt_query_qp(statep->channel, &qp_attrs);
5721 IBTF_DPRINTF_L4(cmlog, "ibcm_invoke_qp_modify: "
5722 "qp_info.qp_state = %x", qp_attrs.qp_info.qp_state);
5723 }
5724 #endif
5725
5726 return (status);
5727 }
5728
5729
5730 /*
5731 * ibcm_verify_req_gids_and_svcid
5732 * Validation of LIDs, GIDs and SVC ID
5733 *
5734 * INPUTS:
5735 * statep - state pointer
5736 * cm_req_msgp - REQ message pointer
5737 *
5738 * RETURN VALUE: IBCM_SUCCESS/IBCM_FAILURE
5739 *
5740 */
5741 ibcm_status_t
ibcm_verify_req_gids_and_svcid(ibcm_state_data_t * statep,ibcm_req_msg_t * cm_req_msgp)5742 ibcm_verify_req_gids_and_svcid(ibcm_state_data_t *statep,
5743 ibcm_req_msg_t *cm_req_msgp)
5744 {
5745 ib_gid_t gid;
5746 ib_gid_t agid;
5747 ib_lid_t lid;
5748 ibt_status_t status;
5749 ibtl_cm_hca_port_t port;
5750 ibt_cm_reason_t reject_reason = IBT_CM_SUCCESS;
5751 ibcm_svc_info_t *svc_infop;
5752 ibcm_svc_bind_t *svc_bindp;
5753 ibcm_svc_bind_t *tmp_bindp;
5754 ib_pkey_t pkey;
5755 uint8_t port_num;
5756 ib_guid_t hca_guid;
5757 ibcm_ip_pvtdata_t *ip_data;
5758
5759 /* Verify LID and GID of primary port */
5760
5761 gid.gid_prefix = b2h64(cm_req_msgp->req_primary_r_port_gid.gid_prefix);
5762 gid.gid_guid = b2h64(cm_req_msgp->req_primary_r_port_gid.gid_guid);
5763
5764 IBTF_DPRINTF_L4(cmlog, "ibcm_verify_req_gids: statep 0x%p"
5765 " PRIM _r_gid (%llx, %llx)", statep, gid.gid_prefix,
5766 gid.gid_guid);
5767
5768 IBTF_DPRINTF_L4(cmlog, "ibcm_verify_req_gids: statep 0x%p "
5769 "PRIM passive lid %x", statep,
5770 b2h16(cm_req_msgp->req_primary_r_port_lid));
5771
5772 /* Verify GID validity, if specified */
5773 if ((status = ibtl_cm_get_hca_port(gid, 0, &port)) == IBT_SUCCESS) {
5774
5775 IBTF_DPRINTF_L4(cmlog, "ibcm_verify_req_gids: statep 0x%p "
5776 "prim_port_num %d", statep, port.hp_port);
5777
5778 IBTF_DPRINTF_L4(cmlog, "ibcm_verify_req_gids: statep 0x%p "
5779 "passive hca_guid 0x%llX", statep, port.hp_hca_guid);
5780
5781 port_num = port.hp_port;
5782 hca_guid = port.hp_hca_guid;
5783 }
5784
5785 if (status != IBT_SUCCESS) {
5786 IBTF_DPRINTF_L2(cmlog, "ibcm_verify_req_gids: statep 0x%p "
5787 "ibtl_cm_get_hca_port() primary port failed = %d", statep,
5788 status);
5789 reject_reason = IBT_CM_PRIM_GID;
5790 /* we will search for an acceptable GID to this port */
5791 port_num = statep->stored_reply_addr.port_num;
5792 hca_guid = statep->hcap->hca_guid;
5793
5794 } else if (port.hp_base_lid !=
5795 (b2h16(cm_req_msgp->req_primary_r_port_lid) &
5796 (~((1 << port.hp_lmc) - 1)))) {
5797 IBTF_DPRINTF_L2(cmlog, "ibcm_verify_req_gids: statep 0x%p "
5798 "primary port lid invalid (%x, %x, %x)", statep,
5799 port.hp_base_lid,
5800 b2h16(cm_req_msgp->req_primary_r_port_lid), port.hp_lmc);
5801 reject_reason = IBT_CM_PRIM_LID;
5802 } else {
5803
5804 statep->local_hca_guid = port.hp_hca_guid;
5805 statep->prim_port = port.hp_port;
5806 statep->prim_src_path_bits =
5807 b2h16(cm_req_msgp->req_primary_r_port_lid) -
5808 port.hp_base_lid;
5809
5810 IBTF_DPRINTF_L4(cmlog, "ibcm_verify_req_gids: "
5811 "statep 0x%p prim_port_path_bits %d ",
5812 statep, statep->prim_src_path_bits);
5813
5814 /* Verify LID and GID of alternate port. Post REJ if invalid */
5815
5816 /* Need a bcopy, as alt port gid is unaligned in req message */
5817 bcopy(&cm_req_msgp->req_alt_r_port_gid[0], &agid,
5818 sizeof (ib_gid_t));
5819 agid.gid_prefix = b2h64(agid.gid_prefix);
5820 agid.gid_guid = b2h64(agid.gid_guid);
5821
5822 IBTF_DPRINTF_L4(cmlog, "ibcm_verify_req_gids: statep 0x%p"
5823 " Alt port_gid is (%llX:%llX)", statep, agid.gid_prefix,
5824 agid.gid_guid);
5825
5826 if ((agid.gid_prefix != 0) || (agid.gid_guid != 0)) {
5827
5828 /* Verify GID validity, if specified */
5829 if ((status = ibtl_cm_get_hca_port(agid,
5830 statep->local_hca_guid, &port)) != IBT_SUCCESS) {
5831 IBTF_DPRINTF_L2(cmlog,
5832 "ibcm_verify_req_gids: ibtl_cm_get_hca_port"
5833 " statep 0x%p alternate port failed = %d",
5834 statep, status);
5835 reject_reason = IBT_CM_ALT_GID;
5836
5837 } else if (port.hp_base_lid !=
5838 (b2h16(cm_req_msgp->req_alt_r_port_lid) &
5839 (~((1 << port.hp_lmc) - 1)))) {
5840
5841 IBTF_DPRINTF_L2(cmlog,
5842 "ibcm_verify_req_gids: statep 0x%p "
5843 "alternate port lid invalid (%x, %x, %x)",
5844 statep, port.hp_base_lid,
5845 cm_req_msgp->req_alt_r_port_lid,
5846 port.hp_lmc);
5847 reject_reason = IBT_CM_ALT_LID;
5848 } else { /* Alt LID and GID are valid */
5849 statep->alt_port = port.hp_port;
5850 statep->alt_src_path_bits =
5851 b2h16(cm_req_msgp->req_alt_r_port_lid) -
5852 port.hp_base_lid;
5853
5854 IBTF_DPRINTF_L4(cmlog, "ibcm_verify_req_gids: "
5855 "statep 0x%p alt_port_num %d "
5856 "alt_rc_hca_guid 0x%llX", statep,
5857 port.hp_port, port.hp_hca_guid);
5858
5859 IBTF_DPRINTF_L4(cmlog, "ibcm_verify_req_gids: "
5860 "statep 0x%p alt_port_path_bits %d ",
5861 statep, statep->alt_src_path_bits);
5862 }
5863 }
5864 }
5865
5866 mutex_enter(&ibcm_svc_info_lock);
5867 svc_infop = ibcm_find_svc_entry(statep->svcid);
5868
5869 /*
5870 * Note: When we return SUCCESS, the reader lock won't get dropped
5871 * until after the cm_handler is called from ibcm_cep_state_req().
5872 */
5873
5874 IBTF_DPRINTF_L4(cmlog, "ibcm_verify_req_gids: "
5875 "ibcm_find_svc_entry found svc_infop %p", svc_infop);
5876
5877 /*
5878 * Send REJ with reject reason "invalid service id" for the
5879 * the following cases :-
5880 * Service id is valid, but not available at gid/lid of REQ
5881 * Service id is invalid
5882 */
5883
5884 if (svc_infop == NULL || svc_infop->svc_bind_list == NULL) {
5885 mutex_exit(&ibcm_svc_info_lock);
5886
5887 IBTF_DPRINTF_L2(cmlog, "ibcm_verify_req_gids_and_svcid: "
5888 "statep 0x%p svc_id %llX svc_infop NULL", statep,
5889 statep->svcid);
5890
5891 /* Send a REJ with invalid SID reason */
5892 ibcm_post_rej_mad(statep,
5893 IBT_CM_INVALID_SID, IBT_CM_FAILURE_REQ, NULL, 0);
5894 return (IBCM_FAILURE);
5895 }
5896
5897 if (svc_infop->svc_rc_handler == NULL) {
5898 mutex_exit(&ibcm_svc_info_lock);
5899
5900 /* Send a REJ with invalid SID reason */
5901 ibcm_post_rej_mad(statep,
5902 IBT_CM_INVALID_SRV_TYPE, IBT_CM_FAILURE_REQ, NULL, 0);
5903 return (IBCM_FAILURE);
5904 }
5905
5906 /*
5907 * Check if ServiceID is in RDMA IP CM SID range, if yes, we parse
5908 * the REQ's Private Data and verify for it's goodness.
5909 */
5910 if (((statep->svcid & IB_SID_IPADDR_PREFIX_MASK) == 0) &&
5911 (statep->svcid & IB_SID_IPADDR_PREFIX)) {
5912 ibt_ari_ip_t ari_ip;
5913 boolean_t rdma_rej_mad = B_FALSE;
5914
5915 if (cm_req_msgp->req_private_data == NULL) {
5916 mutex_exit(&ibcm_svc_info_lock);
5917
5918 IBTF_DPRINTF_L2(cmlog, "ibcm_verify_req_gids_and_svcid:"
5919 " RDMA CM IP REQ Priv Data is NULL");
5920
5921 /* Send a REJ with CONSUMER REJ */
5922 ibcm_post_rej_mad(statep, IBT_CM_CONSUMER,
5923 IBT_CM_FAILURE_REQ, NULL, 0);
5924 return (IBCM_FAILURE);
5925 }
5926 ip_data = (ibcm_ip_pvtdata_t *)cm_req_msgp->req_private_data;
5927
5928 bzero(&ari_ip, sizeof (ibt_ari_ip_t));
5929
5930 /* RDMA IP CM Layer Rejects this */
5931 if (ip_data->ip_MajV != IBT_CM_IP_MAJ_VER) {
5932 IBTF_DPRINTF_L2(cmlog, "ibcm_verify_req_gids_and_svcid:"
5933 "IP MajorVer mis-match %d", ip_data->ip_MajV);
5934 ari_ip.ip_reason = IBT_ARI_IP_MAJOR_VERSION;
5935 ari_ip.ip_suggested_version = IBT_CM_IP_MAJ_VER;
5936 ari_ip.ip_suggested = B_TRUE;
5937 rdma_rej_mad = B_TRUE;
5938 } else if (ip_data->ip_MinV != IBT_CM_IP_MIN_VER) {
5939 IBTF_DPRINTF_L2(cmlog, "ibcm_verify_req_gids_and_svcid:"
5940 "IP MinorVer mis-match %d", ip_data->ip_MinV);
5941 ari_ip.ip_reason = IBT_ARI_IP_MINOR_VERSION;
5942 ari_ip.ip_suggested_version = IBT_CM_IP_MIN_VER;
5943 ari_ip.ip_suggested = B_TRUE;
5944 rdma_rej_mad = B_TRUE;
5945 } else if ((ip_data->ip_ipv != IBT_CM_IP_IPV_V4) &&
5946 (ip_data->ip_ipv != IBT_CM_IP_IPV_V6)) {
5947 IBTF_DPRINTF_L2(cmlog, "ibcm_verify_req_gids_and_svcid:"
5948 " Invalid IPV specified %d", ip_data->ip_ipv);
5949 ari_ip.ip_reason = IBT_ARI_IP_IPV;
5950 ari_ip.ip_suggested_version = IBT_CM_IP_IPV_V4;
5951 ari_ip.ip_suggested = B_TRUE;
5952 rdma_rej_mad = B_TRUE;
5953 } else {
5954 /*
5955 * Validate whether ip_addr specified are non-NULL.
5956 *
5957 * NOTE:
5958 * RDMA ULP which is servicing this SID, should validate
5959 * the correctness of srcip/dstip and accordingly post
5960 * REJ related to ibt_ari_ip_reason_t of
5961 * IBT_ARI_IP_SRC_ADDR, IBT_ARI_IP_DST_ADDR and
5962 * IBT_ARI_IP_UNKNOWN_ADDR.
5963 */
5964 if (ip_data->ip_ipv == IBT_CM_IP_IPV_V4) {
5965 if (ip_data->ip_srcv4 == 0) {
5966 IBTF_DPRINTF_L2(cmlog,
5967 "ibcm_verify_req_gids_and_svcid: "
5968 "Invalid NULL V4 SrcIp specified");
5969 rdma_rej_mad = B_TRUE;
5970 ari_ip.ip_reason = IBT_ARI_IP_SRC_ADDR;
5971 ari_ip.ip_suggested = B_TRUE;
5972 ari_ip.ip_suggested_version =
5973 IBT_CM_IP_IPV_V4;
5974 } else if (ip_data->ip_dstv4 == 0) {
5975 IBTF_DPRINTF_L2(cmlog,
5976 "ibcm_verify_req_gids_and_svcid: "
5977 "Invalid NULL V4 DstIp specified");
5978 rdma_rej_mad = B_TRUE;
5979 ari_ip.ip_reason = IBT_ARI_IP_DST_ADDR;
5980 ari_ip.ip_suggested = B_TRUE;
5981 ari_ip.ip_suggested_version =
5982 IBT_CM_IP_IPV_V4;
5983 }
5984 } else if (ip_data->ip_ipv == IBT_CM_IP_IPV_V6) {
5985 if (IN6_IS_ADDR_UNSPECIFIED(
5986 &ip_data->ip_srcv6)) {
5987 IBTF_DPRINTF_L2(cmlog,
5988 "ibcm_verify_req_gids_and_svcid: "
5989 "Invalid NULL V6 SrcIp specified");
5990 rdma_rej_mad = B_TRUE;
5991 ari_ip.ip_reason = IBT_ARI_IP_SRC_ADDR;
5992 ari_ip.ip_suggested = B_TRUE;
5993 ari_ip.ip_suggested_version =
5994 IBT_CM_IP_IPV_V6;
5995 } else if (IN6_IS_ADDR_UNSPECIFIED(
5996 &ip_data->ip_dstv6)) {
5997 IBTF_DPRINTF_L2(cmlog,
5998 "ibcm_verify_req_gids_and_svcid: "
5999 "Invalid NULL V6 DstIp specified");
6000 rdma_rej_mad = B_TRUE;
6001 ari_ip.ip_reason = IBT_ARI_IP_DST_ADDR;
6002 ari_ip.ip_suggested = B_TRUE;
6003 ari_ip.ip_suggested_version =
6004 IBT_CM_IP_IPV_V6;
6005 }
6006 }
6007 /* TBD: IBT_ARI_IP_UNKNOWN_ADDR */
6008 }
6009 if (rdma_rej_mad == B_TRUE) {
6010 ibt_ari_con_t cons_rej;
6011
6012 mutex_exit(&ibcm_svc_info_lock);
6013
6014 cons_rej.rej_ari_len = 1 + sizeof (ibt_ari_ip_t);
6015 cons_rej.rej_ari[0] = 0; /* Rejected by CM Layer */
6016 bcopy(&ari_ip, &cons_rej.rej_ari[1],
6017 sizeof (ibt_ari_ip_t));
6018 /* Send a REJ with CONSUMER REJ */
6019 ibcm_post_rej_mad(statep, IBT_CM_CONSUMER,
6020 IBT_CM_FAILURE_REQ, &cons_rej,
6021 sizeof (ibt_ari_con_t));
6022 return (IBCM_FAILURE);
6023 }
6024 }
6025
6026 /* find the best "bind" entry that enables this port */
6027
6028 pkey = b2h16(cm_req_msgp->req_part_key);
6029 svc_bindp = NULL;
6030 tmp_bindp = svc_infop->svc_bind_list;
6031 while (tmp_bindp) {
6032 if (tmp_bindp->sbind_hcaguid == hca_guid &&
6033 tmp_bindp->sbind_port == port_num) {
6034 if (gid.gid_guid ==
6035 tmp_bindp->sbind_gid.gid_guid &&
6036 gid.gid_prefix ==
6037 tmp_bindp->sbind_gid.gid_prefix) {
6038 /* gid match => really good match */
6039 svc_bindp = tmp_bindp;
6040 if (pkey == tmp_bindp->sbind_pkey)
6041 /* absolute best match */
6042 break;
6043 } else if (svc_bindp == NULL) {
6044 /* port match => a good match */
6045 svc_bindp = tmp_bindp;
6046 }
6047 }
6048 tmp_bindp = tmp_bindp->sbind_link;
6049 }
6050 if (svc_bindp == NULL) { /* port not enabled for this SID */
6051 mutex_exit(&ibcm_svc_info_lock);
6052 IBTF_DPRINTF_L2(cmlog,
6053 "ibcm_verify_req_gids_and_svcid: statep 0x%p "
6054 "no binding found", statep);
6055 ibcm_post_rej_mad(statep,
6056 IBT_CM_INVALID_SID, IBT_CM_FAILURE_REQ, NULL, 0);
6057 return (IBCM_FAILURE);
6058 }
6059 /* copy the GID in case we need it in REJ below */
6060 gid.gid_prefix = b2h64(svc_bindp->sbind_gid.gid_prefix);
6061 gid.gid_guid = b2h64(svc_bindp->sbind_gid.gid_guid);
6062
6063 statep->state_cm_private = svc_bindp->sbind_cm_private;
6064 statep->state_svc_infop = svc_infop;
6065 statep->cm_handler = svc_infop->svc_rc_handler;
6066 if (reject_reason == IBT_CM_SUCCESS)
6067 IBCM_SVC_INCR(svc_infop);
6068 mutex_exit(&ibcm_svc_info_lock);
6069
6070 /*
6071 * If the service id is valid, but gid in REQ is invalid,
6072 * then send a REJ with invalid gid
6073 * For Invalid primary gid, the ARI field is filled with
6074 * with gid from svcinfo
6075 * For invalid prim/alt gid reject, CM uses one of the gids
6076 * registered in ARI.
6077 * For invalid prim/alt lid reject, CM uses the base lid in ARI
6078 */
6079 if (reject_reason != IBT_CM_SUCCESS) {
6080
6081 switch (reject_reason) {
6082
6083 case IBT_CM_PRIM_GID :
6084 case IBT_CM_ALT_GID :
6085 ibcm_post_rej_mad(statep,
6086 reject_reason, IBT_CM_FAILURE_REQ,
6087 &gid, sizeof (ib_gid_t));
6088 break;
6089
6090 case IBT_CM_PRIM_LID :
6091 case IBT_CM_ALT_LID :
6092
6093 lid = h2b16(port.hp_base_lid);
6094 ibcm_post_rej_mad(statep,
6095 reject_reason, IBT_CM_FAILURE_REQ,
6096 &lid, sizeof (ib_lid_t));
6097 break;
6098 }
6099
6100 return (IBCM_FAILURE);
6101 }
6102
6103 /* Service, primary/alt gid and lid are all valid */
6104
6105 return (IBCM_SUCCESS);
6106 }
6107
6108 /*
6109 * ibcm_cep_state_req:
6110 * QP state transition function called for an incoming REQ on passive side
6111 * LIDs and GIDs should be maintained and validated by the client handler
6112 *
6113 * INPUTS:
6114 * statep - state pointer
6115 * cm_req_msgp - REQ message pointer
6116 * reject_reason - Rejection reason See Section 12.6.7.2 rev1.0a IB Spec
6117 * arej_info_len - Additional Rejection reason info length
6118 *
6119 * RETURN VALUE: IBCM_SEND_REP/IBCM_SEND_REJ
6120 */
6121 ibcm_status_t
ibcm_cep_state_req(ibcm_state_data_t * statep,ibcm_req_msg_t * cm_req_msgp,ibt_cm_reason_t * reject_reason,uint8_t * arej_len)6122 ibcm_cep_state_req(ibcm_state_data_t *statep, ibcm_req_msg_t *cm_req_msgp,
6123 ibt_cm_reason_t *reject_reason, uint8_t *arej_len)
6124 {
6125 void *priv_data = NULL;
6126 ibt_cm_event_t event;
6127 ibt_cm_status_t cb_status;
6128 ibcm_status_t status;
6129 ibt_cm_return_args_t ret_args;
6130 ibcm_clnt_reply_info_t clnt_info;
6131
6132 IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_req: statep 0x%p", statep);
6133 IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_req: SID 0x%lX",
6134 b2h64(cm_req_msgp->req_svc_id));
6135 /* client handler should be valid */
6136 ASSERT(statep->cm_handler != NULL);
6137
6138 bzero(&event, sizeof (event));
6139
6140 /* Fill in ibt_cm_event_t */
6141 event.cm_type = IBT_CM_EVENT_REQ_RCV;
6142 event.cm_session_id = statep;
6143 IBCM_EVT_REQ(event).req_service_id = b2h64(cm_req_msgp->req_svc_id);
6144 IBCM_EVT_REQ(event).req_transport =
6145 ((uint8_t *)&cm_req_msgp->req_remote_eecn_plus)[3] >> 1 & 0x3;
6146 IBCM_EVT_REQ(event).req_timeout = ibt_ib2usec(
6147 (((uint8_t *)&cm_req_msgp->req_remote_eecn_plus)[3] >> 3) & 0x1F);
6148 IBCM_EVT_REQ(event).req_retry_cnt =
6149 ((uint8_t *)&cm_req_msgp->req_starting_psn_plus)[3] & 0x7;
6150 IBCM_EVT_REQ(event).req_rnr_retry_cnt = cm_req_msgp->req_mtu_plus & 0x7;
6151 IBCM_EVT_REQ(event).req_pkey = b2h16(cm_req_msgp->req_part_key);
6152 IBCM_EVT_REQ(event).req_rdma_ra_in =
6153 ((uint8_t *)&cm_req_msgp->req_local_qpn_plus)[3];
6154 IBCM_EVT_REQ(event).req_rdma_ra_out =
6155 ((uint8_t *)&cm_req_msgp->req_local_eec_no_plus)[3];
6156
6157 /* Check for HCA limits for RDMA Resources */
6158 if (IBCM_EVT_REQ(event).req_rdma_ra_in >
6159 statep->hcap->hca_max_rdma_in_qp) {
6160 IBTF_DPRINTF_L2(cmlog, "ibcm_cep_state_req: statep 0x%p, REQ "
6161 "req_rdma_ra_in %d is greater than HCA Limit %d, resetting"
6162 "it to HCA limit", statep,
6163 IBCM_EVT_REQ(event).req_rdma_ra_in,
6164 statep->hcap->hca_max_rdma_in_qp);
6165 IBCM_EVT_REQ(event).req_rdma_ra_in =
6166 statep->hcap->hca_max_rdma_in_qp;
6167 }
6168
6169 if (IBCM_EVT_REQ(event).req_rdma_ra_out >
6170 statep->hcap->hca_max_rdma_out_qp) {
6171 IBTF_DPRINTF_L2(cmlog, "ibcm_cep_state_req: statep 0x%p, REQ "
6172 "req_rdma_ra_out %d is greater than HCA Limit %d, resetting"
6173 "it to HCA limit", statep,
6174 IBCM_EVT_REQ(event).req_rdma_ra_out,
6175 statep->hcap->hca_max_rdma_out_qp);
6176 IBCM_EVT_REQ(event).req_rdma_ra_out =
6177 statep->hcap->hca_max_rdma_out_qp;
6178 }
6179
6180 /* Account for CM and other software delays */
6181 if (IBCM_EVT_REQ(event).req_timeout > ibcm_sw_delay) {
6182 IBCM_EVT_REQ(event).req_timeout -= ibcm_sw_delay;
6183 IBTF_DPRINTF_L5(cmlog, "ibcm_cep_state_req: statep 0x%p"
6184 "Avail resp time %d (usec)", statep,
6185 IBCM_EVT_REQ(event).req_timeout);
6186 } else {
6187 IBTF_DPRINTF_L2(cmlog, "ibcm_cep_state_req: statep 0x%p "
6188 "REQ rem_resp_time < local sw delay 0x%x", statep,
6189 IBCM_EVT_REQ(event).req_timeout);
6190
6191 IBCM_EVT_REQ(event).req_timeout = 0;
6192 }
6193
6194 IBCM_EVT_REQ(event).req_prim_hca_port = statep->prim_port;
6195 IBCM_EVT_REQ(event).req_alt_hca_port = statep->alt_port;
6196 IBCM_EVT_REQ(event).req_hca_guid = statep->local_hca_guid;
6197 IBCM_EVT_REQ(event).req_remote_qpn = statep->remote_qpn;
6198
6199 if (((uint8_t *)&cm_req_msgp->req_remote_eecn_plus)[3] &
6200 IBT_CM_FLOW_CONTROL)
6201 IBCM_EVT_REQ(event).req_flags |= IBT_CM_FLOW_CONTROL;
6202
6203 if ((cm_req_msgp->req_max_cm_retries_plus >> 3) & 0x1)
6204 IBCM_EVT_REQ(event).req_flags |= IBT_CM_SRQ_EXISTS;
6205
6206 /* Initialize req.req_prim_addr */
6207 ibcm_set_primary_adds_vect(statep, &IBCM_EVT_REQ(event).req_prim_addr,
6208 cm_req_msgp);
6209
6210 /* Initialize req.req_alternate_path if they exist */
6211 if (b2h16(cm_req_msgp->req_alt_l_port_lid) != 0) {
6212 ibcm_set_alt_adds_vect(statep,
6213 &IBCM_EVT_REQ(event).req_alt_addr, cm_req_msgp);
6214
6215 /* Verify, alt path is not same as primary */
6216 if (ibcm_compare_prim_alt_paths(
6217 &event.cm_event.req.req_prim_addr,
6218 &event.cm_event.req.req_alt_addr) == B_TRUE) {
6219 /* XXX New REJ code needed */
6220 *reject_reason = IBT_CM_NO_RESC;
6221 IBTF_DPRINTF_L2(cmlog, "ibcm_cep_state_req: statep 0x%p"
6222 " Alt and prim paths are same", statep);
6223 mutex_enter(&ibcm_svc_info_lock);
6224 IBCM_SVC_DECR(statep->state_svc_infop);
6225 mutex_exit(&ibcm_svc_info_lock);
6226 return (IBCM_SEND_REJ);
6227 }
6228 }
6229
6230 #ifdef NO_EEC_SUPPORT_YET
6231 IBCM_EVT_REQ(event).req_rdc_exists = cm_req_msgp->req_mtu_plus >> 3 & 1;
6232 IBCM_EVT_REQ(event).req_remote_eecn =
6233 b2h32(cm_req_msgp->req_remote_eecn_plus) >> 8;
6234 IBCM_EVT_REQ(event).req_local_eecn =
6235 b2h32(cm_req_msgp->req_local_eec_no_plus) >> 8;
6236 IBCM_EVT_REQ(event).req_remote_qkey =
6237 b2h32(cm_req_msgp->req_local_qkey);
6238 #endif
6239
6240 /* cm_req_msgp->req_private_data to event.cm_event.cm_priv_data */
6241 event.cm_priv_data = cm_req_msgp->req_private_data;
6242
6243 event.cm_priv_data_len = IBT_REQ_PRIV_DATA_SZ;
6244
6245 /*
6246 * Allocate priv_data of size IBT_MAX_PRIV_DATA_SZ
6247 */
6248 priv_data = kmem_zalloc(IBT_MAX_PRIV_DATA_SZ, KM_SLEEP);
6249
6250 bzero(&ret_args, sizeof (ret_args));
6251
6252 /* Fill in the default values from REQ, that client can modify */
6253 ret_args.cm_ret.rep.cm_rdma_ra_in = IBCM_EVT_REQ(event).req_rdma_ra_out;
6254 ret_args.cm_ret.rep.cm_rdma_ra_out = IBCM_EVT_REQ(event).req_rdma_ra_in;
6255 ret_args.cm_ret.rep.cm_rnr_retry_cnt = cm_req_msgp->req_mtu_plus & 0x7;
6256
6257 ibcm_insert_trace(statep, IBCM_TRACE_CALLED_REQ_RCVD_EVENT);
6258
6259 /* Invoke the client handler */
6260 statep->req_msgp = cm_req_msgp;
6261 cb_status = statep->cm_handler(statep->state_cm_private, &event,
6262 &ret_args, priv_data, IBT_REP_PRIV_DATA_SZ);
6263 statep->req_msgp = NULL;
6264
6265 ibcm_insert_trace(statep, IBCM_TRACE_RET_REQ_RCVD_EVENT);
6266
6267 mutex_enter(&ibcm_svc_info_lock);
6268 IBCM_SVC_DECR(statep->state_svc_infop);
6269 mutex_exit(&ibcm_svc_info_lock);
6270
6271 IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_req: Client handler returned %d"
6272 " statep 0x%p", cb_status, statep);
6273
6274 if (cb_status == IBT_CM_DEFER) {
6275
6276 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(statep->defer_cm_msg))
6277
6278 if (statep->defer_cm_msg == NULL)
6279 statep->defer_cm_msg =
6280 kmem_zalloc(IBCM_MSG_SIZE, KM_SLEEP);
6281 bcopy(cm_req_msgp, statep->defer_cm_msg, IBCM_MSG_SIZE);
6282
6283 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(statep->defer_cm_msg))
6284
6285 /*
6286 * unblock any blocked cm proceed api calls. Do not access
6287 * statep after cv_signal
6288 */
6289 mutex_enter(&statep->state_mutex);
6290 statep->clnt_proceed = IBCM_UNBLOCK;
6291 cv_broadcast(&statep->block_client_cv);
6292 mutex_exit(&statep->state_mutex);
6293
6294 kmem_free(priv_data, IBT_MAX_PRIV_DATA_SZ);
6295 return (IBCM_DEFER);
6296 }
6297
6298 /* fail any blocked cm proceed api call - client bug */
6299 mutex_enter(&statep->state_mutex);
6300 statep->clnt_proceed = IBCM_FAIL;
6301 cv_broadcast(&statep->block_client_cv);
6302 mutex_exit(&statep->state_mutex);
6303
6304 clnt_info.reply_event = (ibt_cm_proceed_reply_t *)&ret_args.cm_ret;
6305 clnt_info.priv_data = priv_data;
6306 clnt_info.priv_data_len = ret_args.cm_ret_len;
6307
6308 status =
6309 ibcm_process_cep_req_cm_hdlr(statep, cb_status,
6310 &clnt_info, reject_reason, arej_len, cm_req_msgp);
6311 kmem_free(priv_data, IBT_MAX_PRIV_DATA_SZ);
6312 return (status);
6313 }
6314
6315 /*
6316 * ibcm_process_cep_req_cm_hdlr:
6317 * Processes the response from client handler for an incoming REQ.
6318 */
6319 ibcm_status_t
ibcm_process_cep_req_cm_hdlr(ibcm_state_data_t * statep,ibt_cm_status_t cb_status,ibcm_clnt_reply_info_t * clnt_info,ibt_cm_reason_t * reject_reason,uint8_t * arej_len,ibcm_req_msg_t * cm_req_msg)6320 ibcm_process_cep_req_cm_hdlr(ibcm_state_data_t *statep,
6321 ibt_cm_status_t cb_status, ibcm_clnt_reply_info_t *clnt_info,
6322 ibt_cm_reason_t *reject_reason, uint8_t *arej_len,
6323 ibcm_req_msg_t *cm_req_msg)
6324 {
6325 ibt_status_t status;
6326 ibt_qp_query_attr_t qp_attrs;
6327 ibcm_state_data_t *old_statep;
6328 ibt_channel_hdl_t channel;
6329 ib_guid_t local_ca_guid;
6330 ibcm_rej_msg_t *rej_msgp;
6331 #ifdef NO_EEC_SUPPORT_YET
6332 ibt_eec_query_attr_t eec_attrs;
6333 #endif
6334
6335 if (cb_status == IBT_CM_DEFAULT)
6336 cb_status = IBT_CM_REJECT;
6337
6338 /* verify status */
6339 if (cb_status == IBT_CM_ACCEPT) {
6340 *reject_reason = IBT_CM_SUCCESS;
6341 } else if (cb_status == IBT_CM_REJECT) {
6342 *reject_reason = IBT_CM_CONSUMER;
6343 } else if (cb_status == IBT_CM_REDIRECT_PORT) {
6344 *reject_reason = IBT_CM_PORT_REDIRECT;
6345 } else if (cb_status == IBT_CM_REDIRECT) {
6346 *reject_reason = IBT_CM_REDIRECT_CM;
6347 } else if (cb_status == IBT_CM_NO_CHANNEL) {
6348 *reject_reason = IBT_CM_NO_CHAN;
6349 } else if (cb_status == IBT_CM_NO_RESOURCE) {
6350 *reject_reason = IBT_CM_NO_RESC;
6351 } else {
6352 IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_req_cm_hdlr: statep %p"
6353 " Client handler unexpected return %x", statep, cb_status);
6354 *reject_reason = IBT_CM_CONSUMER;
6355 }
6356
6357 /* client handler gave CM ok */
6358 if (cb_status == IBT_CM_ACCEPT) {
6359 ibcm_rep_msg_t *rep_msgp = (ibcm_rep_msg_t *)
6360 IBCM_OUT_MSGP(statep->stored_msg);
6361
6362
6363 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*statep))
6364 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rep_msgp))
6365
6366 /*
6367 * Check first if ret_args make sense. If not, bailout
6368 * here rather than going along and panicing later.
6369 */
6370 channel = clnt_info->reply_event->rep.cm_channel;
6371 if (IBCM_INVALID_CHANNEL(channel)) {
6372 IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_req_cm_hdlr: "
6373 "statep 0x%p server's QP handle is NULL", statep);
6374 *reject_reason = IBT_CM_NO_CHAN;
6375 }
6376
6377 IBCM_GET_CHAN_PRIVATE(channel, old_statep);
6378
6379 if ((*reject_reason == IBT_CM_SUCCESS) &&
6380 (old_statep != NULL)) {
6381 IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_req_cm_hdlr: "
6382 "statep 0x%p Channel being re-used on passive side",
6383 statep);
6384 *reject_reason = IBT_CM_NO_CHAN;
6385 }
6386 if (old_statep != NULL)
6387 IBCM_RELEASE_CHAN_PRIVATE(channel);
6388
6389 if (*reject_reason != IBT_CM_SUCCESS) {
6390 ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
6391 IBT_CM_FAILURE_REQ, *reject_reason, NULL, 0);
6392 return (IBCM_SEND_REJ);
6393 }
6394
6395 statep->channel = channel;
6396 status = ibt_query_qp(channel, &qp_attrs);
6397
6398 if (status != IBT_SUCCESS) {
6399 IBTF_DPRINTF_L3(cmlog, "ibcm_process_cep_req_cm_hdlr: "
6400 "statep %p ibt_query_qp failed %d", statep, status);
6401 *reject_reason = IBT_CM_NO_RESC;
6402 ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
6403 IBT_CM_FAILURE_REQ, IBT_CM_CI_FAILURE, NULL, 0);
6404 return (IBCM_SEND_REJ);
6405 }
6406
6407 if (qp_attrs.qp_info.qp_trans != IBT_RC_SRV) {
6408 IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_req_cm_hdlr: "
6409 "statep %p qp is not RC channel on server", statep);
6410 *reject_reason = IBT_CM_INVALID_SRV_TYPE;
6411 ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
6412 IBT_CM_FAILURE_REQ, IBT_CM_CHAN_INVALID_STATE,
6413 NULL, 0);
6414 return (IBCM_SEND_REJ);
6415 }
6416
6417 if (qp_attrs.qp_info.qp_state != IBT_STATE_INIT &&
6418 statep->is_this_ofuv_chan == B_FALSE) {
6419 IBTF_DPRINTF_L3(cmlog, "ibcm_process_cep_req_cm_hdlr: "
6420 "qp state != INIT on server");
6421 *reject_reason = IBT_CM_CHAN_INVALID_STATE;
6422 ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
6423 IBT_CM_FAILURE_REQ, IBT_CM_CHAN_INVALID_STATE,
6424 NULL, 0);
6425 return (IBCM_SEND_REJ);
6426 } else if (statep->is_this_ofuv_chan &&
6427 qp_attrs.qp_info.qp_state != IBT_STATE_RTR &&
6428 qp_attrs.qp_info.qp_state != IBT_STATE_INIT) {
6429 IBTF_DPRINTF_L3(cmlog, "ibcm_process_cep_req_cm_hdlr: "
6430 "qp state != INIT or RTR on server");
6431 *reject_reason = IBT_CM_CHAN_INVALID_STATE;
6432 ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
6433 IBT_CM_FAILURE_REQ, IBT_CM_CHAN_INVALID_STATE,
6434 NULL, 0);
6435 return (IBCM_SEND_REJ);
6436 }
6437
6438 if (statep->is_this_ofuv_chan &&
6439 qp_attrs.qp_info.qp_state == IBT_STATE_RTR &&
6440 qp_attrs.qp_info.qp_transport.rc.rc_path.cep_hca_port_num !=
6441 statep->prim_port) {
6442 IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_req_cm_hdlr: "
6443 "QP port invalid");
6444 *reject_reason = IBT_CM_CHAN_INVALID_STATE;
6445 ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
6446 IBT_CM_FAILURE_REQ, IBT_CM_CHAN_INVALID_STATE,
6447 NULL, 0);
6448 return (IBCM_SEND_REJ);
6449 } else if (statep->is_this_ofuv_chan &&
6450 qp_attrs.qp_info.qp_state == IBT_STATE_RTR) {
6451 goto skip_init_trans;
6452 }
6453
6454 /* Init to Init, if required */
6455 if (qp_attrs.qp_info.qp_transport.rc.rc_path.cep_hca_port_num !=
6456 statep->prim_port) {
6457
6458 ibt_qp_info_t qp_info;
6459 ibt_cep_modify_flags_t cep_flags;
6460
6461 IBTF_DPRINTF_L5(cmlog, "ibcm_process_cep_req_cm_hdlr: "
6462 "chan 0x%p chan port %d", channel,
6463 qp_attrs.qp_info.qp_transport.rc.rc_path.\
6464 cep_hca_port_num);
6465
6466 IBTF_DPRINTF_L5(cmlog, "ibcm_process_cep_req_cm_hdlr: "
6467 "chan 0x%p d path port %d", channel,
6468 statep->prim_port);
6469
6470 bzero(&qp_info, sizeof (qp_info));
6471 qp_info.qp_trans = IBT_RC_SRV;
6472 qp_info.qp_state = IBT_STATE_INIT;
6473 qp_info.qp_transport.rc.rc_path.cep_hca_port_num =
6474 statep->prim_port;
6475
6476 cep_flags = IBT_CEP_SET_STATE | IBT_CEP_SET_PORT;
6477
6478 status = ibt_modify_qp(statep->channel, cep_flags,
6479 &qp_info, NULL);
6480
6481 if (status != IBT_SUCCESS) {
6482 IBTF_DPRINTF_L2(cmlog,
6483 "ibcm_process_cep_req_cm_hdlr: "
6484 "chan 0x%p ibt_modify_qp() = %d", channel,
6485 status);
6486 *reject_reason = IBT_CM_NO_RESC;
6487
6488 ibcm_insert_trace(statep,
6489 IBCM_TRACE_INIT_INIT_FAIL);
6490
6491 ibcm_handler_conn_fail(statep,
6492 IBT_CM_FAILURE_REJ_SENT, IBT_CM_FAILURE_REQ,
6493 IBT_CM_CI_FAILURE, NULL, 0);
6494 return (IBCM_SEND_REJ);
6495 } else {
6496 ibcm_insert_trace(statep,
6497 IBCM_TRACE_INIT_INIT);
6498
6499 IBTF_DPRINTF_L5(cmlog,
6500 "ibcm_process_cep_req_cm_hdlr: "
6501 "chan 0x%p ibt_modify_qp() = %d", channel,
6502 status);
6503 }
6504 }
6505 skip_init_trans:
6506 /* Do sanity tests even if we are skipping RTR */
6507
6508 /* fill in the REP msg based on ret_args from client */
6509 if (clnt_info->reply_event->rep.cm_rdma_ra_out >
6510 ((uint8_t *)&cm_req_msg->req_local_qpn_plus)[3]) {
6511 IBTF_DPRINTF_L2(cmlog, "ibcm_process_req_cm_hdlr "
6512 "statep 0x%p ERROR: InitiatorDepth(%d) is Greater "
6513 "than ResponderResource(%d)", statep,
6514 clnt_info->reply_event->rep.cm_rdma_ra_out,
6515 ((uint8_t *)&cm_req_msg->req_local_qpn_plus)[3]);
6516 *reject_reason = IBT_CM_NOT_SUPPORTED;
6517 ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
6518 IBT_CM_FAILURE_REQ, IBT_CM_NOT_SUPPORTED, NULL, 0);
6519 return (IBCM_SEND_REJ);
6520 }
6521
6522 /* Check for HCA limits for RDMA Resources */
6523 if (clnt_info->reply_event->rep.cm_rdma_ra_in >
6524 statep->hcap->hca_max_rdma_in_qp) {
6525 IBTF_DPRINTF_L2(cmlog, "ibcm_process_req_cm_hdlr: "
6526 "statep %p, ERROR: client specified rdma_ra_in %d "
6527 "is greater than HCA Limit %d, rejecting MAD",
6528 statep, clnt_info->reply_event->rep.cm_rdma_ra_in,
6529 statep->hcap->hca_max_rdma_in_qp);
6530 *reject_reason = IBT_CM_NOT_SUPPORTED;
6531 ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
6532 IBT_CM_FAILURE_REQ, IBT_CM_NOT_SUPPORTED, NULL, 0);
6533 return (IBCM_SEND_REJ);
6534 }
6535
6536 if (clnt_info->reply_event->rep.cm_rdma_ra_out >
6537 statep->hcap->hca_max_rdma_out_qp) {
6538 IBTF_DPRINTF_L2(cmlog, "ibcm_process_req_cm_hdlr: "
6539 "statep %p, ERROR: client specified rdma_ra_out %d "
6540 "is greater than HCA Limit %d, rejecting MAD",
6541 statep, clnt_info->reply_event->rep.cm_rdma_ra_out,
6542 statep->hcap->hca_max_rdma_out_qp);
6543 *reject_reason = IBT_CM_NOT_SUPPORTED;
6544 ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
6545 IBT_CM_FAILURE_REQ, IBT_CM_NOT_SUPPORTED, NULL, 0);
6546 return (IBCM_SEND_REJ);
6547 }
6548
6549 rep_msgp->rep_resp_resources =
6550 clnt_info->reply_event->rep.cm_rdma_ra_in;
6551 rep_msgp->rep_initiator_depth =
6552 clnt_info->reply_event->rep.cm_rdma_ra_out;
6553
6554 /* IBT_CM_FLOW_CONTROL is always set by default. */
6555 rep_msgp->rep_target_delay_plus |= IBT_CM_FLOW_CONTROL;
6556
6557 rep_msgp->rep_rnr_retry_cnt_plus =
6558 (clnt_info->reply_event->rep.cm_rnr_retry_cnt & 0x7) << 5;
6559
6560 /*
6561 * Check out whether SRQ is associated with this channel.
6562 * If yes, then set the appropriate bit.
6563 */
6564 if (qp_attrs.qp_srq != NULL) {
6565 rep_msgp->rep_rnr_retry_cnt_plus |= (1 << 4);
6566 }
6567
6568 local_ca_guid = h2b64(statep->local_hca_guid);
6569 bcopy(&local_ca_guid, rep_msgp->rep_local_ca_guid,
6570 sizeof (ib_guid_t));
6571
6572 if (statep->is_this_ofuv_chan &&
6573 qp_attrs.qp_info.qp_state == IBT_STATE_RTR)
6574 goto skip_rtr_trans;
6575
6576 /* Transition QP from Init to RTR state */
6577 if (ibcm_invoke_qp_modify(statep, cm_req_msg, rep_msgp) !=
6578 IBT_SUCCESS) {
6579
6580 IBTF_DPRINTF_L2(cmlog, "ibcm_process_req_cm_hdlr "
6581 "statep 0x%p ibcm_invoke_qp_modify failed because "
6582 "of invalid data", statep);
6583 *reject_reason = IBT_CM_NO_RESC;
6584 ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
6585 IBT_CM_FAILURE_REQ, IBT_CM_CI_FAILURE, NULL, 0);
6586 return (IBCM_SEND_REJ);
6587 }
6588 skip_rtr_trans:
6589
6590 /*
6591 * Link statep and channel, once CM determines it is
6592 * post REP definitely.
6593 */
6594 IBCM_SET_CHAN_PRIVATE(statep->channel, statep);
6595
6596 /*
6597 * Fill up the REP fields from ret_args
6598 * failover status, from ret_args
6599 *
6600 * Fill up local QPN and EECN from ret_args->channel
6601 */
6602
6603 /* fill in REP msg bytes Qkey, Starting PSN, 12-15, and 16-19 */
6604 IBTF_DPRINTF_L4(cmlog, "ibcm_process_cep_req_cm_hdlr: "
6605 "qp_info.qp_state = %x", qp_attrs.qp_info.qp_state);
6606
6607 rep_msgp->rep_local_qpn_plus = h2b32(qp_attrs.qp_qpn << 8);
6608
6609 statep->local_qpn = qp_attrs.qp_qpn;
6610
6611 switch (qp_attrs.qp_info.qp_trans) {
6612 case IBT_RD_SRV:
6613 rep_msgp->rep_local_qkey = h2b32(
6614 qp_attrs.qp_info.qp_transport.rd.rd_qkey);
6615 break;
6616 case IBT_RC_SRV:
6617 rep_msgp->rep_starting_psn_plus =
6618 h2b32(IBCM_QP_RC(qp_attrs).rc_rq_psn << 8);
6619 break;
6620 case IBT_UC_SRV:
6621 rep_msgp->rep_starting_psn_plus =
6622 h2b32(IBCM_QP_UC(qp_attrs).uc_sq_psn << 8);
6623 break;
6624 }
6625
6626 #ifdef NO_EEC_SUPPORT_YET
6627 if (ret_args.cm_channel.ch_eec != NULL) {
6628 status = ibt_query_eec(ret_args.cm_channel.ch_eec,
6629 &eec_attrs);
6630 if (status == IBT_SUCCESS) {
6631 rep_msgp->rep_local_eecn_plus =
6632 h2b32(((uint32_t)eec_attrs.eec_eecn << 8));
6633 }
6634 }
6635 #endif
6636
6637 /* figure out Target ACK delay */
6638 rep_msgp->rep_target_delay_plus |= (status == IBT_SUCCESS) ?
6639 statep->hcap->hca_ack_delay << 3 : 0;
6640
6641 IBTF_DPRINTF_L4(cmlog, "ibcm_process_cep_req_cm_hdlr:statep %p "
6642 "REP priv len %x", statep, clnt_info->priv_data_len);
6643 /* Copy PrivateData from priv_data */
6644 if (clnt_info->priv_data_len != 0) {
6645 bcopy(clnt_info->priv_data, rep_msgp->rep_private_data,
6646 min(IBT_REP_PRIV_DATA_SZ,
6647 clnt_info->priv_data_len));
6648 }
6649
6650 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*statep))
6651 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*rep_msgp))
6652
6653 return (IBCM_SEND_REP);
6654 }
6655
6656 /* REJ message */
6657 rej_msgp = (ibcm_rej_msg_t *)IBCM_OUT_MSGP(statep->stored_msg);
6658
6659 IBTF_DPRINTF_L4(cmlog, "ibcm_process_cep_req_cm_hdlr: statep %p REJ "
6660 "priv len %x", statep, clnt_info->priv_data_len);
6661
6662 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rej_msgp))
6663
6664 /* if priv_data_len != 0 use priv_data to copy back to rej_priv_data */
6665 if (clnt_info->priv_data_len != 0) {
6666 bcopy(clnt_info->priv_data, rej_msgp->rej_private_data,
6667 min(IBT_REJ_PRIV_DATA_SZ, clnt_info->priv_data_len));
6668 }
6669
6670 if (cb_status == IBT_CM_REDIRECT_PORT) {
6671 ib_gid_t tgid;
6672
6673 tgid.gid_guid =
6674 h2b64(clnt_info->reply_event->rej.ari_gid.gid_guid);
6675 tgid.gid_prefix =
6676 h2b64(clnt_info->reply_event->rej.ari_gid.gid_prefix);
6677
6678 *arej_len = sizeof (ib_gid_t);
6679 bcopy(&tgid, &rej_msgp->rej_addl_rej_info, sizeof (ib_gid_t));
6680
6681 IBTF_DPRINTF_L3(cmlog, "ibcm_process_cep_req_cm_hdlr: ari_gid= "
6682 "%llX:%llX", tgid.gid_prefix, tgid.gid_guid);
6683
6684 } else if (cb_status == IBT_CM_REDIRECT) {
6685 ibcm_classportinfo_msg_t tclp;
6686
6687 ibcm_init_clp_to_mad(&tclp,
6688 &clnt_info->reply_event->rej.ari_redirect);
6689 bcopy(&tclp, rej_msgp->rej_addl_rej_info, sizeof (tclp));
6690
6691 *arej_len = sizeof (ibcm_classportinfo_msg_t);
6692
6693 } else if (cb_status == IBT_CM_REJECT) {
6694
6695 /* Fill up the REJ fields, from ret_args */
6696 *arej_len = min(
6697 clnt_info->reply_event->rej.ari_consumer.rej_ari_len,
6698 IBT_CM_ADDL_REJ_LEN);
6699 bcopy(clnt_info->reply_event->rej.ari_consumer.rej_ari,
6700 &rej_msgp->rej_addl_rej_info, *arej_len);
6701
6702 /*
6703 * RDMA IP REQ was passed up to the ULP, the ULP decided to do
6704 * a "normal" consumer REJ, by the returning IBT_CM_REJECT in
6705 * the cm handler.
6706 * CM has to do some extra stuff too, it has to
6707 * a) return REJ code 28 (consumer) and b) put 0x1 in the first
6708 * byte of the ARI data, to indicate that this is a RDMA aware
6709 * ULP that is doing a consumer reject. The ULP should have
6710 * put its consumer specific data into ibt_arej_info_t(9s) at
6711 * byte 1 of the rej_ari[] array.
6712 */
6713 if (((statep->svcid & IB_SID_IPADDR_PREFIX_MASK) == 0) &&
6714 (statep->svcid & IB_SID_IPADDR_PREFIX)) {
6715 rej_msgp->rej_addl_rej_info[0] = 1;
6716 }
6717 }
6718
6719 rej_msgp->rej_msg_type_plus = IBT_CM_FAILURE_REQ << 6;
6720
6721 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*rej_msgp))
6722
6723 return (IBCM_SEND_REJ);
6724 }
6725
6726 /*
6727 * ibcm_cep_state_rep:
6728 * QP state transition function called for an incoming REP on active side
6729 *
6730 * INPUTS:
6731 * statep - state pointer
6732 * cm_rep_msg - REP message pointer
6733 * reject_reason - Rejection reason See Section 12.6.7.2 rev1.0a IB Spec
6734 *
6735 * RETURN VALUE:
6736 */
6737 ibcm_status_t
ibcm_cep_state_rep(ibcm_state_data_t * statep,ibcm_rep_msg_t * cm_rep_msgp,ibt_cm_reason_t * reject_reason,uint8_t * arej_len)6738 ibcm_cep_state_rep(ibcm_state_data_t *statep, ibcm_rep_msg_t *cm_rep_msgp,
6739 ibt_cm_reason_t *reject_reason, uint8_t *arej_len)
6740 {
6741 void *priv_data = NULL;
6742 ibcm_status_t rval = IBCM_SEND_RTU;
6743 ibt_cm_event_t event;
6744 ibt_cm_status_t cb_status = IBT_CM_ACCEPT;
6745 ibt_cm_return_args_t ret_args;
6746 ibcm_clnt_reply_info_t clnt_info;
6747 uint8_t req_init_depth;
6748
6749 IBTF_DPRINTF_L3(cmlog, "ibcm_cep_state_rep: statep 0x%p", statep);
6750
6751 /* Check first if client handler is valid */
6752 if (statep->cm_handler != NULL) {
6753 /* initialize fields in ibt_cm_event_t */
6754 bzero(&event, sizeof (event));
6755 event.cm_type = IBT_CM_EVENT_REP_RCV;
6756 event.cm_channel = statep->channel;
6757 event.cm_session_id = statep;
6758
6759 IBCM_EVT_REP(event).rep_rdma_ra_in =
6760 cm_rep_msgp->rep_initiator_depth;
6761 req_init_depth =
6762 ((uint8_t *)&(((ibcm_req_msg_t *)IBCM_OUT_MSGP(
6763 statep->stored_msg))->req_local_eec_no_plus))[3];
6764 IBCM_EVT_REP(event).rep_rdma_ra_out =
6765 min(cm_rep_msgp->rep_resp_resources, req_init_depth);
6766
6767 IBTF_DPRINTF_L3(cmlog, "ibcm_cep_state_rep: statep 0x%p, "
6768 "InitDepth %d, RespResr %d", statep,
6769 cm_rep_msgp->rep_initiator_depth,
6770 IBCM_EVT_REP(event).rep_rdma_ra_out);
6771
6772 IBCM_EVT_REP(event).rep_service_time = ibt_ib2usec(
6773 ((uint8_t *)&(((ibcm_req_msg_t *)IBCM_OUT_MSGP(
6774 statep->stored_msg))->req_starting_psn_plus))[3] >> 3);
6775
6776 IBCM_EVT_REP(event).rep_service_time -=
6777 2 * statep->pkt_life_time - ibcm_sw_delay;
6778
6779 IBCM_EVT_REP(event).rep_failover_status =
6780 cm_rep_msgp->rep_target_delay_plus >> 1 & 3;
6781
6782 if (cm_rep_msgp->rep_target_delay_plus & 0x1)
6783 IBCM_EVT_REP(event).rep_flags |= IBT_CM_FLOW_CONTROL;
6784
6785 if ((cm_rep_msgp->rep_rnr_retry_cnt_plus >> 4) & 0x1)
6786 IBCM_EVT_REP(event).rep_flags |= IBT_CM_SRQ_EXISTS;
6787
6788 IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_rep: statep 0x%p "
6789 "rep_service_time %d", statep,
6790 IBCM_EVT_REP(event).rep_service_time);
6791
6792 event.cm_priv_data = &(cm_rep_msgp->rep_private_data[0]);
6793 event.cm_priv_data_len = IBT_REP_PRIV_DATA_SZ;
6794
6795 /*
6796 * Allocate priv_data of size IBT_MAX_PRIV_DATA_SZ
6797 */
6798 priv_data = kmem_zalloc(IBT_MAX_PRIV_DATA_SZ, KM_SLEEP);
6799 bzero(&ret_args, sizeof (ret_args));
6800
6801
6802 ibcm_insert_trace(statep, IBCM_TRACE_CALLED_REP_RCVD_EVENT);
6803
6804 /* invoke the CM handler */
6805 cb_status = statep->cm_handler(statep->state_cm_private, &event,
6806 &ret_args, priv_data, IBT_RTU_PRIV_DATA_SZ);
6807
6808 ibcm_insert_trace(statep, IBCM_TRACE_RET_REP_RCVD_EVENT);
6809
6810 IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_rep: statep 0x%p "
6811 "Client handler returned %x", statep, cb_status);
6812
6813 if (cb_status == IBT_CM_DEFER) {
6814 if (statep->defer_cm_msg == NULL)
6815 statep->defer_cm_msg =
6816 kmem_zalloc(IBCM_MSG_SIZE, KM_SLEEP);
6817 bcopy(cm_rep_msgp, statep->defer_cm_msg, IBCM_MSG_SIZE);
6818
6819 /* unblock any blocked cm proceed api calls */
6820 mutex_enter(&statep->state_mutex);
6821 statep->clnt_proceed = IBCM_UNBLOCK;
6822 cv_broadcast(&statep->block_client_cv);
6823 mutex_exit(&statep->state_mutex);
6824
6825 kmem_free(priv_data, IBT_MAX_PRIV_DATA_SZ);
6826 return (IBCM_DEFER);
6827 }
6828 }
6829
6830 /* fail any blocked cm proceed api calls - client bug */
6831 mutex_enter(&statep->state_mutex);
6832 statep->clnt_proceed = IBCM_FAIL;
6833 cv_broadcast(&statep->block_client_cv);
6834 mutex_exit(&statep->state_mutex);
6835
6836 clnt_info.reply_event = (ibt_cm_proceed_reply_t *)&ret_args.cm_ret;
6837 clnt_info.priv_data = priv_data;
6838 clnt_info.priv_data_len = ret_args.cm_ret_len;
6839
6840 rval =
6841 ibcm_process_cep_rep_cm_hdlr(statep, cb_status, &clnt_info,
6842 reject_reason, arej_len, cm_rep_msgp);
6843
6844 if (priv_data != NULL)
6845 kmem_free(priv_data, IBT_MAX_PRIV_DATA_SZ);
6846 return (rval);
6847 }
6848
6849
6850 /*
6851 * ibcm_process_cep_rep_cm_hdlr:
6852 * Processes the response from client handler for an incoming REP.
6853 */
6854 ibcm_status_t
ibcm_process_cep_rep_cm_hdlr(ibcm_state_data_t * statep,ibt_cm_status_t cb_status,ibcm_clnt_reply_info_t * clnt_info,ibt_cm_reason_t * reject_reason,uint8_t * arej_len,ibcm_rep_msg_t * cm_rep_msgp)6855 ibcm_process_cep_rep_cm_hdlr(ibcm_state_data_t *statep,
6856 ibt_cm_status_t cb_status, ibcm_clnt_reply_info_t *clnt_info,
6857 ibt_cm_reason_t *reject_reason, uint8_t *arej_len,
6858 ibcm_rep_msg_t *cm_rep_msgp)
6859 {
6860 ibcm_status_t rval = IBCM_SEND_RTU;
6861 ibcm_rej_msg_t *rej_msgp;
6862
6863 if (cb_status == IBT_CM_DEFAULT)
6864 cb_status = IBT_CM_ACCEPT;
6865
6866 if (cb_status == IBT_CM_REJECT) {
6867 *reject_reason = IBT_CM_CONSUMER;
6868 } else if (cb_status == IBT_CM_REDIRECT_PORT) {
6869 *reject_reason = IBT_CM_PORT_REDIRECT;
6870 } else if (cb_status == IBT_CM_REDIRECT) {
6871 *reject_reason = IBT_CM_REDIRECT_CM;
6872 } else if (cb_status == IBT_CM_NO_RESOURCE) {
6873 *reject_reason = IBT_CM_NO_RESC;
6874 } else if (cb_status != IBT_CM_ACCEPT) {
6875 IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_rep_cm_hdlr: statep "
6876 "0x%p, Client handler returned unexpected value %d",
6877 statep, cb_status);
6878 *reject_reason = IBT_CM_CONSUMER;
6879 } else
6880 *reject_reason = IBT_CM_SUCCESS;
6881
6882
6883 /* We come here if status is ACCEPT or CM handler is NULL */
6884 if (cb_status == IBT_CM_ACCEPT) {
6885 ib_time_t time;
6886
6887 time = ibt_usec2ib(statep->pkt_life_time * 2 +
6888 ibt_ib2usec(cm_rep_msgp->rep_target_delay_plus >> 3));
6889
6890 IBTF_DPRINTF_L5(cmlog, "ibcm_process_cep_rep_cm_hdlr: statep %p"
6891 " active cep_timeout(usec) 0x%x ", statep, time);
6892
6893 IBTF_DPRINTF_L4(cmlog, "ibcm_process_cep_rep_cm_hdlr: statep %p"
6894 " passive hca_ack_delay(ib_time) = 0x%x, ", statep,
6895 cm_rep_msgp->rep_target_delay_plus >> 3);
6896
6897 IBTF_DPRINTF_L5(cmlog, "ibcm_process_cep_rep_cm_hdlr: statep %p"
6898 " rnr_retry_cnt = 0x%x", statep,
6899 cm_rep_msgp->rep_rnr_retry_cnt_plus >> 5);
6900
6901 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*statep))
6902 statep->starting_psn =
6903 b2h32(cm_rep_msgp->rep_starting_psn_plus) >> 8;
6904
6905 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*statep))
6906
6907 /* Call IBTL CM's qp modify function from Init to RTR */
6908 if (ibcm_invoke_qp_modify(statep,
6909 (ibcm_req_msg_t *)IBCM_OUT_MSGP(statep->stored_msg),
6910 cm_rep_msgp) != IBT_SUCCESS) {
6911
6912 IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_rep_cm_hdlr: "
6913 "statep %p, ibcm_invoke_qp_modify to RTR failed",
6914 statep);
6915 *reject_reason = IBT_CM_NO_RESC;
6916 /*
6917 * Call modify qp function from RTR to RTS
6918 * RDMA initiator depth on active is same as negotiated
6919 * passive REP's responder resources
6920 */
6921 } else if (ibcm_invoke_rtu_qp_modify(statep, time, cm_rep_msgp)
6922 != IBT_SUCCESS) {
6923
6924 IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_rep_cm_hdlr: "
6925 "statep %p ibcm_invoke_rtu_qp_modify to RTS failed",
6926 statep);
6927 (void) ibcm_cep_to_error_state(statep);
6928 *reject_reason = IBT_CM_NO_RESC;
6929 }
6930
6931 if (*reject_reason == IBT_CM_NO_RESC) {
6932
6933 /* Disassociate statep and QP */
6934 IBCM_SET_CHAN_PRIVATE(statep->channel, NULL);
6935
6936 ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
6937 IBT_CM_FAILURE_REP, IBT_CM_CI_FAILURE, NULL, 0);
6938 return (IBCM_SEND_REJ); /* send REJ */
6939 }
6940
6941 if (clnt_info->priv_data_len != 0) {
6942 ibcm_rtu_msg_t *rtu_msgp;
6943 rtu_msgp = (ibcm_rtu_msg_t *)
6944 IBCM_OUT_MSGP(statep->stored_msg);
6945 bcopy(clnt_info->priv_data, rtu_msgp->rtu_private_data,
6946 min(IBT_RTU_PRIV_DATA_SZ,
6947 clnt_info->priv_data_len));
6948 }
6949
6950 *reject_reason = IBT_CM_SUCCESS;
6951 return (rval);
6952 }
6953
6954 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rej_msgp))
6955
6956 /* Fill up the REJ fields, from ret_args */
6957 rej_msgp = (ibcm_rej_msg_t *)IBCM_OUT_MSGP(statep->stored_msg);
6958 rej_msgp->rej_msg_type_plus = IBT_CM_FAILURE_REP << 6;
6959
6960 /* if priv_len != 0 use priv_data to copy back to rej_priv_data */
6961 if (clnt_info->priv_data_len != 0)
6962 bcopy(clnt_info->priv_data, rej_msgp->rej_private_data,
6963 min(IBT_REJ_PRIV_DATA_SZ, clnt_info->priv_data_len));
6964
6965 if (clnt_info->reply_event != NULL)
6966 *arej_len =
6967 min(clnt_info->reply_event->rej.ari_consumer.rej_ari_len,
6968 IBT_CM_ADDL_REJ_LEN);
6969
6970 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(clnt_info->reply_event->rej))
6971
6972 if (*arej_len != 0) /* asserts that clnt_info->reply_event != 0 */
6973 bcopy(clnt_info->reply_event->rej.ari_consumer.rej_ari,
6974 &rej_msgp->rej_addl_rej_info, *arej_len);
6975
6976 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(clnt_info->reply_event->rej))
6977
6978 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*rej_msgp))
6979
6980 rval = IBCM_SEND_REJ;
6981
6982 /* Disassociate statep and QP */
6983 IBCM_SET_CHAN_PRIVATE(statep->channel, NULL);
6984
6985 /* callback client, to enable client to do resource cleanup */
6986 ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
6987 IBT_CM_FAILURE_REP, *reject_reason, NULL, 0);
6988
6989 return (rval);
6990 }
6991
6992 /*
6993 * ibcm_invoke_rtu_qp_modify:
6994 * Helper function to modify QP for RTU only called from
6995 * ibcm_cep_state_rtu() and ibcm_cep_send_rtu()
6996 *
6997 * INPUTS:
6998 * statep - connection state pointer
6999 *
7000 * RETURN VALUE:
7001 */
7002 static ibt_status_t
ibcm_invoke_rtu_qp_modify(ibcm_state_data_t * statep,ib_time_t timeout,ibcm_rep_msg_t * rep_msg)7003 ibcm_invoke_rtu_qp_modify(ibcm_state_data_t *statep, ib_time_t timeout,
7004 ibcm_rep_msg_t *rep_msg)
7005 {
7006 ibt_status_t status;
7007 ibt_qp_info_t qp_info;
7008 ibt_cep_modify_flags_t cep_flags = IBT_CEP_SET_RTR_RTS;
7009
7010 /* Start filling up ibt_qp_info_t. */
7011 bzero(&qp_info, sizeof (qp_info));
7012 qp_info.qp_trans = ibtl_cm_get_chan_type(statep->channel);
7013 qp_info.qp_current_state = IBT_STATE_RTR;
7014
7015 switch (qp_info.qp_trans) {
7016 case IBT_RC_SRV:
7017 IBCM_QPINFO_RC_PATH(qp_info).cep_timeout = timeout;
7018 IBCM_QPINFO_RC(qp_info).rc_retry_cnt = statep->cep_retry_cnt;
7019 IBCM_QPINFO_RC(qp_info).rc_rnr_retry_cnt =
7020 statep->local_qp_rnr_cnt;
7021 IBCM_QPINFO_RC(qp_info).rc_sq_psn = statep->starting_psn;
7022
7023 if (statep->mode == IBCM_ACTIVE_MODE) {
7024 IBCM_QPINFO_RC(qp_info).rc_rdma_ra_out =
7025 rep_msg->rep_resp_resources;
7026 } else {
7027 IBCM_QPINFO_RC(qp_info).rc_rdma_ra_out =
7028 rep_msg->rep_initiator_depth;
7029 }
7030 if (statep->alt_port &&
7031 (((rep_msg->rep_target_delay_plus >> 1) & 0x3) ==
7032 IBT_CM_FAILOVER_ACCEPT)) {
7033 /* failover was accepted */
7034 cep_flags |= IBT_CEP_SET_MIG;
7035 IBCM_QPINFO_RC(qp_info).rc_mig_state =
7036 IBT_STATE_REARMED;
7037 }
7038
7039 break;
7040 /* XXX RD? */
7041 case IBT_UC_SRV:
7042 IBCM_QPINFO_UC_PATH(qp_info).cep_timeout = timeout;
7043 break;
7044 default:
7045 IBTF_DPRINTF_L2(cmlog, "ibcm_invoke_rtu_qp_modify: "
7046 "unknow svc_type = %x", qp_info.qp_trans);
7047 break;
7048 }
7049
7050 /* Call modify_qp */
7051 status = ibt_modify_qp(statep->channel, cep_flags, &qp_info, NULL);
7052 IBTF_DPRINTF_L4(cmlog, "ibcm_invoke_rtu_qp_modify: statep 0x%p "
7053 "modify qp status = %d", statep, status);
7054
7055 if (status == IBT_SUCCESS)
7056 ibcm_insert_trace(statep, IBCM_TRACE_RTR_RTS);
7057 else
7058 ibcm_insert_trace(statep, IBCM_TRACE_RTR_RTS_FAIL);
7059
7060 #ifdef DEBUG
7061 print_modify_qp("RTR to RTS", statep->channel, cep_flags, &qp_info);
7062
7063 if (statep->channel != NULL) {
7064 ibt_qp_query_attr_t qp_attrs;
7065
7066 (void) ibt_query_qp(statep->channel, &qp_attrs);
7067 IBTF_DPRINTF_L4(cmlog, "ibcm_invoke_rtu_qp_modify: "
7068 "qp_info.qp_state = %x", qp_attrs.qp_info.qp_state);
7069 }
7070 #endif
7071 return (status);
7072 }
7073
7074
7075 /*
7076 * ibcm_cep_state_rtu:
7077 * QP state transition function called for an incoming RTU
7078 * on passive side.
7079 *
7080 * INPUTS:
7081 * statep - connection state pointer
7082 * cm_rtu_msg - RTU message pointer
7083 *
7084 */
7085 void
ibcm_cep_state_rtu(ibcm_state_data_t * statep,ibcm_rtu_msg_t * cm_rtu_msgp)7086 ibcm_cep_state_rtu(ibcm_state_data_t *statep, ibcm_rtu_msg_t *cm_rtu_msgp)
7087 {
7088 ibt_status_t status;
7089 ibt_cm_event_t event;
7090 ibcm_rep_msg_t *rep_msgp = (ibcm_rep_msg_t *)
7091 IBCM_OUT_MSGP(statep->stored_msg);
7092
7093 IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_rtu: statep 0x%p", statep);
7094
7095 ASSERT(statep->channel != NULL);
7096
7097 /* RDMA initiator depth taken from negotiated REP values */
7098 status = ibcm_invoke_rtu_qp_modify(statep,
7099 ibt_usec2ib(statep->remote_ack_delay), rep_msgp);
7100
7101 if (status != IBT_SUCCESS) {
7102
7103 (void) ibcm_cep_to_error_state(statep);
7104 /*
7105 * Disassociate statep and QP, as there is a
7106 * QP associated with this statep.
7107 */
7108 IBCM_SET_CHAN_PRIVATE(statep->channel, NULL);
7109
7110 ibcm_post_rej_mad(statep, IBT_CM_NO_RESC,
7111 IBT_CM_FAILURE_UNKNOWN, NULL, 0);
7112 /*
7113 * Invoke CM handler, so client/server can do
7114 * resource cleanup. No private data can be returned here
7115 */
7116 ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
7117 IBT_CM_FAILURE_UNKNOWN, IBT_CM_NO_RESC, NULL, 0);
7118
7119 /* unblock any pending DREQ threads */
7120 mutex_enter(&statep->state_mutex);
7121 statep->cep_in_rts = IBCM_FAIL;
7122 cv_broadcast(&statep->block_mad_cv);
7123 mutex_exit(&statep->state_mutex);
7124 return;
7125 }
7126
7127 mutex_enter(&statep->state_mutex);
7128 statep->state = IBCM_STATE_ESTABLISHED;
7129 ibtl_cm_chan_is_open(statep->channel);
7130 mutex_exit(&statep->state_mutex);
7131
7132 /* invoke the CM handler */
7133 ASSERT(statep->cm_handler != NULL);
7134
7135 bzero(&event, sizeof (event));
7136 event.cm_channel = statep->channel;
7137 event.cm_session_id = NULL;
7138
7139 event.cm_type = IBT_CM_EVENT_CONN_EST;
7140 if (cm_rtu_msgp != NULL) {
7141 event.cm_priv_data = &(cm_rtu_msgp->rtu_private_data[0]);
7142 event.cm_priv_data_len = IBT_RTU_PRIV_DATA_SZ;
7143 }
7144
7145 ibcm_insert_trace(statep, IBCM_TRACE_CALLED_CONN_EST_EVENT);
7146
7147 (void) statep->cm_handler(statep->state_cm_private, &event, NULL,
7148 NULL, 0);
7149
7150 ibcm_insert_trace(statep, IBCM_TRACE_RET_CONN_EST_EVENT);
7151 if (ibcm_enable_trace & 4)
7152 ibcm_dump_conn_trace(statep);
7153 else
7154 IBTF_DPRINTF_L2(cmlog, "ibcm_cep_state_rtu CONN_EST Channel %p",
7155 statep->channel);
7156
7157 /* unblock any pending DREQ threads */
7158 mutex_enter(&statep->state_mutex);
7159 statep->cep_in_rts = IBCM_UNBLOCK;
7160 cv_broadcast(&statep->block_mad_cv);
7161 mutex_exit(&statep->state_mutex);
7162 }
7163
7164
7165 /*
7166 * ibcm_cep_send_rtu:
7167 * QP state transition function called for an outgoing RTU
7168 * on active side.
7169 *
7170 * INPUTS:
7171 * statep - connection state pointer
7172 *
7173 * RETURN VALUE:
7174 */
7175 void
ibcm_cep_send_rtu(ibcm_state_data_t * statep)7176 ibcm_cep_send_rtu(ibcm_state_data_t *statep)
7177 {
7178 /* invoke the CM handler */
7179 if (statep->cm_handler) {
7180 ibt_cm_event_t event;
7181
7182 bzero(&event, sizeof (event));
7183 event.cm_type = IBT_CM_EVENT_CONN_EST;
7184 event.cm_channel = statep->channel;
7185 event.cm_session_id = NULL;
7186 event.cm_priv_data = NULL;
7187 event.cm_priv_data_len = 0;
7188
7189 ibcm_insert_trace(statep, IBCM_TRACE_CALLED_CONN_EST_EVENT);
7190
7191 (void) statep->cm_handler(statep->state_cm_private, &event,
7192 NULL, NULL, 0);
7193
7194 ibcm_insert_trace(statep, IBCM_TRACE_RET_CONN_EST_EVENT);
7195
7196 } else {
7197 IBTF_DPRINTF_L2(cmlog, "ibcm_cep_send_rtu: cm_handler NULL");
7198 }
7199 if (ibcm_enable_trace & 4)
7200 ibcm_dump_conn_trace(statep);
7201 else
7202 IBTF_DPRINTF_L2(cmlog, "ibcm_cep_send_rtu CONN_EST Channel %p",
7203 statep->channel);
7204
7205 /* unblock any pending DREQ threads */
7206 mutex_enter(&statep->state_mutex);
7207 statep->cep_in_rts = IBCM_UNBLOCK;
7208 cv_broadcast(&statep->block_mad_cv);
7209 mutex_exit(&statep->state_mutex);
7210 }
7211
7212
7213 /*
7214 * ibcm_cep_to_error_state:
7215 * CEP state transition function. Changes state to IBT_STATE_ERROR
7216 *
7217 * INPUTS:
7218 * statep - connection state pointer
7219 *
7220 * RETURN VALUE:
7221 * IBT_SUCCESS - if able to change state otherwise failure
7222 */
7223 ibt_status_t
ibcm_cep_to_error_state(ibcm_state_data_t * statep)7224 ibcm_cep_to_error_state(ibcm_state_data_t *statep)
7225 {
7226 ibt_status_t status = IBT_SUCCESS;
7227
7228 if (statep->channel != NULL) {
7229 ibt_qp_info_t qp_info;
7230
7231 bzero(&qp_info, sizeof (qp_info));
7232 /* For now, set it to RC type */
7233 qp_info.qp_trans = IBT_RC_SRV;
7234 qp_info.qp_state = IBT_STATE_ERROR;
7235
7236 /* Call modify_qp to move to ERROR state */
7237 status = ibt_modify_qp(statep->channel, IBT_CEP_SET_STATE,
7238 &qp_info, NULL);
7239
7240 IBTF_DPRINTF_L4(cmlog, "ibcm_cep_to_error_state: "
7241 "statep %p ibt_modify_qp() = %d", statep, status);
7242
7243 if (status == IBT_SUCCESS)
7244 ibcm_insert_trace(statep, IBCM_TRACE_ERROR);
7245 else
7246 ibcm_insert_trace(statep, IBCM_TRACE_ERROR_FAIL);
7247
7248 }
7249
7250 #ifdef NO_EEC_SUPPORT_YET
7251 if (statep->channel.ch_eec != NULL) {
7252 ibt_eec_info_t eec_info;
7253
7254 bzero(&eec_info, sizeof (ibt_eec_info_t));
7255 eec_info.eec_state = what;
7256
7257 /* Call modify_eec */
7258 status = ibtl_cm_modify_eec(statep->channel.ch_eec, &eec_info,
7259 IBT_CEP_SET_NOTHING);
7260 IBTF_DPRINTF_L4(cmlog, "ibcm_cep_to_error_state: "
7261 "ibtl_cm_modify_eec() returned = %x", status);
7262 }
7263 #endif
7264
7265 return (status);
7266 }
7267
7268
7269 /*
7270 * ibcm_cep_state_rej:
7271 * QP state transition function called for an incoming REJ
7272 * on active/passive side
7273 *
7274 * INPUTS:
7275 * statep - connection state pointer
7276 * rej_msgp - REJ message pointer
7277 * rej_state - State where REJ processing began
7278 *
7279 * RETURN VALUE:
7280 */
7281 void
ibcm_cep_state_rej(ibcm_state_data_t * statep,ibcm_rej_msg_t * rej_msgp,ibcm_conn_state_t rej_state)7282 ibcm_cep_state_rej(ibcm_state_data_t *statep, ibcm_rej_msg_t *rej_msgp,
7283 ibcm_conn_state_t rej_state)
7284 {
7285 ibt_cm_event_t event;
7286 ibt_status_t status;
7287
7288 IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_rej: statep 0x%p", statep);
7289
7290 ibcm_path_cache_purge();
7291
7292 if ((rej_state == IBCM_STATE_REP_SENT) ||
7293 (rej_state == IBCM_STATE_MRA_REP_RCVD)) {
7294 status = ibcm_cep_to_error_state(statep);
7295 IBTF_DPRINTF_L5(cmlog, "ibcm_cep_state_rej: statep 0x%p "
7296 "ibcm_cep_to_error_state returned %d", statep,
7297 status);
7298 }
7299
7300 if (statep->channel)
7301 ibtl_cm_chan_open_is_aborted(statep->channel);
7302
7303 /* Disassociate state structure and CM */
7304 IBCM_SET_CHAN_PRIVATE(statep->channel, NULL);
7305
7306 /* invoke the CM handler */
7307 bzero(&event, sizeof (event));
7308 if (statep->cm_handler) {
7309 event.cm_type = IBT_CM_EVENT_FAILURE;
7310 event.cm_channel = statep->channel;
7311 event.cm_session_id = NULL;
7312
7313 /*
7314 * copy rej_msgp->rej_private_data to
7315 * event.cm_event.cm_priv_data
7316 */
7317 event.cm_priv_data = &(rej_msgp->rej_private_data[0]);
7318 event.cm_priv_data_len = IBT_REJ_PRIV_DATA_SZ;
7319
7320 event.cm_event.failed.cf_code = IBT_CM_FAILURE_REJ_RCV;
7321 event.cm_event.failed.cf_msg = rej_msgp->rej_msg_type_plus >> 6;
7322 event.cm_event.failed.cf_reason =
7323 b2h16(rej_msgp->rej_rejection_reason);
7324
7325 IBTF_DPRINTF_L3(cmlog, "ibcm_cep_state_rej: rej_reason = %d",
7326 event.cm_event.failed.cf_reason);
7327
7328 ibcm_copy_addl_rej(statep, rej_msgp, &event.cm_event.failed);
7329
7330 (void) statep->cm_handler(statep->state_cm_private, &event,
7331 NULL, NULL, 0);
7332 }
7333
7334 if (statep->open_return_data != NULL)
7335 bcopy(&event.cm_event.failed.cf_additional,
7336 &statep->open_return_data->rc_arej_info,
7337 sizeof (ibt_arej_info_t));
7338 if (ibcm_enable_trace != 0)
7339 ibcm_dump_conn_trace(statep);
7340 mutex_enter(&statep->state_mutex);
7341 ibcm_open_done(statep);
7342 mutex_exit(&statep->state_mutex);
7343 }
7344
7345 /* Used to initialize client args with addl rej information from REJ MAD */
7346 static void
ibcm_copy_addl_rej(ibcm_state_data_t * statep,ibcm_rej_msg_t * rej_msgp,ibt_cm_conn_failed_t * failed)7347 ibcm_copy_addl_rej(ibcm_state_data_t *statep, ibcm_rej_msg_t *rej_msgp,
7348 ibt_cm_conn_failed_t *failed)
7349 {
7350 uint16_t rej_reason = b2h16(rej_msgp->rej_rejection_reason);
7351 uint8_t ari_len = rej_msgp->rej_reject_info_len_plus >> 1;
7352 ibcm_classportinfo_msg_t tclp;
7353 ibt_arej_info_t *cf_addl = &failed->cf_additional;
7354
7355 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cf_addl))
7356 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(failed->cf_arej_info_valid))
7357
7358 failed->cf_arej_info_valid = B_FALSE;
7359
7360 IBTF_DPRINTF_L3(cmlog, "ibcm_copy_addl_rej: rej_reason = %d "
7361 "ari_len = %d", rej_reason, ari_len);
7362
7363 if ((statep->mode == IBCM_PASSIVE_MODE) &&
7364 (rej_reason != IBT_CM_CONSUMER))
7365 return;
7366
7367 switch (rej_reason) {
7368 case IBT_CM_PRIM_GID:
7369 case IBT_CM_ALT_GID:
7370 case IBT_CM_PORT_REDIRECT:
7371 if (ari_len < sizeof (ib_gid_t))
7372 break;
7373 failed->cf_arej_info_valid = B_TRUE;
7374 bcopy(rej_msgp->rej_addl_rej_info, &cf_addl->ari_gid,
7375 sizeof (ib_gid_t));
7376 cf_addl->ari_gid.gid_guid = b2h64(cf_addl->ari_gid.gid_guid);
7377 cf_addl->ari_gid.gid_prefix =
7378 b2h64(cf_addl->ari_gid.gid_prefix);
7379
7380 IBTF_DPRINTF_L4(cmlog, "ibcm_copy_addl_rej: ari_gid= %llX:%llX",
7381 cf_addl->ari_gid.gid_prefix, cf_addl->ari_gid.gid_guid);
7382
7383 break;
7384 case IBT_CM_PRIM_LID:
7385 case IBT_CM_ALT_LID:
7386 if (ari_len < sizeof (ib_lid_t))
7387 break;
7388 failed->cf_arej_info_valid = B_TRUE;
7389 bcopy(rej_msgp->rej_addl_rej_info, &cf_addl->ari_lid,
7390 sizeof (ib_lid_t));
7391 cf_addl->ari_lid = b2h16(cf_addl->ari_lid);
7392 IBTF_DPRINTF_L4(cmlog, "ibcm_copy_addl_rej: ari_lid= 0x%lX",
7393 cf_addl->ari_lid);
7394
7395 break;
7396 case IBT_CM_INVALID_PRIM_SL:
7397 case IBT_CM_INVALID_ALT_SL:
7398 if (ari_len < 1)
7399 break;
7400 failed->cf_arej_info_valid = B_TRUE;
7401 /* take the first 4 bits */
7402 cf_addl->ari_sl = rej_msgp->rej_addl_rej_info[0] >> 4;
7403 break;
7404 case IBT_CM_INVALID_PRIM_TC:
7405 case IBT_CM_INVALID_ALT_TC:
7406 if (ari_len < 1)
7407 break;
7408 failed->cf_arej_info_valid = B_TRUE;
7409 /* take the first byte */
7410 cf_addl->ari_tclass = rej_msgp->rej_addl_rej_info[0];
7411 break;
7412 case IBT_CM_INVALID_PRIM_HOP:
7413 case IBT_CM_INVALID_ALT_HOP:
7414 if (ari_len < 1)
7415 break;
7416 failed->cf_arej_info_valid = B_TRUE;
7417 /* take the first byte */
7418 cf_addl->ari_hop = rej_msgp->rej_addl_rej_info[0];
7419 break;
7420 case IBT_CM_INVALID_PRIM_RATE:
7421 case IBT_CM_INVALID_ALT_RATE:
7422 if (ari_len < 1)
7423 break;
7424 failed->cf_arej_info_valid = B_TRUE;
7425 /* take the first 6 bits */
7426 cf_addl->ari_rate = rej_msgp->rej_addl_rej_info[0] >> 2;
7427 break;
7428 case IBT_CM_REDIRECT_CM:
7429 if (ari_len < sizeof (ibcm_classportinfo_msg_t))
7430 break;
7431 failed->cf_arej_info_valid = B_TRUE;
7432 bcopy(rej_msgp->rej_addl_rej_info, &tclp, sizeof (tclp));
7433 ibcm_init_clp_from_mad(&tclp, &cf_addl->ari_redirect);
7434 break;
7435 case IBT_CM_INVALID_MTU:
7436 if (ari_len < 1)
7437 break;
7438 failed->cf_arej_info_valid = B_TRUE;
7439 /* take the first 4 bits */
7440 cf_addl->ari_mtu = rej_msgp->rej_addl_rej_info[0] >> 4;
7441 break;
7442 case IBT_CM_CONSUMER:
7443 if (ari_len == 0)
7444 break;
7445 failed->cf_arej_info_valid = B_TRUE;
7446 if (ari_len > IBT_CM_ADDL_REJ_LEN)
7447 ari_len = IBT_CM_ADDL_REJ_LEN;
7448 bcopy(&rej_msgp->rej_addl_rej_info,
7449 cf_addl->ari_consumer.rej_ari, ari_len);
7450 cf_addl->ari_consumer.rej_ari_len = ari_len;
7451 break;
7452 case IBT_CM_INVALID_PRIM_FLOW:
7453 case IBT_CM_INVALID_ALT_FLOW:
7454 if (ari_len < 3) /* 3 bytes needed for 20 bits */
7455 break;
7456 failed->cf_arej_info_valid = B_TRUE;
7457 /* take the first 20 bits */
7458 cf_addl->ari_flow =
7459 b2h32(*(uint32_t *)&rej_msgp->rej_addl_rej_info) >> 12;
7460 break;
7461 default:
7462 break;
7463 }
7464
7465 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(failed->cf_arej_info_valid))
7466 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*cf_addl))
7467 }
7468
7469
7470 /* Used to copy classportinfo to MAD from client initialized args */
7471 static void
ibcm_init_clp_to_mad(ibcm_classportinfo_msg_t * clp,ibt_redirect_info_t * rinfo)7472 ibcm_init_clp_to_mad(ibcm_classportinfo_msg_t *clp, ibt_redirect_info_t *rinfo)
7473 {
7474
7475 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*clp))
7476
7477 bcopy(&ibcm_clpinfo, clp, sizeof (ibcm_clpinfo));
7478
7479 clp->RedirectGID_hi = h2b64(rinfo->rdi_gid.gid_prefix);
7480 clp->RedirectGID_lo = h2b64(rinfo->rdi_gid.gid_guid);
7481 clp->RedirectTC_plus =
7482 h2b32((rinfo->rdi_tclass << 24) | (rinfo->rdi_sl << 20) |
7483 (rinfo->rdi_flow & 0xfffff));
7484 clp->RedirectLID = h2b16(rinfo->rdi_dlid);
7485 clp->RedirectQP_plus = h2b32(rinfo->rdi_qpn & 0xffffff);
7486 clp->RedirectQ_Key = h2b32(rinfo->rdi_qkey);
7487 clp->RedirectP_Key = h2b16(rinfo->rdi_pkey);
7488
7489 IBTF_DPRINTF_L4(cmlog, "ibcm_init_clp_to_mad: RedirectGID= %llX:%llX,"
7490 " RedirectLID= 0x%lX", clp->RedirectGID_hi, clp->RedirectGID_lo,
7491 clp->RedirectLID);
7492
7493 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*clp))
7494 }
7495
7496
7497 /* Used to initialize classportinfo to be returned to clients, from MAD */
7498 static void
ibcm_init_clp_from_mad(ibcm_classportinfo_msg_t * clp,ibt_redirect_info_t * rinfo)7499 ibcm_init_clp_from_mad(ibcm_classportinfo_msg_t *clp,
7500 ibt_redirect_info_t *rinfo)
7501 {
7502 uint32_t temp32;
7503
7504 rinfo->rdi_gid.gid_prefix = b2h64(clp->RedirectGID_hi);
7505 rinfo->rdi_gid.gid_guid = b2h64(clp->RedirectGID_lo);
7506 temp32 = b2h32(clp->RedirectTC_plus);
7507 rinfo->rdi_tclass = temp32 >> 24;
7508 rinfo->rdi_sl = (temp32 >> 20) & 0xf;
7509 rinfo->rdi_flow = temp32 & 0xffff;
7510 rinfo->rdi_dlid = b2h16(clp->RedirectLID);
7511 rinfo->rdi_qpn = b2h32(clp->RedirectQP_plus & 0xffffff);
7512 rinfo->rdi_qkey = b2h32(clp->RedirectQ_Key);
7513 rinfo->rdi_pkey = b2h16(clp->RedirectP_Key);
7514
7515 IBTF_DPRINTF_L4(cmlog, "ibcm_init_clp_from_mad: RedirectGID= %llX:%llX,"
7516 " RedirectLID= 0x%lX", rinfo->rdi_gid.gid_prefix,
7517 rinfo->rdi_gid.gid_guid, rinfo->rdi_dlid);
7518 }
7519
7520
7521 /*
7522 * ibcm_cep_state_rej_est:
7523 * QP state transition function called for an incoming REJ
7524 * on active side in established state
7525 *
7526 * INPUTS:
7527 * statep - connection state pointer
7528 *
7529 * RETURN VALUE:
7530 */
7531 void
ibcm_cep_state_rej_est(ibcm_state_data_t * statep)7532 ibcm_cep_state_rej_est(ibcm_state_data_t *statep)
7533 {
7534 ibt_cm_event_t event;
7535 ibt_status_t status;
7536
7537 IBTF_DPRINTF_L3(cmlog, "ibcm_cep_state_rej_est:");
7538
7539 status = ibcm_cep_to_error_state(statep);
7540 IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_rej_est: statep 0x%p "
7541 "ibcm_cep_to_error_state returned %d", statep, status);
7542
7543 /* Disassociate state structure and CM */
7544 IBCM_SET_CHAN_PRIVATE(statep->channel, NULL);
7545
7546 ibtl_cm_chan_is_closing(statep->channel);
7547
7548 /* invoke the CM handler */
7549 if (statep->cm_handler) {
7550 bzero(&event, sizeof (event));
7551 event.cm_type = IBT_CM_EVENT_CONN_CLOSED;
7552 event.cm_channel = statep->channel;
7553 event.cm_session_id = NULL;
7554
7555 event.cm_priv_data = NULL;
7556 event.cm_priv_data_len = 0;
7557
7558 event.cm_event.closed = IBT_CM_CLOSED_REJ_RCVD;
7559
7560 IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_rej_est: "
7561 "rej_reason = %d", event.cm_event.failed.cf_reason);
7562
7563 ibcm_insert_trace(statep, IBCM_TRACE_CALLED_CONN_CLOSE_EVENT);
7564
7565 (void) statep->cm_handler(statep->state_cm_private, &event,
7566 NULL, NULL, 0);
7567
7568 ibcm_insert_trace(statep, IBCM_TRACE_RET_CONN_CLOSE_EVENT);
7569
7570 }
7571 }
7572
7573
7574 /*
7575 * ibcm_sidr_req_ud_handler:
7576 * Invoke Client's UD handler For SIDR_REQ msg
7577 *
7578 * INPUTS:
7579 * ud_statep - ud_state pointer
7580 * sidr_reqp - SIDR_REQ message pointer
7581 *
7582 * RETURN VALUE: IBCM_SEND_REP/IBCM_SEND_REJ
7583 */
7584 static ibcm_status_t
ibcm_sidr_req_ud_handler(ibcm_ud_state_data_t * ud_statep,ibcm_sidr_req_msg_t * sidr_reqp,ibcm_mad_addr_t * cm_mad_addr,ibt_sidr_status_t * sidr_status)7585 ibcm_sidr_req_ud_handler(ibcm_ud_state_data_t *ud_statep,
7586 ibcm_sidr_req_msg_t *sidr_reqp, ibcm_mad_addr_t *cm_mad_addr,
7587 ibt_sidr_status_t *sidr_status)
7588 {
7589 void *priv_data = NULL;
7590 ibt_cm_ud_event_t ud_event;
7591 ibcm_sidr_rep_msg_t *sidr_repp;
7592 ibt_cm_ud_return_args_t ud_ret_args;
7593 ibt_cm_status_t cb_status;
7594 ibt_qp_query_attr_t qp_attr;
7595 ibt_status_t retval;
7596 ibcm_ud_clnt_reply_info_t ud_clnt_info;
7597
7598 /* Check first if UD client handler is valid */
7599 ASSERT(ud_statep->ud_cm_handler != NULL);
7600
7601 /* Fill in ibt_cm_ud_event_t */
7602 ud_event.cm_type = IBT_CM_UD_EVENT_SIDR_REQ;
7603 ud_event.cm_session_id = ud_statep;
7604 ud_event.cm_event.sidr_req.sreq_service_id = ud_statep->ud_svc_id;
7605 ud_event.cm_event.sidr_req.sreq_hca_guid = ud_statep->ud_hcap->hca_guid;
7606 ud_event.cm_event.sidr_req.sreq_pkey = b2h16(sidr_reqp->sidr_req_pkey);
7607 ud_event.cm_event.sidr_req.sreq_hca_port = cm_mad_addr->port_num;
7608
7609 ud_event.cm_priv_data =
7610 &(sidr_reqp->sidr_req_private_data[0]);
7611 ud_event.cm_priv_data_len = IBT_SIDR_REQ_PRIV_DATA_SZ;
7612
7613 sidr_repp =
7614 (ibcm_sidr_rep_msg_t *)IBCM_OUT_MSGP(ud_statep->ud_stored_msg);
7615
7616 priv_data = &(sidr_repp->sidr_rep_private_data[0]);
7617
7618 bzero(&ud_ret_args, sizeof (ud_ret_args));
7619
7620 /* Invoke the client handler */
7621 cb_status = ud_statep->ud_cm_handler(ud_statep->ud_state_cm_private,
7622 &ud_event, &ud_ret_args, priv_data, IBT_SIDR_REP_PRIV_DATA_SZ);
7623
7624 if (cb_status == IBT_CM_DEFER) {
7625
7626 /* unblock any blocked cm ud proceed api calls */
7627 mutex_enter(&ud_statep->ud_state_mutex);
7628 ud_statep->ud_clnt_proceed = IBCM_UNBLOCK;
7629 cv_broadcast(&ud_statep->ud_block_client_cv);
7630 mutex_exit(&ud_statep->ud_state_mutex);
7631
7632 return (IBCM_DEFER);
7633 }
7634
7635 /* fail any blocked ud cm proceed api calls - client bug */
7636 mutex_enter(&ud_statep->ud_state_mutex);
7637 ud_statep->ud_clnt_proceed = IBCM_FAIL;
7638 cv_broadcast(&ud_statep->ud_block_client_cv);
7639 mutex_exit(&ud_statep->ud_state_mutex);
7640
7641 /* do the query qp as soon as possible, after return from cm handler */
7642 if (cb_status == IBT_CM_ACCEPT) {
7643 retval = ibt_query_qp(ud_ret_args.ud_channel, &qp_attr);
7644 if (retval != IBT_SUCCESS) {
7645 IBTF_DPRINTF_L2(cmlog, "ibcm_sidr_req_ud_handler: "
7646 "Failed to retrieve QPN from the channel: %d",
7647 retval);
7648 *sidr_status = IBT_CM_SREP_NO_CHAN;
7649 return (IBCM_SEND_SIDR_REP);
7650 } else if (qp_attr.qp_info.qp_trans != IBT_UD_SRV) {
7651 IBTF_DPRINTF_L2(cmlog, "ibcm_sidr_req_ud_handler: "
7652 "Server/Passive returned non-UD %d transport type "
7653 "QP", qp_attr.qp_info.qp_trans);
7654 *sidr_status = IBT_CM_SREP_NO_CHAN;
7655 return (IBCM_SEND_SIDR_REP);
7656 }
7657
7658 ud_clnt_info.ud_qkey = qp_attr.qp_info.qp_transport.ud.ud_qkey;
7659 ud_clnt_info.ud_qpn = qp_attr.qp_qpn;
7660 }
7661
7662 ud_clnt_info.priv_data = priv_data;
7663 ud_clnt_info.priv_data_len = ud_ret_args.ud_ret_len;
7664
7665 ud_clnt_info.redirect_infop = &ud_ret_args.ud_redirect;
7666
7667 ibcm_process_sidr_req_cm_hdlr(ud_statep, cb_status, &ud_clnt_info,
7668 sidr_status, sidr_repp);
7669
7670 return (IBCM_SEND_SIDR_REP);
7671 }
7672
7673 /*ARGSUSED*/
7674 void
ibcm_process_sidr_req_cm_hdlr(ibcm_ud_state_data_t * ud_statep,ibt_cm_status_t cb_status,ibcm_ud_clnt_reply_info_t * ud_clnt_info,ibt_sidr_status_t * sidr_status,ibcm_sidr_rep_msg_t * sidr_repp)7675 ibcm_process_sidr_req_cm_hdlr(ibcm_ud_state_data_t *ud_statep,
7676 ibt_cm_status_t cb_status, ibcm_ud_clnt_reply_info_t *ud_clnt_info,
7677 ibt_sidr_status_t *sidr_status, ibcm_sidr_rep_msg_t *sidr_repp)
7678 {
7679 void *sidr_rep_privp;
7680
7681 IBTF_DPRINTF_L5(cmlog, "ibcm_process_sidr_req_cm_hdlr(%p, %x, "
7682 "%p, %p, %p)", ud_statep, cb_status, ud_clnt_info,
7683 sidr_status, sidr_repp);
7684
7685 if (cb_status == IBT_CM_DEFAULT)
7686 cb_status = IBT_CM_REJECT;
7687
7688 if (cb_status == IBT_CM_ACCEPT)
7689 *sidr_status = IBT_CM_SREP_CHAN_VALID;
7690 else if ((cb_status == IBT_CM_REJECT) ||
7691 (cb_status == IBT_CM_NO_RESOURCE))
7692 *sidr_status = IBT_CM_SREP_REJ;
7693 else if (cb_status == IBT_CM_NO_CHANNEL)
7694 *sidr_status = IBT_CM_SREP_NO_CHAN;
7695 else if (cb_status == IBT_CM_REDIRECT)
7696 *sidr_status = IBT_CM_SREP_REDIRECT;
7697 else *sidr_status = IBT_CM_SREP_REJ;
7698
7699 /*
7700 * For Accept and reject copy the private data, if ud_clnt_info
7701 * priv_data does not point to SIDR Response private data. This
7702 * copy is needed for ibt_cm_ud_proceed().
7703 */
7704 sidr_rep_privp = (void *)(&(sidr_repp->sidr_rep_private_data[0]));
7705 if ((cb_status == IBT_CM_ACCEPT || cb_status == IBT_CM_REJECT) &&
7706 (ud_clnt_info->priv_data != sidr_rep_privp) &&
7707 ud_clnt_info->priv_data_len) {
7708 bcopy(ud_clnt_info->priv_data, sidr_rep_privp,
7709 min(ud_clnt_info->priv_data_len,
7710 IBT_SIDR_REP_PRIV_DATA_SZ));
7711 }
7712
7713 if (*sidr_status != IBT_CM_SREP_CHAN_VALID) {
7714 IBTF_DPRINTF_L2(cmlog, "ibcm_process_sidr_req_cm_hdlr: "
7715 "ud_handler return a failure: %d", cb_status);
7716 if (*sidr_status == IBT_CM_SREP_REDIRECT) {
7717 /*
7718 * typecasting to ibcm_classportinfo_msg_t is ok, as addl info
7719 * begins at offset 24 in sidr rep
7720 */
7721 ibcm_init_clp_to_mad(
7722 (ibcm_classportinfo_msg_t *)
7723 &sidr_repp->sidr_rep_class_port_info,
7724 ud_clnt_info->redirect_infop);
7725 }
7726 return;
7727 }
7728
7729
7730 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sidr_repp))
7731
7732 sidr_repp->sidr_rep_qkey =
7733 h2b32(ud_clnt_info->ud_qkey);
7734 sidr_repp->sidr_rep_qpn_plus = h2b32(ud_clnt_info->ud_qpn << 8);
7735
7736 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sidr_repp))
7737 }
7738
7739 /*
7740 * ibcm_sidr_rep_ud_handler:
7741 * Invoke Client's UD handler For SIDR_REP msg
7742 *
7743 * INPUTS:
7744 * ud_statep - ud_state pointer
7745 * sidr_rep_msgp - SIDR_REQ message pointer
7746 *
7747 */
7748 static void
ibcm_sidr_rep_ud_handler(ibcm_ud_state_data_t * ud_statep,ibcm_sidr_rep_msg_t * sidr_rep_msgp)7749 ibcm_sidr_rep_ud_handler(ibcm_ud_state_data_t *ud_statep,
7750 ibcm_sidr_rep_msg_t *sidr_rep_msgp)
7751 {
7752 ibt_cm_ud_event_t ud_event;
7753
7754 IBTF_DPRINTF_L5(cmlog, "ibcm_sidr_rep_ud_handler: ud_statep 0x%p",
7755 ud_statep);
7756
7757 /* Check first if UD client handler is valid */
7758 if (ud_statep->ud_cm_handler == NULL) {
7759 IBTF_DPRINTF_L2(cmlog, "ibcm_sidr_rep_ud_handler: "
7760 "cm_handler NULL");
7761 return;
7762 }
7763
7764 /* Fill in ibt_cm_ud_event_t */
7765 ud_event.cm_type = IBT_CM_UD_EVENT_SIDR_REP;
7766 ud_event.cm_session_id = NULL;
7767 ud_event.cm_event.sidr_rep.srep_status =
7768 sidr_rep_msgp->sidr_rep_rep_status;
7769 ud_event.cm_event.sidr_rep.srep_remote_qpn =
7770 b2h32(sidr_rep_msgp->sidr_rep_qpn_plus) >> 8;
7771 ud_event.cm_event.sidr_rep.srep_remote_qkey =
7772 h2b32(sidr_rep_msgp->sidr_rep_qkey);
7773
7774 if (ud_event.cm_event.sidr_rep.srep_status == IBT_CM_SREP_REDIRECT) {
7775 /*
7776 * typecasting to ibcm_classportinfo_msg_t is ok, as addl info
7777 * begins at offset 24 in sidr rep
7778 */
7779 ibcm_init_clp_from_mad(
7780 (ibcm_classportinfo_msg_t *)
7781 sidr_rep_msgp->sidr_rep_class_port_info,
7782 &ud_event.cm_event.sidr_rep.srep_redirect);
7783
7784 if (ud_statep->ud_return_data != NULL)
7785 bcopy(&ud_event.cm_event.sidr_rep.srep_redirect,
7786 &ud_statep->ud_return_data->ud_redirect,
7787 sizeof (ibt_redirect_info_t));
7788 }
7789
7790 ud_event.cm_priv_data = &(sidr_rep_msgp->sidr_rep_private_data[0]);
7791 ud_event.cm_priv_data_len = IBT_SIDR_REP_PRIV_DATA_SZ;
7792
7793 /* Invoke the client handler - inform only, so ignore retval */
7794 (void) ud_statep->ud_cm_handler(ud_statep->ud_state_cm_private,
7795 &ud_event, NULL, NULL, 0);
7796
7797
7798 }
7799
7800 /*
7801 * ibcm_process_lap_msg:
7802 * This call processes an incoming LAP message
7803 *
7804 * INPUTS:
7805 * hcap - HCA entry pointer
7806 * input_madp - incoming CM LAP MAD
7807 * cm_mad_addr - Address information for the MAD
7808 *
7809 * RETURN VALUE: NONE
7810 */
7811 /* ARGSUSED */
7812 void
ibcm_process_lap_msg(ibcm_hca_info_t * hcap,uint8_t * input_madp,ibcm_mad_addr_t * cm_mad_addr)7813 ibcm_process_lap_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
7814 ibcm_mad_addr_t *cm_mad_addr)
7815 {
7816 ibcm_status_t state_lookup_status;
7817 ibcm_lap_msg_t *lap_msg = (ibcm_lap_msg_t *)
7818 (&input_madp[IBCM_MAD_HDR_SIZE]);
7819 ibcm_apr_msg_t *apr_msg;
7820 ibcm_state_data_t *statep = NULL;
7821
7822 IBTF_DPRINTF_L4(cmlog, "ibcm_process_lap_msg:");
7823
7824 rw_enter(&hcap->hca_state_rwlock, RW_READER);
7825
7826 state_lookup_status = ibcm_lookup_msg(IBCM_INCOMING_LAP,
7827 b2h32(lap_msg->lap_remote_comm_id), 0, 0, hcap, &statep);
7828
7829 rw_exit(&hcap->hca_state_rwlock);
7830
7831 IBTF_DPRINTF_L4(cmlog, "ibcm_process_lap_msg: lookup status %x"
7832 " com id %x", state_lookup_status,
7833 b2h32(lap_msg->lap_remote_comm_id));
7834
7835 if (state_lookup_status != IBCM_LOOKUP_EXISTS) {
7836 /* Post a REJ message ? - but spec doesn't state so */
7837 return;
7838 }
7839
7840 /* There is an existing state structure entry with active comid */
7841
7842 ibcm_insert_trace(statep, IBCM_TRACE_INCOMING_LAP);
7843
7844 mutex_enter(&statep->state_mutex);
7845
7846 if ((statep->state == IBCM_STATE_ESTABLISHED) &&
7847 (statep->ap_state == IBCM_AP_STATE_IDLE) &&
7848 (statep->mode == IBCM_PASSIVE_MODE)) {
7849 if ((statep->lapr_msg) &&
7850 (IBCM_OUT_HDRP(statep->lapr_msg)->TransactionID ==
7851 ((ib_mad_hdr_t *)(input_madp))->TransactionID))
7852 ibcm_post_stored_apr_mad(statep, input_madp);
7853 else {
7854 ibcm_status_t clnt_response;
7855
7856 statep->ap_state = IBCM_AP_STATE_LAP_RCVD;
7857 statep->clnt_proceed = IBCM_BLOCK;
7858 mutex_exit(&statep->state_mutex);
7859
7860 if (statep->lapr_msg == NULL) {
7861 if (ibcm_alloc_out_msg(
7862 statep->stored_reply_addr.ibmf_hdl,
7863 &statep->lapr_msg, MAD_METHOD_SEND) !=
7864 IBT_SUCCESS) {
7865
7866 mutex_enter(&statep->state_mutex);
7867 statep->clnt_proceed = IBCM_FAIL;
7868 cv_broadcast(&statep->block_client_cv);
7869 IBCM_REF_CNT_DECR(statep);
7870 mutex_exit(&statep->state_mutex);
7871 return;
7872 }
7873 }
7874 apr_msg = (ibcm_apr_msg_t *)
7875 IBCM_OUT_MSGP(statep->lapr_msg);
7876 IBCM_OUT_HDRP(statep->lapr_msg)->TransactionID =
7877 ((ib_mad_hdr_t *)(input_madp))->TransactionID;
7878 clnt_response =
7879 ibcm_cep_state_lap(statep, lap_msg, apr_msg);
7880 IBTF_DPRINTF_L4(cmlog, "ibcm_process_lap_msg:"
7881 " statep 0x%p apr status %d", statep,
7882 apr_msg->apr_ap_status);
7883
7884 if (clnt_response == IBCM_DEFER) {
7885 IBTF_DPRINTF_L4(cmlog, "ibcm_process_lap_msg: "
7886 "client returned DEFER response");
7887 return;
7888 }
7889
7890 /* fail any blocked cm proceed api calls - client bug */
7891 mutex_enter(&statep->state_mutex);
7892 statep->clnt_proceed = IBCM_FAIL;
7893 cv_broadcast(&statep->block_client_cv);
7894 mutex_exit(&statep->state_mutex);
7895
7896 ibcm_post_apr_mad(statep);
7897 return;
7898 }
7899 } /* drop the LAP MAD in any other state */
7900
7901 IBCM_REF_CNT_DECR(statep); /* decrement the ref count */
7902 mutex_exit(&statep->state_mutex);
7903 }
7904
7905 /*
7906 * ibcm_post_stored_apr_mad:
7907 * Builds and posts an APR MAD from the stored APR MAD
7908 *
7909 * INPUTS:
7910 * statep - pointer to ibcm_state_data_t
7911 * input_madp - pointer to incoming lap mad
7912 *
7913 * RETURN VALUE:
7914 * NONE
7915 *
7916 * This function is called holding the state mutex, and returns
7917 * holding the state mutex
7918 */
7919 static void
ibcm_post_stored_apr_mad(ibcm_state_data_t * statep,uint8_t * input_madp)7920 ibcm_post_stored_apr_mad(ibcm_state_data_t *statep, uint8_t *input_madp)
7921 {
7922 ibmf_msg_t *ibmf_apr_msg;
7923 uint8_t apr_msg[IBCM_MSG_SIZE];
7924
7925 /* Need to make a copy, else an incoming new LAP may modify lapr_msg */
7926 bcopy(IBCM_OUT_MSGP(statep->lapr_msg), apr_msg, IBCM_MSG_SIZE);
7927
7928 mutex_exit(&statep->state_mutex);
7929
7930 if (ibcm_alloc_out_msg(statep->stored_reply_addr.ibmf_hdl,
7931 &ibmf_apr_msg, MAD_METHOD_SEND) != IBT_SUCCESS) {
7932 IBTF_DPRINTF_L2(cmlog, "ibcm_post_stored_apr_mad: "
7933 "ibcm_alloc_out_msg failed");
7934 mutex_enter(&statep->state_mutex);
7935 return;
7936 }
7937
7938 bcopy(apr_msg, IBCM_OUT_MSGP(ibmf_apr_msg), IBCM_MSG_SIZE);
7939
7940 IBCM_OUT_HDRP(ibmf_apr_msg)->AttributeID =
7941 h2b16(IBCM_INCOMING_APR + IBCM_ATTR_BASE_ID);
7942
7943 IBCM_OUT_HDRP(ibmf_apr_msg)->TransactionID =
7944 ((ib_mad_hdr_t *)(input_madp))->TransactionID;
7945
7946 ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_APR);
7947
7948 ibcm_post_rc_mad(statep, ibmf_apr_msg, ibcm_post_stored_apr_complete,
7949 ibmf_apr_msg);
7950
7951 /* ibcm_free_out_msg done in ibcm_post_stored_apr_complete */
7952
7953 mutex_enter(&statep->state_mutex);
7954 }
7955
7956 /*
7957 * ibcm_cep_state_lap:
7958 * This call processes an incoming LAP message for cep state
7959 * transition and invoking cm handler
7960 *
7961 * INPUTS:
7962 * statep - pointer to ibcm_state_data_t
7963 * lap_msg - lap msg received
7964 * apr_msg - apr msg to be sent
7965 *
7966 * RETURN VALUE: NONE
7967 */
7968 ibcm_status_t
ibcm_cep_state_lap(ibcm_state_data_t * statep,ibcm_lap_msg_t * lap_msg,ibcm_apr_msg_t * apr_msg)7969 ibcm_cep_state_lap(ibcm_state_data_t *statep, ibcm_lap_msg_t *lap_msg,
7970 ibcm_apr_msg_t *apr_msg)
7971 {
7972 ibt_cm_event_t event;
7973 ibt_cm_return_args_t ret_args;
7974 ibt_cm_status_t cb_status;
7975 ibcm_clnt_reply_info_t clnt_info;
7976
7977
7978 IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_lap: statep 0x%p", statep);
7979
7980 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*apr_msg))
7981
7982 /* If APM is not supported, return error */
7983 if (!(statep->hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG)) {
7984 apr_msg->apr_ap_status = IBT_CM_AP_NOT_SUPPORTED;
7985 return (IBCM_SEND_APR);
7986 }
7987
7988 if (statep->local_qpn !=
7989 b2h32(lap_msg->lap_remote_qpn_eecn_plus) >> 8) {
7990 apr_msg->apr_ap_status = IBT_CM_AP_REJECT;
7991 IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_lap: local_qpn %x does "
7992 "not match remote's remote_qpn %x", statep->local_qpn,
7993 b2h32(lap_msg->lap_remote_qpn_eecn_plus) >> 8);
7994 return (IBCM_SEND_APR);
7995 }
7996
7997 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*apr_msg))
7998
7999 /* Fill up the event */
8000 bzero(&event, sizeof (event));
8001 event.cm_type = IBT_CM_EVENT_LAP_RCV;
8002 event.cm_channel = statep->channel;
8003 event.cm_session_id = statep;
8004 event.cm_priv_data = lap_msg->lap_private_data;
8005 event.cm_priv_data_len = IBT_LAP_PRIV_DATA_SZ;
8006 event.cm_event.lap.lap_timeout = ibt_ib2usec(
8007 ((uint8_t *)&lap_msg->lap_remote_qpn_eecn_plus)[3] >> 3);
8008
8009 ibcm_fill_adds_from_lap(&event.cm_event.lap.lap_alternate_path,
8010 lap_msg, IBCM_PASSIVE_MODE);
8011
8012 cb_status = statep->cm_handler(statep->state_cm_private, &event,
8013 &ret_args, apr_msg->apr_private_data, IBT_APR_PRIV_DATA_SZ);
8014
8015 IBTF_DPRINTF_L3(cmlog, "ibcm_cep_state_lap: cb_status = %d", cb_status);
8016 if (cb_status == IBT_CM_DEFER) {
8017
8018 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(statep->defer_cm_msg))
8019
8020 if (statep->defer_cm_msg == NULL)
8021 statep->defer_cm_msg =
8022 kmem_zalloc(IBCM_MSG_SIZE, KM_SLEEP);
8023 bcopy(lap_msg, statep->defer_cm_msg, IBCM_MSG_SIZE);
8024
8025 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(statep->defer_cm_msg))
8026
8027 /* unblock any blocked cm proceed api calls */
8028 mutex_enter(&statep->state_mutex);
8029 statep->clnt_proceed = IBCM_UNBLOCK;
8030 cv_broadcast(&statep->block_client_cv);
8031 mutex_exit(&statep->state_mutex);
8032
8033 return (IBCM_DEFER);
8034 }
8035
8036 clnt_info.reply_event = (ibt_cm_proceed_reply_t *)&ret_args.cm_ret;
8037 clnt_info.priv_data = NULL;
8038 clnt_info.priv_data_len = 0;
8039
8040 ibcm_process_cep_lap_cm_hdlr(statep, cb_status, &clnt_info, lap_msg,
8041 apr_msg);
8042 return (IBCM_SEND_APR);
8043 }
8044
8045 /*
8046 * ibcm_fill_adds_from_lap:
8047 * Fills the address vector (part of event structure passed to
8048 * client) from the LAP message
8049 *
8050 * INPUTS:
8051 * adds - Address vector to be filled-in
8052 * lap_msg - LAP message used to fill the address vector
8053 *
8054 * RETURN VALUE: NONE
8055 */
8056 static void
ibcm_fill_adds_from_lap(ibt_adds_vect_t * adds,ibcm_lap_msg_t * lap_msg,ibcm_mode_t mode)8057 ibcm_fill_adds_from_lap(ibt_adds_vect_t *adds, ibcm_lap_msg_t *lap_msg,
8058 ibcm_mode_t mode)
8059 {
8060 adds->av_srvl = lap_msg->lap_alt_sl_plus >> 4;
8061 if (mode == IBCM_PASSIVE_MODE) {
8062 adds->av_dgid.gid_prefix =
8063 b2h64(lap_msg->lap_alt_l_port_gid.gid_prefix);
8064 adds->av_dgid.gid_guid =
8065 b2h64(lap_msg->lap_alt_l_port_gid.gid_guid);
8066 adds->av_sgid.gid_prefix =
8067 b2h64(lap_msg->lap_alt_r_port_gid.gid_prefix);
8068 adds->av_sgid.gid_guid =
8069 b2h64(lap_msg->lap_alt_r_port_gid.gid_guid);
8070 adds->av_dlid = b2h16(lap_msg->lap_alt_l_port_lid);
8071 } else {
8072 adds->av_sgid.gid_prefix =
8073 b2h64(lap_msg->lap_alt_l_port_gid.gid_prefix);
8074 adds->av_sgid.gid_guid =
8075 b2h64(lap_msg->lap_alt_l_port_gid.gid_guid);
8076 adds->av_dgid.gid_prefix =
8077 b2h64(lap_msg->lap_alt_r_port_gid.gid_prefix);
8078 adds->av_dgid.gid_guid =
8079 b2h64(lap_msg->lap_alt_r_port_gid.gid_guid);
8080 adds->av_dlid = b2h16(lap_msg->lap_alt_r_port_lid);
8081 }
8082
8083 IBTF_DPRINTF_L4(cmlog, "ibcm_fill_adds_from_lap: SGID=(%llX:%llX)",
8084 adds->av_sgid.gid_prefix, adds->av_sgid.gid_guid);
8085
8086 IBTF_DPRINTF_L4(cmlog, "ibcm_fill_adds_from_lap: DGID=(%llX:%llX)",
8087 adds->av_dgid.gid_prefix, adds->av_dgid.gid_guid);
8088
8089 adds->av_srate = lap_msg->lap_alt_srate_plus & 0x3f;
8090
8091 /* next copy off the GRH info if it exists */
8092 if ((lap_msg->lap_alt_sl_plus & 0x8) == 0) {
8093 uint32_t flow_tclass = b2h32(lap_msg->lap_alt_flow_label_plus);
8094
8095 adds->av_send_grh = B_TRUE;
8096 adds->av_flow = flow_tclass >> 12;
8097 adds->av_tclass = flow_tclass & 0xff;
8098 adds->av_hop = lap_msg->lap_alt_hop_limit;
8099 } else {
8100 adds->av_send_grh = B_FALSE;
8101 }
8102 }
8103
8104 /*
8105 * ibcm_process_cep_lap_cm_hdlr:
8106 * Processes the cm handler response for an incoming LAP.
8107 */
8108
8109 void
ibcm_process_cep_lap_cm_hdlr(ibcm_state_data_t * statep,ibt_cm_status_t cb_status,ibcm_clnt_reply_info_t * clnt_info,ibcm_lap_msg_t * lap_msg,ibcm_apr_msg_t * apr_msg)8110 ibcm_process_cep_lap_cm_hdlr(ibcm_state_data_t *statep,
8111 ibt_cm_status_t cb_status, ibcm_clnt_reply_info_t *clnt_info,
8112 ibcm_lap_msg_t *lap_msg, ibcm_apr_msg_t *apr_msg)
8113 {
8114 ibtl_cm_hca_port_t port;
8115 ibt_qp_query_attr_t qp_attrs;
8116 ibt_cep_modify_flags_t cep_flags;
8117 ibt_status_t status;
8118 ibt_adds_vect_t *adds;
8119
8120 if (cb_status == IBT_CM_DEFAULT)
8121 cb_status = IBT_CM_REJECT;
8122
8123 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*apr_msg))
8124
8125 /* verify status */
8126 apr_msg->apr_addl_info_len = 0;
8127 if (cb_status == IBT_CM_ACCEPT) {
8128 apr_msg->apr_ap_status = IBT_CM_AP_LOADED;
8129 } else if (cb_status == IBT_CM_REJECT) {
8130 apr_msg->apr_ap_status = IBT_CM_AP_REJECT;
8131 } else if (cb_status == IBT_CM_REDIRECT) {
8132 apr_msg->apr_ap_status = IBT_CM_AP_REDIRECT;
8133 /* copy redirect info to APR */
8134 apr_msg->apr_addl_info_len = sizeof (ibcm_classportinfo_msg_t);
8135 ibcm_init_clp_to_mad(
8136 (ibcm_classportinfo_msg_t *)apr_msg->apr_addl_info,
8137 &clnt_info->reply_event->apr);
8138 } else if (cb_status == IBT_CM_NO_RESOURCE) {
8139 apr_msg->apr_ap_status = IBT_CM_AP_REJECT;
8140 } else {
8141 IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_lap_cm_hdlr: statep %p"
8142 " Client handler unexpected return %x", statep, cb_status);
8143 cb_status = IBT_CM_REJECT;
8144 apr_msg->apr_ap_status = IBT_CM_AP_REJECT;
8145 }
8146
8147 IBTF_DPRINTF_L4(cmlog, "ibcm_process_cep_lap_cm_hdlr: statep 0x%p "
8148 " client handler returned %d, apr status %d", statep, cb_status,
8149 apr_msg->apr_ap_status);
8150
8151 /* copy private data to outgoing apr, specified via priv_data */
8152 if ((clnt_info->priv_data != NULL) && (clnt_info->priv_data_len > 0))
8153 bcopy(clnt_info->priv_data, apr_msg->apr_private_data,
8154 min(clnt_info->priv_data_len, IBT_APR_PRIV_DATA_SZ));
8155
8156 if (cb_status != IBT_CM_ACCEPT)
8157 return;
8158
8159 if (ibt_query_qp(statep->channel, &qp_attrs) != IBT_SUCCESS ||
8160 (qp_attrs.qp_info.qp_state != IBT_STATE_RTS &&
8161 qp_attrs.qp_info.qp_state != IBT_STATE_SQD)) {
8162 apr_msg->apr_ap_status = IBT_CM_AP_REJECT;
8163 return;
8164 }
8165
8166 /* Fill up input args for ibt_modify_qp */
8167 cep_flags = IBT_CEP_SET_ALT_PATH | IBT_CEP_SET_STATE;
8168
8169 /* do RTS=>RTS or SQD=>SQD. The next line is needed for RTS=>RTS. */
8170 qp_attrs.qp_info.qp_current_state = qp_attrs.qp_info.qp_state;
8171
8172 adds = &IBCM_QP_RC(qp_attrs).rc_alt_path.cep_adds_vect;
8173 ibcm_fill_adds_from_lap(adds, lap_msg, IBCM_PASSIVE_MODE);
8174
8175 if ((status = ibtl_cm_get_hca_port(adds->av_sgid,
8176 statep->local_hca_guid, &port)) != IBT_SUCCESS) {
8177
8178 IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_lap_cm_hdlr:"
8179 " ibtl_cm_get_hca_port failed status %d", status);
8180 apr_msg->apr_ap_status = IBT_CM_AP_REJECT;
8181 return;
8182 }
8183
8184 IBCM_QP_RC(qp_attrs).rc_alt_path.cep_hca_port_num = port.hp_port;
8185
8186 IBTF_DPRINTF_L4(cmlog, "ibcm_process_cep_lap_cm_hdlr: statep 0x%p "
8187 "gid = (%llx, %llx), port_num = %d", statep,
8188 IBCM_QP_RC(qp_attrs).rc_alt_path.cep_adds_vect.av_dgid.
8189 gid_prefix,
8190 IBCM_QP_RC(qp_attrs).rc_alt_path.cep_adds_vect.av_dgid.gid_guid,
8191 port.hp_port);
8192
8193 /* The pkey is same as the primary path */
8194 status = ibt_pkey2index_byguid(statep->local_hca_guid,
8195 port.hp_port, statep->pkey,
8196 &IBCM_QP_RC(qp_attrs).rc_alt_path.cep_pkey_ix);
8197
8198 if (status != IBT_SUCCESS) {
8199 IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_lap_cm_hdlr: statep %p"
8200 " ibt_pkey2index_byguid failed %d", statep, status);
8201 apr_msg->apr_ap_status = IBT_CM_AP_REJECT;
8202 return;
8203 }
8204
8205 IBCM_QP_RC(qp_attrs).rc_alt_path.cep_timeout =
8206 lap_msg->lap_alt_local_acktime_plus >> 3;
8207
8208 qp_attrs.qp_info.qp_trans = IBT_RC_SRV;
8209 if (IBCM_QP_RC(qp_attrs).rc_mig_state == IBT_STATE_MIGRATED) {
8210 IBTF_DPRINTF_L3(cmlog, "ibcm_process_cep_lap_cm_hdlr: statep %p"
8211 ": rearming APM", statep);
8212 cep_flags |= IBT_CEP_SET_MIG;
8213 IBCM_QP_RC(qp_attrs).rc_mig_state = IBT_STATE_REARMED;
8214 }
8215 status = ibt_modify_qp(statep->channel, cep_flags, &qp_attrs.qp_info,
8216 NULL);
8217
8218 if (status != IBT_SUCCESS) {
8219 ibcm_insert_trace(statep, IBCM_TRACE_SET_ALT_FAIL);
8220 } else
8221 ibcm_insert_trace(statep, IBCM_TRACE_SET_ALT);
8222
8223 #ifdef DEBUG
8224 (void) ibt_query_qp(statep->channel, &qp_attrs);
8225 print_modify_qp("PASSIVE LAP QUERY", statep->channel,
8226 cep_flags, &qp_attrs.qp_info);
8227 #endif
8228
8229 if (status != IBT_SUCCESS) {
8230 apr_msg->apr_ap_status = IBT_CM_AP_REJECT;
8231 IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_lap_cm_hdlr:"
8232 " ibt_modify_qp() returned = %d", status);
8233 return;
8234 }
8235 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*apr_msg))
8236 }
8237
8238
8239 /*
8240 * ibcm_post_apr_mad:
8241 * Posts a APR MAD and starts timer
8242 *
8243 * INPUTS:
8244 * statep - state pointer
8245 *
8246 * RETURN VALUE: NONE
8247 */
8248 void
ibcm_post_apr_mad(ibcm_state_data_t * statep)8249 ibcm_post_apr_mad(ibcm_state_data_t *statep)
8250 {
8251 ibcm_apr_msg_t *apr_msgp;
8252
8253 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*apr_msgp))
8254
8255 apr_msgp = (ibcm_apr_msg_t *)IBCM_OUT_MSGP(statep->lapr_msg);
8256
8257 apr_msgp->apr_local_comm_id = h2b32(statep->local_comid);
8258 apr_msgp->apr_remote_comm_id = h2b32(statep->remote_comid);
8259 IBCM_OUT_HDRP(statep->lapr_msg)->AttributeID =
8260 h2b16(IBCM_INCOMING_APR + IBCM_ATTR_BASE_ID);
8261
8262 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*apr_msgp))
8263
8264 ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_APR);
8265
8266 ibcm_post_rc_mad(statep, statep->lapr_msg, ibcm_post_apr_complete,
8267 statep);
8268 }
8269
8270 /*
8271 * ibcm_process_apr_msg:
8272 * This call processes an incoming APR message
8273 *
8274 * INPUTS:
8275 * hcap - HCA entry pointer
8276 * input_madp - incoming CM SIDR REP MAD
8277 * cm_mad_addr - Address information for the MAD to be posted
8278 *
8279 * RETURN VALUE: NONE
8280 */
8281 /*ARGSUSED*/
8282 void
ibcm_process_apr_msg(ibcm_hca_info_t * hcap,uint8_t * input_madp,ibcm_mad_addr_t * cm_mad_addr)8283 ibcm_process_apr_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
8284 ibcm_mad_addr_t *cm_mad_addr)
8285 {
8286 ibcm_status_t state_lookup_status;
8287 ibcm_apr_msg_t *apr_msg = (ibcm_apr_msg_t *)
8288 (&input_madp[IBCM_MAD_HDR_SIZE]);
8289 ibcm_state_data_t *statep = NULL;
8290
8291 IBTF_DPRINTF_L4(cmlog, "ibcm_process_apr_msg:");
8292
8293 rw_enter(&hcap->hca_state_rwlock, RW_READER);
8294 state_lookup_status = ibcm_lookup_msg(IBCM_INCOMING_APR,
8295 b2h32(apr_msg->apr_remote_comm_id), 0, 0, hcap, &statep);
8296 rw_exit(&hcap->hca_state_rwlock);
8297
8298 if (state_lookup_status != IBCM_LOOKUP_EXISTS) {
8299 return;
8300 }
8301
8302 /* if transaction id is not as expected, drop the APR mad */
8303 if (IBCM_OUT_HDRP(statep->lapr_msg)->TransactionID !=
8304 ((ib_mad_hdr_t *)(input_madp))->TransactionID) {
8305 mutex_enter(&statep->state_mutex);
8306 IBCM_REF_CNT_DECR(statep);
8307 mutex_exit(&statep->state_mutex);
8308 IBTF_DPRINTF_L3(cmlog, "ibcm_process_apr_msg: statep 0x%p"
8309 ": rcv'd APR MAD with comid 0x%x",
8310 statep, b2h32(apr_msg->apr_remote_comm_id));
8311 IBTF_DPRINTF_L3(cmlog, "ibcm_process_apr_msg: "
8312 "tid expected 0x%llX tid found 0x%llX",
8313 b2h64(IBCM_OUT_HDRP(statep->lapr_msg)->TransactionID),
8314 b2h64(((ib_mad_hdr_t *)(input_madp))->TransactionID));
8315 return;
8316 }
8317
8318 IBTF_DPRINTF_L4(cmlog, "ibcm_process_apr_msg: statep 0x%p "
8319 "lookup status %x", statep, state_lookup_status);
8320
8321 mutex_enter(&statep->state_mutex);
8322
8323 if (!((statep->state == IBCM_STATE_ESTABLISHED) &&
8324 ((statep->ap_state == IBCM_AP_STATE_LAP_SENT) ||
8325 (statep->ap_state == IBCM_AP_STATE_MRA_LAP_RCVD)))) {
8326 IBCM_REF_CNT_DECR(statep); /* decrement the ref count */
8327 mutex_exit(&statep->state_mutex);
8328 return;
8329 }
8330
8331 statep->ap_state = IBCM_AP_STATE_APR_RCVD;
8332
8333 /* cancel the LAP timer */
8334 if (statep->timerid != 0) {
8335 timeout_id_t timer_val;
8336 timer_val = statep->timerid;
8337 statep->timerid = 0;
8338 mutex_exit(&statep->state_mutex);
8339 (void) untimeout(timer_val);
8340 } else {
8341 mutex_exit(&statep->state_mutex);
8342 }
8343
8344 ibcm_insert_trace(statep, IBCM_TRACE_INCOMING_APR);
8345
8346 ibcm_cep_state_apr(statep,
8347 (ibcm_lap_msg_t *)IBCM_OUT_MSGP(statep->lapr_msg), apr_msg);
8348
8349 mutex_enter(&statep->state_mutex);
8350 statep->ap_state = IBCM_AP_STATE_IDLE;
8351
8352 /* unblock any DREQ threads and close channels */
8353 cv_broadcast(&statep->block_mad_cv);
8354
8355 statep->ap_done = B_TRUE;
8356
8357 /* wake up blocking ibt_set_alt_path */
8358 cv_broadcast(&statep->block_client_cv);
8359
8360 IBCM_REF_CNT_DECR(statep); /* decrement the ref count */
8361 mutex_exit(&statep->state_mutex);
8362 }
8363
8364 static void
ibcm_set_apr_arej(int ap_status,ibcm_apr_msg_t * apr_msgp,ibt_arej_info_t * ari,boolean_t * ari_valid)8365 ibcm_set_apr_arej(int ap_status, ibcm_apr_msg_t *apr_msgp,
8366 ibt_arej_info_t *ari, boolean_t *ari_valid)
8367 {
8368 uint8_t ari_len = apr_msgp->apr_addl_info_len;
8369 ibcm_classportinfo_msg_t tclp;
8370
8371 *ari_valid = B_FALSE;
8372
8373 IBTF_DPRINTF_L3(cmlog, "ibcm_set_apr_arej: apr_status = %d "
8374 "ari_len = %d", ap_status, ari_len);
8375
8376 _NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ari))
8377
8378 switch (ap_status) {
8379 case IBT_CM_AP_REDIRECT:
8380 if (ari_len < sizeof (ibcm_classportinfo_msg_t))
8381 break;
8382 *ari_valid = B_TRUE;
8383 bcopy(apr_msgp->apr_addl_info, &tclp, sizeof (tclp));
8384 ibcm_init_clp_from_mad(&tclp, &ari->ari_redirect);
8385 break;
8386 case IBT_CM_AP_RLID_REJECTED:
8387 if (ari_len < sizeof (ib_lid_t))
8388 break;
8389 *ari_valid = B_TRUE;
8390 bcopy(apr_msgp->apr_addl_info, &ari->ari_lid,
8391 sizeof (ib_lid_t));
8392 ari->ari_lid = b2h16(ari->ari_lid);
8393 break;
8394 case IBT_CM_AP_RGID_REJECTED:
8395 if (ari_len < sizeof (ib_gid_t))
8396 break;
8397 *ari_valid = B_TRUE;
8398 bcopy(apr_msgp->apr_addl_info, &ari->ari_gid,
8399 sizeof (ib_gid_t));
8400 ari->ari_gid.gid_guid = b2h64(ari->ari_gid.gid_guid);
8401 ari->ari_gid.gid_prefix = b2h64(ari->ari_gid.gid_prefix);
8402
8403 IBTF_DPRINTF_L4(cmlog, "ibcm_set_apr_arej: ari_gid= %llX:%llX",
8404 ari->ari_gid.gid_prefix, ari->ari_gid.gid_guid);
8405 break;
8406 case IBT_CM_AP_FLOW_REJECTED:
8407 if (ari_len < 3) /* 3 bytes needed for 20 bits */
8408 break;
8409 *ari_valid = B_TRUE;
8410 /* take the first 20 bits */
8411 ari->ari_flow =
8412 b2h32(*(uint32_t *)&apr_msgp->apr_addl_info) >> 12;
8413 break;
8414 case IBT_CM_AP_TCLASS_REJECTED:
8415 if (ari_len < 1)
8416 break;
8417 *ari_valid = B_TRUE;
8418 /* take the first byte */
8419 ari->ari_tclass = apr_msgp->apr_addl_info[0];
8420 break;
8421 case IBT_CM_AP_HOP_REJECTED:
8422 if (ari_len < 1)
8423 break;
8424 *ari_valid = B_TRUE;
8425 /* take the first byte */
8426 ari->ari_hop = apr_msgp->apr_addl_info[0];
8427 break;
8428 case IBT_CM_AP_RATE_REJECTED:
8429 if (ari_len < 1)
8430 break;
8431 *ari_valid = B_TRUE;
8432 /* take the first 6 bits */
8433 ari->ari_rate = apr_msgp->apr_addl_info[0] >> 2;
8434 break;
8435 case IBT_CM_AP_SL_REJECTED:
8436 if (ari_len < 1)
8437 break;
8438 *ari_valid = B_TRUE;
8439 /* take the first 4 bits */
8440 ari->ari_sl = apr_msgp->apr_addl_info[0] >> 4;
8441 break;
8442 default:
8443 break;
8444 }
8445 _NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*ari))
8446 }
8447
8448 /*
8449 * ibcm_cep_state_apr:
8450 * This call processes an incoming APR message
8451 *
8452 * INPUTS:
8453 * statep - pointer to ibcm_state_data_t
8454 * lap_msg - lap msg sent earlier
8455 * apr_msg - apr msg received
8456 *
8457 * RETURN VALUE: NONE
8458 */
8459 void
ibcm_cep_state_apr(ibcm_state_data_t * statep,ibcm_lap_msg_t * lap_msg,ibcm_apr_msg_t * apr_msg)8460 ibcm_cep_state_apr(ibcm_state_data_t *statep, ibcm_lap_msg_t *lap_msg,
8461 ibcm_apr_msg_t *apr_msg)
8462 {
8463 ibt_cm_event_t event;
8464 ibcm_status_t status = IBCM_SUCCESS;
8465 uint8_t ap_status = apr_msg->apr_ap_status;
8466
8467 IBTF_DPRINTF_L3(cmlog, "ibcm_cep_state_apr: statep 0x%p, ap_status %d",
8468 statep, ap_status);
8469
8470 if (ap_status == IBT_CM_AP_LOADED)
8471 status = ibcm_set_qp_from_apr(statep, lap_msg);
8472
8473 if (statep->ap_return_data != NULL) { /* blocking call */
8474
8475 /* copy the private data */
8476 if ((statep->ap_return_data->ap_priv_data != NULL) &&
8477 (statep->ap_return_data->ap_priv_data_len > 0))
8478 bcopy(apr_msg->apr_private_data,
8479 statep->ap_return_data->ap_priv_data,
8480 statep->ap_return_data->ap_priv_data_len);
8481
8482 /* initialize the ap status */
8483 if (status == IBCM_FAILURE) {
8484 statep->ap_return_data->ap_status = IBT_CM_AP_REJECT;
8485 statep->ap_return_data->ap_arej_info_valid = B_FALSE;
8486 } else {
8487 statep->ap_return_data->ap_status = ap_status;
8488 ibcm_set_apr_arej(ap_status, apr_msg,
8489 &statep->ap_return_data->ap_arej_info,
8490 &statep->ap_return_data->ap_arej_info_valid);
8491 }
8492
8493 /* do a cv signal for a blocking ibt_set_alt_path */
8494 mutex_enter(&statep->state_mutex);
8495 statep->ap_done = B_TRUE;
8496 cv_broadcast(&statep->block_client_cv);
8497 mutex_exit(&statep->state_mutex);
8498
8499 } else { /* Non blocking call */
8500 /* Fill up the event */
8501
8502 bzero(&event, sizeof (event));
8503 event.cm_type = IBT_CM_EVENT_APR_RCV;
8504 event.cm_channel = statep->channel;
8505 event.cm_session_id = NULL;
8506 event.cm_priv_data = apr_msg->apr_private_data;
8507 event.cm_priv_data_len = IBT_APR_PRIV_DATA_SZ;
8508 if (status == IBCM_FAILURE) {
8509 event.cm_event.apr.apr_status = IBT_CM_AP_REJECT;
8510 event.cm_event.apr.apr_arej_info_valid = B_FALSE;
8511 } else {
8512 event.cm_event.apr.apr_status = ap_status;
8513 ibcm_set_apr_arej(ap_status, apr_msg,
8514 &event.cm_event.apr.apr_arej_info,
8515 &event.cm_event.apr.apr_arej_info_valid);
8516 }
8517
8518 /* initialize the ap status */
8519 statep->cm_handler(statep->state_cm_private, &event,
8520 NULL, apr_msg->apr_private_data, IBT_APR_PRIV_DATA_SZ);
8521 }
8522 mutex_enter(&statep->state_mutex);
8523 ibcm_open_done(statep);
8524 mutex_exit(&statep->state_mutex);
8525 }
8526
8527 /*
8528 * ibcm_set_qp_from_apr:
8529 * This call sets QP's alt path info based on APR message contents
8530 *
8531 * INPUTS:
8532 * statep - pointer to ibcm_state_data_t
8533 * lap_msg - lap msg sent earlier
8534 *
8535 * RETURN VALUE: ibcm_status_t
8536 */
8537 static ibcm_status_t
ibcm_set_qp_from_apr(ibcm_state_data_t * statep,ibcm_lap_msg_t * lap_msg)8538 ibcm_set_qp_from_apr(ibcm_state_data_t *statep, ibcm_lap_msg_t *lap_msg)
8539 {
8540 ibtl_cm_hca_port_t port;
8541 ibt_adds_vect_t *adds;
8542
8543 ibt_qp_query_attr_t qp_attrs;
8544 ibt_cep_modify_flags_t cep_flags;
8545 ibt_status_t status;
8546
8547 IBTF_DPRINTF_L3(cmlog, "ibcm_set_qp_from_apr: statep 0x%p", statep);
8548
8549 status = ibt_query_qp(statep->channel, &qp_attrs);
8550 if (status != IBT_SUCCESS ||
8551 (qp_attrs.qp_info.qp_state != IBT_STATE_RTS &&
8552 qp_attrs.qp_info.qp_state != IBT_STATE_SQD)) {
8553 IBTF_DPRINTF_L2(cmlog, "ibcm_set_qp_from_apr: ibt_query_qp "
8554 "failed, status = %d, qp_state = %d", statep, status,
8555 qp_attrs.qp_info.qp_state);
8556 return (IBCM_FAILURE);
8557 }
8558
8559 /* Fill up input args for ibt_modify_qp */
8560 cep_flags = IBT_CEP_SET_ALT_PATH | IBT_CEP_SET_STATE;
8561
8562 /* do RTS=>RTS or SQD=>SQD. The next line is needed for RTS=>RTS. */
8563 qp_attrs.qp_info.qp_current_state = qp_attrs.qp_info.qp_state;
8564
8565 /* Fill up input args for ibt_modify_qp */
8566 adds = &IBCM_QP_RC(qp_attrs).rc_alt_path.cep_adds_vect;
8567
8568 ibcm_fill_adds_from_lap(adds, lap_msg, IBCM_ACTIVE_MODE);
8569
8570 if ((status = ibtl_cm_get_hca_port(adds->av_sgid,
8571 statep->local_hca_guid, &port)) != IBT_SUCCESS) {
8572 IBTF_DPRINTF_L2(cmlog, "ibcm_set_qp_from_apr: "
8573 "ibtl_cm_get_hca_port failed status = %d", status);
8574 IBTF_DPRINTF_L5(cmlog, "ibcm_set_qp_from_apr:"
8575 " ibtl_cm_get_hca_port sgid guid %llX",
8576 adds->av_sgid.gid_guid);
8577 IBTF_DPRINTF_L5(cmlog, "ibcm_set_qp_from_apr:"
8578 " ibtl_cm_get_hca_port sgid prefix %llX ",
8579 adds->av_sgid.gid_prefix);
8580 return (IBCM_FAILURE);
8581 }
8582
8583 IBCM_QP_RC(qp_attrs).rc_alt_path.cep_hca_port_num =
8584 port.hp_port;
8585
8586 IBTF_DPRINTF_L4(cmlog, "ibcm_set_qp_from_apr: "
8587 "gid = %llx:%llx, port_num = %d",
8588 IBCM_QP_RC(qp_attrs).rc_alt_path.cep_adds_vect.av_sgid.
8589 gid_prefix,
8590 IBCM_QP_RC(qp_attrs).rc_alt_path.cep_adds_vect.av_sgid.gid_guid,
8591 port.hp_port);
8592
8593 /* The pkey is same as the primary path */
8594 status = ibt_pkey2index_byguid(statep->local_hca_guid,
8595 port.hp_port, statep->pkey,
8596 &IBCM_QP_RC(qp_attrs).rc_alt_path.cep_pkey_ix);
8597
8598 if (status != IBT_SUCCESS) {
8599 IBTF_DPRINTF_L2(cmlog, "ibcm_set_qp_from_apr: "
8600 "ibt_pkey2index_byguid failed %d", status);
8601 return (IBCM_FAILURE);
8602 }
8603 qp_attrs.qp_info.qp_trans = IBT_RC_SRV;
8604 IBCM_QP_RC(qp_attrs).rc_alt_path.cep_timeout =
8605 ibt_usec2ib(statep->remote_ack_delay +
8606 2 * statep->rc_alt_pkt_lt);
8607 if (IBCM_QP_RC(qp_attrs).rc_mig_state == IBT_STATE_MIGRATED) {
8608 /* Need to rearm */
8609 IBTF_DPRINTF_L3(cmlog, "ibcm_set_qp_from_apr: statep 0x%p: "
8610 "rearming APM", statep);
8611 cep_flags |= IBT_CEP_SET_MIG;
8612 IBCM_QP_RC(qp_attrs).rc_mig_state = IBT_STATE_REARMED;
8613 }
8614
8615 status = ibt_modify_qp(statep->channel, cep_flags, &qp_attrs.qp_info,
8616 NULL);
8617
8618 if (status != IBT_SUCCESS)
8619 ibcm_insert_trace(statep, IBCM_TRACE_SET_ALT_FAIL);
8620 else
8621 ibcm_insert_trace(statep, IBCM_TRACE_SET_ALT);
8622
8623 #ifdef DEBUG
8624 (void) ibt_query_qp(statep->channel, &qp_attrs);
8625 print_modify_qp("ACTIVE LAP QUERY", statep->channel,
8626 cep_flags, &qp_attrs.qp_info);
8627 #endif
8628
8629 if (status != IBT_SUCCESS) {
8630 IBTF_DPRINTF_L2(cmlog, "ibcm_set_qp_from_apr:"
8631 " ibt_modify_qp() failed, status = %d", status);
8632 return (IBCM_FAILURE);
8633 }
8634
8635 return (IBCM_SUCCESS);
8636 }
8637
8638 /*
8639 * ibcm_sync_lapr_idle:
8640 *
8641 * This call either cancels a LAP/APR operation or waits
8642 * until the operation is complete
8643 *
8644 * INPUTS:
8645 * statep Pointer to ibcm_state_data_t
8646 *
8647 * RETURN VALUE: NONE
8648 *
8649 * This function is called holding state mutex
8650 * This function returns, releasing the state mutex
8651 */
8652 void
ibcm_sync_lapr_idle(ibcm_state_data_t * statep)8653 ibcm_sync_lapr_idle(ibcm_state_data_t *statep)
8654 {
8655 timeout_id_t timer_val = statep->timerid;
8656 ibt_cm_event_t event;
8657
8658 IBTF_DPRINTF_L3(cmlog, "ibcm_sync_lapr_idle:"
8659 "statep %p state %d ap_state %d", statep, statep->state,
8660 statep->ap_state);
8661
8662 ASSERT(MUTEX_HELD(&statep->state_mutex));
8663 _NOTE(LOCK_RELEASED_AS_SIDE_EFFECT(&statep->state_mutex))
8664
8665 /* Busy AP states on active/passive sides */
8666 if ((statep->ap_state == IBCM_AP_STATE_LAP_RCVD) ||
8667 (statep->ap_state == IBCM_AP_STATE_APR_RCVD) ||
8668 (statep->ap_state == IBCM_AP_STATE_MRA_LAP_SENT) ||
8669 (statep->ap_state == IBCM_AP_STATE_TIMED_OUT)) {
8670
8671 /* wait till ap_state becomes IBCM_AP_STATE_IDLE */
8672 while (statep->ap_state != IBCM_AP_STATE_IDLE)
8673 cv_wait(&statep->block_mad_cv, &statep->state_mutex);
8674
8675 mutex_exit(&statep->state_mutex);
8676
8677 } else if ((statep->ap_state == IBCM_AP_STATE_LAP_SENT) ||
8678 (statep->ap_state == IBCM_AP_STATE_MRA_LAP_RCVD)) {
8679
8680 /* fail the client's ibt_set_alt_path */
8681
8682 /* blocking ibt_set_alt_path */
8683 if (statep->ap_return_data != NULL) {
8684 statep->ap_return_data->ap_status =
8685 IBT_CM_AP_ABORT;
8686 statep->ap_state = IBCM_AP_STATE_IDLE;
8687 cv_broadcast(&statep->block_client_cv);
8688 IBTF_DPRINTF_L3(cmlog, "ibcm_sync_lapr_idle:"
8689 "blocked wait");
8690 }
8691
8692 statep->timerid = 0;
8693 /* Cancel the timeout */
8694 mutex_exit(&statep->state_mutex);
8695 if (timer_val != 0)
8696 (void) untimeout(timer_val);
8697
8698 /* Non blocking ibt_set_alt_path */
8699 if (statep->ap_return_data == NULL) {
8700
8701 /* Fill up the event */
8702
8703 bzero(&event, sizeof (event));
8704 event.cm_type = IBT_CM_EVENT_APR_RCV;
8705 event.cm_channel = statep->channel;
8706 event.cm_session_id = NULL;
8707 event.cm_priv_data = NULL;
8708 event.cm_priv_data_len = 0;
8709 event.cm_event.apr.apr_status = IBT_CM_AP_ABORT;
8710
8711 /* Call the cm handler */
8712 statep->cm_handler(statep->state_cm_private, &event,
8713 NULL, NULL, 0);
8714 IBTF_DPRINTF_L3(cmlog, "ibcm_sync_lapr_idle:"
8715 "non-blocked wait");
8716 }
8717 } else mutex_exit(&statep->state_mutex);
8718
8719 ASSERT(!MUTEX_HELD(&statep->state_mutex));
8720 }
8721
8722 #ifdef DEBUG
8723
8724 /*
8725 * Debug function used to print all the modify qp attributes.
8726 * Useful to manually verify the modify qp parameters are as
8727 * expected
8728 */
8729 static void
print_modify_qp(char * prefix,ibt_qp_hdl_t ibt_qp,ibt_cep_modify_flags_t flags,ibt_qp_info_t * qp_attr)8730 print_modify_qp(char *prefix, ibt_qp_hdl_t ibt_qp,
8731 ibt_cep_modify_flags_t flags, ibt_qp_info_t *qp_attr)
8732 {
8733 IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP %s %p", prefix, ibt_qp);
8734 IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP flags 0x%x", flags);
8735
8736 IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP "
8737 "rc_rdma_ra_in %d rc_rdma_ra_out %d",
8738 qp_attr->qp_transport.rc.rc_rdma_ra_in,
8739 qp_attr->qp_transport.rc.rc_rdma_ra_out);
8740
8741 IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP primary: "
8742 "port %d path bits %d dlid %X",
8743 qp_attr->qp_transport.rc.rc_path.cep_hca_port_num,
8744 qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_src_path,
8745 qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_dlid);
8746 IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP primary: "
8747 "pkey index %d cep_timeout %d",
8748 qp_attr->qp_transport.rc.rc_path.cep_pkey_ix,
8749 qp_attr->qp_transport.rc.rc_path.cep_timeout);
8750 IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP primary: "
8751 "srvl %d flow label %d tclass %d",
8752 qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_srvl,
8753 qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_flow,
8754 qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_tclass);
8755 IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP primary: "
8756 "hop %d srate %d sgid_ix %d send_grh %d",
8757 qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_hop,
8758 qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_srate,
8759 qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_sgid_ix,
8760 qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_send_grh);
8761 IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP primary: "
8762 "dgid prefix %llX dgid guid %llX",
8763 qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_dgid.gid_prefix,
8764 qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_dgid.gid_guid);
8765 IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP primary: "
8766 "sgid prefix %llX sgid guid %llX",
8767 qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_sgid.gid_prefix,
8768 qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_sgid.gid_guid);
8769
8770 IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP alternate: "
8771 "port %d path bits %d dlid %X",
8772 qp_attr->qp_transport.rc.rc_alt_path.cep_hca_port_num,
8773 qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_src_path,
8774 qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_dlid);
8775 IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP alternate: "
8776 "pkey index %d cep_timeout %d",
8777 qp_attr->qp_transport.rc.rc_alt_path.cep_pkey_ix,
8778 qp_attr->qp_transport.rc.rc_alt_path.cep_timeout);
8779 IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP alternate: "
8780 "srvl %d flow label %d tclass %d",
8781 qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_srvl,
8782 qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_flow,
8783 qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_tclass);
8784 IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP alternate: "
8785 "hop %d srate %d sgid_ix %d send_grh %d",
8786 qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_hop,
8787 qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_srate,
8788 qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_sgid_ix,
8789 qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_send_grh);
8790 IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP alternate: "
8791 "dgid prefix %llX dgid guid %llX",
8792 qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_dgid.
8793 gid_prefix,
8794 qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_dgid.
8795 gid_guid);
8796 IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP alternate: "
8797 "sgid prefix %llX sgid guid %llX",
8798 qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_sgid.
8799 gid_prefix,
8800 qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_sgid.
8801 gid_guid);
8802 }
8803 #endif
8804