#include <sys/ib/mgt/ibcm/ibcm_impl.h>
#include <sys/callb.h>
static void ibcm_set_primary_adds_vect(ibcm_state_data_t *,
ibt_adds_vect_t *, ibcm_req_msg_t *);
static void ibcm_set_alt_adds_vect(ibcm_state_data_t *,
ibt_adds_vect_t *, ibcm_req_msg_t *);
static ibt_status_t ibcm_set_primary_cep_path(ibcm_state_data_t *,
ibt_cep_path_t *, ibcm_req_msg_t *);
static ibt_status_t ibcm_set_alt_cep_path(ibcm_state_data_t *,
ibt_cep_path_t *, ibcm_req_msg_t *);
static ibt_status_t ibcm_invoke_qp_modify(ibcm_state_data_t *,
ibcm_req_msg_t *, ibcm_rep_msg_t *);
static ibt_status_t ibcm_invoke_rtu_qp_modify(ibcm_state_data_t *,
ib_time_t, ibcm_rep_msg_t *);
static ibcm_status_t ibcm_sidr_req_ud_handler(ibcm_ud_state_data_t *,
ibcm_sidr_req_msg_t *, ibcm_mad_addr_t *,
ibt_sidr_status_t *);
static void ibcm_sidr_rep_ud_handler(ibcm_ud_state_data_t *,
ibcm_sidr_rep_msg_t *);
static void ibcm_handler_conn_fail(ibcm_state_data_t *,
uint8_t cf_code, uint8_t cf_msg,
ibt_cm_reason_t rej_reason, uint8_t *,
ibt_priv_data_len_t);
static void ibcm_build_n_post_rej_mad(uint8_t *input_madp,
ib_com_id_t, ibcm_mad_addr_t *, int, uint16_t);
static void ibcm_post_drep_mad(ibcm_state_data_t *);
static ibcm_status_t ibcm_verify_req_gids_and_svcid(
ibcm_state_data_t *statep,
ibcm_req_msg_t *cm_req_msgp);
static void ibcm_timeout_client_cb(ibcm_state_data_t *statep);
static void ibcm_ud_timeout_client_cb(
ibcm_ud_state_data_t *ud_statep);
static void ibcm_process_dreq_timeout(ibcm_state_data_t *statep);
static void ibcm_fill_adds_from_lap(ibt_adds_vect_t *adds,
ibcm_lap_msg_t *lap_msg, ibcm_mode_t mode);
static void ibcm_post_stored_apr_mad(ibcm_state_data_t *statep,
uint8_t *input_madp);
static ibcm_status_t ibcm_set_qp_from_apr(ibcm_state_data_t *statep,
ibcm_lap_msg_t *lap_msg);
static boolean_t ibcm_compare_prim_alt_paths(ibt_adds_vect_t *prim,
ibt_adds_vect_t *alt);
static void ibcm_process_get_classport_info(ibcm_hca_info_t *hcap,
uint8_t *input_madp, ibcm_mad_addr_t *cm_mad_addr);
static void ibcm_decode_classport_info(ibcm_hca_info_t *hcap,
uint8_t *input_madp, ibcm_mad_addr_t *cm_mad_addr);
static void ibcm_post_rej_ver_mismatch(uint8_t *input_madp,
ibcm_mad_addr_t *cm_mad_addr);
static void ibcm_init_clp_to_mad(ibcm_classportinfo_msg_t *clp,
ibt_redirect_info_t *rinfo);
static void ibcm_init_clp_from_mad(ibcm_classportinfo_msg_t *clp,
ibt_redirect_info_t *rinfo);
static void ibcm_copy_addl_rej(ibcm_state_data_t *statep,
ibcm_rej_msg_t *rej_msgp,
ibt_cm_conn_failed_t *failed);
static void ibcm_return_open_data(ibcm_state_data_t *statep,
ibcm_rep_msg_t *rep_msgp,
ibt_cm_reason_t reject_reason);
int ibcm_recv_tasks = 0;
int ibcm_max_recv_tasks = 24;
int ibcm_recv_timeouts = 0;
clock_t ibcm_mra_service_timeout_max = 0;
#ifdef DEBUG
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);
#endif
_NOTE(READ_ONLY_DATA(ibt_arej_info_u))
void
ibcm_process_incoming_mad(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
void *args)
{
uint8_t method;
ib_mad_hdr_t *in_mad_hdr;
ibcm_hca_info_t *hcap;
ibcm_port_info_t *portp;
ibcm_mad_addr_t *cm_mad_addr;
ibcm_event_type_t attr_id;
ibcm_mad_addr_t loc_mad_addr;
ibcm_qp_list_t *cm_qp_entry;
int ibmf_status;
if (msgp->im_msg_status != IBMF_SUCCESS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: "
"bad status %x", msgp->im_msg_status);
if ((ibmf_status = ibmf_free_msg(ibmf_handle, &msgp)) !=
IBMF_SUCCESS)
IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: "
"ibmf_free_msg failed %d", ibmf_status);
return;
}
cm_qp_entry = (ibcm_qp_list_t *)args;
IBTF_DPRINTF_L5(cmlog, "ibcm_process_incoming_mad: ibmf_hdl %p "
"msg %p args %p", ibmf_handle, msgp, args);
#ifdef DEBUG
if (ibcm_test_mode > 1)
ibcm_query_qp(ibmf_handle, cm_qp_entry->qp_cm);
#endif
portp = cm_qp_entry->qp_port;
hcap = portp->port_hcap;
IBTF_DPRINTF_L4(cmlog, "ibcm_process_incoming_mad: CM MAD on "
"port %d", portp->port_num);
if (ibcm_inc_hca_acc_cnt(hcap) != IBCM_SUCCESS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: "
"hca not in attach state");
if ((ibmf_status = ibmf_free_msg(ibmf_handle, &msgp)) !=
IBMF_SUCCESS)
IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: "
"ibmf_free_msg failed %d", ibmf_status);
return;
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cm_mad_addr))
cm_mad_addr = &loc_mad_addr;
bzero(cm_mad_addr, sizeof (ibcm_mad_addr_t));
cm_mad_addr->port_num = portp->port_num;
in_mad_hdr = msgp->im_msgbufs_recv.im_bufs_mad_hdr;
if (in_mad_hdr->MgmtClass != MAD_MGMT_CLASS_COMM_MGT) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: "
"bad mgmt class %x", in_mad_hdr->MgmtClass);
if ((ibmf_status = ibmf_free_msg(ibmf_handle, &msgp)) !=
IBMF_SUCCESS)
IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: "
"ibmf_free_msg failed %d", ibmf_status);
ibcm_dec_hca_acc_cnt(hcap);
return;
}
cm_mad_addr->rcvd_addr = msgp->im_local_addr;
if (msgp->im_msg_flags & IBMF_MSG_FLAGS_GLOBAL_ADDRESS) {
cm_mad_addr->grh_hdr = msgp->im_global_addr;
cm_mad_addr->grh_exists = B_TRUE;
IBTF_DPRINTF_L3(cmlog, "ibcm_process_incoming_mad: "
"CM recv GID GUID %llX sender GID GUID %llX",
msgp->im_global_addr.ig_recver_gid.gid_guid,
msgp->im_global_addr.ig_sender_gid.gid_guid);
}
cm_mad_addr->ibmf_hdl = ibmf_handle;
cm_mad_addr->cm_qp_entry = cm_qp_entry;
if (cm_qp_entry->qp_cm != IBMF_QP_HANDLE_DEFAULT)
cm_mad_addr->rcvd_addr.ia_p_key = cm_qp_entry->qp_pkey;
if (cm_mad_addr->rcvd_addr.ia_p_key & 0x8000)
IBTF_DPRINTF_L5(cmlog, "ibcm_process_incoming_mad: PKEY %x",
cm_mad_addr->rcvd_addr.ia_p_key);
else
IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: CM MAD "
"arrived from limited PKEY %x",
cm_mad_addr->rcvd_addr.ia_p_key);
method = in_mad_hdr->R_Method;
attr_id = b2h16(in_mad_hdr->AttributeID);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_incoming_mad: "
"Method %x Attribute %x", method, attr_id);
if (in_mad_hdr->ClassVersion != IBCM_MAD_CLASS_VERSION) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: "
"unsupported ibcm class version %x",
in_mad_hdr->ClassVersion);
if (attr_id == (IBCM_INCOMING_REQ + IBCM_ATTR_BASE_ID))
ibcm_post_rej_ver_mismatch(
(uint8_t *)IBCM_IN_HDRP(msgp), cm_mad_addr);
if ((ibmf_status = ibmf_free_msg(ibmf_handle, &msgp)) !=
IBMF_SUCCESS)
IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: "
"ibmf_free_msg failed %d", ibmf_status);
ibcm_dec_hca_acc_cnt(hcap);
return;
}
IBTF_DPRINTF_L4(cmlog, "ibcm_process_incoming_mad: "
"Transaction Id 0x%llX", b2h64(in_mad_hdr->TransactionID));
#ifdef DEBUG
ibcm_decode_tranid(b2h64(in_mad_hdr->TransactionID), NULL);
#endif
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*cm_mad_addr))
if ((attr_id == MAD_ATTR_ID_CLASSPORTINFO) &&
((method == MAD_METHOD_GET) ||
(method == MAD_METHOD_GET_RESPONSE))) {
if (method == MAD_METHOD_GET)
ibcm_process_get_classport_info(hcap,
(uint8_t *)IBCM_IN_HDRP(msgp), cm_mad_addr);
else if (method == MAD_METHOD_GET_RESPONSE)
ibcm_decode_classport_info(hcap,
(uint8_t *)IBCM_IN_HDRP(msgp), cm_mad_addr);
} else if ((attr_id >= IBCM_ATTR_BASE_ID) &&
(attr_id < (IBCM_ATTR_BASE_ID + IBCM_MAX_EVENTS)) &&
(method == MAD_METHOD_SEND)) {
attr_id -= IBCM_ATTR_BASE_ID;
ASSERT(msgp->im_msgbufs_recv.im_bufs_mad_hdr != NULL);
ibcm_sm_funcs_tbl[attr_id](hcap,
(uint8_t *)IBCM_IN_HDRP(msgp), cm_mad_addr);
} else {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: "
"unknown Method %x or Attribute %x", method, attr_id);
}
ibcm_dec_hca_acc_cnt(hcap);
if ((ibmf_status = ibmf_free_msg(ibmf_handle, &msgp)) != IBMF_SUCCESS)
IBTF_DPRINTF_L2(cmlog, "ibcm_process_incoming_mad: "
"ibmf_free_msg failed %d", ibmf_status);
}
typedef struct ibcm_taskq_args_s {
ibmf_handle_t tq_ibmf_handle;
ibmf_msg_t *tq_ibmf_msgp;
void *tq_args;
} ibcm_taskq_args_t;
#define IBCM_RECV_MAX 128
ibcm_taskq_args_t ibcm_recv_array[IBCM_RECV_MAX + 1];
int ibcm_get, ibcm_put;
int ibcm_recv_total;
int ibcm_recv_queued;
_NOTE(READ_ONLY_DATA(ibcm_taskq_args_t))
static int
ibcm_recv_dequeue(ibmf_handle_t *ibmf_handlep, ibmf_msg_t **msgpp, void **argsp)
{
ibcm_taskq_args_t *tq;
if (ibcm_put == ibcm_get)
return (0);
if (++ibcm_get >= IBCM_RECV_MAX)
ibcm_get = 0;
tq = ibcm_recv_array + ibcm_get;
*ibmf_handlep = tq->tq_ibmf_handle;
*msgpp = tq->tq_ibmf_msgp;
*argsp = tq->tq_args;
return (1);
}
static int
ibcm_recv_enqueue(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, void *args)
{
int next;
ibcm_taskq_args_t *tq;
ASSERT(MUTEX_HELD(&ibcm_recv_mutex));
next = ibcm_put + 1;
if (next >= IBCM_RECV_MAX)
next = 0;
if (next != ibcm_get) {
ibcm_recv_queued++;
ibcm_put = next;
tq = ibcm_recv_array + next;
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*tq))
tq->tq_ibmf_handle = ibmf_handle;
tq->tq_ibmf_msgp = msgp;
tq->tq_args = args;
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*tq))
return (1);
} else {
return (0);
}
}
void
ibcm_drop_msg(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp)
{
int ibmf_status;
IBTF_DPRINTF_L2(cmlog, "ibcm_drop_msg: discarding MAD");
if ((ibmf_status = ibmf_free_msg(ibmf_handle, &msgp)) != IBMF_SUCCESS)
IBTF_DPRINTF_L2(cmlog, "ibcm_drop_msg: "
"ibmf_free_msg failed %d", ibmf_status);
}
static void
ibcm_recv_task(void *args)
{
ibcm_taskq_args_t *taskq_args;
ibmf_handle_t ibmf_handle;
ibmf_msg_t *msgp;
taskq_args = (ibcm_taskq_args_t *)args;
IBTF_DPRINTF_L4(cmlog, "ibcm_recv_task: Processing incoming MAD"
" via taskq");
ibcm_process_incoming_mad(taskq_args->tq_ibmf_handle,
taskq_args->tq_ibmf_msgp, taskq_args->tq_args);
kmem_free(taskq_args, sizeof (ibcm_taskq_args_t));
mutex_enter(&ibcm_recv_mutex);
while (ibcm_recv_dequeue(&ibmf_handle, &msgp, &args)) {
mutex_exit(&ibcm_recv_mutex);
ibcm_process_incoming_mad(ibmf_handle, msgp, args);
mutex_enter(&ibcm_recv_mutex);
}
--ibcm_recv_tasks;
mutex_exit(&ibcm_recv_mutex);
}
static void
ibcm_recv_timeout_cb(void *args)
{
ibcm_taskq_args_t *tq = (ibcm_taskq_args_t *)args;
int rv = 1;
mutex_enter(&ibcm_recv_mutex);
ibcm_recv_timeouts--;
if (ibcm_recv_tasks == 0) {
ibcm_recv_tasks++;
mutex_exit(&ibcm_recv_mutex);
if (taskq_dispatch(ibcm_taskq, ibcm_recv_task, tq,
TQ_NOQUEUE | TQ_NOSLEEP) == TASKQID_INVALID) {
mutex_enter(&ibcm_recv_mutex);
if (--ibcm_recv_tasks == 0) {
(void) timeout(ibcm_recv_timeout_cb, tq, 1);
ibcm_recv_timeouts++;
} else {
rv = ibcm_recv_enqueue(tq->tq_ibmf_handle,
tq->tq_ibmf_msgp, tq->tq_args);
kmem_free(tq, sizeof (*tq));
}
mutex_exit(&ibcm_recv_mutex);
}
} else {
rv = ibcm_recv_enqueue(tq->tq_ibmf_handle,
tq->tq_ibmf_msgp, tq->tq_args);
kmem_free(tq, sizeof (*tq));
mutex_exit(&ibcm_recv_mutex);
}
if (rv == 0)
ibcm_drop_msg(tq->tq_ibmf_handle, tq->tq_ibmf_msgp);
}
static int
ibcm_recv_add_one(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, void *args)
{
int rv;
ibcm_taskq_args_t *tq;
mutex_enter(&ibcm_recv_mutex);
ibcm_recv_total++;
if (ibcm_recv_tasks >= ibcm_max_recv_tasks) {
rv = ibcm_recv_enqueue(ibmf_handle, msgp, args);
mutex_exit(&ibcm_recv_mutex);
return (rv);
} else {
ibcm_recv_tasks++;
mutex_exit(&ibcm_recv_mutex);
tq = kmem_alloc(sizeof (*tq), KM_NOSLEEP);
if (tq == NULL) {
mutex_enter(&ibcm_recv_mutex);
if (--ibcm_recv_tasks > 0)
rv = ibcm_recv_enqueue(ibmf_handle, msgp, args);
else
rv = 0;
mutex_exit(&ibcm_recv_mutex);
return (rv);
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*tq))
tq->tq_ibmf_handle = ibmf_handle;
tq->tq_ibmf_msgp = msgp;
tq->tq_args = args;
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*tq))
if (taskq_dispatch(ibcm_taskq, ibcm_recv_task, tq,
TQ_NOQUEUE | TQ_NOSLEEP) == TASKQID_INVALID) {
mutex_enter(&ibcm_recv_mutex);
if (--ibcm_recv_tasks == 0) {
(void) timeout(ibcm_recv_timeout_cb, tq, 1);
ibcm_recv_timeouts++;
rv = 1;
} else {
rv = ibcm_recv_enqueue(ibmf_handle, msgp, args);
kmem_free(tq, sizeof (*tq));
}
mutex_exit(&ibcm_recv_mutex);
return (rv);
} else {
return (1);
}
}
}
void
ibcm_recv_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, void *args)
{
if (ibcm_recv_add_one(ibmf_handle, msgp, args) == 0)
ibcm_drop_msg(ibmf_handle, msgp);
}
void
ibcm_process_req_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
ibcm_mad_addr_t *cm_mad_addr)
{
ibt_priv_data_len_t arej_info_len = 0;
ib_qpn_t remote_qpn;
ib_guid_t remote_hca_guid;
ib_com_id_t remote_comid;
ib_com_id_t local_comid;
ibcm_status_t state_lookup_status;
ibcm_status_t comid_lookup_status;
ibcm_status_t response;
ibcm_req_msg_t *req_msgp =
(ibcm_req_msg_t *)&input_madp[IBCM_MAD_HDR_SIZE];
ibt_cm_reason_t reject_reason = IBT_CM_SUCCESS;
ibcm_state_data_t *statep;
ibcm_state_data_t *stale_statep = NULL;
ibcm_status_t svc_gid_check;
uint32_t psn24_timeout5_retry3;
ibt_tran_srv_t trans;
IBTF_DPRINTF_L5(cmlog, "ibcm_process_req_msg(%p, %p, %p)",
hcap, input_madp, cm_mad_addr);
remote_hca_guid = b2h64(req_msgp->req_local_ca_guid);
remote_qpn = b2h32(req_msgp->req_local_qpn_plus) >> 8;
remote_comid = b2h32(req_msgp->req_local_comm_id);
IBCM_DUMP_RAW_MSG((uchar_t *)input_madp);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_req_msg: remote_comid = %x"
" remote_qpn = %x", remote_comid, remote_qpn);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_req_msg: remote_hcaguid = %llX",
remote_hca_guid);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*statep))
new_req:
if (ibcm_alloc_comid(hcap, &local_comid) != IBCM_SUCCESS) {
ibcm_build_n_post_rej_mad(input_madp,
b2h32(req_msgp->req_local_comm_id), cm_mad_addr,
IBT_CM_FAILURE_REQ, IBT_CM_NO_RESC);
return;
}
statep = kmem_zalloc(sizeof (*statep), KM_SLEEP);
rw_enter(&hcap->hca_state_rwlock, RW_WRITER);
state_lookup_status = ibcm_lookup_msg(IBCM_INCOMING_REQ,
local_comid, remote_qpn, remote_hca_guid, hcap, &statep);
if (state_lookup_status == IBCM_LOOKUP_NEW) {
mutex_enter(&statep->state_mutex);
rw_exit(&hcap->hca_state_rwlock);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_req_msg: New statep 0x%p"
" created", statep);
psn24_timeout5_retry3 = b2h32(req_msgp->req_starting_psn_plus);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*statep))
if (ibcm_alloc_out_msg(cm_mad_addr->ibmf_hdl,
&statep->stored_msg, MAD_METHOD_SEND) != IBT_SUCCESS) {
IBCM_REF_CNT_DECR(statep);
statep->state = IBCM_STATE_DELETE;
mutex_exit(&statep->state_mutex);
ibcm_inc_hca_res_cnt(hcap);
ibcm_delete_state_data(statep);
return;
}
if (ibcm_alloc_out_msg(cm_mad_addr->ibmf_hdl,
&statep->dreq_msg, MAD_METHOD_SEND) != IBT_SUCCESS) {
IBCM_REF_CNT_DECR(statep);
statep->state = IBCM_STATE_DELETE;
mutex_exit(&statep->state_mutex);
IBTF_DPRINTF_L2(cmlog, "ibcm_process_req_msg: "
"statep 0x%p: Failed to allocate dreq_msg", statep);
ibcm_inc_hca_res_cnt(hcap);
ibcm_delete_state_data(statep);
return;
}
statep->mode = IBCM_PASSIVE_MODE;
statep->hcap = hcap;
statep->remote_comid = remote_comid;
statep->svcid = b2h64(req_msgp->req_svc_id);
statep->local_qp_rnr_cnt =
req_msgp->req_mtu_plus & 0x7;
statep->remote_ack_delay =
ibt_ib2usec(req_msgp->req_primary_localtime_plus >> 3);
statep->cep_retry_cnt = psn24_timeout5_retry3 & 0x7;
statep->max_cm_retries = req_msgp->req_max_cm_retries_plus >> 4;
statep->remaining_retry_cnt = statep->max_cm_retries;
statep->pkt_life_time = statep->remote_ack_delay/2;
statep->timer_value =
ibt_ib2usec(psn24_timeout5_retry3 >> 3 & 0x1f);
statep->starting_psn = psn24_timeout5_retry3 >> 8;
IBTF_DPRINTF_L4(cmlog, "ibcm_process_req_msg: statep 0x%p "
"active cep timeout(usec) = %u",
statep, statep->remote_ack_delay);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_req_msg: "
"passive timer(usec) = %u", statep->timer_value);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_req_msg: "
"approx pkt lt(usec)= %u ", statep->pkt_life_time);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_req_msg: "
"max cm retries %u", statep->max_cm_retries);
IBCM_OUT_HDRP(statep->stored_msg)->TransactionID =
((ib_mad_hdr_t *)(input_madp))->TransactionID;
statep->stale_clock = gethrtime() +
(hrtime_t)(ibcm_adj_btime * 1000000000) +
(hrtime_t)statep->remote_ack_delay *
(statep->max_cm_retries * (1000 / 2));
mutex_exit(&statep->state_mutex);
ibcm_insert_trace(statep, IBCM_TRACE_INCOMING_REQ);
ibcm_inc_hca_res_cnt(hcap);
ibcm_build_reply_mad_addr(cm_mad_addr,
&statep->stored_reply_addr);
if (statep->stored_reply_addr.cm_qp_entry == NULL) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_req_msg: "
"statep 0x%p cm_qp_entry alloc failed", statep);
mutex_enter(&statep->state_mutex);
IBCM_REF_CNT_DECR(statep);
statep->state = IBCM_STATE_DELETE;
mutex_exit(&statep->state_mutex);
ibcm_delete_state_data(statep);
return;
}
stale_statep = statep;
rw_enter(&hcap->hca_state_rwlock, RW_WRITER);
comid_lookup_status = ibcm_lookup_msg(IBCM_INCOMING_REQ_STALE,
remote_comid, 0, remote_hca_guid, hcap, &stale_statep);
rw_exit(&hcap->hca_state_rwlock);
if (comid_lookup_status == IBCM_LOOKUP_EXISTS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_req_msg: "
"dup comid %x stale_statep 0x%p statep 0x%p",
remote_comid, stale_statep, statep);
ibcm_insert_trace(stale_statep,
IBCM_TRACE_STALE_DETECT);
ibcm_post_rej_mad(statep, IBT_CM_DUP_COM_ID,
IBT_CM_FAILURE_REQ, NULL, 0);
mutex_enter(&stale_statep->state_mutex);
if (stale_statep->state == IBCM_STATE_ESTABLISHED) {
stale_statep->state =
IBCM_STATE_TRANSIENT_DREQ_SENT;
stale_statep->stale = B_TRUE;
ibcm_sync_lapr_idle(stale_statep);
if (stale_statep->dreq_msg == NULL)
(void) ibcm_alloc_out_msg(stale_statep->
stored_reply_addr.ibmf_hdl,
&stale_statep->dreq_msg,
MAD_METHOD_SEND);
if (stale_statep->dreq_msg != NULL) {
ibcm_post_dreq_mad(stale_statep);
mutex_enter(&stale_statep->state_mutex);
} else {
mutex_enter(&stale_statep->state_mutex);
stale_statep->state =
IBCM_STATE_ESTABLISHED;
cv_broadcast(
&stale_statep->block_mad_cv);
}
}
IBCM_REF_CNT_DECR(stale_statep);
mutex_exit(&stale_statep->state_mutex);
mutex_enter(&statep->state_mutex);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
return;
}
trans = ((uint8_t *)&req_msgp->req_remote_eecn_plus)[3] >> 1 &
0x3;
if ((trans != IBT_RC_SRV) && (trans != IBT_UC_SRV) &&
(trans != IBT_RD_SRV)) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_req_msg: "
"statep 0x%p invalid transport type %x", statep,
trans);
ibcm_post_rej_mad(statep, IBT_CM_INVALID_SRV_TYPE,
IBT_CM_FAILURE_REQ, NULL, 0);
mutex_enter(&statep->state_mutex);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
return;
}
svc_gid_check = ibcm_verify_req_gids_and_svcid(statep,
req_msgp);
if (svc_gid_check == IBCM_FAILURE) {
IBTF_DPRINTF_L3(cmlog, "ibcm_process_req_msg: Either "
"gid or sid invalid for statep 0x%p", statep);
mutex_enter(&statep->state_mutex);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
return;
}
response = ibcm_cep_state_req(statep, req_msgp,
&reject_reason, &arej_info_len);
if (response == IBCM_DEFER) {
IBTF_DPRINTF_L4(cmlog, "ibcm_process_req_msg: "
"statep %0xp client returned DEFER response",
statep);
return;
}
ibcm_handle_cep_req_response(statep, response,
reject_reason, arej_info_len);
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*statep))
return;
} else {
rw_exit(&hcap->hca_state_rwlock);
ibcm_free_comid(hcap, local_comid);
}
if (state_lookup_status == IBCM_LOOKUP_EXISTS) {
hrtime_t cur_time;
mutex_enter(&statep->state_mutex);
cur_time = gethrtime();
if ((remote_comid == statep->remote_comid) &&
(IBCM_OUT_HDRP(statep->stored_msg)->TransactionID ==
((ib_mad_hdr_t *)(input_madp))->TransactionID) &&
(cur_time <= statep->stale_clock)) {
ibcm_insert_trace(statep, IBCM_TRACE_INCOMING_REQ);
if (statep->state == IBCM_STATE_REP_SENT)
ibcm_resend_rep_mad(statep);
else if (statep->state == IBCM_STATE_REJ_SENT)
ibcm_resend_rej_mad(statep);
else if (statep->state == IBCM_STATE_MRA_SENT)
ibcm_resend_mra_mad(statep);
} else if ((statep->state == IBCM_STATE_REJ_SENT) &&
remote_comid != statep->remote_comid) {
timeout_id_t timer_val;
IBTF_DPRINTF_L2(cmlog, "ibcm_process_req_msg: "
"statep 0x%p being retired, REMOTE_QPN %x",
statep, remote_qpn);
statep->state = IBCM_STATE_DELETE;
timer_val = statep->timerid;
statep->timerid = 0;
mutex_exit(&statep->state_mutex);
if (timer_val)
(void) untimeout(timer_val);
IBCM_REF_CNT_DECR(statep);
ibcm_delete_state_data(statep);
goto new_req;
} else {
ibcm_insert_trace(statep, IBCM_TRACE_STALE_DETECT);
IBTF_DPRINTF_L2(cmlog, "ibcm_process_req_msg: "
"stale detected statep %p state %x",
statep, statep->state);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_req_msg: "
"cur_time 0x%llX stale_clock 0x%llX", cur_time,
statep->stale_clock);
if (statep->state == IBCM_STATE_ESTABLISHED) {
statep->state = IBCM_STATE_TRANSIENT_DREQ_SENT;
statep->stale = B_TRUE;
ibcm_sync_lapr_idle(statep);
if (statep->dreq_msg == NULL)
(void) ibcm_alloc_out_msg(
statep->stored_reply_addr.ibmf_hdl,
&statep->dreq_msg, MAD_METHOD_SEND);
if (statep->dreq_msg != NULL)
ibcm_post_dreq_mad(statep);
else {
mutex_enter(&statep->state_mutex);
statep->state = IBCM_STATE_ESTABLISHED;
cv_broadcast(&statep->block_mad_cv);
mutex_exit(&statep->state_mutex);
}
} else {
mutex_exit(&statep->state_mutex);
}
ibcm_build_n_post_rej_mad(input_madp,
b2h32(req_msgp->req_local_comm_id),
cm_mad_addr, IBT_CM_FAILURE_REQ, IBT_CM_CONN_STALE);
mutex_enter(&statep->state_mutex);
}
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
}
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)
{
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*statep))
if (response == IBCM_SEND_REP)
ibcm_post_rep_mad(statep);
else {
ASSERT(response == IBCM_SEND_REJ);
IBTF_DPRINTF_L4(cmlog, "ibcm_handle_cep_req_response: statep %p"
" posting REJ reject_reason = %d", statep, reject_reason);
ibcm_post_rej_mad(statep,
reject_reason, IBT_CM_FAILURE_REQ,
NULL, arej_info_len);
}
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*statep))
mutex_enter(&statep->state_mutex);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
void
ibcm_process_rep_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
ibcm_mad_addr_t *cm_mad_addr)
{
ibt_priv_data_len_t arej_info_len = 0;
ib_com_id_t local_comid;
timeout_id_t timer_val;
ibcm_status_t lookup_status;
ibcm_status_t stale_lookup_status;
ibcm_status_t stale_comid_lookup_status;
ibcm_status_t response;
ibcm_rep_msg_t *rep_msgp;
ibt_cm_reason_t reject_reason;
ibcm_state_data_t *statep = NULL;
ibcm_state_data_t *stale_qpn = NULL;
ibcm_state_data_t *stale_comid = NULL;
ib_guid_t remote_ca_guid;
IBTF_DPRINTF_L3(cmlog, "ibcm_process_rep_msg:");
rep_msgp = (ibcm_rep_msg_t *)(&input_madp[IBCM_MAD_HDR_SIZE]);
IBCM_DUMP_RAW_MSG((uchar_t *)input_madp);
IBTF_DPRINTF_L5(cmlog, "ibcm_process_rep_msg: active comid: %x",
rep_msgp->rep_remote_comm_id);
local_comid = b2h32(rep_msgp->rep_remote_comm_id);
rw_enter(&hcap->hca_state_rwlock, RW_READER);
lookup_status = ibcm_lookup_msg(IBCM_INCOMING_REP, local_comid, 0, 0,
hcap, &statep);
rw_exit(&hcap->hca_state_rwlock);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_rep_msg: lkup status %x, "
"statep 0x%p active comid %x", lookup_status, statep, local_comid);
if (lookup_status == IBCM_LOOKUP_FAIL) {
ibcm_build_n_post_rej_mad(input_madp,
b2h32(rep_msgp->rep_local_comm_id), cm_mad_addr,
IBT_CM_FAILURE_REP, IBT_CM_INVALID_CID);
return;
}
if (IBCM_OUT_HDRP(statep->stored_msg)->TransactionID !=
((ib_mad_hdr_t *)(input_madp))->TransactionID) {
IBTF_DPRINTF_L3(cmlog, "ibcm_process_rep_msg: statep 0x%p, "
"An REP MAD with tid expected 0x%llX tid found 0x%llX ",
statep,
b2h64(IBCM_OUT_HDRP(statep->stored_msg)->TransactionID),
b2h64(((ib_mad_hdr_t *)(input_madp))->TransactionID));
mutex_enter(&statep->state_mutex);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
return;
}
ibcm_insert_trace(statep, IBCM_TRACE_INCOMING_REP);
mutex_enter(&statep->state_mutex);
if (statep->state == IBCM_STATE_ESTABLISHED ||
statep->state == IBCM_STATE_DREQ_SENT)
ibcm_resend_rtu_mad(statep);
else if (statep->state == IBCM_STATE_REJ_SENT)
ibcm_resend_rej_mad(statep);
else if (statep->state == IBCM_STATE_MRA_REP_SENT)
ibcm_resend_mra_mad(statep);
else if ((statep->state == IBCM_STATE_REQ_SENT) ||
(statep->state == IBCM_STATE_REP_WAIT)) {
statep->state = IBCM_STATE_REP_RCVD;
statep->clnt_proceed = IBCM_BLOCK;
statep->local_qp_rnr_cnt =
rep_msgp->rep_rnr_retry_cnt_plus >> 5;
if (statep->timerid != 0) {
timer_val = statep->timerid;
statep->timerid = 0;
mutex_exit(&statep->state_mutex);
(void) untimeout(timer_val);
} else {
mutex_exit(&statep->state_mutex);
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*statep))
statep->stored_reply_addr.rcvd_addr.ia_remote_qno =
cm_mad_addr->rcvd_addr.ia_remote_qno;
statep->remote_qpn = b2h32(rep_msgp->rep_local_qpn_plus) >> 8;
statep->remote_comid = b2h32(rep_msgp->rep_local_comm_id);
bcopy(rep_msgp->rep_local_ca_guid, &remote_ca_guid,
sizeof (ib_guid_t));
statep->remote_hca_guid = b2h64(remote_ca_guid);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_rep_msg: statep 0x%p "
"passive cid = %x passive qpn = %x", statep,
statep->remote_comid, statep->remote_qpn);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_rep_msg: statep 0x%p "
"passive hcaguid = %llX", statep, statep->remote_hca_guid);
stale_qpn = statep;
stale_comid = statep;
rw_enter(&hcap->hca_state_rwlock, RW_WRITER);
stale_lookup_status = ibcm_lookup_msg(IBCM_INCOMING_REP_STALE,
0, statep->remote_qpn, statep->remote_hca_guid, hcap,
&stale_qpn);
stale_comid_lookup_status = ibcm_lookup_msg(
IBCM_INCOMING_REQ_STALE, statep->remote_comid, 0,
statep->remote_hca_guid, hcap, &stale_comid);
rw_exit(&hcap->hca_state_rwlock);
mutex_enter(&stale_qpn->state_mutex);
if ((stale_lookup_status == IBCM_LOOKUP_EXISTS) &&
(stale_comid_lookup_status != IBCM_LOOKUP_EXISTS) &&
(stale_qpn->state == IBCM_STATE_REJ_SENT)) {
timeout_id_t timer_val;
IBTF_DPRINTF_L3(cmlog, "ibcm_process_rep_msg: "
"statep 0x%p being retired, REMOTE_QPN %x",
stale_qpn, statep->remote_qpn);
stale_qpn->state = IBCM_STATE_DELETE;
timer_val = stale_qpn->timerid;
stale_qpn->timerid = 0;
mutex_exit(&stale_qpn->state_mutex);
if (timer_val)
(void) untimeout(timer_val);
IBCM_REF_CNT_DECR(stale_qpn);
ibcm_delete_state_data(stale_qpn);
stale_qpn = statep;
rw_enter(&hcap->hca_state_rwlock, RW_WRITER);
stale_lookup_status = ibcm_lookup_msg(
IBCM_INCOMING_REP_STALE, 0, statep->remote_qpn,
statep->remote_hca_guid, hcap, &stale_qpn);
rw_exit(&hcap->hca_state_rwlock);
} else
mutex_exit(&stale_qpn->state_mutex);
if ((stale_lookup_status == IBCM_LOOKUP_EXISTS) ||
(stale_comid_lookup_status == IBCM_LOOKUP_EXISTS)) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_rep_msg: "
"statep 0x%p stale detected "
"qpn_lkup %d comid_lkup %d", statep,
stale_lookup_status, stale_comid_lookup_status);
IBCM_SET_CHAN_PRIVATE(statep->channel, NULL);
if (stale_lookup_status == IBCM_LOOKUP_EXISTS)
reject_reason = IBT_CM_CONN_STALE;
else
reject_reason = IBT_CM_DUP_COM_ID;
ibcm_handler_conn_fail(statep,
IBT_CM_FAILURE_REJ_SENT, IBT_CM_FAILURE_REP,
reject_reason,
IBCM_REJ_PRIV(statep->stored_msg),
IBT_REJ_PRIV_DATA_SZ);
ibcm_post_rej_mad(statep, reject_reason,
IBT_CM_FAILURE_REP, NULL, 0);
if (stale_lookup_status == IBCM_LOOKUP_EXISTS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_rep_msg: "
"state_qpn 0x%p stale QPN detected "
"state %X", stale_qpn, stale_qpn->state);
ibcm_insert_trace(stale_qpn,
IBCM_TRACE_STALE_DETECT);
mutex_enter(&stale_qpn->state_mutex);
if (stale_qpn->state ==
IBCM_STATE_ESTABLISHED) {
stale_qpn->state =
IBCM_STATE_TRANSIENT_DREQ_SENT;
stale_qpn->stale = B_TRUE;
ibcm_sync_lapr_idle(stale_qpn);
if (stale_qpn->dreq_msg == NULL)
(void) ibcm_alloc_out_msg(
stale_qpn->
stored_reply_addr.ibmf_hdl,
&stale_qpn->dreq_msg,
MAD_METHOD_SEND);
if (stale_qpn->dreq_msg != NULL) {
ibcm_post_dreq_mad(stale_qpn);
mutex_enter(
&stale_qpn->state_mutex);
} else {
mutex_enter(
&stale_qpn->state_mutex);
stale_qpn->state =
IBCM_STATE_ESTABLISHED;
cv_broadcast(
&stale_qpn->block_mad_cv);
}
}
IBCM_REF_CNT_DECR(stale_qpn);
mutex_exit(&stale_qpn->state_mutex);
}
if (stale_comid_lookup_status == IBCM_LOOKUP_EXISTS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_rep_msg: "
"state_comid 0x%p stale COMID detected "
"state %X", stale_comid,
stale_comid->state);
mutex_enter(&stale_comid->state_mutex);
if (!((stale_lookup_status ==
IBCM_LOOKUP_EXISTS) &&
(stale_qpn == stale_comid)) &&
(stale_comid->state ==
IBCM_STATE_ESTABLISHED)) {
ibcm_insert_trace(stale_comid,
IBCM_TRACE_STALE_DETECT);
stale_comid->state =
IBCM_STATE_TRANSIENT_DREQ_SENT;
stale_comid->stale = B_TRUE;
ibcm_sync_lapr_idle(stale_comid);
if (stale_comid->dreq_msg == NULL)
(void) ibcm_alloc_out_msg(
stale_comid->
stored_reply_addr.ibmf_hdl,
&stale_comid->dreq_msg,
MAD_METHOD_SEND);
if (stale_comid->dreq_msg != NULL) {
ibcm_post_dreq_mad(stale_comid);
mutex_enter(
&stale_comid->state_mutex);
} else {
mutex_enter(
&stale_comid->state_mutex);
stale_comid->state =
IBCM_STATE_ESTABLISHED;
cv_broadcast(
&stale_comid->block_mad_cv);
}
}
IBCM_REF_CNT_DECR(stale_comid);
mutex_exit(&stale_comid->state_mutex);
}
ibcm_return_open_data(statep, rep_msgp, reject_reason);
return;
}
ASSERT(stale_lookup_status == IBCM_LOOKUP_NEW);
statep->remote_ack_delay =
ibt_ib2usec(rep_msgp->rep_target_delay_plus >> 3);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_rep_msg: statep 0x%p"
" passive hca_ack_delay= %x ", statep,
statep->remote_ack_delay);
response = ibcm_cep_state_rep(statep, rep_msgp,
&reject_reason, &arej_info_len);
if (response == IBCM_DEFER) {
IBTF_DPRINTF_L4(cmlog, "ibcm_process_rep_msg: "
"statep 0x%p client returned DEFER response",
statep);
return;
}
ibcm_handle_cep_rep_response(statep, response,
reject_reason, arej_info_len, rep_msgp);
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*statep))
return;
} else if (statep->state == IBCM_STATE_DELETE) {
mutex_exit(&statep->state_mutex);
ibcm_build_n_post_rej_mad(input_madp,
b2h32(rep_msgp->rep_local_comm_id), cm_mad_addr,
IBT_CM_FAILURE_REP, IBT_CM_INVALID_CID);
mutex_enter(&statep->state_mutex);
} else {
#ifdef DEBUG
if (ibcm_test_mode > 0)
if (statep->state == IBCM_STATE_REP_RCVD)
IBTF_DPRINTF_L2(cmlog, "ibcm_process_rep_msg: "
"REP re-send from passive for statep 0x%p"
" in state %d", statep, statep->state);
else
IBTF_DPRINTF_L2(cmlog, "ibcm_process_rep_msg: "
"Unexpected REP for statep 0x%p in "
"state %d", statep, statep->state);
#endif
}
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
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)
{
mutex_enter(&statep->state_mutex);
while (statep->send_mad_flags & IBCM_REQ_POST_BUSY)
cv_wait(&statep->block_mad_cv, &statep->state_mutex);
mutex_exit(&statep->state_mutex);
if (response == IBCM_SEND_RTU) {
if (ibcm_post_rtu_mad(statep) != IBCM_SUCCESS) {
mutex_enter(&statep->state_mutex);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
return;
}
ibcm_cep_send_rtu(statep);
} else {
IBTF_DPRINTF_L4(cmlog, "ibcm_handle_cep_rep_response: statep %p"
" posting REJ reject_reason = %d", statep, reject_reason);
ASSERT(response == IBCM_SEND_REJ);
ibcm_post_rej_mad(statep, reject_reason, IBT_CM_FAILURE_REP,
NULL, arej_info_len);
}
ibcm_return_open_data(statep, rep_msgp, reject_reason);
}
static void
ibcm_return_open_data(ibcm_state_data_t *statep, ibcm_rep_msg_t *rep_msgp,
ibt_cm_reason_t reject_reason)
{
if (statep->open_return_data != NULL) {
if (statep->open_return_data->rc_priv_data_len > 0)
bcopy(rep_msgp->rep_private_data,
statep->open_return_data->rc_priv_data,
statep->open_return_data->rc_priv_data_len);
statep->open_return_data->rc_rdma_ra_in =
rep_msgp->rep_initiator_depth;
statep->open_return_data->rc_rdma_ra_out =
rep_msgp->rep_resp_resources;
statep->open_return_data->rc_failover_status =
rep_msgp->rep_target_delay_plus >> 1 & 3;
statep->open_return_data->rc_status = reject_reason;
mutex_enter(&statep->state_mutex);
statep->open_done = B_TRUE;
cv_broadcast(&statep->block_client_cv);
} else mutex_enter(&statep->state_mutex);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
void
ibcm_process_mra_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
ibcm_mad_addr_t *cm_mad_addr)
{
ibcm_status_t state_lookup_status;
ibcm_mra_msg_t *mra_msgp =
(ibcm_mra_msg_t *)(&input_madp[IBCM_MAD_HDR_SIZE]);
ibcm_state_data_t *statep = NULL;
uint8_t mra_msg;
IBTF_DPRINTF_L4(cmlog, "ibcm_process_mra_msg:");
rw_enter(&hcap->hca_state_rwlock, RW_READER);
state_lookup_status = ibcm_lookup_msg(IBCM_INCOMING_MRA,
b2h32(mra_msgp->mra_remote_comm_id), 0, 0, hcap, &statep);
rw_exit(&hcap->hca_state_rwlock);
if (state_lookup_status != IBCM_LOOKUP_EXISTS) {
ibcm_build_n_post_rej_mad(input_madp,
b2h32(mra_msgp->mra_local_comm_id), cm_mad_addr,
IBT_CM_FAILURE_UNKNOWN, IBT_CM_INVALID_CID);
return;
}
if (IBCM_OUT_HDRP(statep->stored_msg)->TransactionID !=
((ib_mad_hdr_t *)(input_madp))->TransactionID) {
mutex_enter(&statep->state_mutex);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
IBTF_DPRINTF_L3(cmlog, "ibcm_process_mra_msg: statep 0x%p "
"MRA MAD with tid expected 0x%llX tid found 0x%llX "
"com id 0x%x arrived", statep,
b2h64(IBCM_OUT_HDRP(statep->stored_msg)->TransactionID),
b2h64(((ib_mad_hdr_t *)(input_madp))->TransactionID),
b2h32(mra_msgp->mra_local_comm_id));
return;
}
ibcm_insert_trace(statep, IBCM_TRACE_INCOMING_MRA);
mutex_enter(&statep->state_mutex);
mra_msg = mra_msgp->mra_message_type_plus >> 6;
if ((mra_msg != IBT_CM_MRA_TYPE_REQ) &&
(mra_msg != IBT_CM_MRA_TYPE_REP) &&
(mra_msg != IBT_CM_MRA_TYPE_LAP)) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_mra_msg: statep 0x%p "
"Unexpected MRA MSG Type %x", statep, mra_msg);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
return;
}
if ((statep->state == IBCM_STATE_REQ_SENT) ||
(statep->state == IBCM_STATE_REP_SENT) ||
((statep->state == IBCM_STATE_ESTABLISHED) &&
(statep->ap_state == IBCM_AP_STATE_LAP_SENT))) {
timeout_id_t timer_val = statep->timerid;
clock_t service_timeout;
if (statep->state == IBCM_STATE_REQ_SENT) {
mra_msg = IBT_CM_MRA_TYPE_REQ;
statep->state = IBCM_STATE_REP_WAIT;
} else if (statep->state == IBCM_STATE_REP_SENT) {
mra_msg = IBT_CM_MRA_TYPE_REP;
statep->state = IBCM_STATE_MRA_REP_RCVD;
} else {
mra_msg = IBT_CM_MRA_TYPE_LAP;
statep->ap_state = IBCM_AP_STATE_MRA_LAP_RCVD;
}
statep->timerid = 0;
mutex_exit(&statep->state_mutex);
(void) untimeout(timer_val);
service_timeout =
ibt_ib2usec(mra_msgp->mra_service_timeout_plus >> 3);
if (ibcm_mra_service_timeout_max &&
ibcm_mra_service_timeout_max < service_timeout) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_mra_msg: "
"Unexpected MRA Service Timeout value (%ld), Max "
"allowed is (%ld)", service_timeout,
ibcm_mra_service_timeout_max);
service_timeout = ibcm_mra_service_timeout_max;
}
if (statep->cm_handler != NULL) {
ibt_cm_event_t event;
bzero(&event, sizeof (event));
event.cm_type = IBT_CM_EVENT_MRA_RCV;
event.cm_channel = statep->channel;
event.cm_session_id = NULL;
event.cm_priv_data = mra_msgp->mra_private_data;
event.cm_priv_data_len = IBT_MRA_PRIV_DATA_SZ;
event.cm_event.mra.mra_msg_type = mra_msg;
event.cm_event.mra.mra_service_time = service_timeout;
(void) statep->cm_handler(statep->state_cm_private,
&event, NULL, NULL, 0);
}
mutex_enter(&statep->state_mutex);
if ((statep->state == IBCM_STATE_REP_WAIT) ||
(statep->state == IBCM_STATE_MRA_REP_RCVD) ||
(statep->ap_state == IBCM_AP_STATE_MRA_LAP_RCVD)) {
statep->remaining_retry_cnt = statep->max_cm_retries;
statep->timer_stored_state = statep->state;
statep->timer_value = statep->pkt_life_time +
service_timeout;
statep->timerid = IBCM_TIMEOUT(statep,
statep->timer_value);
}
} else if (statep->state == IBCM_STATE_DELETE) {
mutex_exit(&statep->state_mutex);
ibcm_build_n_post_rej_mad(input_madp,
b2h32(mra_msgp->mra_local_comm_id), cm_mad_addr,
IBT_CM_FAILURE_UNKNOWN, IBT_CM_INVALID_CID);
mutex_enter(&statep->state_mutex);
} else {
#ifdef DEBUG
if (ibcm_test_mode > 0)
IBTF_DPRINTF_L2(cmlog, "ibcm_process_mra_msg: "
"Unexpected mra for statep 0x%p in state %d",
statep, statep->state);
#endif
}
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
void
ibcm_process_rtu_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
ibcm_mad_addr_t *cm_mad_addr)
{
timeout_id_t timer_val;
ibcm_status_t status;
ibcm_rtu_msg_t *rtu_msg =
(ibcm_rtu_msg_t *)(&input_madp[IBCM_MAD_HDR_SIZE]);
ibcm_state_data_t *statep = NULL;
IBTF_DPRINTF_L4(cmlog, "ibcm_process_rtu_msg:");
rw_enter(&hcap->hca_state_rwlock, RW_READER);
status = ibcm_lookup_msg(IBCM_INCOMING_RTU,
b2h32(rtu_msg->rtu_remote_comm_id), 0, 0, hcap, &statep);
rw_exit(&hcap->hca_state_rwlock);
if (status != IBCM_LOOKUP_EXISTS) {
ibcm_build_n_post_rej_mad(input_madp,
b2h32(rtu_msg->rtu_local_comm_id), cm_mad_addr,
IBT_CM_FAILURE_UNKNOWN, IBT_CM_INVALID_CID);
return;
}
if (IBCM_OUT_HDRP(statep->stored_msg)->TransactionID !=
((ib_mad_hdr_t *)(input_madp))->TransactionID) {
mutex_enter(&statep->state_mutex);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
IBTF_DPRINTF_L3(cmlog, "ibcm_process_rtu_msg: statep 0x%p "
"An RTU MAD with tid expected 0x%llX tid found 0x%llX "
"com id 0x%x arrived", statep,
b2h64(IBCM_OUT_HDRP(statep->stored_msg)->TransactionID),
b2h64(((ib_mad_hdr_t *)(input_madp))->TransactionID),
b2h32(rtu_msg->rtu_remote_comm_id));
return;
}
ibcm_insert_trace(statep, IBCM_TRACE_INCOMING_RTU);
mutex_enter(&statep->state_mutex);
if ((statep->state == IBCM_STATE_REP_SENT) ||
(statep->state == IBCM_STATE_MRA_REP_RCVD)) {
statep->state = IBCM_STATE_TRANSIENT_ESTABLISHED;
timer_val = statep->timerid;
statep->timerid = 0;
mutex_exit(&statep->state_mutex);
(void) untimeout(timer_val);
ibcm_cep_state_rtu(statep, rtu_msg);
mutex_enter(&statep->state_mutex);
} else if (statep->state == IBCM_STATE_REJ_SENT) {
ibcm_resend_rej_mad(statep);
} else if (statep->state == IBCM_STATE_DELETE) {
mutex_exit(&statep->state_mutex);
ibcm_build_n_post_rej_mad(input_madp,
b2h32(rtu_msg->rtu_local_comm_id), cm_mad_addr,
IBT_CM_FAILURE_UNKNOWN, IBT_CM_INVALID_CID);
mutex_enter(&statep->state_mutex);
} else {
#ifdef DEBUG
if ((ibcm_test_mode > 0) &&
(statep->state != IBCM_STATE_ESTABLISHED))
IBTF_DPRINTF_L2(cmlog, "ibcm_process_rtu_msg: "
"Unexpected rtu for statep 0x%p in state %d",
statep, statep->state);
#endif
}
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
void
ibcm_process_rej_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
ibcm_mad_addr_t *cm_mad_addr)
{
ibcm_status_t state_lookup_status;
ibcm_rej_msg_t *rej_msg =
(ibcm_rej_msg_t *)(&input_madp[IBCM_MAD_HDR_SIZE]);
ibcm_state_data_t *statep = NULL;
ib_guid_t remote_hca_guid;
ibcm_conn_state_t rej_state;
IBTF_DPRINTF_L4(cmlog, "ibcm_process_rej_msg:");
rw_enter(&hcap->hca_state_rwlock, RW_READER);
if ((b2h32(rej_msg->rej_remote_comm_id) == 0) &&
((rej_msg->rej_reject_info_len_plus >> 1) >= sizeof (ib_guid_t)) &&
(b2h16(rej_msg->rej_rejection_reason) == IBT_CM_TIMEOUT)) {
bcopy(rej_msg->rej_addl_rej_info, &remote_hca_guid,
sizeof (ib_guid_t));
remote_hca_guid = b2h64(remote_hca_guid);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_rej_msg: "
"hca guid in REJ's ARI = %llX", remote_hca_guid);
state_lookup_status = ibcm_lookup_msg(IBCM_INCOMING_REJ_RCOMID,
b2h32(rej_msg->rej_local_comm_id), 0, remote_hca_guid,
hcap, &statep);
} else
state_lookup_status = ibcm_lookup_msg(IBCM_INCOMING_REJ,
b2h32(rej_msg->rej_remote_comm_id), 0, 0, hcap, &statep);
rw_exit(&hcap->hca_state_rwlock);
if (state_lookup_status != IBCM_LOOKUP_EXISTS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_rej_msg: no statep with "
"local com id %x remote com id %x reason %d",
b2h32(rej_msg->rej_remote_comm_id),
b2h32(rej_msg->rej_local_comm_id),
b2h16(rej_msg->rej_rejection_reason));
return;
}
IBTF_DPRINTF_L2(cmlog, "ibcm_process_rej_msg: statep 0x%p INCOMING_REJ",
statep);
ibcm_insert_trace(statep, IBCM_TRACE_INCOMING_REJ);
if (ibcm_enable_trace & 2)
ibcm_dump_conn_trace(statep);
mutex_enter(&statep->state_mutex);
rej_state = statep->state;
if ((statep->state == IBCM_STATE_REP_SENT) ||
(statep->state == IBCM_STATE_REQ_SENT) ||
(statep->state == IBCM_STATE_REP_WAIT) ||
(statep->state == IBCM_STATE_MRA_REP_RCVD)) {
timeout_id_t timer_val = statep->timerid;
statep->state = IBCM_STATE_DELETE;
if (timer_val != 0) {
statep->timerid = 0;
mutex_exit(&statep->state_mutex);
(void) untimeout(timer_val);
} else {
mutex_exit(&statep->state_mutex);
}
ibcm_cep_state_rej(statep, rej_msg, rej_state);
if (statep->open_return_data != NULL) {
statep->open_return_data->rc_status =
b2h16(rej_msg->rej_rejection_reason);
if (statep->open_return_data->rc_priv_data_len > 0)
bcopy(rej_msg->rej_private_data,
statep->open_return_data->rc_priv_data,
min(
statep->open_return_data->rc_priv_data_len,
IBT_REJ_PRIV_DATA_SZ));
mutex_enter(&statep->state_mutex);
statep->open_done = B_TRUE;
cv_broadcast(&statep->block_client_cv);
} else {
mutex_enter(&statep->state_mutex);
}
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
ibcm_delete_state_data(statep);
} else if ((statep->state == IBCM_STATE_ESTABLISHED) &&
(statep->mode == IBCM_ACTIVE_MODE)) {
IBTF_DPRINTF_L4(cmlog, "ibcm_process_rej_msg: statep 0x%p "
"REJ in established state", statep);
statep->state = IBCM_STATE_TIMEWAIT;
ibcm_sync_lapr_idle(statep);
mutex_enter(&statep->state_mutex);
while (statep->cep_in_rts == IBCM_BLOCK)
cv_wait(&statep->block_mad_cv, &statep->state_mutex);
mutex_exit(&statep->state_mutex);
ibcm_cep_state_rej_est(statep);
mutex_enter(&statep->state_mutex);
statep->timer_value = statep->remote_ack_delay;
statep->timer_value += (2 * statep->pkt_life_time);
statep->remaining_retry_cnt = 0;
statep->timer_stored_state = statep->state;
statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
} else if (((statep->state == IBCM_STATE_REQ_RCVD) ||
(statep->state == IBCM_STATE_REP_RCVD) ||
(statep->state == IBCM_STATE_MRA_SENT) ||
(statep->state == IBCM_STATE_MRA_REP_SENT)) &&
(b2h16(rej_msg->rej_rejection_reason) == IBT_CM_TIMEOUT)) {
if (statep->abort_flag == IBCM_ABORT_INIT)
statep->abort_flag = IBCM_ABORT_REJ;
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
} else {
#ifdef DEBUG
if ((ibcm_test_mode > 0) &&
(statep->state != IBCM_STATE_DELETE))
IBTF_DPRINTF_L2(cmlog, "ibcm_process_rej_msg: "
"Unexpected rej for statep 0x%p in state %d",
statep, statep->state);
#endif
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
}
void
ibcm_process_dreq_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
ibcm_mad_addr_t *cm_mad_addr)
{
void *priv_data = NULL;
ibcm_status_t state_lookup_status;
ib_qpn_t local_qpn;
ibcm_dreq_msg_t *dreq_msgp =
(ibcm_dreq_msg_t *)(&input_madp[IBCM_MAD_HDR_SIZE]);
ibcm_state_data_t *statep = NULL;
uint8_t close_event_type;
ibt_cm_status_t cb_status;
IBTF_DPRINTF_L4(cmlog, "ibcm_process_dreq_msg:");
rw_enter(&hcap->hca_state_rwlock, RW_READER);
state_lookup_status = ibcm_lookup_msg(IBCM_INCOMING_DREQ,
b2h32(dreq_msgp->dreq_remote_comm_id), 0, 0, hcap, &statep);
rw_exit(&hcap->hca_state_rwlock);
local_qpn = b2h32(dreq_msgp->dreq_remote_qpn_eecn_plus) >> 8;
if (state_lookup_status != IBCM_LOOKUP_EXISTS) {
IBTF_DPRINTF_L3(cmlog, "ibcm_process_dreq_msg: no statep with"
"com id %x", b2h32(dreq_msgp->dreq_remote_comm_id));
return;
}
IBTF_DPRINTF_L4(cmlog, "ibcm_process_dreq_msg: statep 0x%p "
"lookup status %x dreq qpn = %x", statep, state_lookup_status,
local_qpn);
mutex_enter(&statep->state_mutex);
if ((statep->local_qpn != local_qpn) ||
(statep->remote_comid != b2h32(dreq_msgp->dreq_local_comm_id))) {
IBTF_DPRINTF_L3(cmlog, "ibcm_process_dreq_msg:"
"statep->local_qpn = %x qpn in dreq = %x"
"statep->remote_comid = %x local comid in dreq = %x",
statep->local_qpn, local_qpn, statep->remote_comid,
b2h32(dreq_msgp->dreq_local_comm_id));
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
return;
}
if (statep->state == IBCM_STATE_TRANSIENT_DREQ_SENT ||
statep->drep_in_progress) {
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
return;
}
switch (statep->state) {
case IBCM_STATE_ESTABLISHED:
case IBCM_STATE_DREQ_SENT:
case IBCM_STATE_TIMEWAIT:
break;
default:
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
return;
}
statep->drep_in_progress = 1;
if (statep->drep_msg == NULL) {
mutex_exit(&statep->state_mutex);
if (ibcm_alloc_out_msg(statep->stored_reply_addr.ibmf_hdl,
&statep->drep_msg, MAD_METHOD_SEND) != IBT_SUCCESS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_dreq_msg: "
"statep 0x%p ibcm_alloc_out_msg failed", statep);
mutex_enter(&statep->state_mutex);
statep->drep_in_progress = 0;
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
return;
}
mutex_enter(&statep->state_mutex);
}
if (statep->state == IBCM_STATE_TRANSIENT_DREQ_SENT) {
IBCM_REF_CNT_DECR(statep);
statep->drep_in_progress = 0;
mutex_exit(&statep->state_mutex);
return;
}
if ((statep->state == IBCM_STATE_ESTABLISHED) ||
(statep->state == IBCM_STATE_DREQ_SENT)) {
timeout_id_t timer_val = statep->timerid;
if (statep->state == IBCM_STATE_DREQ_SENT) {
statep->state = IBCM_STATE_DREQ_RCVD;
statep->timerid = 0;
ibcm_close_done(statep, 0);
mutex_exit(&statep->state_mutex);
close_event_type = IBT_CM_CLOSED_DUP;
if (timer_val != 0) {
(void) untimeout(timer_val);
}
} else {
boolean_t is_ofuv = statep->is_this_ofuv_chan;
statep->state = IBCM_STATE_DREQ_RCVD;
statep->clnt_proceed = IBCM_BLOCK;
ibcm_sync_lapr_idle(statep);
mutex_enter(&statep->state_mutex);
while (statep->cep_in_rts == IBCM_BLOCK)
cv_wait(&statep->block_mad_cv,
&statep->state_mutex);
mutex_exit(&statep->state_mutex);
close_event_type = IBT_CM_CLOSED_DREQ_RCVD;
if (is_ofuv == B_FALSE)
(void) ibcm_cep_to_error_state(statep);
}
mutex_enter(&statep->state_mutex);
statep->drep_in_progress = 0;
IBCM_OUT_HDRP(statep->drep_msg)->TransactionID =
((ib_mad_hdr_t *)(input_madp))->TransactionID;
priv_data = &(((ibcm_drep_msg_t *)
IBCM_OUT_MSGP(statep->drep_msg))->drep_private_data[0]);
if (statep->close_ret_status)
*statep->close_ret_status = close_event_type;
if (statep->close_nocb_state != IBCM_FAIL) {
ibtl_cm_chan_is_closing(statep->channel);
statep->close_nocb_state = IBCM_BLOCK;
}
mutex_exit(&statep->state_mutex);
if (statep->cm_handler != NULL) {
ibt_cm_event_t event;
ibt_cm_return_args_t ret_args;
bzero(&event, sizeof (event));
bzero(&ret_args, sizeof (ret_args));
event.cm_type = IBT_CM_EVENT_CONN_CLOSED;
event.cm_channel = statep->channel;
event.cm_session_id = statep;
event.cm_priv_data = dreq_msgp->dreq_private_data;
event.cm_priv_data_len = IBT_DREQ_PRIV_DATA_SZ;
event.cm_event.closed = close_event_type;
ibcm_insert_trace(statep,
IBCM_TRACE_CALLED_CONN_CLOSE_EVENT);
cb_status = statep->cm_handler(statep->state_cm_private,
&event, &ret_args, priv_data,
IBT_DREP_PRIV_DATA_SZ);
ibcm_insert_trace(statep,
IBCM_TRACE_RET_CONN_CLOSE_EVENT);
if (cb_status == IBT_CM_DEFER) {
mutex_enter(&statep->state_mutex);
statep->clnt_proceed =
IBCM_UNBLOCK;
cv_broadcast(&statep->block_client_cv);
mutex_exit(&statep->state_mutex);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_dreq_msg:"
" statep 0x%p client returned DEFER "
"response", statep);
return;
}
}
mutex_enter(&statep->state_mutex);
statep->clnt_proceed = IBCM_FAIL;
statep->close_nocb_state = IBCM_FAIL;
statep->close_done = B_TRUE;
cv_broadcast(&statep->block_client_cv);
mutex_exit(&statep->state_mutex);
ibcm_handle_cep_dreq_response(statep, NULL, 0);
} else if (statep->state == IBCM_STATE_TIMEWAIT) {
statep->drep_in_progress = 0;
if (statep->send_mad_flags & IBCM_DREP_POST_BUSY) {
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
return;
}
statep->send_mad_flags |= IBCM_DREP_POST_BUSY;
mutex_exit(&statep->state_mutex);
IBCM_OUT_HDRP(statep->drep_msg)->TransactionID =
((ib_mad_hdr_t *)(input_madp))->TransactionID;
ibcm_post_drep_mad(statep);
} else {
#ifdef DEBUG
if ((ibcm_test_mode > 0) &&
(statep->state != IBCM_STATE_DELETE))
IBTF_DPRINTF_L2(cmlog, "ibcm_process_dreq_msg: "
"Unexpected dreq for statep 0x%p in state %d",
statep, statep->state);
#endif
IBCM_REF_CNT_DECR(statep);
statep->drep_in_progress = 0;
mutex_exit(&statep->state_mutex);
}
}
void
ibcm_handle_cep_dreq_response(ibcm_state_data_t *statep, void *priv_data,
ibt_priv_data_len_t priv_data_len)
{
if ((priv_data != NULL) && (priv_data_len > 0))
bcopy(priv_data,
&(((ibcm_drep_msg_t *)
IBCM_OUT_MSGP(statep->drep_msg))->drep_private_data[0]),
min(priv_data_len, IBT_DREP_PRIV_DATA_SZ));
ibcm_post_drep_mad(statep);
}
void
ibcm_post_dreq_mad(void *vstatep)
{
ibcm_state_data_t *statep = vstatep;
ibcm_dreq_msg_t *dreq_msgp;
ASSERT(statep->dreq_msg != NULL);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*dreq_msgp))
dreq_msgp = (ibcm_dreq_msg_t *)IBCM_OUT_MSGP(statep->dreq_msg);
dreq_msgp->dreq_local_comm_id = h2b32(statep->local_comid);
dreq_msgp->dreq_remote_comm_id = h2b32(statep->remote_comid);
dreq_msgp->dreq_remote_qpn_eecn_plus = h2b32(statep->remote_qpn << 8);
IBCM_OUT_HDRP(statep->dreq_msg)->AttributeID =
h2b16(IBCM_INCOMING_DREQ + IBCM_ATTR_BASE_ID);
mutex_enter(&statep->state_mutex);
while (statep->cep_in_rts == IBCM_BLOCK)
cv_wait(&statep->block_mad_cv, &statep->state_mutex);
mutex_exit(&statep->state_mutex);
(void) ibcm_cep_to_error_state(statep);
IBCM_OUT_HDRP(statep->dreq_msg)->TransactionID =
h2b64(ibcm_generate_tranid(IBCM_INCOMING_DREQ, statep->local_comid,
0));
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*dreq_msgp))
mutex_enter(&statep->state_mutex);
statep->state = IBCM_STATE_DREQ_SENT;
cv_broadcast(&statep->block_mad_cv);
statep->timer_stored_state = statep->state;
statep->timer_value = statep->remote_ack_delay;
if (statep->mode == IBCM_ACTIVE_MODE) {
statep->timer_value += (2 * statep->pkt_life_time);
}
statep->remaining_retry_cnt = statep->max_cm_retries + 1;
statep->timerid = IBCM_TIMEOUT(statep, 0);
mutex_exit(&statep->state_mutex);
}
static void
ibcm_post_drep_mad(ibcm_state_data_t *statep)
{
ibcm_drep_msg_t *drep_msgp;
drep_msgp = (ibcm_drep_msg_t *)IBCM_OUT_MSGP(statep->drep_msg);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*drep_msgp))
IBTF_DPRINTF_L4(cmlog, "ibcm_post_drep_mad:");
drep_msgp->drep_local_comm_id = h2b32(statep->local_comid);
drep_msgp->drep_remote_comm_id = h2b32(statep->remote_comid);
IBCM_OUT_HDRP(statep->drep_msg)->AttributeID =
h2b16(IBCM_INCOMING_DREP + IBCM_ATTR_BASE_ID);
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*drep_msgp))
ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_DREP);
ibcm_post_rc_mad(statep, statep->drep_msg, ibcm_post_drep_complete,
statep);
}
void
ibcm_process_drep_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
ibcm_mad_addr_t *cm_mad_addr)
{
ibcm_status_t state_lookup_status;
ibcm_drep_msg_t *drep_msgp =
(ibcm_drep_msg_t *)(&input_madp[IBCM_MAD_HDR_SIZE]);
ibcm_state_data_t *statep = NULL;
IBTF_DPRINTF_L4(cmlog, "ibcm_process_drep_msg:");
rw_enter(&hcap->hca_state_rwlock, RW_READER);
state_lookup_status = ibcm_lookup_msg(IBCM_INCOMING_DREP,
b2h32(drep_msgp->drep_remote_comm_id), 0, 0, hcap, &statep);
rw_exit(&hcap->hca_state_rwlock);
if (state_lookup_status != IBCM_LOOKUP_EXISTS) {
IBTF_DPRINTF_L3(cmlog, "ibcm_process_drep_msg: no statep with"
"com id %x", b2h32(drep_msgp->drep_remote_comm_id));
return;
}
if (IBCM_OUT_HDRP(statep->dreq_msg)->TransactionID !=
((ib_mad_hdr_t *)(input_madp))->TransactionID) {
mutex_enter(&statep->state_mutex);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
IBTF_DPRINTF_L3(cmlog, "ibcm_process_drep_msg: statep 0x%p "
"DREP with tid expected 0x%llX tid found 0x%llX", statep,
b2h64(IBCM_OUT_HDRP(statep->dreq_msg)->TransactionID),
b2h64(((ib_mad_hdr_t *)(input_madp))->TransactionID));
return;
}
ibcm_insert_trace(statep, IBCM_TRACE_INCOMING_DREP);
mutex_enter(&statep->state_mutex);
if (statep->state == IBCM_STATE_DREQ_SENT) {
timeout_id_t timer_val = statep->timerid;
statep->state = IBCM_STATE_DREP_RCVD;
statep->timerid = 0;
mutex_exit(&statep->state_mutex);
(void) untimeout(timer_val);
if (statep->stale == B_TRUE)
IBTF_DPRINTF_L2(cmlog, "ibcm_process_drep_msg: "
"statep 0x%p Unexpected DREP received for a stale "
"DREQ sent", statep);
mutex_enter(&statep->state_mutex);
if (statep->close_nocb_state != IBCM_FAIL) {
ibtl_cm_chan_is_closing(statep->channel);
statep->close_nocb_state = IBCM_BLOCK;
}
mutex_exit(&statep->state_mutex);
if (statep->cm_handler != NULL) {
ibt_cm_event_t event;
ibt_cm_return_args_t ret_args;
bzero(&event, sizeof (event));
bzero(&ret_args, sizeof (ret_args));
event.cm_type = IBT_CM_EVENT_CONN_CLOSED;
event.cm_channel = statep->channel;
event.cm_session_id = NULL;
if (statep->stale == B_TRUE) {
event.cm_event.closed = IBT_CM_CLOSED_STALE;
event.cm_priv_data = NULL;
event.cm_priv_data_len = 0;
} else {
event.cm_event.closed = IBT_CM_CLOSED_DREP_RCVD;
event.cm_priv_data =
drep_msgp->drep_private_data;
event.cm_priv_data_len = IBT_DREP_PRIV_DATA_SZ;
}
ibcm_insert_trace(statep,
IBCM_TRACE_CALLED_CONN_CLOSE_EVENT);
(void) statep->cm_handler(statep->state_cm_private,
&event, &ret_args, NULL, 0);
ibcm_insert_trace(statep,
IBCM_TRACE_RET_CONN_CLOSE_EVENT);
}
if ((statep->close_ret_priv_data != NULL) &&
(statep->close_ret_priv_data_len != NULL) &&
(*statep->close_ret_priv_data_len > 0)) {
bcopy(drep_msgp->drep_private_data,
statep->close_ret_priv_data,
min(*statep->close_ret_priv_data_len,
IBT_DREP_PRIV_DATA_SZ));
}
mutex_enter(&statep->state_mutex);
if (statep->close_ret_status)
*statep->close_ret_status = IBT_CM_CLOSED_DREP_RCVD;
statep->close_done = B_TRUE;
statep->close_nocb_state = IBCM_FAIL;
cv_broadcast(&statep->block_client_cv);
statep->state = statep->timer_stored_state =
IBCM_STATE_TIMEWAIT;
ibcm_close_done(statep, 0);
statep->remaining_retry_cnt = 0;
statep->timer_value = statep->remote_ack_delay;
if (statep->mode == IBCM_ACTIVE_MODE) {
statep->timer_value += (2 * statep->pkt_life_time);
}
statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
}
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
void
ibcm_resend_rtu_mad(ibcm_state_data_t *statep)
{
ASSERT(MUTEX_HELD(&statep->state_mutex));
IBTF_DPRINTF_L3(cmlog, "ibcm_resend_rtu_mad statep %p ", statep);
if (!(statep->send_mad_flags & IBCM_RTU_POST_BUSY)) {
statep->send_mad_flags |= IBCM_RTU_POST_BUSY;
IBCM_REF_CNT_INCR(statep);
mutex_exit(&statep->state_mutex);
ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_RTU);
ibcm_post_rc_mad(statep, statep->stored_msg,
ibcm_post_rtu_complete, statep);
mutex_enter(&statep->state_mutex);
}
}
void
ibcm_resend_rej_mad(ibcm_state_data_t *statep)
{
timeout_id_t timer_val = statep->timerid;
ASSERT(MUTEX_HELD(&statep->state_mutex));
IBTF_DPRINTF_L3(cmlog, "ibcm_resend_rej_mad statep %p ", statep);
if (timer_val == 0)
return;
statep->timerid = 0;
if (!(statep->send_mad_flags & IBCM_REJ_POST_BUSY)) {
statep->send_mad_flags |= IBCM_REJ_POST_BUSY;
IBCM_REF_CNT_INCR(statep);
mutex_exit(&statep->state_mutex);
(void) untimeout(timer_val);
ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_REJ);
if (ibcm_enable_trace & 2)
ibcm_dump_conn_trace(statep);
else
IBTF_DPRINTF_L2(cmlog, "ibcm_resend_rej_mad statep %p "
"OUTGOING_REJ", statep);
ibcm_post_rc_mad(statep, statep->stored_msg,
ibcm_post_rej_complete, statep);
mutex_enter(&statep->state_mutex);
}
}
void
ibcm_resend_rep_mad(ibcm_state_data_t *statep)
{
timeout_id_t timer_val = statep->timerid;
ASSERT(MUTEX_HELD(&statep->state_mutex));
IBTF_DPRINTF_L3(cmlog, "ibcm_resend_rep_mad statep %p ", statep);
if (timer_val != 0) {
statep->remaining_retry_cnt = statep->max_cm_retries;
if (!(statep->send_mad_flags & IBCM_REP_POST_BUSY)) {
statep->send_mad_flags |= IBCM_REP_POST_BUSY;
IBCM_REF_CNT_INCR(statep);
mutex_exit(&statep->state_mutex);
ibcm_insert_trace(statep, IBCM_TRACE_OUT_REP_RETRY);
ibcm_post_rc_mad(statep, statep->stored_msg,
ibcm_resend_post_rep_complete, statep);
mutex_enter(&statep->state_mutex);
}
}
}
void
ibcm_resend_mra_mad(ibcm_state_data_t *statep)
{
ASSERT(MUTEX_HELD(&statep->state_mutex));
IBTF_DPRINTF_L3(cmlog, "ibcm_resend_mra_mad statep %p ", statep);
if (statep->send_mad_flags & IBCM_MRA_POST_BUSY)
return;
statep->send_mad_flags |= IBCM_MRA_POST_BUSY;
statep->mra_time = gethrtime();
IBCM_REF_CNT_INCR(statep);
mutex_exit(&statep->state_mutex);
ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_MRA);
ibcm_post_rc_mad(statep, statep->mra_msg, ibcm_post_mra_complete,
statep);
mutex_enter(&statep->state_mutex);
}
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)
{
ibcm_rej_msg_t *rej_msg =
(ibcm_rej_msg_t *)IBCM_OUT_MSGP(statep->stored_msg);
IBTF_DPRINTF_L3(cmlog, "ibcm_post_rej_mad: "
"statep = %p, reject_reason = %d", statep, reject_reason);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rej_msg))
rej_msg->rej_local_comm_id = h2b32(statep->local_comid);
rej_msg->rej_remote_comm_id = h2b32(statep->remote_comid);
rej_msg->rej_msg_type_plus = (which_msg & 0x3) << 6;
rej_msg->rej_reject_info_len_plus = arej_info_len << 1;
rej_msg->rej_rejection_reason = h2b16((uint16_t)reject_reason);
if ((arej_info_len != 0) && (addl_rej_info != NULL))
bcopy(addl_rej_info, rej_msg->rej_addl_rej_info, arej_info_len);
IBCM_OUT_HDRP(statep->stored_msg)->AttributeID =
h2b16(IBCM_INCOMING_REJ + IBCM_ATTR_BASE_ID);
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*rej_msg))
mutex_enter(&statep->state_mutex);
statep->close_done = B_TRUE;
statep->close_nocb_state = IBCM_FAIL;
cv_signal(&statep->block_client_cv);
statep->timer_stored_state = statep->state = IBCM_STATE_REJ_SENT;
statep->send_mad_flags |= IBCM_REJ_POST_BUSY;
IBCM_REF_CNT_INCR(statep);
mutex_exit(&statep->state_mutex);
ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_REJ);
if (ibcm_enable_trace & 2)
ibcm_dump_conn_trace(statep);
else
IBTF_DPRINTF_L2(cmlog, "ibcm_post_rej_mad statep %p "
"OUTGOING_REJ", statep);
ibcm_post_rc_mad(statep, statep->stored_msg, ibcm_post_rej_complete,
statep);
}
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)
{
ibcm_rej_msg_t *rej_msg;
ibmf_msg_t *cm_rej_msg;
ibcm_mad_addr_t rej_reply_addr;
IBTF_DPRINTF_L3(cmlog, "ibcm_build_n_post_rej_mad: "
"remote_comid: %x reject_reason %d", remote_comid, reject_reason);
if (ibcm_alloc_out_msg(cm_mad_addr->ibmf_hdl, &cm_rej_msg,
MAD_METHOD_SEND) != IBT_SUCCESS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_build_n_post_rej_mad: "
"ibcm_alloc_out_msg failed");
return;
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rej_msg))
IBCM_OUT_HDRP(cm_rej_msg)->TransactionID =
((ib_mad_hdr_t *)(input_madp))->TransactionID;
rej_msg = (ibcm_rej_msg_t *)IBCM_OUT_MSGP(cm_rej_msg);
rej_msg->rej_local_comm_id = 0;
rej_msg->rej_remote_comm_id = h2b32(remote_comid);
rej_msg->rej_msg_type_plus = (which_msg & 0x3) << 6;
rej_msg->rej_reject_info_len_plus = 0;
rej_msg->rej_rejection_reason = h2b16(reject_reason);
IBCM_OUT_HDRP(cm_rej_msg)->AttributeID =
h2b16(IBCM_INCOMING_REJ + IBCM_ATTR_BASE_ID);
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*rej_msg))
ibcm_build_reply_mad_addr(cm_mad_addr, &rej_reply_addr);
if (rej_reply_addr.cm_qp_entry != NULL) {
(void) ibcm_post_mad(cm_rej_msg, &rej_reply_addr, NULL, NULL);
ibcm_release_qp(rej_reply_addr.cm_qp_entry);
}
(void) ibcm_free_out_msg(cm_mad_addr->ibmf_hdl, &cm_rej_msg);
}
static void
ibcm_post_rej_ver_mismatch(uint8_t *input_madp, ibcm_mad_addr_t *cm_mad_addr)
{
ibcm_req_msg_t *req_msgp =
(ibcm_req_msg_t *)&input_madp[IBCM_MAD_HDR_SIZE];
ibcm_rej_msg_t *rej_msg;
ibmf_msg_t *cm_rej_msg;
ibcm_mad_addr_t rej_reply_addr;
IBTF_DPRINTF_L3(cmlog, "ibcm_post_rej_ver_mismatch: remote comid %x",
b2h32(req_msgp->req_local_comm_id));
if (ibcm_alloc_out_msg(cm_mad_addr->ibmf_hdl, &cm_rej_msg,
MAD_METHOD_SEND) != IBT_SUCCESS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_post_rej_ver_mismatch: "
"ibcm_alloc_out_msg failed");
return;
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rej_msg))
IBCM_OUT_HDRP(cm_rej_msg)->TransactionID =
((ib_mad_hdr_t *)(input_madp))->TransactionID;
rej_msg = (ibcm_rej_msg_t *)IBCM_OUT_MSGP(cm_rej_msg);
rej_msg->rej_local_comm_id = 0;
rej_msg->rej_remote_comm_id = req_msgp->req_local_comm_id;
rej_msg->rej_msg_type_plus = IBT_CM_FAILURE_REQ << 6;
rej_msg->rej_rejection_reason = h2b16(IBT_CM_CLASS_NO_SUPPORT);
rej_msg->rej_reject_info_len_plus = 1 << 1;
rej_msg->rej_addl_rej_info[0] = IBCM_MAD_CLASS_VERSION;
IBCM_OUT_HDRP(cm_rej_msg)->AttributeID =
h2b16(IBCM_INCOMING_REJ + IBCM_ATTR_BASE_ID);
IBCM_OUT_HDRP(cm_rej_msg)->Status = h2b16(MAD_STATUS_BAD_VERSION);
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*rej_msg))
ibcm_build_reply_mad_addr(cm_mad_addr, &rej_reply_addr);
if (rej_reply_addr.cm_qp_entry != NULL) {
(void) ibcm_post_mad(cm_rej_msg, &rej_reply_addr, NULL, NULL);
ibcm_release_qp(rej_reply_addr.cm_qp_entry);
}
(void) ibcm_free_out_msg(cm_mad_addr->ibmf_hdl, &cm_rej_msg);
}
void
ibcm_post_rep_mad(ibcm_state_data_t *statep)
{
ibcm_rep_msg_t *rep_msgp =
(ibcm_rep_msg_t *)IBCM_OUT_MSGP(statep->stored_msg);
ibmf_msg_t *mra_msg = NULL;
boolean_t ret = B_FALSE;
IBTF_DPRINTF_L4(cmlog, "ibcm_post_rep_mad: statep 0x%p", statep);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rep_msgp))
rep_msgp->rep_local_comm_id = h2b32(statep->local_comid);
rep_msgp->rep_remote_comm_id = h2b32(statep->remote_comid);
IBCM_OUT_HDRP(statep->stored_msg)->AttributeID =
h2b16(IBCM_INCOMING_REP + IBCM_ATTR_BASE_ID);
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*rep_msgp))
mutex_enter(&statep->state_mutex);
if (statep->mra_msg != NULL) {
if (!(statep->send_mad_flags & IBCM_MRA_POST_BUSY)) {
mra_msg = statep->mra_msg;
statep->mra_msg = NULL;
} else statep->delete_mra_msg = B_TRUE;
}
if (statep->abort_flag == IBCM_ABORT_CLIENT) {
statep->state = IBCM_STATE_ABORTED;
mutex_exit(&statep->state_mutex);
ibcm_process_abort(statep);
ibcm_post_rej_mad(statep, IBT_CM_CONSUMER, IBT_CM_FAILURE_REQ,
NULL, 0);
ret = B_TRUE;
} else if (statep->abort_flag & IBCM_ABORT_REJ) {
statep->state = IBCM_STATE_DELETE;
mutex_exit(&statep->state_mutex);
ibcm_process_abort(statep);
ibcm_delete_state_data(statep);
ret = B_TRUE;
} else {
statep->state = statep->timer_stored_state =
IBCM_STATE_REP_SENT;
statep->remaining_retry_cnt = statep->max_cm_retries;
statep->send_mad_flags |= IBCM_REP_POST_BUSY;
IBCM_REF_CNT_INCR(statep);
mutex_exit(&statep->state_mutex);
}
if (mra_msg != NULL)
(void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl,
&mra_msg);
if (ret == B_TRUE)
return;
ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_REP);
ibcm_post_rc_mad(statep, statep->stored_msg, ibcm_post_rep_complete,
statep);
}
ibcm_status_t
ibcm_post_rtu_mad(ibcm_state_data_t *statep)
{
ibcm_rtu_msg_t *rtu_msg;
ibmf_msg_t *mra_msg = NULL;
boolean_t ret = B_FALSE;
IBTF_DPRINTF_L4(cmlog, "ibcm_post_rtu_mad: statep 0x%p", statep);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rtu_msg))
rtu_msg = (ibcm_rtu_msg_t *)IBCM_OUT_MSGP(statep->stored_msg);
rtu_msg->rtu_local_comm_id = h2b32(statep->local_comid);
rtu_msg->rtu_remote_comm_id = h2b32(statep->remote_comid);
IBCM_OUT_HDRP(statep->stored_msg)->AttributeID =
h2b16(IBCM_INCOMING_RTU + IBCM_ATTR_BASE_ID);
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*rtu_msg))
mutex_enter(&statep->state_mutex);
if (statep->mra_msg != NULL) {
if (!(statep->send_mad_flags & IBCM_MRA_POST_BUSY)) {
mra_msg = statep->mra_msg;
statep->mra_msg = NULL;
} else statep->delete_mra_msg = B_TRUE;
}
if (statep->abort_flag == IBCM_ABORT_CLIENT) {
statep->state = IBCM_STATE_ABORTED;
mutex_exit(&statep->state_mutex);
ibcm_process_abort(statep);
ibcm_post_rej_mad(statep, IBT_CM_CONSUMER, IBT_CM_FAILURE_REP,
NULL, 0);
ret = B_TRUE;
} else if (statep->abort_flag & IBCM_ABORT_REJ) {
statep->state = IBCM_STATE_DELETE;
mutex_exit(&statep->state_mutex);
ibcm_process_abort(statep);
ibcm_delete_state_data(statep);
ret = B_TRUE;
} else {
statep->state = IBCM_STATE_ESTABLISHED;
ibtl_cm_chan_is_open(statep->channel);
statep->send_mad_flags |= IBCM_RTU_POST_BUSY;
IBCM_REF_CNT_INCR(statep);
mutex_exit(&statep->state_mutex);
}
if (mra_msg != NULL)
(void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl,
&mra_msg);
if (ret == B_TRUE)
return (IBCM_FAILURE);
ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_RTU);
ibcm_post_rc_mad(statep, statep->stored_msg, ibcm_post_rtu_complete,
statep);
return (IBCM_SUCCESS);
}
void
ibcm_process_abort(ibcm_state_data_t *statep)
{
IBTF_DPRINTF_L3(cmlog, "ibcm_process_abort: statep 0x%p", statep);
(void) ibcm_cep_to_error_state(statep);
IBCM_SET_CHAN_PRIVATE(statep->channel, NULL);
if (statep->cm_handler) {
ibt_cm_event_t event;
ibt_cm_return_args_t ret_args;
bzero(&event, sizeof (event));
bzero(&ret_args, sizeof (ret_args));
if (statep->abort_flag & IBCM_ABORT_REJ)
ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_RCV,
IBT_CM_FAILURE_UNKNOWN, IBT_CM_TIMEOUT, NULL, 0);
else {
ibcm_path_cache_purge();
event.cm_type = IBT_CM_EVENT_CONN_CLOSED;
event.cm_channel = statep->channel;
event.cm_event.closed = IBT_CM_CLOSED_ABORT;
ibcm_insert_trace(statep,
IBCM_TRACE_CALLED_CONN_CLOSE_EVENT);
if (statep->channel)
ibtl_cm_chan_open_is_aborted(statep->channel);
(void) statep->cm_handler(statep->state_cm_private,
&event, &ret_args, NULL, 0);
ibcm_insert_trace(statep,
IBCM_TRACE_RET_CONN_CLOSE_EVENT);
mutex_enter(&statep->state_mutex);
ibcm_open_done(statep);
mutex_exit(&statep->state_mutex);
}
}
mutex_enter(&statep->state_mutex);
statep->cm_retries++;
statep->open_done = B_TRUE;
statep->close_done = B_TRUE;
statep->close_nocb_state = IBCM_FAIL;
if (statep->open_return_data != NULL) {
if (statep->abort_flag & IBCM_ABORT_REJ)
statep->open_return_data->rc_status = IBT_CM_TIMEOUT;
else statep->open_return_data->rc_status = IBT_CM_ABORT;
}
cv_broadcast(&statep->block_client_cv);
mutex_exit(&statep->state_mutex);
if (ibcm_enable_trace != 0)
ibcm_dump_conn_trace(statep);
}
void
ibcm_timeout_cb(void *arg)
{
ibcm_state_data_t *statep = (ibcm_state_data_t *)arg;
mutex_enter(&statep->state_mutex);
if ((statep->timer_stored_state != statep->state) ||
((statep->timer_stored_state == IBCM_STATE_ESTABLISHED) &&
(statep->ap_state != statep->timer_stored_ap_state))) {
mutex_exit(&statep->state_mutex);
return;
}
IBTF_DPRINTF_L3(cmlog, "ibcm_timeout_cb: statep 0x%p state %x "
"ap_state %x", statep, statep->state, statep->ap_state);
if (statep->state == IBCM_STATE_REJ_SENT) {
statep->state = IBCM_STATE_DELETE;
mutex_exit(&statep->state_mutex);
ibcm_delete_state_data(statep);
return;
} else if (statep->state == IBCM_STATE_TIMEWAIT) {
statep->state = IBCM_STATE_DELETE;
mutex_exit(&statep->state_mutex);
if (statep->channel)
ibtl_cm_chan_is_closed(statep->channel);
if (statep->recycle_arg) {
struct ibcm_taskq_recycle_arg_s *recycle_arg;
recycle_arg = statep->recycle_arg;
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(
statep->recycle_arg))
statep->recycle_arg = NULL;
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(statep->recycle_arg))
if (taskq_dispatch(ibcm_taskq, ibcm_process_rc_recycle,
recycle_arg, TQ_NOQUEUE | TQ_NOSLEEP) ==
TASKQID_INVALID) {
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(
statep->recycle_arg))
statep->recycle_arg = recycle_arg;
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(
statep->recycle_arg))
ibcm_add_tlist(statep);
return;
}
}
ibcm_delete_state_data(statep);
return;
} else if (statep->remaining_retry_cnt > 0) {
ibcm_conn_state_t stored_state;
ibcm_ap_state_t stored_ap_state;
statep->remaining_retry_cnt--;
IBTF_DPRINTF_L3(cmlog, "ibcm_timeout_cb: statep 0x%p "
"attr-id= 0x%x, retries remaining = 0x%x", statep,
b2h16(IBCM_OUT_HDRP(statep->stored_msg)->AttributeID),
statep->remaining_retry_cnt);
if (statep->timer_stored_state == IBCM_STATE_REP_SENT) {
if (statep->send_mad_flags & IBCM_REP_POST_BUSY) {
statep->timerid = IBCM_TIMEOUT(statep,
statep->timer_value);
mutex_exit(&statep->state_mutex);
ibcm_insert_trace(statep,
IBCM_TRACE_TIMEOUT_REP);
return;
}
statep->send_mad_flags |= IBCM_REP_POST_BUSY;
} else if (statep->timer_stored_state == IBCM_STATE_REQ_SENT) {
ASSERT((statep->send_mad_flags & IBCM_REQ_POST_BUSY)
== 0);
statep->send_mad_flags |= IBCM_REQ_POST_BUSY;
}
IBCM_REF_CNT_INCR(statep);
stored_state = statep->timer_stored_state;
stored_ap_state = statep->timer_stored_ap_state;
mutex_exit(&statep->state_mutex);
if (stored_state == IBCM_STATE_REQ_SENT) {
ibcm_insert_trace(statep, IBCM_TRACE_OUT_REQ_RETRY);
ibcm_post_rc_mad(statep, statep->stored_msg,
ibcm_post_req_complete, statep);
} else if (stored_state == IBCM_STATE_REP_WAIT) {
ibcm_insert_trace(statep, IBCM_TRACE_OUT_REQ_RETRY);
ibcm_post_rc_mad(statep, statep->stored_msg,
ibcm_post_rep_wait_complete, statep);
} else if (stored_state == IBCM_STATE_REP_SENT) {
ibcm_insert_trace(statep, IBCM_TRACE_OUT_REP_RETRY);
ibcm_post_rc_mad(statep, statep->stored_msg,
ibcm_post_rep_complete, statep);
} else if (stored_state == IBCM_STATE_MRA_REP_RCVD) {
ibcm_insert_trace(statep, IBCM_TRACE_OUT_REP_RETRY);
mutex_enter(&statep->state_mutex);
statep->mra_time = gethrtime();
mutex_exit(&statep->state_mutex);
ibcm_post_rc_mad(statep, statep->stored_msg,
ibcm_post_mra_rep_complete, statep);
} else if (stored_state == IBCM_STATE_DREQ_SENT) {
mutex_enter(&statep->state_mutex);
if (statep->remaining_retry_cnt ==
statep->max_cm_retries)
ibcm_insert_trace(statep,
IBCM_TRACE_OUTGOING_DREQ);
else {
ibcm_insert_trace(statep,
IBCM_TRACE_OUT_DREQ_RETRY);
statep->cm_retries++;
ibcm_close_done(statep, 0);
}
mutex_exit(&statep->state_mutex);
ibcm_post_rc_mad(statep, statep->dreq_msg,
ibcm_post_dreq_complete, statep);
} else if (stored_ap_state == IBCM_AP_STATE_LAP_SENT) {
ibcm_insert_trace(statep, IBCM_TRACE_OUT_LAP_RETRY);
ibcm_post_rc_mad(statep, statep->lapr_msg,
ibcm_post_lap_complete, statep);
} else if (stored_ap_state == IBCM_AP_STATE_MRA_LAP_RCVD) {
ibcm_insert_trace(statep, IBCM_TRACE_OUT_LAP_RETRY);
mutex_enter(&statep->state_mutex);
statep->mra_time = gethrtime();
mutex_exit(&statep->state_mutex);
ibcm_post_rc_mad(statep, statep->lapr_msg,
ibcm_post_mra_lap_complete, statep);
}
return;
} else if ((statep->state == IBCM_STATE_REQ_SENT) ||
(statep->state == IBCM_STATE_REP_SENT) ||
(statep->state == IBCM_STATE_MRA_REP_RCVD) ||
(statep->state == IBCM_STATE_REP_WAIT)) {
statep->timedout_state = statep->state;
statep->state = IBCM_STATE_TIMED_OUT;
IBTF_DPRINTF_L3(cmlog, "ibcm_timeout_cb: "
"max retries done for statep 0x%p", statep);
statep->cm_retries++;
mutex_exit(&statep->state_mutex);
if ((statep->timedout_state == IBCM_STATE_REP_SENT) ||
(statep->timedout_state == IBCM_STATE_MRA_REP_RCVD))
(void) ibcm_cep_to_error_state(statep);
IBCM_SET_CHAN_PRIVATE(statep->channel, NULL);
if (statep->cm_handler != NULL) {
ibcm_add_tlist(statep);
} else {
ib_guid_t local_hca_guid;
mutex_enter(&statep->state_mutex);
if (statep->open_return_data != NULL) {
statep->open_return_data->rc_status =
IBT_CM_TIMEOUT;
statep->open_done = B_TRUE;
cv_broadcast(&statep->block_client_cv);
}
mutex_exit(&statep->state_mutex);
local_hca_guid = h2b64(statep->local_hca_guid);
ibcm_post_rej_mad(statep, IBT_CM_TIMEOUT,
(statep->timedout_state == IBCM_STATE_REP_SENT ||
statep->timedout_state == IBCM_STATE_MRA_REP_RCVD) ?
IBT_CM_FAILURE_REP: IBT_CM_FAILURE_REQ,
&local_hca_guid, sizeof (ib_guid_t));
}
} else if ((statep->ap_state == IBCM_AP_STATE_LAP_SENT) ||
(statep->ap_state == IBCM_AP_STATE_MRA_LAP_RCVD)) {
IBTF_DPRINTF_L4(cmlog, "ibcm_timeout_cb: statep 0x%p "
"LAP timed out", statep);
statep->timedout_state = statep->state;
statep->ap_state = IBCM_AP_STATE_TIMED_OUT;
ibcm_open_done(statep);
if (statep->cm_handler != NULL) {
ibcm_add_tlist(statep);
} else if (statep->ap_return_data != NULL) {
statep->ap_return_data->ap_status = IBT_CM_AP_TIMEOUT;
statep->ap_done = B_TRUE;
cv_broadcast(&statep->block_client_cv);
statep->ap_state = IBCM_AP_STATE_IDLE;
cv_broadcast(&statep->block_mad_cv);
}
mutex_exit(&statep->state_mutex);
} else if (statep->state == IBCM_STATE_DREQ_SENT) {
statep->timedout_state = statep->state;
statep->state = IBCM_STATE_TIMED_OUT;
if (statep->close_nocb_state != IBCM_FAIL) {
ASSERT(statep->close_nocb_state == IBCM_UNBLOCK);
ibtl_cm_chan_is_closing(statep->channel);
statep->close_nocb_state = IBCM_BLOCK;
}
mutex_exit(&statep->state_mutex);
if (statep->cm_handler != NULL) {
ibcm_add_tlist(statep);
return;
}
ibcm_process_dreq_timeout(statep);
} else {
#ifdef DEBUG
if (ibcm_test_mode > 0)
IBTF_DPRINTF_L2(cmlog, "ibcm_timeout_cb: "
"Unexpected unhandled timeout for statep 0x%p "
"state %d", statep, statep->state);
#endif
mutex_exit(&statep->state_mutex);
}
}
void
ibcm_post_req_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, void *args)
{
ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
IBTF_DPRINTF_L4(cmlog, "ibcm_post_req_complete statep %p ", statep);
mutex_enter(&statep->state_mutex);
ibcm_flow_dec(statep->post_time, "REQ");
ibcm_insert_trace(statep, IBCM_TRACE_REQ_POST_COMPLETE);
statep->send_mad_flags &= ~IBCM_REQ_POST_BUSY;
cv_signal(&statep->block_mad_cv);
if (statep->state == IBCM_STATE_REQ_SENT)
statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
void
ibcm_post_rep_wait_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
void *args)
{
ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
IBTF_DPRINTF_L4(cmlog, "ibcm_post_rep_wait_complete statep %p", statep);
mutex_enter(&statep->state_mutex);
ibcm_flow_dec(statep->post_time, "REQ_RETRY");
ibcm_insert_trace(statep, IBCM_TRACE_REQ_POST_COMPLETE);
if (statep->state == IBCM_STATE_REP_WAIT)
statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
void
ibcm_post_rep_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, void *args)
{
ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
IBTF_DPRINTF_L4(cmlog, "ibcm_post_rep_complete statep %p", statep);
mutex_enter(&statep->state_mutex);
ibcm_flow_dec(statep->post_time, "REP");
ibcm_insert_trace(statep, IBCM_TRACE_REP_POST_COMPLETE);
statep->send_mad_flags &= ~IBCM_REP_POST_BUSY;
if (statep->state == IBCM_STATE_REP_SENT)
statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
void
ibcm_resend_post_rep_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
void *args)
{
ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
IBTF_DPRINTF_L4(cmlog, "ibcm_resend_post_rep_complete(%p)", statep);
mutex_enter(&statep->state_mutex);
ibcm_flow_dec(statep->post_time, "REP_RETRY");
ibcm_insert_trace(statep, IBCM_TRACE_REP_POST_COMPLETE);
statep->send_mad_flags &= ~IBCM_REP_POST_BUSY;
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
void
ibcm_post_mra_rep_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
void *args)
{
ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
IBTF_DPRINTF_L4(cmlog, "ibcm_post_mra_rep_complete statep %p", statep);
mutex_enter(&statep->state_mutex);
ibcm_flow_dec(statep->mra_time, "MRA_REP");
ibcm_insert_trace(statep, IBCM_TRACE_REP_POST_COMPLETE);
if (statep->state == IBCM_STATE_MRA_REP_RCVD)
statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
void
ibcm_post_mra_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
void *args)
{
ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
IBTF_DPRINTF_L4(cmlog, "ibcm_post_mra_complete statep %p", statep);
mutex_enter(&statep->state_mutex);
ibcm_flow_dec(statep->mra_time, "MRA");
ibcm_insert_trace(statep, IBCM_TRACE_MRA_POST_COMPLETE);
if (statep->delete_mra_msg == B_TRUE) {
ibmf_msg_t *mra_msg;
mra_msg = statep->mra_msg;
statep->mra_msg = NULL;
mutex_exit(&statep->state_mutex);
(void) ibcm_free_out_msg(statep->stored_reply_addr.ibmf_hdl,
&mra_msg);
mutex_enter(&statep->state_mutex);
}
statep->send_mad_flags &= ~IBCM_MRA_POST_BUSY;
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
void
ibcm_post_dreq_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, void *args)
{
ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
IBTF_DPRINTF_L4(cmlog, "ibcm_post_dreq_complete statep %p", statep);
mutex_enter(&statep->state_mutex);
ibcm_flow_dec(statep->post_time, "DREQ");
ibcm_insert_trace(statep, IBCM_TRACE_DREQ_POST_COMPLETE);
if (statep->state == IBCM_STATE_DREQ_SENT)
statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
ibcm_close_done(statep, 1);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
void
ibcm_post_lap_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp, void *args)
{
ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
IBTF_DPRINTF_L4(cmlog, "ibcm_post_lap_complete statep %p", statep);
mutex_enter(&statep->state_mutex);
ibcm_flow_dec(statep->post_time, "LAP");
ibcm_insert_trace(statep, IBCM_TRACE_LAP_POST_COMPLETE);
if (statep->ap_state == IBCM_AP_STATE_LAP_SENT)
statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
void
ibcm_post_mra_lap_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
void *args)
{
ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
IBTF_DPRINTF_L4(cmlog, "ibcm_post_mra_lap_complete statep %p", statep);
mutex_enter(&statep->state_mutex);
ibcm_flow_dec(statep->mra_time, "MRA_LAP");
ibcm_insert_trace(statep, IBCM_TRACE_LAP_POST_COMPLETE);
if (statep->ap_state == IBCM_AP_STATE_MRA_LAP_RCVD)
statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
void
ibcm_post_rej_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
void *args)
{
ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
IBTF_DPRINTF_L4(cmlog, "ibcm_post_rej_complete statep %p", statep);
mutex_enter(&statep->state_mutex);
ibcm_flow_dec(statep->post_time, "REJ");
ibcm_insert_trace(statep, IBCM_TRACE_REJ_POST_COMPLETE);
statep->send_mad_flags &= ~IBCM_REJ_POST_BUSY;
if (statep->state == IBCM_STATE_REJ_SENT) {
statep->remaining_retry_cnt = 0;
statep->timerid = IBCM_TIMEOUT(statep,
statep->timer_value * statep->max_cm_retries);
}
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
void
ibcm_post_rtu_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
void *args)
{
ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
IBTF_DPRINTF_L4(cmlog, "ibcm_post_rtu_complete statep %p", statep);
mutex_enter(&statep->state_mutex);
ibcm_flow_dec(statep->post_time, "RTU");
ibcm_insert_trace(statep, IBCM_TRACE_RTU_POST_COMPLETE);
statep->send_mad_flags &= ~IBCM_RTU_POST_BUSY;
IBCM_REF_CNT_DECR(statep);
ibcm_open_done(statep);
mutex_exit(&statep->state_mutex);
}
void
ibcm_post_apr_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
void *args)
{
ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
IBTF_DPRINTF_L4(cmlog, "ibcm_post_apr_complete statep %p", statep);
mutex_enter(&statep->state_mutex);
ibcm_flow_dec(statep->post_time, "APR");
ibcm_insert_trace(statep, IBCM_TRACE_APR_POST_COMPLETE);
statep->ap_state = IBCM_AP_STATE_IDLE;
cv_broadcast(&statep->block_mad_cv);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
void
ibcm_post_stored_apr_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
void *args)
{
ibmf_msg_t *ibmf_apr_msg = (ibmf_msg_t *)args;
IBTF_DPRINTF_L4(cmlog, "ibcm_post_stored_apr_complete args %p", args);
ibcm_flow_dec(0, "APR_RESEND");
(void) ibcm_free_out_msg(ibmf_handle, &ibmf_apr_msg);
}
void
ibcm_post_drep_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
void *args)
{
ibcm_state_data_t *statep = (ibcm_state_data_t *)args;
IBTF_DPRINTF_L4(cmlog, "ibcm_post_drep_complete statep %p", statep);
mutex_enter(&statep->state_mutex);
ibcm_flow_dec(statep->post_time, "DREP");
ibcm_insert_trace(statep, IBCM_TRACE_DREP_POST_COMPLETE);
statep->send_mad_flags &= ~IBCM_REJ_POST_BUSY;
if (statep->state == IBCM_STATE_DREQ_RCVD) {
ibcm_close_done(statep, 1);
statep->state = IBCM_STATE_TIMEWAIT;
statep->timer_value = statep->remote_ack_delay;
if (statep->mode == IBCM_ACTIVE_MODE)
statep->timer_value += (2 * statep->pkt_life_time);
statep->remaining_retry_cnt = 0;
statep->timer_stored_state = statep->state;
statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
}
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
void
ibcm_post_sidr_rep_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
void *args)
{
ibcm_ud_state_data_t *ud_statep = (ibcm_ud_state_data_t *)args;
IBTF_DPRINTF_L4(cmlog, "ibcm_post_sidr_rep_complete ud_statep %p",
ud_statep);
ibcm_flow_dec(0, "SIDR_REP");
mutex_enter(&ud_statep->ud_state_mutex);
ud_statep->ud_send_mad_flags &= ~IBCM_SREP_POST_BUSY;
ud_statep->ud_remaining_retry_cnt = 0;
if (ud_statep->ud_state == IBCM_STATE_SIDR_REP_SENT)
ud_statep->ud_timerid = IBCM_UD_TIMEOUT(ud_statep,
ud_statep->ud_timer_value);
IBCM_UD_REF_CNT_DECR(ud_statep);
mutex_exit(&ud_statep->ud_state_mutex);
}
void
ibcm_post_sidr_req_complete(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
void *args)
{
ibcm_ud_state_data_t *ud_statep = (ibcm_ud_state_data_t *)args;
IBTF_DPRINTF_L4(cmlog, "ibcm_post_sidr_req_complete ud_statep %p",
ud_statep);
ibcm_flow_dec(0, "SIDR_REQ");
mutex_enter(&ud_statep->ud_state_mutex);
if (ud_statep->ud_state == IBCM_STATE_SIDR_REQ_SENT)
ud_statep->ud_timerid = IBCM_UD_TIMEOUT(ud_statep,
ud_statep->ud_timer_value);
IBCM_UD_REF_CNT_DECR(ud_statep);
mutex_exit(&ud_statep->ud_state_mutex);
}
void
ibcm_process_dreq_timeout(ibcm_state_data_t *statep)
{
mutex_enter(&statep->state_mutex);
statep->state = statep->timer_stored_state =
IBCM_STATE_TIMEWAIT;
ibcm_close_done(statep, 0);
statep->timer_value = statep->remote_ack_delay;
if (statep->mode == IBCM_ACTIVE_MODE) {
statep->timer_value += (2 * statep->pkt_life_time);
}
statep->timerid = IBCM_TIMEOUT(statep, statep->timer_value);
if (statep->close_ret_status)
if (statep->stale == B_TRUE)
*statep->close_ret_status = IBT_CM_CLOSED_STALE;
else *statep->close_ret_status = IBT_CM_CLOSED_DREQ_TIMEOUT;
statep->close_done = B_TRUE;
if (statep->close_ret_priv_data_len != NULL)
*statep->close_ret_priv_data_len = 0;
statep->close_nocb_state = IBCM_FAIL;
cv_broadcast(&statep->block_client_cv);
mutex_exit(&statep->state_mutex);
}
void
ibcm_add_tlist(ibcm_state_data_t *statep)
{
mutex_enter(&ibcm_timeout_list_lock);
statep->timeout_next = NULL;
if (ibcm_timeout_list_hdr == NULL) {
ibcm_timeout_list_hdr = statep;
} else {
ibcm_timeout_list_tail->timeout_next = statep;
}
ibcm_timeout_list_tail = statep;
cv_signal(&ibcm_timeout_list_cv);
mutex_exit(&ibcm_timeout_list_lock);
IBTF_DPRINTF_L3(cmlog, "ibcm_add_tlist: "
"attached state = %p to timeout list", statep);
}
void
ibcm_run_tlist_thread(void)
{
mutex_enter(&ibcm_timeout_list_lock);
cv_signal(&ibcm_timeout_list_cv);
mutex_exit(&ibcm_timeout_list_lock);
}
void
ibcm_add_ud_tlist(ibcm_ud_state_data_t *ud_statep)
{
mutex_enter(&ibcm_timeout_list_lock);
ud_statep->ud_timeout_next = NULL;
if (ibcm_ud_timeout_list_hdr == NULL) {
ibcm_ud_timeout_list_hdr = ud_statep;
} else {
ibcm_ud_timeout_list_tail->ud_timeout_next = ud_statep;
}
ibcm_ud_timeout_list_tail = ud_statep;
cv_signal(&ibcm_timeout_list_cv);
mutex_exit(&ibcm_timeout_list_lock);
IBTF_DPRINTF_L3(cmlog, "ibcm_add_ud_tlist: "
"attached state = %p to ud timeout list", ud_statep);
}
void
ibcm_process_tlist()
{
ibcm_state_data_t *statep;
ibcm_ud_state_data_t *ud_statep;
callb_cpr_t cprinfo;
IBTF_DPRINTF_L5(cmlog, "ibcm_process_tlist: thread started");
mutex_enter(&ibcm_timeout_list_lock);
CALLB_CPR_INIT(&cprinfo, &ibcm_timeout_list_lock, callb_generic_cpr,
"ibcm_process_tlist");
for (;;) {
if (ibcm_timeout_list_flags & IBCM_TIMEOUT_THREAD_EXIT) {
cv_signal(&ibcm_timeout_thread_done_cv);
break;
}
mutex_exit(&ibcm_timeout_list_lock);
ibcm_check_for_opens();
ibcm_check_for_async_close();
mutex_enter(&ibcm_timeout_list_lock);
if (ibcm_timeout_list_hdr != NULL) {
statep = ibcm_timeout_list_hdr;
ibcm_timeout_list_hdr = statep->timeout_next;
if (ibcm_timeout_list_hdr == NULL)
ibcm_timeout_list_tail = NULL;
statep->timeout_next = NULL;
mutex_exit(&ibcm_timeout_list_lock);
IBTF_DPRINTF_L3(cmlog, "ibcm_process_tlist: "
"scheduling state = %p", statep);
ibcm_timeout_client_cb(statep);
mutex_enter(&ibcm_timeout_list_lock);
} else if (ibcm_ud_timeout_list_hdr != NULL) {
ud_statep = ibcm_ud_timeout_list_hdr;
ibcm_ud_timeout_list_hdr = ud_statep->ud_timeout_next;
if (ibcm_ud_timeout_list_hdr == NULL)
ibcm_ud_timeout_list_tail = NULL;
ud_statep->ud_timeout_next = NULL;
mutex_exit(&ibcm_timeout_list_lock);
IBTF_DPRINTF_L3(cmlog, "ibcm_process_tlist: "
"ud scheduling state = %p", ud_statep);
ibcm_ud_timeout_client_cb(ud_statep);
mutex_enter(&ibcm_timeout_list_lock);
} else {
CALLB_CPR_SAFE_BEGIN(&cprinfo);
cv_wait(&ibcm_timeout_list_cv, &ibcm_timeout_list_lock);
CALLB_CPR_SAFE_END(&cprinfo, &ibcm_timeout_list_lock);
}
}
#ifndef __lock_lint
CALLB_CPR_EXIT(&cprinfo);
#endif
}
void
ibcm_timeout_client_cb(ibcm_state_data_t *statep)
{
mutex_enter(&statep->state_mutex);
if ((statep->state == IBCM_STATE_DELETE) &&
(statep->recycle_arg != NULL)) {
struct ibcm_taskq_recycle_arg_s *recycle_arg;
recycle_arg = statep->recycle_arg;
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(statep->recycle_arg))
statep->recycle_arg = NULL;
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(statep->recycle_arg))
mutex_exit(&statep->state_mutex);
(void) ibcm_process_rc_recycle(recycle_arg);
ibcm_delete_state_data(statep);
return;
}
if ((statep->state == IBCM_STATE_DELETE) &&
(statep->delete_state_data == B_TRUE)) {
mutex_exit(&statep->state_mutex);
ibcm_dealloc_state_data(statep);
return;
}
if (statep->state == IBCM_STATE_TIMED_OUT) {
void *data;
uint8_t cf_msg;
ib_guid_t local_hca_guid;
mutex_exit(&statep->state_mutex);
if (statep->timedout_state == IBCM_STATE_DREQ_SENT) {
ibt_cm_event_t event;
ibt_cm_return_args_t ret_args;
bzero(&event, sizeof (event));
bzero(&ret_args, sizeof (ret_args));
event.cm_type = IBT_CM_EVENT_CONN_CLOSED;
event.cm_channel = statep->channel;
event.cm_session_id = NULL;
event.cm_priv_data = NULL;
event.cm_priv_data_len = 0;
if (statep->stale == B_TRUE)
event.cm_event.closed = IBT_CM_CLOSED_STALE;
else event.cm_event.closed = IBT_CM_CLOSED_DREQ_TIMEOUT;
ibcm_insert_trace(statep,
IBCM_TRACE_CALLED_CONN_CLOSE_EVENT);
(void) statep->cm_handler(statep->state_cm_private,
&event, &ret_args, NULL, 0);
ibcm_insert_trace(statep,
IBCM_TRACE_RET_CONN_CLOSE_EVENT);
ibcm_process_dreq_timeout(statep);
return;
}
data = ((ibcm_rej_msg_t *)
IBCM_OUT_MSGP(statep->stored_msg))->rej_private_data;
if ((statep->timedout_state == IBCM_STATE_REQ_SENT) ||
(statep->timedout_state == IBCM_STATE_REP_WAIT)) {
cf_msg = IBT_CM_FAILURE_REQ;
} else {
ASSERT(
(statep->timedout_state == IBCM_STATE_REP_SENT) ||
(statep->timedout_state ==
IBCM_STATE_MRA_REP_RCVD));
cf_msg = IBT_CM_FAILURE_REP;
}
ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_TIMEOUT,
cf_msg, IBT_CM_TIMEOUT, data, IBT_REJ_PRIV_DATA_SZ);
mutex_enter(&statep->state_mutex);
if (statep->open_return_data != NULL) {
statep->open_return_data->rc_status = IBT_CM_TIMEOUT;
statep->open_done = B_TRUE;
cv_broadcast(&statep->block_client_cv);
}
mutex_exit(&statep->state_mutex);
local_hca_guid = h2b64(statep->local_hca_guid);
ibcm_post_rej_mad(statep, IBT_CM_TIMEOUT,
IBT_CM_FAILURE_UNKNOWN, &local_hca_guid,
sizeof (ib_guid_t));
} else if (statep->ap_state == IBCM_AP_STATE_TIMED_OUT) {
mutex_exit(&statep->state_mutex);
ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_TIMEOUT,
IBT_CM_FAILURE_LAP, IBT_CM_TIMEOUT, NULL, 0);
mutex_enter(&statep->state_mutex);
if (statep->ap_return_data != NULL) {
statep->ap_return_data->ap_status = IBT_CM_AP_TIMEOUT;
statep->ap_done = B_TRUE;
cv_broadcast(&statep->block_client_cv);
}
statep->ap_state = IBCM_AP_STATE_IDLE;
cv_broadcast(&statep->block_mad_cv);
mutex_exit(&statep->state_mutex);
} else {
IBTF_DPRINTF_L2(cmlog, "ibcm_timeout_client_cb "
"Unexpected else path statep %p state %d ap_state %d",
statep, statep->state, statep->ap_state);
mutex_exit(&statep->state_mutex);
}
}
void
ibcm_ud_timeout_client_cb(ibcm_ud_state_data_t *ud_statep)
{
ibt_cm_ud_event_t ud_event;
mutex_enter(&ud_statep->ud_state_mutex);
if ((ud_statep->ud_state == IBCM_STATE_DELETE) &&
(ud_statep->ud_delete_state_data == B_TRUE)) {
mutex_exit(&ud_statep->ud_state_mutex);
ibcm_dealloc_ud_state_data(ud_statep);
return;
} else
mutex_exit(&ud_statep->ud_state_mutex);
ud_event.cm_type = IBT_CM_UD_EVENT_SIDR_REP;
ud_event.cm_session_id = NULL;
ud_event.cm_event.sidr_rep.srep_status = IBT_CM_SREP_TIMEOUT;
(void) ud_statep->ud_cm_handler(ud_statep->ud_state_cm_private,
&ud_event, NULL, NULL, 0);
ibcm_delete_ud_state_data(ud_statep);
}
void
ibcm_process_sidr_req_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
ibcm_mad_addr_t *cm_mad_addr)
{
ib_gid_t gid;
ib_lid_t lid;
uint32_t req_id;
ibcm_status_t state_lookup_status;
ibcm_status_t cm_status;
ibt_sidr_status_t sidr_status;
ibcm_svc_info_t *svc_infop;
ibcm_svc_bind_t *svc_bindp;
ibcm_svc_bind_t *tmp_bindp;
ibcm_sidr_req_msg_t *sidr_reqp = (ibcm_sidr_req_msg_t *)
(&input_madp[IBCM_MAD_HDR_SIZE]);
ibcm_ud_state_data_t *ud_statep = NULL;
ibcm_sidr_srch_t srch_sidr;
ib_pkey_t pkey;
uint8_t port_num;
ib_guid_t hca_guid;
IBTF_DPRINTF_L4(cmlog, "ibcm_process_sidr_req_msg:");
hca_guid = hcap->hca_guid;
port_num = cm_mad_addr->port_num;
lid = cm_mad_addr->rcvd_addr.ia_remote_lid;
req_id = b2h32(sidr_reqp->sidr_req_request_id);
pkey = b2h16(sidr_reqp->sidr_req_pkey);
if (cm_mad_addr->grh_exists == B_TRUE)
gid = cm_mad_addr->grh_hdr.ig_sender_gid;
else
gid.gid_prefix = gid.gid_guid = 0;
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(srch_sidr))
srch_sidr.srch_lid = lid;
srch_sidr.srch_gid = gid;
srch_sidr.srch_grh_exists = cm_mad_addr->grh_exists;
srch_sidr.srch_req_id = req_id;
srch_sidr.srch_mode = IBCM_PASSIVE_MODE;
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(srch_sidr))
rw_enter(&hcap->hca_sidr_list_lock, RW_WRITER);
state_lookup_status = ibcm_find_sidr_entry(&srch_sidr, hcap, &ud_statep,
IBCM_FLAG_LOOKUP_AND_ADD);
rw_exit(&hcap->hca_sidr_list_lock);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_sidr_req_msg: ud_statep 0x%p "
"lookup status %x", ud_statep, state_lookup_status);
if (state_lookup_status == IBCM_LOOKUP_NEW) {
ibcm_inc_hca_res_cnt(hcap);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ud_statep))
if (ibcm_alloc_out_msg(cm_mad_addr->ibmf_hdl,
&ud_statep->ud_stored_msg, MAD_METHOD_SEND) !=
IBT_SUCCESS) {
mutex_enter(&ud_statep->ud_state_mutex);
IBCM_UD_REF_CNT_DECR(ud_statep);
mutex_exit(&ud_statep->ud_state_mutex);
ibcm_delete_ud_state_data(ud_statep);
return;
}
ud_statep->ud_svc_id = b2h64(sidr_reqp->sidr_req_service_id);
ud_statep->ud_state = IBCM_STATE_SIDR_REQ_RCVD;
ud_statep->ud_clnt_proceed = IBCM_BLOCK;
mutex_enter(&ibcm_svc_info_lock);
svc_infop = ibcm_find_svc_entry(ud_statep->ud_svc_id);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_sidr_req_msg: "
" ud_statep 0x%p svc_info %p", ud_statep, svc_infop);
if (svc_infop != NULL) {
svc_bindp = NULL;
tmp_bindp = svc_infop->svc_bind_list;
while (tmp_bindp) {
if (tmp_bindp->sbind_hcaguid == hca_guid &&
tmp_bindp->sbind_port == port_num) {
if (gid.gid_guid ==
tmp_bindp->sbind_gid.gid_guid &&
gid.gid_prefix ==
tmp_bindp->sbind_gid.gid_prefix) {
svc_bindp = tmp_bindp;
if (pkey ==
tmp_bindp->sbind_pkey)
break;
} else if (svc_bindp == NULL) {
svc_bindp = tmp_bindp;
}
}
tmp_bindp = tmp_bindp->sbind_link;
}
if (svc_bindp == NULL) {
svc_infop = NULL;
}
}
IBCM_OUT_HDRP(ud_statep->ud_stored_msg)->TransactionID =
((ib_mad_hdr_t *)(input_madp))->TransactionID;
ibcm_build_reply_mad_addr(cm_mad_addr,
&ud_statep->ud_stored_reply_addr);
if (ud_statep->ud_stored_reply_addr.cm_qp_entry == NULL) {
mutex_exit(&ibcm_svc_info_lock);
mutex_enter(&ud_statep->ud_state_mutex);
IBCM_UD_REF_CNT_DECR(ud_statep);
ud_statep->ud_state = IBCM_STATE_DELETE;
mutex_exit(&ud_statep->ud_state_mutex);
ibcm_delete_ud_state_data(ud_statep);
return;
}
if (svc_infop == NULL || svc_infop->svc_ud_handler == NULL) {
sidr_status = IBT_CM_SREP_SID_INVALID;
} else {
ud_statep->ud_cm_handler = svc_infop->svc_ud_handler;
ud_statep->ud_state_cm_private =
svc_bindp->sbind_cm_private;
IBCM_SVC_INCR(svc_infop);
mutex_exit(&ibcm_svc_info_lock);
cm_status = ibcm_sidr_req_ud_handler(ud_statep,
sidr_reqp, cm_mad_addr, &sidr_status);
mutex_enter(&ibcm_svc_info_lock);
IBCM_SVC_DECR(svc_infop);
}
mutex_exit(&ibcm_svc_info_lock);
if (cm_status == IBCM_DEFER) {
IBTF_DPRINTF_L4(cmlog, "ibcm_process_sidr_req_msg: "
"ud_statep 0x%p client returned DEFER response",
ud_statep);
return;
}
ibcm_post_sidr_rep_mad(ud_statep, sidr_status);
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*ud_statep))
mutex_enter(&ud_statep->ud_state_mutex);
IBCM_UD_REF_CNT_DECR(ud_statep);
mutex_exit(&ud_statep->ud_state_mutex);
} else {
ASSERT(state_lookup_status == IBCM_LOOKUP_EXISTS);
mutex_enter(&ud_statep->ud_state_mutex);
if (ud_statep->ud_state == IBCM_STATE_SIDR_REP_SENT)
ibcm_resend_srep_mad(ud_statep);
IBCM_UD_REF_CNT_DECR(ud_statep);
mutex_exit(&ud_statep->ud_state_mutex);
}
}
void
ibcm_process_sidr_rep_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
ibcm_mad_addr_t *cm_mad_addr)
{
ib_lid_t lid;
ib_gid_t gid;
ibcm_status_t status;
ib_svc_id_t tmp_svc_id;
ibcm_sidr_rep_msg_t *sidr_repp = (ibcm_sidr_rep_msg_t *)
(&input_madp[IBCM_MAD_HDR_SIZE]);
ibcm_ud_state_data_t *ud_statep = NULL;
ibcm_sidr_srch_t srch_sidr;
IBTF_DPRINTF_L4(cmlog, "ibcm_process_sidr_rep_msg:");
lid = cm_mad_addr->rcvd_addr.ia_local_lid;
if (cm_mad_addr->grh_exists == B_TRUE)
gid = cm_mad_addr->grh_hdr.ig_recver_gid;
else
gid.gid_prefix = gid.gid_guid = 0;
IBTF_DPRINTF_L3(cmlog, "ibcm_process_sidr_rep_msg: QPN rcvd = %x",
h2b32(sidr_repp->sidr_rep_qpn_plus) >> 8);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_sidr_rep: lid=%x, (%llX, %llX), "
"grh = %x, id = %x", lid, gid.gid_prefix, gid.gid_guid,
cm_mad_addr->grh_exists, sidr_repp->sidr_rep_request_id);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(srch_sidr))
srch_sidr.srch_lid = lid;
srch_sidr.srch_gid = gid;
srch_sidr.srch_grh_exists = cm_mad_addr->grh_exists;
srch_sidr.srch_req_id = b2h32(sidr_repp->sidr_rep_request_id);
srch_sidr.srch_mode = IBCM_ACTIVE_MODE;
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(srch_sidr))
rw_enter(&hcap->hca_sidr_list_lock, RW_READER);
status = ibcm_find_sidr_entry(&srch_sidr, hcap, &ud_statep,
IBCM_FLAG_LOOKUP);
rw_exit(&hcap->hca_sidr_list_lock);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_sidr_rep_msg: ud_statep 0x%p "
"find sidr entry status = %x", ud_statep, status);
if (status != IBCM_LOOKUP_EXISTS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_sidr_rep_msg: "
"No matching ud_statep for SIDR REP");
return;
}
if (IBCM_OUT_HDRP(ud_statep->ud_stored_msg)->TransactionID !=
((ib_mad_hdr_t *)(input_madp))->TransactionID) {
mutex_enter(&ud_statep->ud_state_mutex);
IBCM_UD_REF_CNT_DECR(ud_statep);
mutex_exit(&ud_statep->ud_state_mutex);
IBTF_DPRINTF_L2(cmlog, "ibcm_process_sidr_rep_msg: "
"ud_statep 0x%p. A SIDR REP MAD with tid expected 0x%llX "
"tid found 0x%llX req_id %x arrived", ud_statep,
b2h64(
IBCM_OUT_HDRP(ud_statep->ud_stored_msg)->TransactionID),
b2h64(((ib_mad_hdr_t *)(input_madp))->TransactionID),
b2h32(sidr_repp->sidr_rep_request_id));
return;
}
mutex_enter(&ud_statep->ud_state_mutex);
bcopy(sidr_repp->sidr_rep_service_id, &tmp_svc_id, sizeof (tmp_svc_id));
bcopy(&tmp_svc_id, sidr_repp->sidr_rep_service_id, sizeof (tmp_svc_id));
if (ud_statep->ud_svc_id != b2h64(tmp_svc_id)) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_sidr_rep_msg: "
"ud_statep -0x%p svcids do not match %llx %llx",
ud_statep, ud_statep->ud_svc_id, b2h64(tmp_svc_id));
IBCM_UD_REF_CNT_DECR(ud_statep);
mutex_exit(&ud_statep->ud_state_mutex);
return;
}
if (ud_statep->ud_state == IBCM_STATE_SIDR_REQ_SENT) {
timeout_id_t timer_val = ud_statep->ud_timerid;
ud_statep->ud_state = IBCM_STATE_SIDR_REP_RCVD;
ud_statep->ud_timerid = 0;
mutex_exit(&ud_statep->ud_state_mutex);
(void) untimeout(timer_val);
ibcm_sidr_rep_ud_handler(ud_statep, sidr_repp);
mutex_enter(&ud_statep->ud_state_mutex);
ud_statep->ud_state = IBCM_STATE_DELETE;
if (ud_statep->ud_return_data != NULL) {
ibt_priv_data_len_t len;
len = min(ud_statep->ud_return_data->ud_priv_data_len,
IBT_SIDR_REP_PRIV_DATA_SZ);
if ((ud_statep->ud_return_data->ud_priv_data != NULL) &&
(len > 0)) {
bcopy(sidr_repp->sidr_rep_private_data,
ud_statep->ud_return_data->ud_priv_data,
len);
}
ud_statep->ud_return_data->ud_status =
sidr_repp->sidr_rep_rep_status;
if (ud_statep->ud_return_data->ud_status ==
IBT_CM_SREP_QPN_VALID) {
ud_statep->ud_return_data->ud_dqpn =
h2b32(sidr_repp->sidr_rep_qpn_plus) >> 8;
ud_statep->ud_return_data->ud_qkey =
b2h32(sidr_repp->sidr_rep_qkey);
}
ud_statep->ud_blocking_done = B_TRUE;
cv_broadcast(&ud_statep->ud_block_client_cv);
}
IBCM_UD_REF_CNT_DECR(ud_statep);
mutex_exit(&ud_statep->ud_state_mutex);
ibcm_delete_ud_state_data(ud_statep);
} else {
IBTF_DPRINTF_L3(cmlog, "ibcm_process_sidr_rep_msg: "
"ud state is = 0x%x", ud_statep->ud_state);
IBCM_UD_REF_CNT_DECR(ud_statep);
mutex_exit(&ud_statep->ud_state_mutex);
}
}
void
ibcm_post_sidr_rep_mad(ibcm_ud_state_data_t *ud_statep,
ibt_sidr_status_t status)
{
ib_svc_id_t tmp_svc_id;
ibcm_sidr_rep_msg_t *sidr_repp =
(ibcm_sidr_rep_msg_t *)IBCM_OUT_MSGP(ud_statep->ud_stored_msg);
clock_t timer_value;
IBTF_DPRINTF_L5(cmlog, "ibcm_post_sidr_rep_mad:");
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sidr_repp))
IBCM_OUT_HDRP(ud_statep->ud_stored_msg)->AttributeID =
h2b16(IBCM_INCOMING_SIDR_REP + IBCM_ATTR_BASE_ID);
sidr_repp->sidr_rep_request_id = h2b32(ud_statep->ud_req_id);
tmp_svc_id = h2b64(ud_statep->ud_svc_id);
bcopy(&tmp_svc_id, sidr_repp->sidr_rep_service_id, sizeof (tmp_svc_id));
sidr_repp->sidr_rep_rep_status = (uint8_t)status;
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*sidr_repp))
ibcm_post_ud_mad(ud_statep, ud_statep->ud_stored_msg, NULL, NULL);
timer_value = ibt_ib2usec(ibcm_max_sidr_rep_store_time);
mutex_enter(&ud_statep->ud_state_mutex);
ud_statep->ud_remaining_retry_cnt = 1;
ud_statep->ud_timer_value = timer_value;
ud_statep->ud_timer_stored_state = ud_statep->ud_state =
IBCM_STATE_SIDR_REP_SENT;
ud_statep->ud_timerid = IBCM_UD_TIMEOUT(ud_statep,
ud_statep->ud_timer_value);
mutex_exit(&ud_statep->ud_state_mutex);
}
void
ibcm_sidr_timeout_cb(void *arg)
{
ibcm_ud_state_data_t *ud_statep = (ibcm_ud_state_data_t *)arg;
mutex_enter(&ud_statep->ud_state_mutex);
ud_statep->ud_timerid = 0;
IBTF_DPRINTF_L3(cmlog, "ibcm_sidr_timeout_cb: ud_statep 0x%p "
"state = 0x%x", ud_statep, ud_statep->ud_state);
if (ud_statep->ud_state == IBCM_STATE_SIDR_REP_SENT) {
ud_statep->ud_state = IBCM_STATE_DELETE;
mutex_exit(&ud_statep->ud_state_mutex);
ibcm_delete_ud_state_data(ud_statep);
} else if ((ud_statep->ud_remaining_retry_cnt > 0) &&
(ud_statep->ud_state == IBCM_STATE_SIDR_REQ_SENT)) {
ud_statep->ud_remaining_retry_cnt--;
IBCM_UD_REF_CNT_INCR(ud_statep);
IBTF_DPRINTF_L4(cmlog, "ibcm_sidr_timeout_cb: "
"ud_statep = %p, retries remaining = 0x%x",
ud_statep, ud_statep->ud_remaining_retry_cnt);
mutex_exit(&ud_statep->ud_state_mutex);
ibcm_post_ud_mad(ud_statep, ud_statep->ud_stored_msg,
ibcm_post_sidr_req_complete, ud_statep);
} else if (ud_statep->ud_state == IBCM_STATE_SIDR_REQ_SENT) {
ud_statep->ud_state = IBCM_STATE_DELETE;
if (ud_statep->ud_return_data != NULL) {
ud_statep->ud_return_data->ud_status =
IBT_CM_SREP_TIMEOUT;
ud_statep->ud_blocking_done = B_TRUE;
cv_broadcast(&ud_statep->ud_block_client_cv);
}
mutex_exit(&ud_statep->ud_state_mutex);
if (ud_statep->ud_cm_handler != NULL) {
ibcm_add_ud_tlist(ud_statep);
return;
}
ibcm_delete_ud_state_data(ud_statep);
} else {
#ifdef DEBUG
if (ibcm_test_mode > 0)
IBTF_DPRINTF_L2(cmlog, "ibcm_sidr_timeout_cb: "
"Nop timeout for ud_statep 0x%p in ud_state %d",
ud_statep, ud_statep->ud_state);
#endif
mutex_exit(&ud_statep->ud_state_mutex);
}
}
void
ibcm_resend_srep_mad(ibcm_ud_state_data_t *ud_statep)
{
timeout_id_t timer_val;
ASSERT(MUTEX_HELD(&ud_statep->ud_state_mutex));
IBTF_DPRINTF_L3(cmlog, "ibcm_resend_srep_mad: ud_statep 0x%p",
ud_statep);
if (ud_statep->ud_send_mad_flags & IBCM_SREP_POST_BUSY)
return;
ud_statep->ud_send_mad_flags |= IBCM_SREP_POST_BUSY;
IBCM_UD_REF_CNT_INCR(ud_statep);
timer_val = ud_statep->ud_timerid;
if (ud_statep->ud_timerid != 0) {
ud_statep->ud_timerid = 0;
mutex_exit(&ud_statep->ud_state_mutex);
(void) untimeout(timer_val);
} else {
mutex_exit(&ud_statep->ud_state_mutex);
}
ibcm_post_ud_mad(ud_statep, ud_statep->ud_stored_msg,
ibcm_post_sidr_rep_complete, ud_statep);
mutex_enter(&ud_statep->ud_state_mutex);
}
void
ibcm_build_reply_mad_addr(ibcm_mad_addr_t *inp_mad_addr,
ibcm_mad_addr_t *out_mad_addr)
{
IBTF_DPRINTF_L5(cmlog, "ibcm_build_reply_mad_addr:");
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*out_mad_addr))
bcopy(inp_mad_addr, out_mad_addr, sizeof (ibcm_mad_addr_t));
if (inp_mad_addr->grh_exists == B_TRUE) {
ib_gid_t sgid = inp_mad_addr->grh_hdr.ig_sender_gid;
out_mad_addr->grh_hdr.ig_sender_gid =
inp_mad_addr->grh_hdr.ig_recver_gid;
out_mad_addr->grh_hdr.ig_recver_gid = sgid;
}
out_mad_addr->cm_qp_entry =
ibcm_find_qp(inp_mad_addr->cm_qp_entry->qp_port->port_hcap,
inp_mad_addr->port_num, inp_mad_addr->rcvd_addr.ia_p_key);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*out_mad_addr))
}
void
ibcm_post_rc_mad(ibcm_state_data_t *statep, ibmf_msg_t *msgp,
ibmf_msg_cb_t post_cb, void *args)
{
ibt_status_t status;
mutex_enter(&statep->state_mutex);
statep->post_time = gethrtime();
mutex_exit(&statep->state_mutex);
status = ibcm_post_mad(msgp, &statep->stored_reply_addr, post_cb,
args);
if ((status != IBT_SUCCESS) && (post_cb != NULL))
(*post_cb)(NULL, msgp, args);
}
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)
{
ibt_status_t status;
status = ibcm_post_mad(msgp, &ud_statep->ud_stored_reply_addr,
ud_post_cb, args);
if ((status != IBT_SUCCESS) && (ud_post_cb != NULL))
(*ud_post_cb)(NULL, msgp, args);
}
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)
{
int post_status;
IBTF_DPRINTF_L5(cmlog, "ibcm_post_mad: "
"ibmf_msg_t = %p, cm_madd_adr = %p", msgp, cm_mad_addr);
IBTF_DPRINTF_L4(cmlog, "ibcm_post_mad: dlid = %x, d_qno= %x",
cm_mad_addr->rcvd_addr.ia_remote_lid,
cm_mad_addr->rcvd_addr.ia_remote_qno);
IBTF_DPRINTF_L4(cmlog, "ibcm_post_mad: p_key = %x, q_key = %x, "
"sl = %x, grh_exists = %x",
cm_mad_addr->rcvd_addr.ia_p_key, cm_mad_addr->rcvd_addr.ia_q_key,
cm_mad_addr->rcvd_addr.ia_service_level, cm_mad_addr->grh_exists);
msgp->im_local_addr = cm_mad_addr->rcvd_addr;
if (cm_mad_addr->grh_exists == B_TRUE)
msgp->im_global_addr = cm_mad_addr->grh_hdr;
if (post_cb)
ibcm_flow_inc();
post_status = ibmf_msg_transport(
cm_mad_addr->ibmf_hdl, cm_mad_addr->cm_qp_entry->qp_cm, msgp,
NULL, post_cb, args, 0);
if (post_status != IBMF_SUCCESS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_post_mad: ibmf_msg_transport "
"failed: status %d, cb = %p", post_status, post_cb);
return (ibcm_ibmf_analyze_error(post_status));
}
return (IBT_SUCCESS);
}
static void
ibcm_process_get_classport_info(ibcm_hca_info_t *hcap, uint8_t *input_madp,
ibcm_mad_addr_t *cm_mad_addr)
{
ibmf_msg_t *msgp;
IBTF_DPRINTF_L5(cmlog, "ibcm_process_get_classport_info: (%p, %p, %p)",
hcap, input_madp, cm_mad_addr);
if (ibcm_alloc_out_msg(cm_mad_addr->ibmf_hdl, &msgp,
MAD_METHOD_GET_RESPONSE) != IBT_SUCCESS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_get_classport_info: "
"ibcm_alloc_out_msg failed");
return;
}
IBCM_OUT_HDRP(msgp)->TransactionID =
((ib_mad_hdr_t *)(input_madp))->TransactionID;
IBCM_OUT_HDRP(msgp)->AttributeID = h2b16(MAD_ATTR_ID_CLASSPORTINFO);
bcopy(&ibcm_clpinfo, IBCM_OUT_MSGP(msgp), sizeof (ibcm_clpinfo));
(void) ibcm_post_mad(msgp, cm_mad_addr, NULL, NULL);
(void) ibcm_free_out_msg(cm_mad_addr->ibmf_hdl, &msgp);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_get_classport_info: done");
}
static void
ibcm_decode_classport_info(ibcm_hca_info_t *hcap, uint8_t *input_madp,
ibcm_mad_addr_t *cm_mad_addr)
{
ibcm_classportinfo_msg_t *portinfop = (ibcm_classportinfo_msg_t *)
(&input_madp[IBCM_MAD_HDR_SIZE]);
IBTF_DPRINTF_L5(cmlog, "ibcm_decode_classport_info: (%p, %p, %p)",
hcap, input_madp, cm_mad_addr);
IBTF_DPRINTF_L4(cmlog, "ibcm_decode_classport_info: "
"Base version %d Class version %d", portinfop->BaseVersion,
portinfop->ClassVersion);
IBTF_DPRINTF_L4(cmlog, "ibcm_decode_classport_info: "
"Cap Mask %d Resp Time %d", portinfop->CapabilityMask,
portinfop->RespTimeValue_plus);
}
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)
{
ibt_cm_event_t event;
ibcm_path_cache_purge();
if (statep->channel)
ibtl_cm_chan_open_is_aborted(statep->channel);
if (statep->cm_handler != NULL) {
bzero(&event, sizeof (ibt_cm_event_t));
event.cm_type = IBT_CM_EVENT_FAILURE;
event.cm_channel = statep->channel;
event.cm_session_id = NULL;
event.cm_priv_data = NULL;
event.cm_priv_data_len = 0;
event.cm_event.failed.cf_code = cf_code;
event.cm_event.failed.cf_msg = cf_msg;
event.cm_event.failed.cf_reason = cf_reason;
ibcm_insert_trace(statep, IBCM_TRACE_CALLED_CONN_FAIL_EVENT);
(void) statep->cm_handler(statep->state_cm_private, &event,
NULL, client_data, client_data_len);
ibcm_insert_trace(statep, IBCM_TRACE_RET_CONN_FAIL_EVENT);
}
if (ibcm_enable_trace != 0)
ibcm_dump_conn_trace(statep);
mutex_enter(&statep->state_mutex);
ibcm_open_done(statep);
mutex_exit(&statep->state_mutex);
}
static void
ibcm_set_primary_adds_vect(ibcm_state_data_t *statep,
ibt_adds_vect_t *adds_vectp, ibcm_req_msg_t *msgp)
{
uint32_t flow_label20_res6_rate6;
flow_label20_res6_rate6 = b2h32(msgp->req_primary_flow_label_plus);
adds_vectp->av_srvl = msgp->req_primary_sl_plus >> 4;
adds_vectp->av_src_path = statep->prim_src_path_bits;
if (statep->mode == IBCM_PASSIVE_MODE) {
adds_vectp->av_dlid = b2h16(msgp->req_primary_l_port_lid);
adds_vectp->av_dgid.gid_prefix =
b2h64(msgp->req_primary_l_port_gid.gid_prefix);
adds_vectp->av_dgid.gid_guid =
b2h64(msgp->req_primary_l_port_gid.gid_guid);
adds_vectp->av_sgid.gid_prefix =
b2h64(msgp->req_primary_r_port_gid.gid_prefix);
adds_vectp->av_sgid.gid_guid =
b2h64(msgp->req_primary_r_port_gid.gid_guid);
adds_vectp->av_srate = flow_label20_res6_rate6 & 0x3f;
} else {
adds_vectp->av_dlid = b2h16(msgp->req_primary_r_port_lid);
adds_vectp->av_dgid.gid_prefix =
b2h64(msgp->req_primary_r_port_gid.gid_prefix);
adds_vectp->av_dgid.gid_guid =
b2h64(msgp->req_primary_r_port_gid.gid_guid);
adds_vectp->av_sgid.gid_prefix =
b2h64(msgp->req_primary_l_port_gid.gid_prefix);
adds_vectp->av_sgid.gid_guid =
b2h64(msgp->req_primary_l_port_gid.gid_guid);
adds_vectp->av_srate = statep->local_srate;
}
if ((msgp->req_primary_sl_plus & 0x8) == 0) {
adds_vectp->av_send_grh = B_TRUE;
adds_vectp->av_flow = flow_label20_res6_rate6 >> 12;
adds_vectp->av_tclass = msgp->req_primary_traffic_class;
adds_vectp->av_hop = msgp->req_primary_hop_limit;
} else {
adds_vectp->av_send_grh = B_FALSE;
}
}
static void
ibcm_set_alt_adds_vect(ibcm_state_data_t *statep,
ibt_adds_vect_t *adds_vectp, ibcm_req_msg_t *msgp)
{
ib_gid_t dgid;
ib_gid_t sgid;
uint32_t flow_label20_res6_rate6;
flow_label20_res6_rate6 = b2h32(msgp->req_alt_flow_label_plus);
adds_vectp->av_srvl = msgp->req_alt_sl_plus >> 4;
adds_vectp->av_src_path = statep->alt_src_path_bits;
if (statep->mode == IBCM_PASSIVE_MODE) {
adds_vectp->av_dlid = b2h16(msgp->req_alt_l_port_lid);
bcopy(&msgp->req_alt_l_port_gid[0], &dgid, sizeof (ib_gid_t));
bcopy(&msgp->req_alt_r_port_gid[0], &sgid, sizeof (ib_gid_t));
adds_vectp->av_srate = flow_label20_res6_rate6 & 0x3f;
} else {
adds_vectp->av_dlid = b2h16(msgp->req_alt_r_port_lid);
bcopy(&msgp->req_alt_r_port_gid[0], &dgid, sizeof (ib_gid_t));
bcopy(&msgp->req_alt_l_port_gid[0], &sgid, sizeof (ib_gid_t));
adds_vectp->av_srate = statep->local_alt_srate;
}
adds_vectp->av_dgid.gid_prefix = b2h64(dgid.gid_prefix);
adds_vectp->av_dgid.gid_guid = b2h64(dgid.gid_guid);
adds_vectp->av_sgid.gid_prefix = b2h64(sgid.gid_prefix);
adds_vectp->av_sgid.gid_guid = b2h64(sgid.gid_guid);
if ((msgp->req_alt_sl_plus & 0x8) == 0) {
adds_vectp->av_send_grh = B_TRUE;
adds_vectp->av_flow = flow_label20_res6_rate6 >> 12;
adds_vectp->av_tclass = msgp->req_alt_traffic_class;
adds_vectp->av_hop = msgp->req_alt_hop_limit;
} else {
adds_vectp->av_send_grh = B_FALSE;
}
}
static ibt_status_t
ibcm_set_primary_cep_path(ibcm_state_data_t *statep, ibt_cep_path_t *pathp,
ibcm_req_msg_t *msgp)
{
ibt_status_t status;
status = ibt_pkey2index_byguid(statep->local_hca_guid,
statep->prim_port, b2h16(msgp->req_part_key), &pathp->cep_pkey_ix);
if (status != IBT_SUCCESS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_set_primary_cep_path: "
"statep 0x%p pkey %x prim_port %d ", statep,
b2h16(msgp->req_part_key), statep->prim_port);
IBTF_DPRINTF_L2(cmlog, "ibcm_set_primary_cep_path: "
"statep 0x%p Invalid PKEY on prim_port, status %d ",
statep, status);
return (status);
}
statep->pkey = b2h16(msgp->req_part_key);
ibcm_set_primary_adds_vect(statep, &pathp->cep_adds_vect, msgp);
return (IBT_SUCCESS);
}
static ibt_status_t
ibcm_set_alt_cep_path(ibcm_state_data_t *statep, ibt_cep_path_t *pathp,
ibcm_req_msg_t *msgp)
{
ibt_status_t status;
if (b2h16(msgp->req_alt_l_port_lid) == 0) {
return (IBT_SUCCESS);
}
status = ibt_pkey2index_byguid(statep->local_hca_guid,
statep->alt_port, b2h16(msgp->req_part_key), &pathp->cep_pkey_ix);
if (status != IBT_SUCCESS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_set_alt_cep_path: "
"statep 0x%p pkey %x alt_port %d ", statep,
b2h16(msgp->req_part_key), statep->alt_port);
IBTF_DPRINTF_L2(cmlog, "ibcm_set_alt_cep_path: "
"statep 0x%p Invalid PKEY on alt_port, status %d ",
statep, status);
return (status);
}
pathp->cep_hca_port_num = statep->alt_port;
ibcm_set_alt_adds_vect(statep, &pathp->cep_adds_vect, msgp);
return (IBT_SUCCESS);
}
static boolean_t
ibcm_compare_prim_alt_paths(ibt_adds_vect_t *prim, ibt_adds_vect_t *alt)
{
if ((alt->av_dlid == prim->av_dlid) &&
(alt->av_dgid.gid_prefix == prim->av_dgid.gid_prefix) &&
(alt->av_dgid.gid_guid == prim->av_dgid.gid_guid) &&
(alt->av_sgid.gid_prefix == prim->av_sgid.gid_prefix) &&
(alt->av_sgid.gid_guid == prim->av_sgid.gid_guid) &&
(alt->av_src_path == prim->av_src_path)) {
return (B_TRUE);
}
return (B_FALSE);
}
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)
{
ibt_status_t status;
ibt_qp_info_t qp_info;
ibt_cep_modify_flags_t cep_flags;
ibt_tran_srv_t trans;
cep_flags = IBT_CEP_SET_INIT_RTR | IBT_CEP_SET_PKEY_IX;
trans = ((uint8_t *)&req_msgp->req_remote_eecn_plus)[3] >> 1 & 0x3;
ASSERT(statep->channel != NULL);
if (b2h16(req_msgp->req_alt_l_port_lid) != 0) {
if (statep->hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG)
cep_flags |= IBT_CEP_SET_ALT_PATH;
else {
rep_msgp->rep_target_delay_plus |=
IBT_CM_FAILOVER_REJ_NOTSUPP << 1;
IBTF_DPRINTF_L3(cmlog, "ibcm_invoke_qp_modify"
" Alt Path specified in REQ, but not supported");
}
}
if (trans == IBT_RD_SRV) {
cep_flags |= IBT_CEP_SET_QKEY;
}
bzero(&qp_info, sizeof (qp_info));
qp_info.qp_trans = trans;
qp_info.qp_state = IBT_STATE_RTR;
qp_info.qp_flags = IBT_CEP_NO_FLAGS;
switch (trans) {
case IBT_RC_SRV:
if (statep->mode == IBCM_ACTIVE_MODE) {
IBCM_QPINFO_RC(qp_info).rc_rq_psn =
b2h32(req_msgp->req_starting_psn_plus) >> 8;
IBCM_QPINFO_RC(qp_info).rc_dst_qpn =
b2h32(rep_msgp->rep_local_qpn_plus) >> 8;
IBCM_QPINFO_RC(qp_info).rc_rdma_ra_in =
rep_msgp->rep_initiator_depth;
} else {
IBCM_QPINFO_RC(qp_info).rc_sq_psn =
IBCM_QPINFO_RC(qp_info).rc_rq_psn =
b2h32(rep_msgp->rep_starting_psn_plus) >> 8;
IBCM_QPINFO_RC(qp_info).rc_dst_qpn =
b2h32(req_msgp->req_local_qpn_plus) >> 8;
IBCM_QPINFO_RC(qp_info).rc_rdma_ra_in =
rep_msgp->rep_resp_resources;
}
IBCM_QPINFO_RC(qp_info).rc_min_rnr_nak =
ibcm_default_rnr_nak_time;
IBCM_QPINFO_RC(qp_info).rc_path_mtu =
req_msgp->req_mtu_plus >> 4;
IBCM_QPINFO_RC(qp_info).rc_retry_cnt =
((uint8_t *)&req_msgp->req_starting_psn_plus)[3] & 0x7;
IBCM_QPINFO_RC(qp_info).rc_rnr_retry_cnt =
req_msgp->req_mtu_plus & 0x7;
if ((status = ibcm_set_primary_cep_path(statep,
&IBCM_QPINFO_RC(qp_info).rc_path, req_msgp)) !=
IBT_SUCCESS)
return (status);
if ((status = ibcm_set_alt_cep_path(statep,
&IBCM_QPINFO_RC(qp_info).rc_alt_path, req_msgp)) !=
IBT_SUCCESS)
return (status);
break;
case IBT_RD_SRV:
if (statep->mode == IBCM_ACTIVE_MODE) {
IBCM_QPINFO(qp_info).rd.rd_qkey =
b2h32(rep_msgp->rep_local_qkey);
} else {
IBCM_QPINFO(qp_info).rd.rd_qkey =
b2h32(req_msgp->req_local_qkey);
}
break;
case IBT_UC_SRV:
if (statep->mode == IBCM_ACTIVE_MODE) {
IBCM_QPINFO_UC(qp_info).uc_sq_psn =
b2h32(req_msgp->req_starting_psn_plus) >> 8;
IBCM_QPINFO_UC(qp_info).uc_dst_qpn =
b2h32(rep_msgp->rep_local_qpn_plus) >> 8;
} else {
IBCM_QPINFO_UC(qp_info).uc_rq_psn =
IBCM_QPINFO_UC(qp_info).uc_sq_psn =
b2h32(rep_msgp->rep_starting_psn_plus) >> 8;
IBCM_QPINFO_UC(qp_info).uc_dst_qpn =
b2h32(req_msgp->req_local_qpn_plus) >> 8;
}
IBCM_QPINFO_UC(qp_info).uc_path_mtu =
req_msgp->req_mtu_plus >> 4;
if ((status = ibcm_set_primary_cep_path(statep,
&IBCM_QPINFO_UC(qp_info).uc_path, req_msgp)) !=
IBT_SUCCESS)
return (status);
if ((status = ibcm_set_alt_cep_path(statep,
&IBCM_QPINFO_UC(qp_info).uc_alt_path, req_msgp)) !=
IBT_SUCCESS)
return (status);
break;
default:
IBTF_DPRINTF_L2(cmlog, "ibcm_invoke_qp_modify: "
"unknown svc_type = %x", trans);
break;
}
status = ibt_modify_qp(statep->channel, cep_flags, &qp_info, NULL);
IBTF_DPRINTF_L4(cmlog, "ibcm_invoke_qp_modify: statep 0x%p"
" ibt_modify_qp() Init to RTR returned = %d", statep, status);
if (status == IBT_SUCCESS)
ibcm_insert_trace(statep, IBCM_TRACE_INIT_RTR);
else
ibcm_insert_trace(statep, IBCM_TRACE_INIT_RTR_FAIL);
#ifdef DEBUG
print_modify_qp("Init to RTR", statep->channel, cep_flags, &qp_info);
if (statep->channel != NULL) {
ibt_qp_query_attr_t qp_attrs;
(void) ibt_query_qp(statep->channel, &qp_attrs);
IBTF_DPRINTF_L4(cmlog, "ibcm_invoke_qp_modify: "
"qp_info.qp_state = %x", qp_attrs.qp_info.qp_state);
}
#endif
return (status);
}
ibcm_status_t
ibcm_verify_req_gids_and_svcid(ibcm_state_data_t *statep,
ibcm_req_msg_t *cm_req_msgp)
{
ib_gid_t gid;
ib_gid_t agid;
ib_lid_t lid;
ibt_status_t status;
ibtl_cm_hca_port_t port;
ibt_cm_reason_t reject_reason = IBT_CM_SUCCESS;
ibcm_svc_info_t *svc_infop;
ibcm_svc_bind_t *svc_bindp;
ibcm_svc_bind_t *tmp_bindp;
ib_pkey_t pkey;
uint8_t port_num;
ib_guid_t hca_guid;
ibcm_ip_pvtdata_t *ip_data;
gid.gid_prefix = b2h64(cm_req_msgp->req_primary_r_port_gid.gid_prefix);
gid.gid_guid = b2h64(cm_req_msgp->req_primary_r_port_gid.gid_guid);
IBTF_DPRINTF_L4(cmlog, "ibcm_verify_req_gids: statep 0x%p"
" PRIM _r_gid (%llx, %llx)", statep, gid.gid_prefix,
gid.gid_guid);
IBTF_DPRINTF_L4(cmlog, "ibcm_verify_req_gids: statep 0x%p "
"PRIM passive lid %x", statep,
b2h16(cm_req_msgp->req_primary_r_port_lid));
if ((status = ibtl_cm_get_hca_port(gid, 0, &port)) == IBT_SUCCESS) {
IBTF_DPRINTF_L4(cmlog, "ibcm_verify_req_gids: statep 0x%p "
"prim_port_num %d", statep, port.hp_port);
IBTF_DPRINTF_L4(cmlog, "ibcm_verify_req_gids: statep 0x%p "
"passive hca_guid 0x%llX", statep, port.hp_hca_guid);
port_num = port.hp_port;
hca_guid = port.hp_hca_guid;
}
if (status != IBT_SUCCESS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_verify_req_gids: statep 0x%p "
"ibtl_cm_get_hca_port() primary port failed = %d", statep,
status);
reject_reason = IBT_CM_PRIM_GID;
port_num = statep->stored_reply_addr.port_num;
hca_guid = statep->hcap->hca_guid;
} else if (port.hp_base_lid !=
(b2h16(cm_req_msgp->req_primary_r_port_lid) &
(~((1 << port.hp_lmc) - 1)))) {
IBTF_DPRINTF_L2(cmlog, "ibcm_verify_req_gids: statep 0x%p "
"primary port lid invalid (%x, %x, %x)", statep,
port.hp_base_lid,
b2h16(cm_req_msgp->req_primary_r_port_lid), port.hp_lmc);
reject_reason = IBT_CM_PRIM_LID;
} else {
statep->local_hca_guid = port.hp_hca_guid;
statep->prim_port = port.hp_port;
statep->prim_src_path_bits =
b2h16(cm_req_msgp->req_primary_r_port_lid) -
port.hp_base_lid;
IBTF_DPRINTF_L4(cmlog, "ibcm_verify_req_gids: "
"statep 0x%p prim_port_path_bits %d ",
statep, statep->prim_src_path_bits);
bcopy(&cm_req_msgp->req_alt_r_port_gid[0], &agid,
sizeof (ib_gid_t));
agid.gid_prefix = b2h64(agid.gid_prefix);
agid.gid_guid = b2h64(agid.gid_guid);
IBTF_DPRINTF_L4(cmlog, "ibcm_verify_req_gids: statep 0x%p"
" Alt port_gid is (%llX:%llX)", statep, agid.gid_prefix,
agid.gid_guid);
if ((agid.gid_prefix != 0) || (agid.gid_guid != 0)) {
if ((status = ibtl_cm_get_hca_port(agid,
statep->local_hca_guid, &port)) != IBT_SUCCESS) {
IBTF_DPRINTF_L2(cmlog,
"ibcm_verify_req_gids: ibtl_cm_get_hca_port"
" statep 0x%p alternate port failed = %d",
statep, status);
reject_reason = IBT_CM_ALT_GID;
} else if (port.hp_base_lid !=
(b2h16(cm_req_msgp->req_alt_r_port_lid) &
(~((1 << port.hp_lmc) - 1)))) {
IBTF_DPRINTF_L2(cmlog,
"ibcm_verify_req_gids: statep 0x%p "
"alternate port lid invalid (%x, %x, %x)",
statep, port.hp_base_lid,
cm_req_msgp->req_alt_r_port_lid,
port.hp_lmc);
reject_reason = IBT_CM_ALT_LID;
} else {
statep->alt_port = port.hp_port;
statep->alt_src_path_bits =
b2h16(cm_req_msgp->req_alt_r_port_lid) -
port.hp_base_lid;
IBTF_DPRINTF_L4(cmlog, "ibcm_verify_req_gids: "
"statep 0x%p alt_port_num %d "
"alt_rc_hca_guid 0x%llX", statep,
port.hp_port, port.hp_hca_guid);
IBTF_DPRINTF_L4(cmlog, "ibcm_verify_req_gids: "
"statep 0x%p alt_port_path_bits %d ",
statep, statep->alt_src_path_bits);
}
}
}
mutex_enter(&ibcm_svc_info_lock);
svc_infop = ibcm_find_svc_entry(statep->svcid);
IBTF_DPRINTF_L4(cmlog, "ibcm_verify_req_gids: "
"ibcm_find_svc_entry found svc_infop %p", svc_infop);
if (svc_infop == NULL || svc_infop->svc_bind_list == NULL) {
mutex_exit(&ibcm_svc_info_lock);
IBTF_DPRINTF_L2(cmlog, "ibcm_verify_req_gids_and_svcid: "
"statep 0x%p svc_id %llX svc_infop NULL", statep,
statep->svcid);
ibcm_post_rej_mad(statep,
IBT_CM_INVALID_SID, IBT_CM_FAILURE_REQ, NULL, 0);
return (IBCM_FAILURE);
}
if (svc_infop->svc_rc_handler == NULL) {
mutex_exit(&ibcm_svc_info_lock);
ibcm_post_rej_mad(statep,
IBT_CM_INVALID_SRV_TYPE, IBT_CM_FAILURE_REQ, NULL, 0);
return (IBCM_FAILURE);
}
if (((statep->svcid & IB_SID_IPADDR_PREFIX_MASK) == 0) &&
(statep->svcid & IB_SID_IPADDR_PREFIX)) {
ibt_ari_ip_t ari_ip;
boolean_t rdma_rej_mad = B_FALSE;
ip_data = (ibcm_ip_pvtdata_t *)cm_req_msgp->req_private_data;
bzero(&ari_ip, sizeof (ibt_ari_ip_t));
if (ip_data->ip_MajV != IBT_CM_IP_MAJ_VER) {
IBTF_DPRINTF_L2(cmlog, "ibcm_verify_req_gids_and_svcid:"
"IP MajorVer mis-match %d", ip_data->ip_MajV);
ari_ip.ip_reason = IBT_ARI_IP_MAJOR_VERSION;
ari_ip.ip_suggested_version = IBT_CM_IP_MAJ_VER;
ari_ip.ip_suggested = B_TRUE;
rdma_rej_mad = B_TRUE;
} else if (ip_data->ip_MinV != IBT_CM_IP_MIN_VER) {
IBTF_DPRINTF_L2(cmlog, "ibcm_verify_req_gids_and_svcid:"
"IP MinorVer mis-match %d", ip_data->ip_MinV);
ari_ip.ip_reason = IBT_ARI_IP_MINOR_VERSION;
ari_ip.ip_suggested_version = IBT_CM_IP_MIN_VER;
ari_ip.ip_suggested = B_TRUE;
rdma_rej_mad = B_TRUE;
} else if ((ip_data->ip_ipv != IBT_CM_IP_IPV_V4) &&
(ip_data->ip_ipv != IBT_CM_IP_IPV_V6)) {
IBTF_DPRINTF_L2(cmlog, "ibcm_verify_req_gids_and_svcid:"
" Invalid IPV specified %d", ip_data->ip_ipv);
ari_ip.ip_reason = IBT_ARI_IP_IPV;
ari_ip.ip_suggested_version = IBT_CM_IP_IPV_V4;
ari_ip.ip_suggested = B_TRUE;
rdma_rej_mad = B_TRUE;
} else {
if (ip_data->ip_ipv == IBT_CM_IP_IPV_V4) {
if (ip_data->ip_srcv4 == 0) {
IBTF_DPRINTF_L2(cmlog,
"ibcm_verify_req_gids_and_svcid: "
"Invalid NULL V4 SrcIp specified");
rdma_rej_mad = B_TRUE;
ari_ip.ip_reason = IBT_ARI_IP_SRC_ADDR;
ari_ip.ip_suggested = B_TRUE;
ari_ip.ip_suggested_version =
IBT_CM_IP_IPV_V4;
} else if (ip_data->ip_dstv4 == 0) {
IBTF_DPRINTF_L2(cmlog,
"ibcm_verify_req_gids_and_svcid: "
"Invalid NULL V4 DstIp specified");
rdma_rej_mad = B_TRUE;
ari_ip.ip_reason = IBT_ARI_IP_DST_ADDR;
ari_ip.ip_suggested = B_TRUE;
ari_ip.ip_suggested_version =
IBT_CM_IP_IPV_V4;
}
} else if (ip_data->ip_ipv == IBT_CM_IP_IPV_V6) {
if (IN6_IS_ADDR_UNSPECIFIED(
&ip_data->ip_srcv6)) {
IBTF_DPRINTF_L2(cmlog,
"ibcm_verify_req_gids_and_svcid: "
"Invalid NULL V6 SrcIp specified");
rdma_rej_mad = B_TRUE;
ari_ip.ip_reason = IBT_ARI_IP_SRC_ADDR;
ari_ip.ip_suggested = B_TRUE;
ari_ip.ip_suggested_version =
IBT_CM_IP_IPV_V6;
} else if (IN6_IS_ADDR_UNSPECIFIED(
&ip_data->ip_dstv6)) {
IBTF_DPRINTF_L2(cmlog,
"ibcm_verify_req_gids_and_svcid: "
"Invalid NULL V6 DstIp specified");
rdma_rej_mad = B_TRUE;
ari_ip.ip_reason = IBT_ARI_IP_DST_ADDR;
ari_ip.ip_suggested = B_TRUE;
ari_ip.ip_suggested_version =
IBT_CM_IP_IPV_V6;
}
}
}
if (rdma_rej_mad == B_TRUE) {
ibt_ari_con_t cons_rej;
mutex_exit(&ibcm_svc_info_lock);
cons_rej.rej_ari_len = 1 + sizeof (ibt_ari_ip_t);
cons_rej.rej_ari[0] = 0;
bcopy(&ari_ip, &cons_rej.rej_ari[1],
sizeof (ibt_ari_ip_t));
ibcm_post_rej_mad(statep, IBT_CM_CONSUMER,
IBT_CM_FAILURE_REQ, &cons_rej,
sizeof (ibt_ari_con_t));
return (IBCM_FAILURE);
}
}
pkey = b2h16(cm_req_msgp->req_part_key);
svc_bindp = NULL;
tmp_bindp = svc_infop->svc_bind_list;
while (tmp_bindp) {
if (tmp_bindp->sbind_hcaguid == hca_guid &&
tmp_bindp->sbind_port == port_num) {
if (gid.gid_guid ==
tmp_bindp->sbind_gid.gid_guid &&
gid.gid_prefix ==
tmp_bindp->sbind_gid.gid_prefix) {
svc_bindp = tmp_bindp;
if (pkey == tmp_bindp->sbind_pkey)
break;
} else if (svc_bindp == NULL) {
svc_bindp = tmp_bindp;
}
}
tmp_bindp = tmp_bindp->sbind_link;
}
if (svc_bindp == NULL) {
mutex_exit(&ibcm_svc_info_lock);
IBTF_DPRINTF_L2(cmlog,
"ibcm_verify_req_gids_and_svcid: statep 0x%p "
"no binding found", statep);
ibcm_post_rej_mad(statep,
IBT_CM_INVALID_SID, IBT_CM_FAILURE_REQ, NULL, 0);
return (IBCM_FAILURE);
}
gid.gid_prefix = b2h64(svc_bindp->sbind_gid.gid_prefix);
gid.gid_guid = b2h64(svc_bindp->sbind_gid.gid_guid);
statep->state_cm_private = svc_bindp->sbind_cm_private;
statep->state_svc_infop = svc_infop;
statep->cm_handler = svc_infop->svc_rc_handler;
if (reject_reason == IBT_CM_SUCCESS)
IBCM_SVC_INCR(svc_infop);
mutex_exit(&ibcm_svc_info_lock);
if (reject_reason != IBT_CM_SUCCESS) {
switch (reject_reason) {
case IBT_CM_PRIM_GID :
case IBT_CM_ALT_GID :
ibcm_post_rej_mad(statep,
reject_reason, IBT_CM_FAILURE_REQ,
&gid, sizeof (ib_gid_t));
break;
case IBT_CM_PRIM_LID :
case IBT_CM_ALT_LID :
lid = h2b16(port.hp_base_lid);
ibcm_post_rej_mad(statep,
reject_reason, IBT_CM_FAILURE_REQ,
&lid, sizeof (ib_lid_t));
break;
}
return (IBCM_FAILURE);
}
return (IBCM_SUCCESS);
}
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)
{
void *priv_data = NULL;
ibt_cm_event_t event;
ibt_cm_status_t cb_status;
ibcm_status_t status;
ibt_cm_return_args_t ret_args;
ibcm_clnt_reply_info_t clnt_info;
IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_req: statep 0x%p", statep);
IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_req: SID 0x%lX",
b2h64(cm_req_msgp->req_svc_id));
ASSERT(statep->cm_handler != NULL);
bzero(&event, sizeof (event));
event.cm_type = IBT_CM_EVENT_REQ_RCV;
event.cm_session_id = statep;
IBCM_EVT_REQ(event).req_service_id = b2h64(cm_req_msgp->req_svc_id);
IBCM_EVT_REQ(event).req_transport =
((uint8_t *)&cm_req_msgp->req_remote_eecn_plus)[3] >> 1 & 0x3;
IBCM_EVT_REQ(event).req_timeout = ibt_ib2usec(
(((uint8_t *)&cm_req_msgp->req_remote_eecn_plus)[3] >> 3) & 0x1F);
IBCM_EVT_REQ(event).req_retry_cnt =
((uint8_t *)&cm_req_msgp->req_starting_psn_plus)[3] & 0x7;
IBCM_EVT_REQ(event).req_rnr_retry_cnt = cm_req_msgp->req_mtu_plus & 0x7;
IBCM_EVT_REQ(event).req_pkey = b2h16(cm_req_msgp->req_part_key);
IBCM_EVT_REQ(event).req_rdma_ra_in =
((uint8_t *)&cm_req_msgp->req_local_qpn_plus)[3];
IBCM_EVT_REQ(event).req_rdma_ra_out =
((uint8_t *)&cm_req_msgp->req_local_eec_no_plus)[3];
if (IBCM_EVT_REQ(event).req_rdma_ra_in >
statep->hcap->hca_max_rdma_in_qp) {
IBTF_DPRINTF_L2(cmlog, "ibcm_cep_state_req: statep 0x%p, REQ "
"req_rdma_ra_in %d is greater than HCA Limit %d, resetting"
"it to HCA limit", statep,
IBCM_EVT_REQ(event).req_rdma_ra_in,
statep->hcap->hca_max_rdma_in_qp);
IBCM_EVT_REQ(event).req_rdma_ra_in =
statep->hcap->hca_max_rdma_in_qp;
}
if (IBCM_EVT_REQ(event).req_rdma_ra_out >
statep->hcap->hca_max_rdma_out_qp) {
IBTF_DPRINTF_L2(cmlog, "ibcm_cep_state_req: statep 0x%p, REQ "
"req_rdma_ra_out %d is greater than HCA Limit %d, resetting"
"it to HCA limit", statep,
IBCM_EVT_REQ(event).req_rdma_ra_out,
statep->hcap->hca_max_rdma_out_qp);
IBCM_EVT_REQ(event).req_rdma_ra_out =
statep->hcap->hca_max_rdma_out_qp;
}
if (IBCM_EVT_REQ(event).req_timeout > ibcm_sw_delay) {
IBCM_EVT_REQ(event).req_timeout -= ibcm_sw_delay;
IBTF_DPRINTF_L5(cmlog, "ibcm_cep_state_req: statep 0x%p"
"Avail resp time %d (usec)", statep,
IBCM_EVT_REQ(event).req_timeout);
} else {
IBTF_DPRINTF_L2(cmlog, "ibcm_cep_state_req: statep 0x%p "
"REQ rem_resp_time < local sw delay 0x%x", statep,
IBCM_EVT_REQ(event).req_timeout);
IBCM_EVT_REQ(event).req_timeout = 0;
}
IBCM_EVT_REQ(event).req_prim_hca_port = statep->prim_port;
IBCM_EVT_REQ(event).req_alt_hca_port = statep->alt_port;
IBCM_EVT_REQ(event).req_hca_guid = statep->local_hca_guid;
IBCM_EVT_REQ(event).req_remote_qpn = statep->remote_qpn;
if (((uint8_t *)&cm_req_msgp->req_remote_eecn_plus)[3] &
IBT_CM_FLOW_CONTROL)
IBCM_EVT_REQ(event).req_flags |= IBT_CM_FLOW_CONTROL;
if ((cm_req_msgp->req_max_cm_retries_plus >> 3) & 0x1)
IBCM_EVT_REQ(event).req_flags |= IBT_CM_SRQ_EXISTS;
ibcm_set_primary_adds_vect(statep, &IBCM_EVT_REQ(event).req_prim_addr,
cm_req_msgp);
if (b2h16(cm_req_msgp->req_alt_l_port_lid) != 0) {
ibcm_set_alt_adds_vect(statep,
&IBCM_EVT_REQ(event).req_alt_addr, cm_req_msgp);
if (ibcm_compare_prim_alt_paths(
&event.cm_event.req.req_prim_addr,
&event.cm_event.req.req_alt_addr) == B_TRUE) {
*reject_reason = IBT_CM_NO_RESC;
IBTF_DPRINTF_L2(cmlog, "ibcm_cep_state_req: statep 0x%p"
" Alt and prim paths are same", statep);
mutex_enter(&ibcm_svc_info_lock);
IBCM_SVC_DECR(statep->state_svc_infop);
mutex_exit(&ibcm_svc_info_lock);
return (IBCM_SEND_REJ);
}
}
#ifdef NO_EEC_SUPPORT_YET
IBCM_EVT_REQ(event).req_rdc_exists = cm_req_msgp->req_mtu_plus >> 3 & 1;
IBCM_EVT_REQ(event).req_remote_eecn =
b2h32(cm_req_msgp->req_remote_eecn_plus) >> 8;
IBCM_EVT_REQ(event).req_local_eecn =
b2h32(cm_req_msgp->req_local_eec_no_plus) >> 8;
IBCM_EVT_REQ(event).req_remote_qkey =
b2h32(cm_req_msgp->req_local_qkey);
#endif
event.cm_priv_data = cm_req_msgp->req_private_data;
event.cm_priv_data_len = IBT_REQ_PRIV_DATA_SZ;
priv_data = kmem_zalloc(IBT_MAX_PRIV_DATA_SZ, KM_SLEEP);
bzero(&ret_args, sizeof (ret_args));
ret_args.cm_ret.rep.cm_rdma_ra_in = IBCM_EVT_REQ(event).req_rdma_ra_out;
ret_args.cm_ret.rep.cm_rdma_ra_out = IBCM_EVT_REQ(event).req_rdma_ra_in;
ret_args.cm_ret.rep.cm_rnr_retry_cnt = cm_req_msgp->req_mtu_plus & 0x7;
ibcm_insert_trace(statep, IBCM_TRACE_CALLED_REQ_RCVD_EVENT);
statep->req_msgp = cm_req_msgp;
cb_status = statep->cm_handler(statep->state_cm_private, &event,
&ret_args, priv_data, IBT_REP_PRIV_DATA_SZ);
statep->req_msgp = NULL;
ibcm_insert_trace(statep, IBCM_TRACE_RET_REQ_RCVD_EVENT);
mutex_enter(&ibcm_svc_info_lock);
IBCM_SVC_DECR(statep->state_svc_infop);
mutex_exit(&ibcm_svc_info_lock);
IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_req: Client handler returned %d"
" statep 0x%p", cb_status, statep);
if (cb_status == IBT_CM_DEFER) {
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(statep->defer_cm_msg))
if (statep->defer_cm_msg == NULL)
statep->defer_cm_msg =
kmem_zalloc(IBCM_MSG_SIZE, KM_SLEEP);
bcopy(cm_req_msgp, statep->defer_cm_msg, IBCM_MSG_SIZE);
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(statep->defer_cm_msg))
mutex_enter(&statep->state_mutex);
statep->clnt_proceed = IBCM_UNBLOCK;
cv_broadcast(&statep->block_client_cv);
mutex_exit(&statep->state_mutex);
kmem_free(priv_data, IBT_MAX_PRIV_DATA_SZ);
return (IBCM_DEFER);
}
mutex_enter(&statep->state_mutex);
statep->clnt_proceed = IBCM_FAIL;
cv_broadcast(&statep->block_client_cv);
mutex_exit(&statep->state_mutex);
clnt_info.reply_event = (ibt_cm_proceed_reply_t *)&ret_args.cm_ret;
clnt_info.priv_data = priv_data;
clnt_info.priv_data_len = ret_args.cm_ret_len;
status =
ibcm_process_cep_req_cm_hdlr(statep, cb_status,
&clnt_info, reject_reason, arej_len, cm_req_msgp);
kmem_free(priv_data, IBT_MAX_PRIV_DATA_SZ);
return (status);
}
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)
{
ibt_status_t status;
ibt_qp_query_attr_t qp_attrs;
ibcm_state_data_t *old_statep;
ibt_channel_hdl_t channel;
ib_guid_t local_ca_guid;
ibcm_rej_msg_t *rej_msgp;
#ifdef NO_EEC_SUPPORT_YET
ibt_eec_query_attr_t eec_attrs;
#endif
if (cb_status == IBT_CM_DEFAULT)
cb_status = IBT_CM_REJECT;
if (cb_status == IBT_CM_ACCEPT) {
*reject_reason = IBT_CM_SUCCESS;
} else if (cb_status == IBT_CM_REJECT) {
*reject_reason = IBT_CM_CONSUMER;
} else if (cb_status == IBT_CM_REDIRECT_PORT) {
*reject_reason = IBT_CM_PORT_REDIRECT;
} else if (cb_status == IBT_CM_REDIRECT) {
*reject_reason = IBT_CM_REDIRECT_CM;
} else if (cb_status == IBT_CM_NO_CHANNEL) {
*reject_reason = IBT_CM_NO_CHAN;
} else if (cb_status == IBT_CM_NO_RESOURCE) {
*reject_reason = IBT_CM_NO_RESC;
} else {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_req_cm_hdlr: statep %p"
" Client handler unexpected return %x", statep, cb_status);
*reject_reason = IBT_CM_CONSUMER;
}
if (cb_status == IBT_CM_ACCEPT) {
ibcm_rep_msg_t *rep_msgp = (ibcm_rep_msg_t *)
IBCM_OUT_MSGP(statep->stored_msg);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*statep))
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rep_msgp))
channel = clnt_info->reply_event->rep.cm_channel;
if (IBCM_INVALID_CHANNEL(channel)) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_req_cm_hdlr: "
"statep 0x%p server's QP handle is NULL", statep);
*reject_reason = IBT_CM_NO_CHAN;
}
IBCM_GET_CHAN_PRIVATE(channel, old_statep);
if ((*reject_reason == IBT_CM_SUCCESS) &&
(old_statep != NULL)) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_req_cm_hdlr: "
"statep 0x%p Channel being re-used on passive side",
statep);
*reject_reason = IBT_CM_NO_CHAN;
}
if (old_statep != NULL)
IBCM_RELEASE_CHAN_PRIVATE(channel);
if (*reject_reason != IBT_CM_SUCCESS) {
ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
IBT_CM_FAILURE_REQ, *reject_reason, NULL, 0);
return (IBCM_SEND_REJ);
}
statep->channel = channel;
status = ibt_query_qp(channel, &qp_attrs);
if (status != IBT_SUCCESS) {
IBTF_DPRINTF_L3(cmlog, "ibcm_process_cep_req_cm_hdlr: "
"statep %p ibt_query_qp failed %d", statep, status);
*reject_reason = IBT_CM_NO_RESC;
ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
IBT_CM_FAILURE_REQ, IBT_CM_CI_FAILURE, NULL, 0);
return (IBCM_SEND_REJ);
}
if (qp_attrs.qp_info.qp_trans != IBT_RC_SRV) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_req_cm_hdlr: "
"statep %p qp is not RC channel on server", statep);
*reject_reason = IBT_CM_INVALID_SRV_TYPE;
ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
IBT_CM_FAILURE_REQ, IBT_CM_CHAN_INVALID_STATE,
NULL, 0);
return (IBCM_SEND_REJ);
}
if (qp_attrs.qp_info.qp_state != IBT_STATE_INIT &&
statep->is_this_ofuv_chan == B_FALSE) {
IBTF_DPRINTF_L3(cmlog, "ibcm_process_cep_req_cm_hdlr: "
"qp state != INIT on server");
*reject_reason = IBT_CM_CHAN_INVALID_STATE;
ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
IBT_CM_FAILURE_REQ, IBT_CM_CHAN_INVALID_STATE,
NULL, 0);
return (IBCM_SEND_REJ);
} else if (statep->is_this_ofuv_chan &&
qp_attrs.qp_info.qp_state != IBT_STATE_RTR &&
qp_attrs.qp_info.qp_state != IBT_STATE_INIT) {
IBTF_DPRINTF_L3(cmlog, "ibcm_process_cep_req_cm_hdlr: "
"qp state != INIT or RTR on server");
*reject_reason = IBT_CM_CHAN_INVALID_STATE;
ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
IBT_CM_FAILURE_REQ, IBT_CM_CHAN_INVALID_STATE,
NULL, 0);
return (IBCM_SEND_REJ);
}
if (statep->is_this_ofuv_chan &&
qp_attrs.qp_info.qp_state == IBT_STATE_RTR &&
qp_attrs.qp_info.qp_transport.rc.rc_path.cep_hca_port_num !=
statep->prim_port) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_req_cm_hdlr: "
"QP port invalid");
*reject_reason = IBT_CM_CHAN_INVALID_STATE;
ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
IBT_CM_FAILURE_REQ, IBT_CM_CHAN_INVALID_STATE,
NULL, 0);
return (IBCM_SEND_REJ);
} else if (statep->is_this_ofuv_chan &&
qp_attrs.qp_info.qp_state == IBT_STATE_RTR) {
goto skip_init_trans;
}
if (qp_attrs.qp_info.qp_transport.rc.rc_path.cep_hca_port_num !=
statep->prim_port) {
ibt_qp_info_t qp_info;
ibt_cep_modify_flags_t cep_flags;
IBTF_DPRINTF_L5(cmlog, "ibcm_process_cep_req_cm_hdlr: "
"chan 0x%p chan port %d", channel,
qp_attrs.qp_info.qp_transport.rc.rc_path.\
cep_hca_port_num);
IBTF_DPRINTF_L5(cmlog, "ibcm_process_cep_req_cm_hdlr: "
"chan 0x%p d path port %d", channel,
statep->prim_port);
bzero(&qp_info, sizeof (qp_info));
qp_info.qp_trans = IBT_RC_SRV;
qp_info.qp_state = IBT_STATE_INIT;
qp_info.qp_transport.rc.rc_path.cep_hca_port_num =
statep->prim_port;
cep_flags = IBT_CEP_SET_STATE | IBT_CEP_SET_PORT;
status = ibt_modify_qp(statep->channel, cep_flags,
&qp_info, NULL);
if (status != IBT_SUCCESS) {
IBTF_DPRINTF_L2(cmlog,
"ibcm_process_cep_req_cm_hdlr: "
"chan 0x%p ibt_modify_qp() = %d", channel,
status);
*reject_reason = IBT_CM_NO_RESC;
ibcm_insert_trace(statep,
IBCM_TRACE_INIT_INIT_FAIL);
ibcm_handler_conn_fail(statep,
IBT_CM_FAILURE_REJ_SENT, IBT_CM_FAILURE_REQ,
IBT_CM_CI_FAILURE, NULL, 0);
return (IBCM_SEND_REJ);
} else {
ibcm_insert_trace(statep,
IBCM_TRACE_INIT_INIT);
IBTF_DPRINTF_L5(cmlog,
"ibcm_process_cep_req_cm_hdlr: "
"chan 0x%p ibt_modify_qp() = %d", channel,
status);
}
}
skip_init_trans:
if (clnt_info->reply_event->rep.cm_rdma_ra_out >
((uint8_t *)&cm_req_msg->req_local_qpn_plus)[3]) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_req_cm_hdlr "
"statep 0x%p ERROR: InitiatorDepth(%d) is Greater "
"than ResponderResource(%d)", statep,
clnt_info->reply_event->rep.cm_rdma_ra_out,
((uint8_t *)&cm_req_msg->req_local_qpn_plus)[3]);
*reject_reason = IBT_CM_NOT_SUPPORTED;
ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
IBT_CM_FAILURE_REQ, IBT_CM_NOT_SUPPORTED, NULL, 0);
return (IBCM_SEND_REJ);
}
if (clnt_info->reply_event->rep.cm_rdma_ra_in >
statep->hcap->hca_max_rdma_in_qp) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_req_cm_hdlr: "
"statep %p, ERROR: client specified rdma_ra_in %d "
"is greater than HCA Limit %d, rejecting MAD",
statep, clnt_info->reply_event->rep.cm_rdma_ra_in,
statep->hcap->hca_max_rdma_in_qp);
*reject_reason = IBT_CM_NOT_SUPPORTED;
ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
IBT_CM_FAILURE_REQ, IBT_CM_NOT_SUPPORTED, NULL, 0);
return (IBCM_SEND_REJ);
}
if (clnt_info->reply_event->rep.cm_rdma_ra_out >
statep->hcap->hca_max_rdma_out_qp) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_req_cm_hdlr: "
"statep %p, ERROR: client specified rdma_ra_out %d "
"is greater than HCA Limit %d, rejecting MAD",
statep, clnt_info->reply_event->rep.cm_rdma_ra_out,
statep->hcap->hca_max_rdma_out_qp);
*reject_reason = IBT_CM_NOT_SUPPORTED;
ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
IBT_CM_FAILURE_REQ, IBT_CM_NOT_SUPPORTED, NULL, 0);
return (IBCM_SEND_REJ);
}
rep_msgp->rep_resp_resources =
clnt_info->reply_event->rep.cm_rdma_ra_in;
rep_msgp->rep_initiator_depth =
clnt_info->reply_event->rep.cm_rdma_ra_out;
rep_msgp->rep_target_delay_plus |= IBT_CM_FLOW_CONTROL;
rep_msgp->rep_rnr_retry_cnt_plus =
(clnt_info->reply_event->rep.cm_rnr_retry_cnt & 0x7) << 5;
if (qp_attrs.qp_srq != NULL) {
rep_msgp->rep_rnr_retry_cnt_plus |= (1 << 4);
}
local_ca_guid = h2b64(statep->local_hca_guid);
bcopy(&local_ca_guid, rep_msgp->rep_local_ca_guid,
sizeof (ib_guid_t));
if (statep->is_this_ofuv_chan &&
qp_attrs.qp_info.qp_state == IBT_STATE_RTR)
goto skip_rtr_trans;
if (ibcm_invoke_qp_modify(statep, cm_req_msg, rep_msgp) !=
IBT_SUCCESS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_req_cm_hdlr "
"statep 0x%p ibcm_invoke_qp_modify failed because "
"of invalid data", statep);
*reject_reason = IBT_CM_NO_RESC;
ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
IBT_CM_FAILURE_REQ, IBT_CM_CI_FAILURE, NULL, 0);
return (IBCM_SEND_REJ);
}
skip_rtr_trans:
IBCM_SET_CHAN_PRIVATE(statep->channel, statep);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_cep_req_cm_hdlr: "
"qp_info.qp_state = %x", qp_attrs.qp_info.qp_state);
rep_msgp->rep_local_qpn_plus = h2b32(qp_attrs.qp_qpn << 8);
statep->local_qpn = qp_attrs.qp_qpn;
switch (qp_attrs.qp_info.qp_trans) {
case IBT_RD_SRV:
rep_msgp->rep_local_qkey = h2b32(
qp_attrs.qp_info.qp_transport.rd.rd_qkey);
break;
case IBT_RC_SRV:
rep_msgp->rep_starting_psn_plus =
h2b32(IBCM_QP_RC(qp_attrs).rc_rq_psn << 8);
break;
case IBT_UC_SRV:
rep_msgp->rep_starting_psn_plus =
h2b32(IBCM_QP_UC(qp_attrs).uc_sq_psn << 8);
break;
}
#ifdef NO_EEC_SUPPORT_YET
if (ret_args.cm_channel.ch_eec != NULL) {
status = ibt_query_eec(ret_args.cm_channel.ch_eec,
&eec_attrs);
if (status == IBT_SUCCESS) {
rep_msgp->rep_local_eecn_plus =
h2b32(((uint32_t)eec_attrs.eec_eecn << 8));
}
}
#endif
rep_msgp->rep_target_delay_plus |= (status == IBT_SUCCESS) ?
statep->hcap->hca_ack_delay << 3 : 0;
IBTF_DPRINTF_L4(cmlog, "ibcm_process_cep_req_cm_hdlr:statep %p "
"REP priv len %x", statep, clnt_info->priv_data_len);
if (clnt_info->priv_data_len != 0) {
bcopy(clnt_info->priv_data, rep_msgp->rep_private_data,
min(IBT_REP_PRIV_DATA_SZ,
clnt_info->priv_data_len));
}
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*statep))
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*rep_msgp))
return (IBCM_SEND_REP);
}
rej_msgp = (ibcm_rej_msg_t *)IBCM_OUT_MSGP(statep->stored_msg);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_cep_req_cm_hdlr: statep %p REJ "
"priv len %x", statep, clnt_info->priv_data_len);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rej_msgp))
if (clnt_info->priv_data_len != 0) {
bcopy(clnt_info->priv_data, rej_msgp->rej_private_data,
min(IBT_REJ_PRIV_DATA_SZ, clnt_info->priv_data_len));
}
if (cb_status == IBT_CM_REDIRECT_PORT) {
ib_gid_t tgid;
tgid.gid_guid =
h2b64(clnt_info->reply_event->rej.ari_gid.gid_guid);
tgid.gid_prefix =
h2b64(clnt_info->reply_event->rej.ari_gid.gid_prefix);
*arej_len = sizeof (ib_gid_t);
bcopy(&tgid, &rej_msgp->rej_addl_rej_info, sizeof (ib_gid_t));
IBTF_DPRINTF_L3(cmlog, "ibcm_process_cep_req_cm_hdlr: ari_gid= "
"%llX:%llX", tgid.gid_prefix, tgid.gid_guid);
} else if (cb_status == IBT_CM_REDIRECT) {
ibcm_classportinfo_msg_t tclp;
ibcm_init_clp_to_mad(&tclp,
&clnt_info->reply_event->rej.ari_redirect);
bcopy(&tclp, rej_msgp->rej_addl_rej_info, sizeof (tclp));
*arej_len = sizeof (ibcm_classportinfo_msg_t);
} else if (cb_status == IBT_CM_REJECT) {
*arej_len = min(
clnt_info->reply_event->rej.ari_consumer.rej_ari_len,
IBT_CM_ADDL_REJ_LEN);
bcopy(clnt_info->reply_event->rej.ari_consumer.rej_ari,
&rej_msgp->rej_addl_rej_info, *arej_len);
if (((statep->svcid & IB_SID_IPADDR_PREFIX_MASK) == 0) &&
(statep->svcid & IB_SID_IPADDR_PREFIX)) {
rej_msgp->rej_addl_rej_info[0] = 1;
}
}
rej_msgp->rej_msg_type_plus = IBT_CM_FAILURE_REQ << 6;
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*rej_msgp))
return (IBCM_SEND_REJ);
}
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)
{
void *priv_data = NULL;
ibcm_status_t rval = IBCM_SEND_RTU;
ibt_cm_event_t event;
ibt_cm_status_t cb_status = IBT_CM_ACCEPT;
ibt_cm_return_args_t ret_args;
ibcm_clnt_reply_info_t clnt_info;
uint8_t req_init_depth;
IBTF_DPRINTF_L3(cmlog, "ibcm_cep_state_rep: statep 0x%p", statep);
if (statep->cm_handler != NULL) {
bzero(&event, sizeof (event));
event.cm_type = IBT_CM_EVENT_REP_RCV;
event.cm_channel = statep->channel;
event.cm_session_id = statep;
IBCM_EVT_REP(event).rep_rdma_ra_in =
cm_rep_msgp->rep_initiator_depth;
req_init_depth =
((uint8_t *)&(((ibcm_req_msg_t *)IBCM_OUT_MSGP(
statep->stored_msg))->req_local_eec_no_plus))[3];
IBCM_EVT_REP(event).rep_rdma_ra_out =
min(cm_rep_msgp->rep_resp_resources, req_init_depth);
IBTF_DPRINTF_L3(cmlog, "ibcm_cep_state_rep: statep 0x%p, "
"InitDepth %d, RespResr %d", statep,
cm_rep_msgp->rep_initiator_depth,
IBCM_EVT_REP(event).rep_rdma_ra_out);
IBCM_EVT_REP(event).rep_service_time = ibt_ib2usec(
((uint8_t *)&(((ibcm_req_msg_t *)IBCM_OUT_MSGP(
statep->stored_msg))->req_starting_psn_plus))[3] >> 3);
IBCM_EVT_REP(event).rep_service_time -=
2 * statep->pkt_life_time - ibcm_sw_delay;
IBCM_EVT_REP(event).rep_failover_status =
cm_rep_msgp->rep_target_delay_plus >> 1 & 3;
if (cm_rep_msgp->rep_target_delay_plus & 0x1)
IBCM_EVT_REP(event).rep_flags |= IBT_CM_FLOW_CONTROL;
if ((cm_rep_msgp->rep_rnr_retry_cnt_plus >> 4) & 0x1)
IBCM_EVT_REP(event).rep_flags |= IBT_CM_SRQ_EXISTS;
IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_rep: statep 0x%p "
"rep_service_time %d", statep,
IBCM_EVT_REP(event).rep_service_time);
event.cm_priv_data = &(cm_rep_msgp->rep_private_data[0]);
event.cm_priv_data_len = IBT_REP_PRIV_DATA_SZ;
priv_data = kmem_zalloc(IBT_MAX_PRIV_DATA_SZ, KM_SLEEP);
bzero(&ret_args, sizeof (ret_args));
ibcm_insert_trace(statep, IBCM_TRACE_CALLED_REP_RCVD_EVENT);
cb_status = statep->cm_handler(statep->state_cm_private, &event,
&ret_args, priv_data, IBT_RTU_PRIV_DATA_SZ);
ibcm_insert_trace(statep, IBCM_TRACE_RET_REP_RCVD_EVENT);
IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_rep: statep 0x%p "
"Client handler returned %x", statep, cb_status);
if (cb_status == IBT_CM_DEFER) {
if (statep->defer_cm_msg == NULL)
statep->defer_cm_msg =
kmem_zalloc(IBCM_MSG_SIZE, KM_SLEEP);
bcopy(cm_rep_msgp, statep->defer_cm_msg, IBCM_MSG_SIZE);
mutex_enter(&statep->state_mutex);
statep->clnt_proceed = IBCM_UNBLOCK;
cv_broadcast(&statep->block_client_cv);
mutex_exit(&statep->state_mutex);
kmem_free(priv_data, IBT_MAX_PRIV_DATA_SZ);
return (IBCM_DEFER);
}
}
mutex_enter(&statep->state_mutex);
statep->clnt_proceed = IBCM_FAIL;
cv_broadcast(&statep->block_client_cv);
mutex_exit(&statep->state_mutex);
clnt_info.reply_event = (ibt_cm_proceed_reply_t *)&ret_args.cm_ret;
clnt_info.priv_data = priv_data;
clnt_info.priv_data_len = ret_args.cm_ret_len;
rval =
ibcm_process_cep_rep_cm_hdlr(statep, cb_status, &clnt_info,
reject_reason, arej_len, cm_rep_msgp);
if (priv_data != NULL)
kmem_free(priv_data, IBT_MAX_PRIV_DATA_SZ);
return (rval);
}
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)
{
ibcm_status_t rval = IBCM_SEND_RTU;
ibcm_rej_msg_t *rej_msgp;
if (cb_status == IBT_CM_DEFAULT)
cb_status = IBT_CM_ACCEPT;
if (cb_status == IBT_CM_REJECT) {
*reject_reason = IBT_CM_CONSUMER;
} else if (cb_status == IBT_CM_REDIRECT_PORT) {
*reject_reason = IBT_CM_PORT_REDIRECT;
} else if (cb_status == IBT_CM_REDIRECT) {
*reject_reason = IBT_CM_REDIRECT_CM;
} else if (cb_status == IBT_CM_NO_RESOURCE) {
*reject_reason = IBT_CM_NO_RESC;
} else if (cb_status != IBT_CM_ACCEPT) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_rep_cm_hdlr: statep "
"0x%p, Client handler returned unexpected value %d",
statep, cb_status);
*reject_reason = IBT_CM_CONSUMER;
} else
*reject_reason = IBT_CM_SUCCESS;
if (cb_status == IBT_CM_ACCEPT) {
ib_time_t time;
time = ibt_usec2ib(statep->pkt_life_time * 2 +
ibt_ib2usec(cm_rep_msgp->rep_target_delay_plus >> 3));
IBTF_DPRINTF_L5(cmlog, "ibcm_process_cep_rep_cm_hdlr: statep %p"
" active cep_timeout(usec) 0x%x ", statep, time);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_cep_rep_cm_hdlr: statep %p"
" passive hca_ack_delay(ib_time) = 0x%x, ", statep,
cm_rep_msgp->rep_target_delay_plus >> 3);
IBTF_DPRINTF_L5(cmlog, "ibcm_process_cep_rep_cm_hdlr: statep %p"
" rnr_retry_cnt = 0x%x", statep,
cm_rep_msgp->rep_rnr_retry_cnt_plus >> 5);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*statep))
statep->starting_psn =
b2h32(cm_rep_msgp->rep_starting_psn_plus) >> 8;
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*statep))
if (ibcm_invoke_qp_modify(statep,
(ibcm_req_msg_t *)IBCM_OUT_MSGP(statep->stored_msg),
cm_rep_msgp) != IBT_SUCCESS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_rep_cm_hdlr: "
"statep %p, ibcm_invoke_qp_modify to RTR failed",
statep);
*reject_reason = IBT_CM_NO_RESC;
} else if (ibcm_invoke_rtu_qp_modify(statep, time, cm_rep_msgp)
!= IBT_SUCCESS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_rep_cm_hdlr: "
"statep %p ibcm_invoke_rtu_qp_modify to RTS failed",
statep);
(void) ibcm_cep_to_error_state(statep);
*reject_reason = IBT_CM_NO_RESC;
}
if (*reject_reason == IBT_CM_NO_RESC) {
IBCM_SET_CHAN_PRIVATE(statep->channel, NULL);
ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
IBT_CM_FAILURE_REP, IBT_CM_CI_FAILURE, NULL, 0);
return (IBCM_SEND_REJ);
}
if (clnt_info->priv_data_len != 0) {
ibcm_rtu_msg_t *rtu_msgp;
rtu_msgp = (ibcm_rtu_msg_t *)
IBCM_OUT_MSGP(statep->stored_msg);
bcopy(clnt_info->priv_data, rtu_msgp->rtu_private_data,
min(IBT_RTU_PRIV_DATA_SZ,
clnt_info->priv_data_len));
}
*reject_reason = IBT_CM_SUCCESS;
return (rval);
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*rej_msgp))
rej_msgp = (ibcm_rej_msg_t *)IBCM_OUT_MSGP(statep->stored_msg);
rej_msgp->rej_msg_type_plus = IBT_CM_FAILURE_REP << 6;
if (clnt_info->priv_data_len != 0)
bcopy(clnt_info->priv_data, rej_msgp->rej_private_data,
min(IBT_REJ_PRIV_DATA_SZ, clnt_info->priv_data_len));
if (clnt_info->reply_event != NULL)
*arej_len =
min(clnt_info->reply_event->rej.ari_consumer.rej_ari_len,
IBT_CM_ADDL_REJ_LEN);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(clnt_info->reply_event->rej))
if (*arej_len != 0)
bcopy(clnt_info->reply_event->rej.ari_consumer.rej_ari,
&rej_msgp->rej_addl_rej_info, *arej_len);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(clnt_info->reply_event->rej))
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*rej_msgp))
rval = IBCM_SEND_REJ;
IBCM_SET_CHAN_PRIVATE(statep->channel, NULL);
ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
IBT_CM_FAILURE_REP, *reject_reason, NULL, 0);
return (rval);
}
static ibt_status_t
ibcm_invoke_rtu_qp_modify(ibcm_state_data_t *statep, ib_time_t timeout,
ibcm_rep_msg_t *rep_msg)
{
ibt_status_t status;
ibt_qp_info_t qp_info;
ibt_cep_modify_flags_t cep_flags = IBT_CEP_SET_RTR_RTS;
bzero(&qp_info, sizeof (qp_info));
qp_info.qp_trans = ibtl_cm_get_chan_type(statep->channel);
qp_info.qp_current_state = IBT_STATE_RTR;
switch (qp_info.qp_trans) {
case IBT_RC_SRV:
IBCM_QPINFO_RC_PATH(qp_info).cep_timeout = timeout;
IBCM_QPINFO_RC(qp_info).rc_retry_cnt = statep->cep_retry_cnt;
IBCM_QPINFO_RC(qp_info).rc_rnr_retry_cnt =
statep->local_qp_rnr_cnt;
IBCM_QPINFO_RC(qp_info).rc_sq_psn = statep->starting_psn;
if (statep->mode == IBCM_ACTIVE_MODE) {
IBCM_QPINFO_RC(qp_info).rc_rdma_ra_out =
rep_msg->rep_resp_resources;
} else {
IBCM_QPINFO_RC(qp_info).rc_rdma_ra_out =
rep_msg->rep_initiator_depth;
}
if (statep->alt_port &&
(((rep_msg->rep_target_delay_plus >> 1) & 0x3) ==
IBT_CM_FAILOVER_ACCEPT)) {
cep_flags |= IBT_CEP_SET_MIG;
IBCM_QPINFO_RC(qp_info).rc_mig_state =
IBT_STATE_REARMED;
}
break;
case IBT_UC_SRV:
IBCM_QPINFO_UC_PATH(qp_info).cep_timeout = timeout;
break;
default:
IBTF_DPRINTF_L2(cmlog, "ibcm_invoke_rtu_qp_modify: "
"unknow svc_type = %x", qp_info.qp_trans);
break;
}
status = ibt_modify_qp(statep->channel, cep_flags, &qp_info, NULL);
IBTF_DPRINTF_L4(cmlog, "ibcm_invoke_rtu_qp_modify: statep 0x%p "
"modify qp status = %d", statep, status);
if (status == IBT_SUCCESS)
ibcm_insert_trace(statep, IBCM_TRACE_RTR_RTS);
else
ibcm_insert_trace(statep, IBCM_TRACE_RTR_RTS_FAIL);
#ifdef DEBUG
print_modify_qp("RTR to RTS", statep->channel, cep_flags, &qp_info);
if (statep->channel != NULL) {
ibt_qp_query_attr_t qp_attrs;
(void) ibt_query_qp(statep->channel, &qp_attrs);
IBTF_DPRINTF_L4(cmlog, "ibcm_invoke_rtu_qp_modify: "
"qp_info.qp_state = %x", qp_attrs.qp_info.qp_state);
}
#endif
return (status);
}
void
ibcm_cep_state_rtu(ibcm_state_data_t *statep, ibcm_rtu_msg_t *cm_rtu_msgp)
{
ibt_status_t status;
ibt_cm_event_t event;
ibcm_rep_msg_t *rep_msgp = (ibcm_rep_msg_t *)
IBCM_OUT_MSGP(statep->stored_msg);
IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_rtu: statep 0x%p", statep);
ASSERT(statep->channel != NULL);
status = ibcm_invoke_rtu_qp_modify(statep,
ibt_usec2ib(statep->remote_ack_delay), rep_msgp);
if (status != IBT_SUCCESS) {
(void) ibcm_cep_to_error_state(statep);
IBCM_SET_CHAN_PRIVATE(statep->channel, NULL);
ibcm_post_rej_mad(statep, IBT_CM_NO_RESC,
IBT_CM_FAILURE_UNKNOWN, NULL, 0);
ibcm_handler_conn_fail(statep, IBT_CM_FAILURE_REJ_SENT,
IBT_CM_FAILURE_UNKNOWN, IBT_CM_NO_RESC, NULL, 0);
mutex_enter(&statep->state_mutex);
statep->cep_in_rts = IBCM_FAIL;
cv_broadcast(&statep->block_mad_cv);
mutex_exit(&statep->state_mutex);
return;
}
mutex_enter(&statep->state_mutex);
statep->state = IBCM_STATE_ESTABLISHED;
ibtl_cm_chan_is_open(statep->channel);
mutex_exit(&statep->state_mutex);
ASSERT(statep->cm_handler != NULL);
bzero(&event, sizeof (event));
event.cm_channel = statep->channel;
event.cm_session_id = NULL;
event.cm_type = IBT_CM_EVENT_CONN_EST;
if (cm_rtu_msgp != NULL) {
event.cm_priv_data = &(cm_rtu_msgp->rtu_private_data[0]);
event.cm_priv_data_len = IBT_RTU_PRIV_DATA_SZ;
}
ibcm_insert_trace(statep, IBCM_TRACE_CALLED_CONN_EST_EVENT);
(void) statep->cm_handler(statep->state_cm_private, &event, NULL,
NULL, 0);
ibcm_insert_trace(statep, IBCM_TRACE_RET_CONN_EST_EVENT);
if (ibcm_enable_trace & 4)
ibcm_dump_conn_trace(statep);
else
IBTF_DPRINTF_L2(cmlog, "ibcm_cep_state_rtu CONN_EST Channel %p",
statep->channel);
mutex_enter(&statep->state_mutex);
statep->cep_in_rts = IBCM_UNBLOCK;
cv_broadcast(&statep->block_mad_cv);
mutex_exit(&statep->state_mutex);
}
void
ibcm_cep_send_rtu(ibcm_state_data_t *statep)
{
if (statep->cm_handler) {
ibt_cm_event_t event;
bzero(&event, sizeof (event));
event.cm_type = IBT_CM_EVENT_CONN_EST;
event.cm_channel = statep->channel;
event.cm_session_id = NULL;
event.cm_priv_data = NULL;
event.cm_priv_data_len = 0;
ibcm_insert_trace(statep, IBCM_TRACE_CALLED_CONN_EST_EVENT);
(void) statep->cm_handler(statep->state_cm_private, &event,
NULL, NULL, 0);
ibcm_insert_trace(statep, IBCM_TRACE_RET_CONN_EST_EVENT);
} else {
IBTF_DPRINTF_L2(cmlog, "ibcm_cep_send_rtu: cm_handler NULL");
}
if (ibcm_enable_trace & 4)
ibcm_dump_conn_trace(statep);
else
IBTF_DPRINTF_L2(cmlog, "ibcm_cep_send_rtu CONN_EST Channel %p",
statep->channel);
mutex_enter(&statep->state_mutex);
statep->cep_in_rts = IBCM_UNBLOCK;
cv_broadcast(&statep->block_mad_cv);
mutex_exit(&statep->state_mutex);
}
ibt_status_t
ibcm_cep_to_error_state(ibcm_state_data_t *statep)
{
ibt_status_t status = IBT_SUCCESS;
if (statep->channel != NULL) {
ibt_qp_info_t qp_info;
bzero(&qp_info, sizeof (qp_info));
qp_info.qp_trans = IBT_RC_SRV;
qp_info.qp_state = IBT_STATE_ERROR;
status = ibt_modify_qp(statep->channel, IBT_CEP_SET_STATE,
&qp_info, NULL);
IBTF_DPRINTF_L4(cmlog, "ibcm_cep_to_error_state: "
"statep %p ibt_modify_qp() = %d", statep, status);
if (status == IBT_SUCCESS)
ibcm_insert_trace(statep, IBCM_TRACE_ERROR);
else
ibcm_insert_trace(statep, IBCM_TRACE_ERROR_FAIL);
}
#ifdef NO_EEC_SUPPORT_YET
if (statep->channel.ch_eec != NULL) {
ibt_eec_info_t eec_info;
bzero(&eec_info, sizeof (ibt_eec_info_t));
eec_info.eec_state = what;
status = ibtl_cm_modify_eec(statep->channel.ch_eec, &eec_info,
IBT_CEP_SET_NOTHING);
IBTF_DPRINTF_L4(cmlog, "ibcm_cep_to_error_state: "
"ibtl_cm_modify_eec() returned = %x", status);
}
#endif
return (status);
}
void
ibcm_cep_state_rej(ibcm_state_data_t *statep, ibcm_rej_msg_t *rej_msgp,
ibcm_conn_state_t rej_state)
{
ibt_cm_event_t event;
ibt_status_t status;
IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_rej: statep 0x%p", statep);
ibcm_path_cache_purge();
if ((rej_state == IBCM_STATE_REP_SENT) ||
(rej_state == IBCM_STATE_MRA_REP_RCVD)) {
status = ibcm_cep_to_error_state(statep);
IBTF_DPRINTF_L5(cmlog, "ibcm_cep_state_rej: statep 0x%p "
"ibcm_cep_to_error_state returned %d", statep,
status);
}
if (statep->channel)
ibtl_cm_chan_open_is_aborted(statep->channel);
IBCM_SET_CHAN_PRIVATE(statep->channel, NULL);
bzero(&event, sizeof (event));
if (statep->cm_handler) {
event.cm_type = IBT_CM_EVENT_FAILURE;
event.cm_channel = statep->channel;
event.cm_session_id = NULL;
event.cm_priv_data = &(rej_msgp->rej_private_data[0]);
event.cm_priv_data_len = IBT_REJ_PRIV_DATA_SZ;
event.cm_event.failed.cf_code = IBT_CM_FAILURE_REJ_RCV;
event.cm_event.failed.cf_msg = rej_msgp->rej_msg_type_plus >> 6;
event.cm_event.failed.cf_reason =
b2h16(rej_msgp->rej_rejection_reason);
IBTF_DPRINTF_L3(cmlog, "ibcm_cep_state_rej: rej_reason = %d",
event.cm_event.failed.cf_reason);
ibcm_copy_addl_rej(statep, rej_msgp, &event.cm_event.failed);
(void) statep->cm_handler(statep->state_cm_private, &event,
NULL, NULL, 0);
}
if (statep->open_return_data != NULL)
bcopy(&event.cm_event.failed.cf_additional,
&statep->open_return_data->rc_arej_info,
sizeof (ibt_arej_info_t));
if (ibcm_enable_trace != 0)
ibcm_dump_conn_trace(statep);
mutex_enter(&statep->state_mutex);
ibcm_open_done(statep);
mutex_exit(&statep->state_mutex);
}
static void
ibcm_copy_addl_rej(ibcm_state_data_t *statep, ibcm_rej_msg_t *rej_msgp,
ibt_cm_conn_failed_t *failed)
{
uint16_t rej_reason = b2h16(rej_msgp->rej_rejection_reason);
uint8_t ari_len = rej_msgp->rej_reject_info_len_plus >> 1;
ibcm_classportinfo_msg_t tclp;
ibt_arej_info_t *cf_addl = &failed->cf_additional;
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cf_addl))
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(failed->cf_arej_info_valid))
failed->cf_arej_info_valid = B_FALSE;
IBTF_DPRINTF_L3(cmlog, "ibcm_copy_addl_rej: rej_reason = %d "
"ari_len = %d", rej_reason, ari_len);
if ((statep->mode == IBCM_PASSIVE_MODE) &&
(rej_reason != IBT_CM_CONSUMER))
return;
switch (rej_reason) {
case IBT_CM_PRIM_GID:
case IBT_CM_ALT_GID:
case IBT_CM_PORT_REDIRECT:
if (ari_len < sizeof (ib_gid_t))
break;
failed->cf_arej_info_valid = B_TRUE;
bcopy(rej_msgp->rej_addl_rej_info, &cf_addl->ari_gid,
sizeof (ib_gid_t));
cf_addl->ari_gid.gid_guid = b2h64(cf_addl->ari_gid.gid_guid);
cf_addl->ari_gid.gid_prefix =
b2h64(cf_addl->ari_gid.gid_prefix);
IBTF_DPRINTF_L4(cmlog, "ibcm_copy_addl_rej: ari_gid= %llX:%llX",
cf_addl->ari_gid.gid_prefix, cf_addl->ari_gid.gid_guid);
break;
case IBT_CM_PRIM_LID:
case IBT_CM_ALT_LID:
if (ari_len < sizeof (ib_lid_t))
break;
failed->cf_arej_info_valid = B_TRUE;
bcopy(rej_msgp->rej_addl_rej_info, &cf_addl->ari_lid,
sizeof (ib_lid_t));
cf_addl->ari_lid = b2h16(cf_addl->ari_lid);
IBTF_DPRINTF_L4(cmlog, "ibcm_copy_addl_rej: ari_lid= 0x%lX",
cf_addl->ari_lid);
break;
case IBT_CM_INVALID_PRIM_SL:
case IBT_CM_INVALID_ALT_SL:
if (ari_len < 1)
break;
failed->cf_arej_info_valid = B_TRUE;
cf_addl->ari_sl = rej_msgp->rej_addl_rej_info[0] >> 4;
break;
case IBT_CM_INVALID_PRIM_TC:
case IBT_CM_INVALID_ALT_TC:
if (ari_len < 1)
break;
failed->cf_arej_info_valid = B_TRUE;
cf_addl->ari_tclass = rej_msgp->rej_addl_rej_info[0];
break;
case IBT_CM_INVALID_PRIM_HOP:
case IBT_CM_INVALID_ALT_HOP:
if (ari_len < 1)
break;
failed->cf_arej_info_valid = B_TRUE;
cf_addl->ari_hop = rej_msgp->rej_addl_rej_info[0];
break;
case IBT_CM_INVALID_PRIM_RATE:
case IBT_CM_INVALID_ALT_RATE:
if (ari_len < 1)
break;
failed->cf_arej_info_valid = B_TRUE;
cf_addl->ari_rate = rej_msgp->rej_addl_rej_info[0] >> 2;
break;
case IBT_CM_REDIRECT_CM:
if (ari_len < sizeof (ibcm_classportinfo_msg_t))
break;
failed->cf_arej_info_valid = B_TRUE;
bcopy(rej_msgp->rej_addl_rej_info, &tclp, sizeof (tclp));
ibcm_init_clp_from_mad(&tclp, &cf_addl->ari_redirect);
break;
case IBT_CM_INVALID_MTU:
if (ari_len < 1)
break;
failed->cf_arej_info_valid = B_TRUE;
cf_addl->ari_mtu = rej_msgp->rej_addl_rej_info[0] >> 4;
break;
case IBT_CM_CONSUMER:
if (ari_len == 0)
break;
failed->cf_arej_info_valid = B_TRUE;
if (ari_len > IBT_CM_ADDL_REJ_LEN)
ari_len = IBT_CM_ADDL_REJ_LEN;
bcopy(&rej_msgp->rej_addl_rej_info,
cf_addl->ari_consumer.rej_ari, ari_len);
cf_addl->ari_consumer.rej_ari_len = ari_len;
break;
case IBT_CM_INVALID_PRIM_FLOW:
case IBT_CM_INVALID_ALT_FLOW:
if (ari_len < 3)
break;
failed->cf_arej_info_valid = B_TRUE;
cf_addl->ari_flow =
b2h32(*(uint32_t *)&rej_msgp->rej_addl_rej_info) >> 12;
break;
default:
break;
}
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(failed->cf_arej_info_valid))
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*cf_addl))
}
static void
ibcm_init_clp_to_mad(ibcm_classportinfo_msg_t *clp, ibt_redirect_info_t *rinfo)
{
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*clp))
bcopy(&ibcm_clpinfo, clp, sizeof (ibcm_clpinfo));
clp->RedirectGID_hi = h2b64(rinfo->rdi_gid.gid_prefix);
clp->RedirectGID_lo = h2b64(rinfo->rdi_gid.gid_guid);
clp->RedirectTC_plus =
h2b32((rinfo->rdi_tclass << 24) | (rinfo->rdi_sl << 20) |
(rinfo->rdi_flow & 0xfffff));
clp->RedirectLID = h2b16(rinfo->rdi_dlid);
clp->RedirectQP_plus = h2b32(rinfo->rdi_qpn & 0xffffff);
clp->RedirectQ_Key = h2b32(rinfo->rdi_qkey);
clp->RedirectP_Key = h2b16(rinfo->rdi_pkey);
IBTF_DPRINTF_L4(cmlog, "ibcm_init_clp_to_mad: RedirectGID= %llX:%llX,"
" RedirectLID= 0x%lX", clp->RedirectGID_hi, clp->RedirectGID_lo,
clp->RedirectLID);
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*clp))
}
static void
ibcm_init_clp_from_mad(ibcm_classportinfo_msg_t *clp,
ibt_redirect_info_t *rinfo)
{
uint32_t temp32;
rinfo->rdi_gid.gid_prefix = b2h64(clp->RedirectGID_hi);
rinfo->rdi_gid.gid_guid = b2h64(clp->RedirectGID_lo);
temp32 = b2h32(clp->RedirectTC_plus);
rinfo->rdi_tclass = temp32 >> 24;
rinfo->rdi_sl = (temp32 >> 20) & 0xf;
rinfo->rdi_flow = temp32 & 0xffff;
rinfo->rdi_dlid = b2h16(clp->RedirectLID);
rinfo->rdi_qpn = b2h32(clp->RedirectQP_plus & 0xffffff);
rinfo->rdi_qkey = b2h32(clp->RedirectQ_Key);
rinfo->rdi_pkey = b2h16(clp->RedirectP_Key);
IBTF_DPRINTF_L4(cmlog, "ibcm_init_clp_from_mad: RedirectGID= %llX:%llX,"
" RedirectLID= 0x%lX", rinfo->rdi_gid.gid_prefix,
rinfo->rdi_gid.gid_guid, rinfo->rdi_dlid);
}
void
ibcm_cep_state_rej_est(ibcm_state_data_t *statep)
{
ibt_cm_event_t event;
ibt_status_t status;
IBTF_DPRINTF_L3(cmlog, "ibcm_cep_state_rej_est:");
status = ibcm_cep_to_error_state(statep);
IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_rej_est: statep 0x%p "
"ibcm_cep_to_error_state returned %d", statep, status);
IBCM_SET_CHAN_PRIVATE(statep->channel, NULL);
ibtl_cm_chan_is_closing(statep->channel);
if (statep->cm_handler) {
bzero(&event, sizeof (event));
event.cm_type = IBT_CM_EVENT_CONN_CLOSED;
event.cm_channel = statep->channel;
event.cm_session_id = NULL;
event.cm_priv_data = NULL;
event.cm_priv_data_len = 0;
event.cm_event.closed = IBT_CM_CLOSED_REJ_RCVD;
IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_rej_est: "
"rej_reason = %d", event.cm_event.failed.cf_reason);
ibcm_insert_trace(statep, IBCM_TRACE_CALLED_CONN_CLOSE_EVENT);
(void) statep->cm_handler(statep->state_cm_private, &event,
NULL, NULL, 0);
ibcm_insert_trace(statep, IBCM_TRACE_RET_CONN_CLOSE_EVENT);
}
}
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)
{
void *priv_data = NULL;
ibt_cm_ud_event_t ud_event;
ibcm_sidr_rep_msg_t *sidr_repp;
ibt_cm_ud_return_args_t ud_ret_args;
ibt_cm_status_t cb_status;
ibt_qp_query_attr_t qp_attr;
ibt_status_t retval;
ibcm_ud_clnt_reply_info_t ud_clnt_info;
ASSERT(ud_statep->ud_cm_handler != NULL);
ud_event.cm_type = IBT_CM_UD_EVENT_SIDR_REQ;
ud_event.cm_session_id = ud_statep;
ud_event.cm_event.sidr_req.sreq_service_id = ud_statep->ud_svc_id;
ud_event.cm_event.sidr_req.sreq_hca_guid = ud_statep->ud_hcap->hca_guid;
ud_event.cm_event.sidr_req.sreq_pkey = b2h16(sidr_reqp->sidr_req_pkey);
ud_event.cm_event.sidr_req.sreq_hca_port = cm_mad_addr->port_num;
ud_event.cm_priv_data =
&(sidr_reqp->sidr_req_private_data[0]);
ud_event.cm_priv_data_len = IBT_SIDR_REQ_PRIV_DATA_SZ;
sidr_repp =
(ibcm_sidr_rep_msg_t *)IBCM_OUT_MSGP(ud_statep->ud_stored_msg);
priv_data = &(sidr_repp->sidr_rep_private_data[0]);
bzero(&ud_ret_args, sizeof (ud_ret_args));
cb_status = ud_statep->ud_cm_handler(ud_statep->ud_state_cm_private,
&ud_event, &ud_ret_args, priv_data, IBT_SIDR_REP_PRIV_DATA_SZ);
if (cb_status == IBT_CM_DEFER) {
mutex_enter(&ud_statep->ud_state_mutex);
ud_statep->ud_clnt_proceed = IBCM_UNBLOCK;
cv_broadcast(&ud_statep->ud_block_client_cv);
mutex_exit(&ud_statep->ud_state_mutex);
return (IBCM_DEFER);
}
mutex_enter(&ud_statep->ud_state_mutex);
ud_statep->ud_clnt_proceed = IBCM_FAIL;
cv_broadcast(&ud_statep->ud_block_client_cv);
mutex_exit(&ud_statep->ud_state_mutex);
if (cb_status == IBT_CM_ACCEPT) {
retval = ibt_query_qp(ud_ret_args.ud_channel, &qp_attr);
if (retval != IBT_SUCCESS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_sidr_req_ud_handler: "
"Failed to retrieve QPN from the channel: %d",
retval);
*sidr_status = IBT_CM_SREP_NO_CHAN;
return (IBCM_SEND_SIDR_REP);
} else if (qp_attr.qp_info.qp_trans != IBT_UD_SRV) {
IBTF_DPRINTF_L2(cmlog, "ibcm_sidr_req_ud_handler: "
"Server/Passive returned non-UD %d transport type "
"QP", qp_attr.qp_info.qp_trans);
*sidr_status = IBT_CM_SREP_NO_CHAN;
return (IBCM_SEND_SIDR_REP);
}
ud_clnt_info.ud_qkey = qp_attr.qp_info.qp_transport.ud.ud_qkey;
ud_clnt_info.ud_qpn = qp_attr.qp_qpn;
}
ud_clnt_info.priv_data = priv_data;
ud_clnt_info.priv_data_len = ud_ret_args.ud_ret_len;
ud_clnt_info.redirect_infop = &ud_ret_args.ud_redirect;
ibcm_process_sidr_req_cm_hdlr(ud_statep, cb_status, &ud_clnt_info,
sidr_status, sidr_repp);
return (IBCM_SEND_SIDR_REP);
}
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)
{
void *sidr_rep_privp;
IBTF_DPRINTF_L5(cmlog, "ibcm_process_sidr_req_cm_hdlr(%p, %x, "
"%p, %p, %p)", ud_statep, cb_status, ud_clnt_info,
sidr_status, sidr_repp);
if (cb_status == IBT_CM_DEFAULT)
cb_status = IBT_CM_REJECT;
if (cb_status == IBT_CM_ACCEPT)
*sidr_status = IBT_CM_SREP_CHAN_VALID;
else if ((cb_status == IBT_CM_REJECT) ||
(cb_status == IBT_CM_NO_RESOURCE))
*sidr_status = IBT_CM_SREP_REJ;
else if (cb_status == IBT_CM_NO_CHANNEL)
*sidr_status = IBT_CM_SREP_NO_CHAN;
else if (cb_status == IBT_CM_REDIRECT)
*sidr_status = IBT_CM_SREP_REDIRECT;
else *sidr_status = IBT_CM_SREP_REJ;
sidr_rep_privp = (void *)(&(sidr_repp->sidr_rep_private_data[0]));
if ((cb_status == IBT_CM_ACCEPT || cb_status == IBT_CM_REJECT) &&
(ud_clnt_info->priv_data != sidr_rep_privp) &&
ud_clnt_info->priv_data_len) {
bcopy(ud_clnt_info->priv_data, sidr_rep_privp,
min(ud_clnt_info->priv_data_len,
IBT_SIDR_REP_PRIV_DATA_SZ));
}
if (*sidr_status != IBT_CM_SREP_CHAN_VALID) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_sidr_req_cm_hdlr: "
"ud_handler return a failure: %d", cb_status);
if (*sidr_status == IBT_CM_SREP_REDIRECT) {
ibcm_init_clp_to_mad(
(ibcm_classportinfo_msg_t *)
&sidr_repp->sidr_rep_class_port_info,
ud_clnt_info->redirect_infop);
}
return;
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sidr_repp))
sidr_repp->sidr_rep_qkey =
h2b32(ud_clnt_info->ud_qkey);
sidr_repp->sidr_rep_qpn_plus = h2b32(ud_clnt_info->ud_qpn << 8);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*sidr_repp))
}
static void
ibcm_sidr_rep_ud_handler(ibcm_ud_state_data_t *ud_statep,
ibcm_sidr_rep_msg_t *sidr_rep_msgp)
{
ibt_cm_ud_event_t ud_event;
IBTF_DPRINTF_L5(cmlog, "ibcm_sidr_rep_ud_handler: ud_statep 0x%p",
ud_statep);
if (ud_statep->ud_cm_handler == NULL) {
IBTF_DPRINTF_L2(cmlog, "ibcm_sidr_rep_ud_handler: "
"cm_handler NULL");
return;
}
ud_event.cm_type = IBT_CM_UD_EVENT_SIDR_REP;
ud_event.cm_session_id = NULL;
ud_event.cm_event.sidr_rep.srep_status =
sidr_rep_msgp->sidr_rep_rep_status;
ud_event.cm_event.sidr_rep.srep_remote_qpn =
b2h32(sidr_rep_msgp->sidr_rep_qpn_plus) >> 8;
ud_event.cm_event.sidr_rep.srep_remote_qkey =
h2b32(sidr_rep_msgp->sidr_rep_qkey);
if (ud_event.cm_event.sidr_rep.srep_status == IBT_CM_SREP_REDIRECT) {
ibcm_init_clp_from_mad(
(ibcm_classportinfo_msg_t *)
sidr_rep_msgp->sidr_rep_class_port_info,
&ud_event.cm_event.sidr_rep.srep_redirect);
if (ud_statep->ud_return_data != NULL)
bcopy(&ud_event.cm_event.sidr_rep.srep_redirect,
&ud_statep->ud_return_data->ud_redirect,
sizeof (ibt_redirect_info_t));
}
ud_event.cm_priv_data = &(sidr_rep_msgp->sidr_rep_private_data[0]);
ud_event.cm_priv_data_len = IBT_SIDR_REP_PRIV_DATA_SZ;
(void) ud_statep->ud_cm_handler(ud_statep->ud_state_cm_private,
&ud_event, NULL, NULL, 0);
}
void
ibcm_process_lap_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
ibcm_mad_addr_t *cm_mad_addr)
{
ibcm_status_t state_lookup_status;
ibcm_lap_msg_t *lap_msg = (ibcm_lap_msg_t *)
(&input_madp[IBCM_MAD_HDR_SIZE]);
ibcm_apr_msg_t *apr_msg;
ibcm_state_data_t *statep = NULL;
IBTF_DPRINTF_L4(cmlog, "ibcm_process_lap_msg:");
rw_enter(&hcap->hca_state_rwlock, RW_READER);
state_lookup_status = ibcm_lookup_msg(IBCM_INCOMING_LAP,
b2h32(lap_msg->lap_remote_comm_id), 0, 0, hcap, &statep);
rw_exit(&hcap->hca_state_rwlock);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_lap_msg: lookup status %x"
" com id %x", state_lookup_status,
b2h32(lap_msg->lap_remote_comm_id));
if (state_lookup_status != IBCM_LOOKUP_EXISTS) {
return;
}
ibcm_insert_trace(statep, IBCM_TRACE_INCOMING_LAP);
mutex_enter(&statep->state_mutex);
if ((statep->state == IBCM_STATE_ESTABLISHED) &&
(statep->ap_state == IBCM_AP_STATE_IDLE) &&
(statep->mode == IBCM_PASSIVE_MODE)) {
if ((statep->lapr_msg) &&
(IBCM_OUT_HDRP(statep->lapr_msg)->TransactionID ==
((ib_mad_hdr_t *)(input_madp))->TransactionID))
ibcm_post_stored_apr_mad(statep, input_madp);
else {
ibcm_status_t clnt_response;
statep->ap_state = IBCM_AP_STATE_LAP_RCVD;
statep->clnt_proceed = IBCM_BLOCK;
mutex_exit(&statep->state_mutex);
if (statep->lapr_msg == NULL) {
if (ibcm_alloc_out_msg(
statep->stored_reply_addr.ibmf_hdl,
&statep->lapr_msg, MAD_METHOD_SEND) !=
IBT_SUCCESS) {
mutex_enter(&statep->state_mutex);
statep->clnt_proceed = IBCM_FAIL;
cv_broadcast(&statep->block_client_cv);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
return;
}
}
apr_msg = (ibcm_apr_msg_t *)
IBCM_OUT_MSGP(statep->lapr_msg);
IBCM_OUT_HDRP(statep->lapr_msg)->TransactionID =
((ib_mad_hdr_t *)(input_madp))->TransactionID;
clnt_response =
ibcm_cep_state_lap(statep, lap_msg, apr_msg);
IBTF_DPRINTF_L4(cmlog, "ibcm_process_lap_msg:"
" statep 0x%p apr status %d", statep,
apr_msg->apr_ap_status);
if (clnt_response == IBCM_DEFER) {
IBTF_DPRINTF_L4(cmlog, "ibcm_process_lap_msg: "
"client returned DEFER response");
return;
}
mutex_enter(&statep->state_mutex);
statep->clnt_proceed = IBCM_FAIL;
cv_broadcast(&statep->block_client_cv);
mutex_exit(&statep->state_mutex);
ibcm_post_apr_mad(statep);
return;
}
}
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
static void
ibcm_post_stored_apr_mad(ibcm_state_data_t *statep, uint8_t *input_madp)
{
ibmf_msg_t *ibmf_apr_msg;
uint8_t apr_msg[IBCM_MSG_SIZE];
bcopy(IBCM_OUT_MSGP(statep->lapr_msg), apr_msg, IBCM_MSG_SIZE);
mutex_exit(&statep->state_mutex);
if (ibcm_alloc_out_msg(statep->stored_reply_addr.ibmf_hdl,
&ibmf_apr_msg, MAD_METHOD_SEND) != IBT_SUCCESS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_post_stored_apr_mad: "
"ibcm_alloc_out_msg failed");
mutex_enter(&statep->state_mutex);
return;
}
bcopy(apr_msg, IBCM_OUT_MSGP(ibmf_apr_msg), IBCM_MSG_SIZE);
IBCM_OUT_HDRP(ibmf_apr_msg)->AttributeID =
h2b16(IBCM_INCOMING_APR + IBCM_ATTR_BASE_ID);
IBCM_OUT_HDRP(ibmf_apr_msg)->TransactionID =
((ib_mad_hdr_t *)(input_madp))->TransactionID;
ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_APR);
ibcm_post_rc_mad(statep, ibmf_apr_msg, ibcm_post_stored_apr_complete,
ibmf_apr_msg);
mutex_enter(&statep->state_mutex);
}
ibcm_status_t
ibcm_cep_state_lap(ibcm_state_data_t *statep, ibcm_lap_msg_t *lap_msg,
ibcm_apr_msg_t *apr_msg)
{
ibt_cm_event_t event;
ibt_cm_return_args_t ret_args;
ibt_cm_status_t cb_status;
ibcm_clnt_reply_info_t clnt_info;
IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_lap: statep 0x%p", statep);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*apr_msg))
if (!(statep->hcap->hca_caps & IBT_HCA_AUTO_PATH_MIG)) {
apr_msg->apr_ap_status = IBT_CM_AP_NOT_SUPPORTED;
return (IBCM_SEND_APR);
}
if (statep->local_qpn !=
b2h32(lap_msg->lap_remote_qpn_eecn_plus) >> 8) {
apr_msg->apr_ap_status = IBT_CM_AP_REJECT;
IBTF_DPRINTF_L4(cmlog, "ibcm_cep_state_lap: local_qpn %x does "
"not match remote's remote_qpn %x", statep->local_qpn,
b2h32(lap_msg->lap_remote_qpn_eecn_plus) >> 8);
return (IBCM_SEND_APR);
}
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*apr_msg))
bzero(&event, sizeof (event));
event.cm_type = IBT_CM_EVENT_LAP_RCV;
event.cm_channel = statep->channel;
event.cm_session_id = statep;
event.cm_priv_data = lap_msg->lap_private_data;
event.cm_priv_data_len = IBT_LAP_PRIV_DATA_SZ;
event.cm_event.lap.lap_timeout = ibt_ib2usec(
((uint8_t *)&lap_msg->lap_remote_qpn_eecn_plus)[3] >> 3);
ibcm_fill_adds_from_lap(&event.cm_event.lap.lap_alternate_path,
lap_msg, IBCM_PASSIVE_MODE);
cb_status = statep->cm_handler(statep->state_cm_private, &event,
&ret_args, apr_msg->apr_private_data, IBT_APR_PRIV_DATA_SZ);
IBTF_DPRINTF_L3(cmlog, "ibcm_cep_state_lap: cb_status = %d", cb_status);
if (cb_status == IBT_CM_DEFER) {
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(statep->defer_cm_msg))
if (statep->defer_cm_msg == NULL)
statep->defer_cm_msg =
kmem_zalloc(IBCM_MSG_SIZE, KM_SLEEP);
bcopy(lap_msg, statep->defer_cm_msg, IBCM_MSG_SIZE);
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(statep->defer_cm_msg))
mutex_enter(&statep->state_mutex);
statep->clnt_proceed = IBCM_UNBLOCK;
cv_broadcast(&statep->block_client_cv);
mutex_exit(&statep->state_mutex);
return (IBCM_DEFER);
}
clnt_info.reply_event = (ibt_cm_proceed_reply_t *)&ret_args.cm_ret;
clnt_info.priv_data = NULL;
clnt_info.priv_data_len = 0;
ibcm_process_cep_lap_cm_hdlr(statep, cb_status, &clnt_info, lap_msg,
apr_msg);
return (IBCM_SEND_APR);
}
static void
ibcm_fill_adds_from_lap(ibt_adds_vect_t *adds, ibcm_lap_msg_t *lap_msg,
ibcm_mode_t mode)
{
adds->av_srvl = lap_msg->lap_alt_sl_plus >> 4;
if (mode == IBCM_PASSIVE_MODE) {
adds->av_dgid.gid_prefix =
b2h64(lap_msg->lap_alt_l_port_gid.gid_prefix);
adds->av_dgid.gid_guid =
b2h64(lap_msg->lap_alt_l_port_gid.gid_guid);
adds->av_sgid.gid_prefix =
b2h64(lap_msg->lap_alt_r_port_gid.gid_prefix);
adds->av_sgid.gid_guid =
b2h64(lap_msg->lap_alt_r_port_gid.gid_guid);
adds->av_dlid = b2h16(lap_msg->lap_alt_l_port_lid);
} else {
adds->av_sgid.gid_prefix =
b2h64(lap_msg->lap_alt_l_port_gid.gid_prefix);
adds->av_sgid.gid_guid =
b2h64(lap_msg->lap_alt_l_port_gid.gid_guid);
adds->av_dgid.gid_prefix =
b2h64(lap_msg->lap_alt_r_port_gid.gid_prefix);
adds->av_dgid.gid_guid =
b2h64(lap_msg->lap_alt_r_port_gid.gid_guid);
adds->av_dlid = b2h16(lap_msg->lap_alt_r_port_lid);
}
IBTF_DPRINTF_L4(cmlog, "ibcm_fill_adds_from_lap: SGID=(%llX:%llX)",
adds->av_sgid.gid_prefix, adds->av_sgid.gid_guid);
IBTF_DPRINTF_L4(cmlog, "ibcm_fill_adds_from_lap: DGID=(%llX:%llX)",
adds->av_dgid.gid_prefix, adds->av_dgid.gid_guid);
adds->av_srate = lap_msg->lap_alt_srate_plus & 0x3f;
if ((lap_msg->lap_alt_sl_plus & 0x8) == 0) {
uint32_t flow_tclass = b2h32(lap_msg->lap_alt_flow_label_plus);
adds->av_send_grh = B_TRUE;
adds->av_flow = flow_tclass >> 12;
adds->av_tclass = flow_tclass & 0xff;
adds->av_hop = lap_msg->lap_alt_hop_limit;
} else {
adds->av_send_grh = B_FALSE;
}
}
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)
{
ibtl_cm_hca_port_t port;
ibt_qp_query_attr_t qp_attrs;
ibt_cep_modify_flags_t cep_flags;
ibt_status_t status;
ibt_adds_vect_t *adds;
if (cb_status == IBT_CM_DEFAULT)
cb_status = IBT_CM_REJECT;
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*apr_msg))
apr_msg->apr_addl_info_len = 0;
if (cb_status == IBT_CM_ACCEPT) {
apr_msg->apr_ap_status = IBT_CM_AP_LOADED;
} else if (cb_status == IBT_CM_REJECT) {
apr_msg->apr_ap_status = IBT_CM_AP_REJECT;
} else if (cb_status == IBT_CM_REDIRECT) {
apr_msg->apr_ap_status = IBT_CM_AP_REDIRECT;
apr_msg->apr_addl_info_len = sizeof (ibcm_classportinfo_msg_t);
ibcm_init_clp_to_mad(
(ibcm_classportinfo_msg_t *)apr_msg->apr_addl_info,
&clnt_info->reply_event->apr);
} else if (cb_status == IBT_CM_NO_RESOURCE) {
apr_msg->apr_ap_status = IBT_CM_AP_REJECT;
} else {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_lap_cm_hdlr: statep %p"
" Client handler unexpected return %x", statep, cb_status);
cb_status = IBT_CM_REJECT;
apr_msg->apr_ap_status = IBT_CM_AP_REJECT;
}
IBTF_DPRINTF_L4(cmlog, "ibcm_process_cep_lap_cm_hdlr: statep 0x%p "
" client handler returned %d, apr status %d", statep, cb_status,
apr_msg->apr_ap_status);
if ((clnt_info->priv_data != NULL) && (clnt_info->priv_data_len > 0))
bcopy(clnt_info->priv_data, apr_msg->apr_private_data,
min(clnt_info->priv_data_len, IBT_APR_PRIV_DATA_SZ));
if (cb_status != IBT_CM_ACCEPT)
return;
if (ibt_query_qp(statep->channel, &qp_attrs) != IBT_SUCCESS ||
(qp_attrs.qp_info.qp_state != IBT_STATE_RTS &&
qp_attrs.qp_info.qp_state != IBT_STATE_SQD)) {
apr_msg->apr_ap_status = IBT_CM_AP_REJECT;
return;
}
cep_flags = IBT_CEP_SET_ALT_PATH | IBT_CEP_SET_STATE;
qp_attrs.qp_info.qp_current_state = qp_attrs.qp_info.qp_state;
adds = &IBCM_QP_RC(qp_attrs).rc_alt_path.cep_adds_vect;
ibcm_fill_adds_from_lap(adds, lap_msg, IBCM_PASSIVE_MODE);
if ((status = ibtl_cm_get_hca_port(adds->av_sgid,
statep->local_hca_guid, &port)) != IBT_SUCCESS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_lap_cm_hdlr:"
" ibtl_cm_get_hca_port failed status %d", status);
apr_msg->apr_ap_status = IBT_CM_AP_REJECT;
return;
}
IBCM_QP_RC(qp_attrs).rc_alt_path.cep_hca_port_num = port.hp_port;
IBTF_DPRINTF_L4(cmlog, "ibcm_process_cep_lap_cm_hdlr: statep 0x%p "
"gid = (%llx, %llx), port_num = %d", statep,
IBCM_QP_RC(qp_attrs).rc_alt_path.cep_adds_vect.av_dgid.
gid_prefix,
IBCM_QP_RC(qp_attrs).rc_alt_path.cep_adds_vect.av_dgid.gid_guid,
port.hp_port);
status = ibt_pkey2index_byguid(statep->local_hca_guid,
port.hp_port, statep->pkey,
&IBCM_QP_RC(qp_attrs).rc_alt_path.cep_pkey_ix);
if (status != IBT_SUCCESS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_lap_cm_hdlr: statep %p"
" ibt_pkey2index_byguid failed %d", statep, status);
apr_msg->apr_ap_status = IBT_CM_AP_REJECT;
return;
}
IBCM_QP_RC(qp_attrs).rc_alt_path.cep_timeout =
lap_msg->lap_alt_local_acktime_plus >> 3;
qp_attrs.qp_info.qp_trans = IBT_RC_SRV;
if (IBCM_QP_RC(qp_attrs).rc_mig_state == IBT_STATE_MIGRATED) {
IBTF_DPRINTF_L3(cmlog, "ibcm_process_cep_lap_cm_hdlr: statep %p"
": rearming APM", statep);
cep_flags |= IBT_CEP_SET_MIG;
IBCM_QP_RC(qp_attrs).rc_mig_state = IBT_STATE_REARMED;
}
status = ibt_modify_qp(statep->channel, cep_flags, &qp_attrs.qp_info,
NULL);
if (status != IBT_SUCCESS) {
ibcm_insert_trace(statep, IBCM_TRACE_SET_ALT_FAIL);
} else
ibcm_insert_trace(statep, IBCM_TRACE_SET_ALT);
#ifdef DEBUG
(void) ibt_query_qp(statep->channel, &qp_attrs);
print_modify_qp("PASSIVE LAP QUERY", statep->channel,
cep_flags, &qp_attrs.qp_info);
#endif
if (status != IBT_SUCCESS) {
apr_msg->apr_ap_status = IBT_CM_AP_REJECT;
IBTF_DPRINTF_L2(cmlog, "ibcm_process_cep_lap_cm_hdlr:"
" ibt_modify_qp() returned = %d", status);
return;
}
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*apr_msg))
}
void
ibcm_post_apr_mad(ibcm_state_data_t *statep)
{
ibcm_apr_msg_t *apr_msgp;
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*apr_msgp))
apr_msgp = (ibcm_apr_msg_t *)IBCM_OUT_MSGP(statep->lapr_msg);
apr_msgp->apr_local_comm_id = h2b32(statep->local_comid);
apr_msgp->apr_remote_comm_id = h2b32(statep->remote_comid);
IBCM_OUT_HDRP(statep->lapr_msg)->AttributeID =
h2b16(IBCM_INCOMING_APR + IBCM_ATTR_BASE_ID);
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*apr_msgp))
ibcm_insert_trace(statep, IBCM_TRACE_OUTGOING_APR);
ibcm_post_rc_mad(statep, statep->lapr_msg, ibcm_post_apr_complete,
statep);
}
void
ibcm_process_apr_msg(ibcm_hca_info_t *hcap, uint8_t *input_madp,
ibcm_mad_addr_t *cm_mad_addr)
{
ibcm_status_t state_lookup_status;
ibcm_apr_msg_t *apr_msg = (ibcm_apr_msg_t *)
(&input_madp[IBCM_MAD_HDR_SIZE]);
ibcm_state_data_t *statep = NULL;
IBTF_DPRINTF_L4(cmlog, "ibcm_process_apr_msg:");
rw_enter(&hcap->hca_state_rwlock, RW_READER);
state_lookup_status = ibcm_lookup_msg(IBCM_INCOMING_APR,
b2h32(apr_msg->apr_remote_comm_id), 0, 0, hcap, &statep);
rw_exit(&hcap->hca_state_rwlock);
if (state_lookup_status != IBCM_LOOKUP_EXISTS) {
return;
}
if (IBCM_OUT_HDRP(statep->lapr_msg)->TransactionID !=
((ib_mad_hdr_t *)(input_madp))->TransactionID) {
mutex_enter(&statep->state_mutex);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
IBTF_DPRINTF_L3(cmlog, "ibcm_process_apr_msg: statep 0x%p"
": rcv'd APR MAD with comid 0x%x",
statep, b2h32(apr_msg->apr_remote_comm_id));
IBTF_DPRINTF_L3(cmlog, "ibcm_process_apr_msg: "
"tid expected 0x%llX tid found 0x%llX",
b2h64(IBCM_OUT_HDRP(statep->lapr_msg)->TransactionID),
b2h64(((ib_mad_hdr_t *)(input_madp))->TransactionID));
return;
}
IBTF_DPRINTF_L4(cmlog, "ibcm_process_apr_msg: statep 0x%p "
"lookup status %x", statep, state_lookup_status);
mutex_enter(&statep->state_mutex);
if (!((statep->state == IBCM_STATE_ESTABLISHED) &&
((statep->ap_state == IBCM_AP_STATE_LAP_SENT) ||
(statep->ap_state == IBCM_AP_STATE_MRA_LAP_RCVD)))) {
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
return;
}
statep->ap_state = IBCM_AP_STATE_APR_RCVD;
if (statep->timerid != 0) {
timeout_id_t timer_val;
timer_val = statep->timerid;
statep->timerid = 0;
mutex_exit(&statep->state_mutex);
(void) untimeout(timer_val);
} else {
mutex_exit(&statep->state_mutex);
}
ibcm_insert_trace(statep, IBCM_TRACE_INCOMING_APR);
ibcm_cep_state_apr(statep,
(ibcm_lap_msg_t *)IBCM_OUT_MSGP(statep->lapr_msg), apr_msg);
mutex_enter(&statep->state_mutex);
statep->ap_state = IBCM_AP_STATE_IDLE;
cv_broadcast(&statep->block_mad_cv);
statep->ap_done = B_TRUE;
cv_broadcast(&statep->block_client_cv);
IBCM_REF_CNT_DECR(statep);
mutex_exit(&statep->state_mutex);
}
static void
ibcm_set_apr_arej(int ap_status, ibcm_apr_msg_t *apr_msgp,
ibt_arej_info_t *ari, boolean_t *ari_valid)
{
uint8_t ari_len = apr_msgp->apr_addl_info_len;
ibcm_classportinfo_msg_t tclp;
*ari_valid = B_FALSE;
IBTF_DPRINTF_L3(cmlog, "ibcm_set_apr_arej: apr_status = %d "
"ari_len = %d", ap_status, ari_len);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ari))
switch (ap_status) {
case IBT_CM_AP_REDIRECT:
if (ari_len < sizeof (ibcm_classportinfo_msg_t))
break;
*ari_valid = B_TRUE;
bcopy(apr_msgp->apr_addl_info, &tclp, sizeof (tclp));
ibcm_init_clp_from_mad(&tclp, &ari->ari_redirect);
break;
case IBT_CM_AP_RLID_REJECTED:
if (ari_len < sizeof (ib_lid_t))
break;
*ari_valid = B_TRUE;
bcopy(apr_msgp->apr_addl_info, &ari->ari_lid,
sizeof (ib_lid_t));
ari->ari_lid = b2h16(ari->ari_lid);
break;
case IBT_CM_AP_RGID_REJECTED:
if (ari_len < sizeof (ib_gid_t))
break;
*ari_valid = B_TRUE;
bcopy(apr_msgp->apr_addl_info, &ari->ari_gid,
sizeof (ib_gid_t));
ari->ari_gid.gid_guid = b2h64(ari->ari_gid.gid_guid);
ari->ari_gid.gid_prefix = b2h64(ari->ari_gid.gid_prefix);
IBTF_DPRINTF_L4(cmlog, "ibcm_set_apr_arej: ari_gid= %llX:%llX",
ari->ari_gid.gid_prefix, ari->ari_gid.gid_guid);
break;
case IBT_CM_AP_FLOW_REJECTED:
if (ari_len < 3)
break;
*ari_valid = B_TRUE;
ari->ari_flow =
b2h32(*(uint32_t *)&apr_msgp->apr_addl_info) >> 12;
break;
case IBT_CM_AP_TCLASS_REJECTED:
if (ari_len < 1)
break;
*ari_valid = B_TRUE;
ari->ari_tclass = apr_msgp->apr_addl_info[0];
break;
case IBT_CM_AP_HOP_REJECTED:
if (ari_len < 1)
break;
*ari_valid = B_TRUE;
ari->ari_hop = apr_msgp->apr_addl_info[0];
break;
case IBT_CM_AP_RATE_REJECTED:
if (ari_len < 1)
break;
*ari_valid = B_TRUE;
ari->ari_rate = apr_msgp->apr_addl_info[0] >> 2;
break;
case IBT_CM_AP_SL_REJECTED:
if (ari_len < 1)
break;
*ari_valid = B_TRUE;
ari->ari_sl = apr_msgp->apr_addl_info[0] >> 4;
break;
default:
break;
}
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(*ari))
}
void
ibcm_cep_state_apr(ibcm_state_data_t *statep, ibcm_lap_msg_t *lap_msg,
ibcm_apr_msg_t *apr_msg)
{
ibt_cm_event_t event;
ibcm_status_t status = IBCM_SUCCESS;
uint8_t ap_status = apr_msg->apr_ap_status;
IBTF_DPRINTF_L3(cmlog, "ibcm_cep_state_apr: statep 0x%p, ap_status %d",
statep, ap_status);
if (ap_status == IBT_CM_AP_LOADED)
status = ibcm_set_qp_from_apr(statep, lap_msg);
if (statep->ap_return_data != NULL) {
if ((statep->ap_return_data->ap_priv_data != NULL) &&
(statep->ap_return_data->ap_priv_data_len > 0))
bcopy(apr_msg->apr_private_data,
statep->ap_return_data->ap_priv_data,
statep->ap_return_data->ap_priv_data_len);
if (status == IBCM_FAILURE) {
statep->ap_return_data->ap_status = IBT_CM_AP_REJECT;
statep->ap_return_data->ap_arej_info_valid = B_FALSE;
} else {
statep->ap_return_data->ap_status = ap_status;
ibcm_set_apr_arej(ap_status, apr_msg,
&statep->ap_return_data->ap_arej_info,
&statep->ap_return_data->ap_arej_info_valid);
}
mutex_enter(&statep->state_mutex);
statep->ap_done = B_TRUE;
cv_broadcast(&statep->block_client_cv);
mutex_exit(&statep->state_mutex);
} else {
bzero(&event, sizeof (event));
event.cm_type = IBT_CM_EVENT_APR_RCV;
event.cm_channel = statep->channel;
event.cm_session_id = NULL;
event.cm_priv_data = apr_msg->apr_private_data;
event.cm_priv_data_len = IBT_APR_PRIV_DATA_SZ;
if (status == IBCM_FAILURE) {
event.cm_event.apr.apr_status = IBT_CM_AP_REJECT;
event.cm_event.apr.apr_arej_info_valid = B_FALSE;
} else {
event.cm_event.apr.apr_status = ap_status;
ibcm_set_apr_arej(ap_status, apr_msg,
&event.cm_event.apr.apr_arej_info,
&event.cm_event.apr.apr_arej_info_valid);
}
statep->cm_handler(statep->state_cm_private, &event,
NULL, apr_msg->apr_private_data, IBT_APR_PRIV_DATA_SZ);
}
mutex_enter(&statep->state_mutex);
ibcm_open_done(statep);
mutex_exit(&statep->state_mutex);
}
static ibcm_status_t
ibcm_set_qp_from_apr(ibcm_state_data_t *statep, ibcm_lap_msg_t *lap_msg)
{
ibtl_cm_hca_port_t port;
ibt_adds_vect_t *adds;
ibt_qp_query_attr_t qp_attrs;
ibt_cep_modify_flags_t cep_flags;
ibt_status_t status;
IBTF_DPRINTF_L3(cmlog, "ibcm_set_qp_from_apr: statep 0x%p", statep);
status = ibt_query_qp(statep->channel, &qp_attrs);
if (status != IBT_SUCCESS ||
(qp_attrs.qp_info.qp_state != IBT_STATE_RTS &&
qp_attrs.qp_info.qp_state != IBT_STATE_SQD)) {
IBTF_DPRINTF_L2(cmlog, "ibcm_set_qp_from_apr: ibt_query_qp "
"failed, status = %d, qp_state = %d", statep, status,
qp_attrs.qp_info.qp_state);
return (IBCM_FAILURE);
}
cep_flags = IBT_CEP_SET_ALT_PATH | IBT_CEP_SET_STATE;
qp_attrs.qp_info.qp_current_state = qp_attrs.qp_info.qp_state;
adds = &IBCM_QP_RC(qp_attrs).rc_alt_path.cep_adds_vect;
ibcm_fill_adds_from_lap(adds, lap_msg, IBCM_ACTIVE_MODE);
if ((status = ibtl_cm_get_hca_port(adds->av_sgid,
statep->local_hca_guid, &port)) != IBT_SUCCESS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_set_qp_from_apr: "
"ibtl_cm_get_hca_port failed status = %d", status);
IBTF_DPRINTF_L5(cmlog, "ibcm_set_qp_from_apr:"
" ibtl_cm_get_hca_port sgid guid %llX",
adds->av_sgid.gid_guid);
IBTF_DPRINTF_L5(cmlog, "ibcm_set_qp_from_apr:"
" ibtl_cm_get_hca_port sgid prefix %llX ",
adds->av_sgid.gid_prefix);
return (IBCM_FAILURE);
}
IBCM_QP_RC(qp_attrs).rc_alt_path.cep_hca_port_num =
port.hp_port;
IBTF_DPRINTF_L4(cmlog, "ibcm_set_qp_from_apr: "
"gid = %llx:%llx, port_num = %d",
IBCM_QP_RC(qp_attrs).rc_alt_path.cep_adds_vect.av_sgid.
gid_prefix,
IBCM_QP_RC(qp_attrs).rc_alt_path.cep_adds_vect.av_sgid.gid_guid,
port.hp_port);
status = ibt_pkey2index_byguid(statep->local_hca_guid,
port.hp_port, statep->pkey,
&IBCM_QP_RC(qp_attrs).rc_alt_path.cep_pkey_ix);
if (status != IBT_SUCCESS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_set_qp_from_apr: "
"ibt_pkey2index_byguid failed %d", status);
return (IBCM_FAILURE);
}
qp_attrs.qp_info.qp_trans = IBT_RC_SRV;
IBCM_QP_RC(qp_attrs).rc_alt_path.cep_timeout =
ibt_usec2ib(statep->remote_ack_delay +
2 * statep->rc_alt_pkt_lt);
if (IBCM_QP_RC(qp_attrs).rc_mig_state == IBT_STATE_MIGRATED) {
IBTF_DPRINTF_L3(cmlog, "ibcm_set_qp_from_apr: statep 0x%p: "
"rearming APM", statep);
cep_flags |= IBT_CEP_SET_MIG;
IBCM_QP_RC(qp_attrs).rc_mig_state = IBT_STATE_REARMED;
}
status = ibt_modify_qp(statep->channel, cep_flags, &qp_attrs.qp_info,
NULL);
if (status != IBT_SUCCESS)
ibcm_insert_trace(statep, IBCM_TRACE_SET_ALT_FAIL);
else
ibcm_insert_trace(statep, IBCM_TRACE_SET_ALT);
#ifdef DEBUG
(void) ibt_query_qp(statep->channel, &qp_attrs);
print_modify_qp("ACTIVE LAP QUERY", statep->channel,
cep_flags, &qp_attrs.qp_info);
#endif
if (status != IBT_SUCCESS) {
IBTF_DPRINTF_L2(cmlog, "ibcm_set_qp_from_apr:"
" ibt_modify_qp() failed, status = %d", status);
return (IBCM_FAILURE);
}
return (IBCM_SUCCESS);
}
void
ibcm_sync_lapr_idle(ibcm_state_data_t *statep)
{
timeout_id_t timer_val = statep->timerid;
ibt_cm_event_t event;
IBTF_DPRINTF_L3(cmlog, "ibcm_sync_lapr_idle:"
"statep %p state %d ap_state %d", statep, statep->state,
statep->ap_state);
ASSERT(MUTEX_HELD(&statep->state_mutex));
_NOTE(LOCK_RELEASED_AS_SIDE_EFFECT(&statep->state_mutex))
if ((statep->ap_state == IBCM_AP_STATE_LAP_RCVD) ||
(statep->ap_state == IBCM_AP_STATE_APR_RCVD) ||
(statep->ap_state == IBCM_AP_STATE_MRA_LAP_SENT) ||
(statep->ap_state == IBCM_AP_STATE_TIMED_OUT)) {
while (statep->ap_state != IBCM_AP_STATE_IDLE)
cv_wait(&statep->block_mad_cv, &statep->state_mutex);
mutex_exit(&statep->state_mutex);
} else if ((statep->ap_state == IBCM_AP_STATE_LAP_SENT) ||
(statep->ap_state == IBCM_AP_STATE_MRA_LAP_RCVD)) {
if (statep->ap_return_data != NULL) {
statep->ap_return_data->ap_status =
IBT_CM_AP_ABORT;
statep->ap_state = IBCM_AP_STATE_IDLE;
cv_broadcast(&statep->block_client_cv);
IBTF_DPRINTF_L3(cmlog, "ibcm_sync_lapr_idle:"
"blocked wait");
}
statep->timerid = 0;
mutex_exit(&statep->state_mutex);
if (timer_val != 0)
(void) untimeout(timer_val);
if (statep->ap_return_data == NULL) {
bzero(&event, sizeof (event));
event.cm_type = IBT_CM_EVENT_APR_RCV;
event.cm_channel = statep->channel;
event.cm_session_id = NULL;
event.cm_priv_data = NULL;
event.cm_priv_data_len = 0;
event.cm_event.apr.apr_status = IBT_CM_AP_ABORT;
statep->cm_handler(statep->state_cm_private, &event,
NULL, NULL, 0);
IBTF_DPRINTF_L3(cmlog, "ibcm_sync_lapr_idle:"
"non-blocked wait");
}
} else mutex_exit(&statep->state_mutex);
ASSERT(!MUTEX_HELD(&statep->state_mutex));
}
#ifdef DEBUG
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)
{
IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP %s %p", prefix, ibt_qp);
IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP flags 0x%x", flags);
IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP "
"rc_rdma_ra_in %d rc_rdma_ra_out %d",
qp_attr->qp_transport.rc.rc_rdma_ra_in,
qp_attr->qp_transport.rc.rc_rdma_ra_out);
IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP primary: "
"port %d path bits %d dlid %X",
qp_attr->qp_transport.rc.rc_path.cep_hca_port_num,
qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_src_path,
qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_dlid);
IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP primary: "
"pkey index %d cep_timeout %d",
qp_attr->qp_transport.rc.rc_path.cep_pkey_ix,
qp_attr->qp_transport.rc.rc_path.cep_timeout);
IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP primary: "
"srvl %d flow label %d tclass %d",
qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_srvl,
qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_flow,
qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_tclass);
IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP primary: "
"hop %d srate %d sgid_ix %d send_grh %d",
qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_hop,
qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_srate,
qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_sgid_ix,
qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_send_grh);
IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP primary: "
"dgid prefix %llX dgid guid %llX",
qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_dgid.gid_prefix,
qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_dgid.gid_guid);
IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP primary: "
"sgid prefix %llX sgid guid %llX",
qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_sgid.gid_prefix,
qp_attr->qp_transport.rc.rc_path.cep_adds_vect.av_sgid.gid_guid);
IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP alternate: "
"port %d path bits %d dlid %X",
qp_attr->qp_transport.rc.rc_alt_path.cep_hca_port_num,
qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_src_path,
qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_dlid);
IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP alternate: "
"pkey index %d cep_timeout %d",
qp_attr->qp_transport.rc.rc_alt_path.cep_pkey_ix,
qp_attr->qp_transport.rc.rc_alt_path.cep_timeout);
IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP alternate: "
"srvl %d flow label %d tclass %d",
qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_srvl,
qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_flow,
qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_tclass);
IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP alternate: "
"hop %d srate %d sgid_ix %d send_grh %d",
qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_hop,
qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_srate,
qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_sgid_ix,
qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_send_grh);
IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP alternate: "
"dgid prefix %llX dgid guid %llX",
qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_dgid.
gid_prefix,
qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_dgid.
gid_guid);
IBTF_DPRINTF_L4(cmlog, "PRINT_MODIFY_QP alternate: "
"sgid prefix %llX sgid guid %llX",
qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_sgid.
gid_prefix,
qp_attr->qp_transport.rc.rc_alt_path.cep_adds_vect.av_sgid.
gid_guid);
}
#endif