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