2 * Copyright (c) 2005 SilverStorm Technologies. All rights reserved.
\r
3 * Copyright (c) 1996-2003 Intel Corporation. All rights reserved.
\r
5 * This software is available to you under the OpenIB.org BSD license
\r
8 * Redistribution and use in source and binary forms, with or
\r
9 * without modification, are permitted provided that the following
\r
10 * conditions are met:
\r
12 * - Redistributions of source code must retain the above
\r
13 * copyright notice, this list of conditions and the following
\r
16 * - Redistributions in binary form must reproduce the above
\r
17 * copyright notice, this list of conditions and the following
\r
18 * disclaimer in the documentation and/or other materials
\r
19 * provided with the distribution.
\r
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\r
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\r
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\r
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
\r
25 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
\r
26 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
\r
27 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
\r
33 #include "al_ci_ca.h"
\r
34 #include "al_cm_shared.h"
\r
35 #include "al_debug.h"
\r
40 static ib_api_status_t
\r
42 IN const ib_qp_handle_t h_qp )
\r
45 ib_api_status_t status;
\r
47 AL_ENTER( AL_DBG_CM );
\r
49 cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) );
\r
50 qp_mod.req_state = IB_QPS_RESET;
\r
52 status = ib_modify_qp( h_qp, &qp_mod );
\r
53 if( status != IB_SUCCESS )
\r
55 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
56 ("ib_modify_qp to IB_QPS_RESET returned %s\n",
\r
57 ib_get_err_str(status) ) );
\r
60 AL_EXIT( AL_DBG_CM );
\r
66 static ib_api_status_t
\r
68 IN const ib_qp_handle_t h_qp,
\r
69 IN ib_gid_t * const p_gid,
\r
70 IN const uint16_t pkey,
\r
71 IN const ib_access_t access_ctrl )
\r
73 ib_port_attr_t *p_port_attr;
\r
75 ib_api_status_t status;
\r
77 AL_ENTER( AL_DBG_CM );
\r
79 cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) );
\r
80 qp_mod.req_state = IB_QPS_INIT;
\r
81 qp_mod.state.init.access_ctrl = access_ctrl;
\r
83 /* Get the port and PKEY information. */
\r
84 ci_ca_lock_attr( h_qp->obj.p_ci_ca );
\r
85 p_port_attr = get_port_attr( h_qp->obj.p_ci_ca->p_pnp_attr, p_gid );
\r
88 ci_ca_unlock_attr( h_qp->obj.p_ci_ca );
\r
89 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("invalid p_gid\n" ) );
\r
90 return IB_INVALID_GID;
\r
93 qp_mod.state.init.primary_port = p_port_attr->port_num;
\r
94 qp_mod.state.init.pkey_index = get_pkey_index( p_port_attr, pkey );
\r
95 ci_ca_unlock_attr( h_qp->obj.p_ci_ca );
\r
97 if( qp_mod.state.init.pkey_index == BAD_PKEY_INDEX )
\r
99 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR, ("invalid PKEY\n" ) );
\r
100 return IB_INVALID_PKEY;
\r
103 status = ib_modify_qp( h_qp, &qp_mod );
\r
104 if( status != IB_SUCCESS )
\r
106 AL_PRINT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
107 ("ib_modify_qp to IB_QPS_INIT returned %s\n",
\r
108 ib_get_err_str(status) ) );
\r
111 AL_EXIT( AL_DBG_CM );
\r
118 * Transition the QP to the INIT state, if it is not already in the
\r
123 IN const ib_qp_handle_t h_qp,
\r
124 IN ib_gid_t * const p_gid,
\r
125 IN const uint16_t pkey,
\r
126 IN const ib_access_t access_ctrl )
\r
128 ib_api_status_t status;
\r
131 * Move to the init state to allow posting of receive buffers.
\r
132 * Chech the current state of the QP. The user may have already
\r
133 * transitioned it and posted some receives to the QP, so we
\r
134 * should not reset the QP if it is already in the INIT state.
\r
136 if( h_qp->state != IB_QPS_INIT )
\r
138 /* Reset the QP. */
\r
139 status = __reset_qp( h_qp );
\r
140 if( status != IB_SUCCESS )
\r
142 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
143 ("__reset_qp returned %s\n", ib_get_err_str(status) ) );
\r
147 /* Initialize the QP. */
\r
148 status = __init_qp( h_qp, p_gid, pkey, access_ctrl );
\r
149 if( status != IB_SUCCESS )
\r
151 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
152 ("__init_qp returned %s.\n", ib_get_err_str(status) ) );
\r
164 IN const ib_qp_handle_t h_qp,
\r
165 IN ib_qp_mod_t * const p_qp_mod_rtr,
\r
166 IN ib_qp_mod_t * const p_qp_mod_rts )
\r
168 ib_api_status_t status;
\r
170 AL_ENTER( AL_DBG_CM );
\r
172 /* Set the QP to RTR. */
\r
173 status = ib_modify_qp( h_qp, p_qp_mod_rtr );
\r
174 if( status != IB_SUCCESS )
\r
176 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
177 ("ib_modify_qp to RTR returned %s.\n", ib_get_err_str(status) ) );
\r
181 /* Set the QP to RTS. */
\r
182 status = ib_modify_qp( h_qp, p_qp_mod_rts );
\r
183 if( status != IB_SUCCESS )
\r
185 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
186 ("ib_modify_qp to RTS returned %s.\n", ib_get_err_str(status) ) );
\r
190 AL_EXIT( AL_DBG_CM );
\r
197 * Transition the QP to the error state to flush all oustanding work
\r
198 * requests, then transition it back into the reset state. This function
\r
199 * may be called when destroying the QP in order to flush all work requests,
\r
200 * so we cannot call through the main API, or the call will fail since the
\r
201 * QP is no longer in the initialize state.
\r
205 IN const ib_qp_handle_t h_qp,
\r
206 IN const uint32_t timewait )
\r
208 ib_qp_mod_t qp_mod;
\r
209 ib_api_status_t status;
\r
211 AL_ENTER( AL_DBG_CM );
\r
213 /* Special checks on the QP state for error handling - see above. */
\r
214 if( !h_qp || !AL_OBJ_IS_TYPE( h_qp, AL_OBJ_TYPE_H_QP ) ||
\r
215 ( (h_qp->obj.state != CL_INITIALIZED) &&
\r
216 (h_qp->obj.state != CL_DESTROYING) ) )
\r
218 AL_PRINT_EXIT( TRACE_LEVEL_WARNING, AL_DBG_CM, ("IB_INVALID_QP_HANDLE\n") );
\r
219 return IB_INVALID_QP_HANDLE;
\r
223 * Only modify the QP if it is not exported to UM. All UM QP modifications
\r
224 * are initiated in UM.
\r
226 if( !AL_OBJ_IS_SUBTYPE( h_qp, AL_OBJ_SUBTYPE_UM_EXPORT ) )
\r
228 cl_memclr( &qp_mod, sizeof(ib_qp_mod_t) );
\r
229 qp_mod.req_state = IB_QPS_ERROR;
\r
231 /* Modify to error state using function pointers - see above. */
\r
232 status = h_qp->pfn_modify_qp( h_qp, &qp_mod, NULL );
\r
233 if( status != IB_SUCCESS )
\r
235 AL_PRINT_EXIT( TRACE_LEVEL_ERROR, AL_DBG_ERROR,
\r
236 ("pfn_modify_qp to IB_QPS_ERROR returned %s\n",
\r
237 ib_get_err_str(status) ) );
\r
243 /* Store the timestamp after which the QP exits timewait. */
\r
244 h_qp->timewait = cl_get_time_stamp() + (((uint64_t)timewait) * 1000);
\r
246 UNUSED_PARAM( timewait );
\r
247 #endif /* CL_KERNEL */
\r
249 AL_EXIT( AL_DBG_CM );
\r
256 * Save the information from a user's CM reply needed to transition the QP
\r
257 * to the RTR and RTS states.
\r
260 cm_save_rep_qp_attr(
\r
261 IN const ib_cm_rep_t * const p_cm_rep,
\r
262 IN const ib_port_attr_t * const p_port_attr,
\r
263 IN const ib_path_rec_t * const p_path_rec,
\r
264 IN const ib_path_rec_t * const p_alt_path_rec,
\r
265 IN OUT ib_qp_mod_t * const p_qp_mod_rtr,
\r
266 IN OUT ib_qp_mod_t * const p_qp_mod_rts )
\r
268 AL_ENTER( AL_DBG_CM );
\r
270 /* Update the QP RTR transition information. */
\r
271 p_qp_mod_rtr->state.rtr.rq_psn = p_cm_rep->h_qp->num;
\r
273 if( p_cm_rep->access_ctrl )
\r
275 p_qp_mod_rtr->state.rtr.opts |= IB_MOD_QP_ACCESS_CTRL;
\r
276 p_qp_mod_rtr->state.rtr.access_ctrl = p_cm_rep->access_ctrl;
\r
279 if( p_cm_rep->sq_depth )
\r
281 p_qp_mod_rtr->state.rtr.opts |= IB_MOD_QP_SQ_DEPTH;
\r
282 p_qp_mod_rtr->state.rtr.sq_depth = p_cm_rep->sq_depth;
\r
285 if( p_cm_rep->rq_depth )
\r
287 p_qp_mod_rtr->state.rtr.opts |= IB_MOD_QP_RQ_DEPTH;
\r
288 p_qp_mod_rtr->state.rtr.rq_depth = p_cm_rep->rq_depth;
\r
291 if( p_cm_rep->rnr_nak_timeout )
\r
293 p_qp_mod_rtr->state.rtr.opts |= IB_MOD_QP_RNR_NAK_TIMEOUT;
\r
294 p_qp_mod_rtr->state.rtr.rnr_nak_timeout = p_cm_rep->rnr_nak_timeout;
\r
297 /* Some common checks for QP RTR and RTS transition information. */
\r
298 if( p_cm_rep->h_qp && p_cm_rep->h_qp->type == IB_QPT_RELIABLE_CONN )
\r
300 p_qp_mod_rts->state.rts.init_depth = p_cm_rep->init_depth;
\r
303 /* Update the QP RTS transition information starting here. */
\r
304 p_qp_mod_rts->state.rts.retry_cnt = p_cm_rep->rnr_retry_cnt;
\r
305 p_qp_mod_rts->state.rts.rnr_retry_cnt = p_cm_rep->rnr_retry_cnt;
\r
306 p_qp_mod_rts->state.rts.rnr_nak_timeout = p_cm_rep->rnr_nak_timeout;
\r
308 if( p_cm_rep->failover_accepted == IB_FAILOVER_ACCEPT_SUCCESS )
\r
310 p_qp_mod_rts->state.rts.opts |= IB_MOD_QP_APM_STATE;
\r
311 p_qp_mod_rts->state.rts.apm_state = IB_APM_REARM;
\r
314 /* Setup the primary address vector. */
\r
315 p_qp_mod_rtr->state.rtr.opts |= IB_MOD_QP_PRIMARY_AV;
\r
316 cm_save_path_av( p_port_attr, p_path_rec, p_cm_rep->rnr_retry_cnt,
\r
317 p_cm_rep->rnr_retry_cnt, &p_qp_mod_rtr->state.rtr.primary_av );
\r
319 /* Setup alternate address vector. */
\r
320 if( p_alt_path_rec->slid )
\r
322 p_qp_mod_rtr->state.rtr.opts |= IB_MOD_QP_ALTERNATE_AV;
\r
323 cm_save_path_av( p_port_attr, p_alt_path_rec, p_cm_rep->rnr_retry_cnt,
\r
324 p_cm_rep->rnr_retry_cnt, &p_qp_mod_rtr->state.rtr.alternate_av );
\r
327 p_qp_mod_rts->state.rts.local_ack_timeout =
\r
328 cm_local_ack_timeout( ib_path_rec_pkt_life( p_path_rec ),
\r
329 p_cm_rep->target_ack_delay );
\r
331 AL_EXIT( AL_DBG_CM );
\r
337 * Save the information from a user's CM RTU needed to transition the QP
\r
338 * to the RTR and RTS states.
\r
341 cm_save_rtu_qp_attr(
\r
342 IN const ib_cm_rtu_t * const p_cm_rtu,
\r
343 IN OUT ib_qp_mod_t * const p_qp_mod_rtr )
\r
345 AL_ENTER( AL_DBG_CM );
\r
347 /* Update the QP RTR transition information. */
\r
348 if( p_cm_rtu->access_ctrl )
\r
350 p_qp_mod_rtr->state.rtr.opts |= IB_MOD_QP_ACCESS_CTRL;
\r
351 p_qp_mod_rtr->state.rtr.access_ctrl = p_cm_rtu->access_ctrl;
\r
354 if( p_cm_rtu->sq_depth )
\r
356 p_qp_mod_rtr->state.rtr.opts |= IB_MOD_QP_SQ_DEPTH;
\r
357 p_qp_mod_rtr->state.rtr.sq_depth = p_cm_rtu->sq_depth;
\r
360 if( p_cm_rtu->rq_depth )
\r
362 p_qp_mod_rtr->state.rtr.opts |= IB_MOD_QP_RQ_DEPTH;
\r
363 p_qp_mod_rtr->state.rtr.rq_depth = p_cm_rtu->rq_depth;
\r
366 AL_EXIT( AL_DBG_CM );
\r
372 * Save the information about a path record needed to specify an
\r
373 * address vector for a connected QP.
\r
377 IN const ib_port_attr_t * const p_port_attr,
\r
378 IN const ib_path_rec_t * const p_path_rec,
\r
379 IN const uint8_t retry_cnt,
\r
380 IN const uint8_t rnr_retry_cnt,
\r
381 OUT ib_av_attr_t * const p_av )
\r
383 p_av->port_num = p_port_attr->port_num;
\r
384 p_av->sl = ib_path_rec_sl( p_path_rec );
\r
385 p_av->dlid = p_path_rec->dlid;
\r
387 if( p_path_rec->hop_flow_raw.val )
\r
389 p_av->grh_valid = TRUE;
\r
390 p_av->grh.ver_class_flow = ib_grh_set_ver_class_flow( 1,
\r
391 p_path_rec->tclass, ib_path_rec_flow_lbl( p_path_rec ) );
\r
392 p_av->grh.resv1 = 0;
\r
393 p_av->grh.resv2 = 0;
\r
394 p_av->grh.hop_limit = ib_path_rec_hop_limit( p_path_rec );
\r
395 p_av->grh.src_gid = p_path_rec->sgid;
\r
396 p_av->grh.dest_gid = p_path_rec->dgid;
\r
400 p_av->grh_valid = FALSE;
\r
403 p_av->static_rate = ib_path_rec_rate( p_path_rec );
\r
404 p_av->path_bits = (uint8_t)(p_path_rec->slid - p_port_attr->lid);
\r
405 p_av->conn.path_mtu = ib_path_rec_mtu( p_path_rec );
\r
406 p_av->conn.local_ack_timeout = cm_local_ack_timeout(
\r
407 ib_path_rec_pkt_life( p_path_rec ), 0 );
\r
409 p_av->conn.seq_err_retry_cnt = retry_cnt;
\r
410 p_av->conn.rnr_retry_cnt = rnr_retry_cnt;
\r
417 * Return the local ACK timeout value based on the given packet lifetime
\r
418 * and target ACK delay. Both input values are assumed to be in the form
\r
419 * 4.096 x 2 ^ input.
\r
422 cm_local_ack_timeout(
\r
423 IN const uint8_t pkt_lifetime,
\r
424 IN const uint8_t target_ack_delay )
\r
427 uint8_t local_ack_timeout;
\r
430 * Since both input and the output values are in the same form, we
\r
431 * can ignore the 4.096 portion by dividing it out.
\r
434 /* Double the packet lifetime to get the round trip time. */
\r
435 timeout = (uint64_t)2 << pkt_lifetime;
\r
437 /* Add in the target ack delay. */
\r
438 if( target_ack_delay )
\r
439 timeout += (uint64_t)1 << target_ack_delay;
\r
441 /* Calculate the local ACK timeout. */
\r
442 local_ack_timeout = 1;
\r
443 while( (1 << local_ack_timeout) <= timeout )
\r
445 local_ack_timeout++;
\r
447 /* Only 5-bits are valid. */
\r
448 if( local_ack_timeout > MAX_LOCAL_ACK_TIMEOUT )
\r
449 return MAX_LOCAL_ACK_TIMEOUT;
\r
452 return local_ack_timeout;
\r
457 * Remove the link between the connection object and QP, but continue
\r
458 * holding any references
\r
462 IN const ib_cm_handle_t h_conn )
\r
464 /* If the connection isn't bound to a QP, just return. */
\r
467 ((al_conn_qp_t*)h_conn->h_qp)->p_conn = NULL;
\r
468 h_conn->h_qp = NULL;
\r