#include <sys/vfs.h>
#include <sys/vnode.h>
#include <sys/errno.h>
#include <sys/cred.h>
#include <sys/uio.h>
#include <sys/semaphore.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/ib/ibtl/ibvti.h>
#include <sys/ib/clients/of/ofa_solaris.h>
#include <sys/ib/clients/of/sol_ofs/sol_ofs_common.h>
#include <sys/ib/clients/of/ofed_kernel.h>
#include <sys/ib/clients/of/sol_uverbs/sol_uverbs.h>
#include <sys/ib/clients/of/sol_uverbs/sol_uverbs_qp.h>
#include <sys/ib/clients/of/sol_uverbs/sol_uverbs_event.h>
static uint32_t ibt_cep_flags2ibv(ibt_cep_flags_t);
static void uverbs_cq_ctrl(uverbs_ucq_uobj_t *, sol_uverbs_cq_ctrl_t);
extern char *sol_uverbs_dbg_str;
typedef struct uverbs_mcast_entry {
llist_head_t list;
ibt_mcg_info_t mcg;
} uverbs_mcast_entry_t;
typedef struct {
int valid;
enum ib_qp_attr_mask req_param[IB_QPT_RAW_ETY + 1];
enum ib_qp_attr_mask opt_param[IB_QPT_RAW_ETY + 1];
} uverbs_qp_state_tbl_t;
static uverbs_qp_state_tbl_t
uverbs_qp_state_table[IB_QPS_ERR + 1][IB_QPS_ERR + 1] = {
[IB_QPS_RESET] = {
[IB_QPS_RESET] = { .valid = 1 },
[IB_QPS_ERR] = { .valid = 1 },
[IB_QPS_INIT] = { .valid = 1,
.req_param = {
[IB_QPT_UD] = (IB_QP_PKEY_INDEX |
IB_QP_PORT | IB_QP_QKEY),
[IB_QPT_UC] = (IB_QP_PKEY_INDEX | IB_QP_PORT |
IB_QP_ACCESS_FLAGS),
[IB_QPT_RC] = (IB_QP_PKEY_INDEX | IB_QP_PORT |
IB_QP_ACCESS_FLAGS),
[IB_QPT_SMI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
[IB_QPT_GSI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
}
},
},
[IB_QPS_INIT] = {
[IB_QPS_RESET] = { .valid = 1 },
[IB_QPS_ERR] = { .valid = 1 },
[IB_QPS_INIT] = { .valid = 1,
.opt_param = {
[IB_QPT_UD] = (IB_QP_PKEY_INDEX | IB_QP_PORT |
IB_QP_QKEY),
[IB_QPT_UC] = (IB_QP_PKEY_INDEX | IB_QP_PORT |
IB_QP_ACCESS_FLAGS),
[IB_QPT_RC] = (IB_QP_PKEY_INDEX | IB_QP_PORT |
IB_QP_ACCESS_FLAGS),
[IB_QPT_SMI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
[IB_QPT_GSI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
}
},
[IB_QPS_RTR] = { .valid = 1,
.req_param = {
[IB_QPT_UC] = (IB_QP_AV | IB_QP_PATH_MTU |
IB_QP_DEST_QPN | IB_QP_RQ_PSN),
[IB_QPT_RC] = (IB_QP_AV | IB_QP_PATH_MTU |
IB_QP_DEST_QPN | IB_QP_RQ_PSN |
IB_QP_MAX_DEST_RD_ATOMIC |
IB_QP_MIN_RNR_TIMER),
},
.opt_param = {
[IB_QPT_UD] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
[IB_QPT_UC] = (IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
IB_QP_PKEY_INDEX),
[IB_QPT_RC] = (IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
IB_QP_PKEY_INDEX),
[IB_QPT_SMI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
[IB_QPT_GSI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
}
}
},
[IB_QPS_RTR] = {
[IB_QPS_RESET] = { .valid = 1 },
[IB_QPS_ERR] = { .valid = 1 },
[IB_QPS_RTS] = { .valid = 1,
.req_param = {
[IB_QPT_UD] = IB_QP_SQ_PSN,
[IB_QPT_UC] = IB_QP_SQ_PSN,
[IB_QPT_RC] = (IB_QP_TIMEOUT |
IB_QP_RETRY_CNT |
IB_QP_RNR_RETRY |
IB_QP_SQ_PSN |
IB_QP_MAX_QP_RD_ATOMIC),
[IB_QPT_SMI] = IB_QP_SQ_PSN,
[IB_QPT_GSI] = IB_QP_SQ_PSN,
},
.opt_param = {
[IB_QPT_UD] = (IB_QP_CUR_STATE | IB_QP_QKEY),
[IB_QPT_UC] = (IB_QP_CUR_STATE |
IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
IB_QP_PATH_MIG_STATE),
[IB_QPT_RC] = (IB_QP_CUR_STATE |
IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
IB_QP_MIN_RNR_TIMER |
IB_QP_PATH_MIG_STATE),
[IB_QPT_SMI] = (IB_QP_CUR_STATE | IB_QP_QKEY),
[IB_QPT_GSI] = (IB_QP_CUR_STATE | IB_QP_QKEY),
}
}
},
[IB_QPS_RTS] = {
[IB_QPS_RESET] = { .valid = 1 },
[IB_QPS_ERR] = { .valid = 1 },
[IB_QPS_RTS] = { .valid = 1,
.opt_param = {
[IB_QPT_UD] = (IB_QP_CUR_STATE | IB_QP_QKEY),
[IB_QPT_UC] = (IB_QP_CUR_STATE |
IB_QP_ACCESS_FLAGS |
IB_QP_ALT_PATH |
IB_QP_PATH_MIG_STATE),
[IB_QPT_RC] = (IB_QP_CUR_STATE |
IB_QP_ACCESS_FLAGS |
IB_QP_ALT_PATH |
IB_QP_PATH_MIG_STATE |
IB_QP_MIN_RNR_TIMER),
[IB_QPT_SMI] = (IB_QP_CUR_STATE | IB_QP_QKEY),
[IB_QPT_GSI] = (IB_QP_CUR_STATE | IB_QP_QKEY),
}
},
[IB_QPS_SQD] = { .valid = 1,
.opt_param = {
[IB_QPT_UD] = IB_QP_EN_SQD_ASYNC_NOTIFY,
[IB_QPT_UC] = IB_QP_EN_SQD_ASYNC_NOTIFY,
[IB_QPT_RC] = IB_QP_EN_SQD_ASYNC_NOTIFY,
[IB_QPT_SMI] = IB_QP_EN_SQD_ASYNC_NOTIFY,
[IB_QPT_GSI] = IB_QP_EN_SQD_ASYNC_NOTIFY
}
},
},
[IB_QPS_SQD] = {
[IB_QPS_RESET] = { .valid = 1 },
[IB_QPS_ERR] = { .valid = 1 },
[IB_QPS_RTS] = { .valid = 1,
.opt_param = {
[IB_QPT_UD] = (IB_QP_CUR_STATE | IB_QP_QKEY),
[IB_QPT_UC] = (IB_QP_CUR_STATE |
IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
IB_QP_PATH_MIG_STATE),
[IB_QPT_RC] = (IB_QP_CUR_STATE |
IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
IB_QP_MIN_RNR_TIMER |
IB_QP_PATH_MIG_STATE),
[IB_QPT_SMI] = (IB_QP_CUR_STATE | IB_QP_QKEY),
[IB_QPT_GSI] = (IB_QP_CUR_STATE | IB_QP_QKEY),
}
},
[IB_QPS_SQD] = { .valid = 1,
.opt_param = {
[IB_QPT_UD] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
[IB_QPT_UC] = (IB_QP_AV | IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
IB_QP_PKEY_INDEX |
IB_QP_PATH_MIG_STATE),
[IB_QPT_RC] = (IB_QP_PORT | IB_QP_AV |
IB_QP_TIMEOUT |
IB_QP_RETRY_CNT |
IB_QP_RNR_RETRY |
IB_QP_MAX_QP_RD_ATOMIC |
IB_QP_MAX_DEST_RD_ATOMIC |
IB_QP_ALT_PATH |
IB_QP_ACCESS_FLAGS |
IB_QP_PKEY_INDEX |
IB_QP_MIN_RNR_TIMER |
IB_QP_PATH_MIG_STATE),
[IB_QPT_SMI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
[IB_QPT_GSI] = (IB_QP_PKEY_INDEX | IB_QP_QKEY),
}
}
},
[IB_QPS_SQE] = {
[IB_QPS_RESET] = { .valid = 1 },
[IB_QPS_ERR] = { .valid = 1 },
[IB_QPS_RTS] = { .valid = 1,
.opt_param = {
[IB_QPT_UD] = (IB_QP_CUR_STATE | IB_QP_QKEY),
[IB_QPT_UC] = (IB_QP_CUR_STATE |
IB_QP_ACCESS_FLAGS),
[IB_QPT_SMI] = (IB_QP_CUR_STATE | IB_QP_QKEY),
[IB_QPT_GSI] = (IB_QP_CUR_STATE | IB_QP_QKEY),
}
}
},
[IB_QPS_ERR] = {
[IB_QPS_RESET] = { .valid = 1 },
[IB_QPS_ERR] = { .valid = 1 }
}
};
static int
uverbs_modify_qp_is_ok(enum ib_qp_state cur_state,
enum ib_qp_state next_state, enum ib_qp_type type,
enum ib_qp_attr_mask *maskp)
{
enum ib_qp_attr_mask req_param, opt_param;
uverbs_qp_state_tbl_t *state_tblp;
enum ib_qp_attr_mask mask = *maskp;
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "modify_qp_is_ok"
"(%x, %x, %x, %x)", cur_state, next_state, type, mask);
if (cur_state < 0 || cur_state > IB_QPS_ERR ||
next_state < 0 || next_state > IB_QPS_ERR) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"modify_qp_is_ok: bad state, cur %d, next %d",
cur_state, next_state);
return (0);
}
if (mask & IB_QP_CUR_STATE &&
cur_state != IB_QPS_RTR && cur_state != IB_QPS_RTS &&
cur_state != IB_QPS_SQD && cur_state != IB_QPS_SQE) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"modify_qp_is_ok: cur_state %d is a bad state",
cur_state);
return (0);
}
state_tblp = &uverbs_qp_state_table[cur_state][next_state];
if (!state_tblp->valid) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "modify_qp: "
"bad transition, cur = %d, next = %d", cur_state,
next_state);
return (0);
}
req_param = state_tblp->req_param[type];
opt_param = state_tblp->opt_param[type];
if ((mask & req_param) != req_param) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"modify_qp_is_ok: cur %d, next %d, "
"missing required parms, spec = 0x%08X, "
"req = 0%08X", cur_state, next_state,
mask, req_param);
return (0);
}
if (mask & ~(req_param | opt_param | IB_QP_STATE)) {
SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str,
"modify_qp_is_ok: cur %d, next %d, "
"illegal optional parms, parms = 0x%08X, "
"illegal = 0x%08X", cur_state, next_state,
mask, mask & ~(req_param | opt_param | IB_QP_STATE));
*maskp = mask & (req_param | opt_param | IB_QP_STATE);
return (0);
}
return (1);
}
int
sol_uverbs_create_qp(uverbs_uctxt_uobj_t *uctxt, char *buf,
int in_len, int out_len)
{
struct ib_uverbs_create_qp cmd;
struct ib_uverbs_create_qp_resp resp;
uverbs_uqp_uobj_t *uqp;
ibt_qp_type_t qp_type;
ibt_qp_alloc_attr_t qp_attr;
ibt_chan_sizes_t qp_sizes;
int rc = 0;
uverbs_upd_uobj_t *upd;
uverbs_ucq_uobj_t *uscq;
uverbs_ucq_uobj_t *urcq;
uverbs_usrq_uobj_t *usrq = NULL;
(void) memcpy(&cmd, buf, sizeof (cmd));
(void) memset(&resp, 0, sizeof (resp));
(void) memset(&qp_attr, 0, sizeof (qp_attr));
(void) memset(&qp_sizes, 0, sizeof (qp_sizes));
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "create_qp(): entry");
switch (cmd.qp_type) {
case IB_QPT_UC:
qp_type = IBT_UC_RQP;
break;
case IB_QPT_UD:
qp_type = IBT_UD_RQP;
break;
case IB_QPT_RC:
qp_type = IBT_RC_RQP;
break;
default:
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"create_qp(): Invalid qp type");
rc = EINVAL;
goto err_out;
}
qp_attr.qp_alloc_flags = IBT_QP_USER_MAP;
if (cmd.is_srq) {
qp_attr.qp_alloc_flags |= IBT_QP_USES_SRQ;
}
qp_attr.qp_flags = IBT_WR_SIGNALED;
if (cmd.sq_sig_all) {
qp_attr.qp_flags = IBT_ALL_SIGNALED;
}
uqp = kmem_zalloc(sizeof (*uqp), KM_NOSLEEP);
if (uqp == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"create_qp(): User object allocation failed");
rc = ENOMEM;
goto err_out;
}
sol_ofs_uobj_init(&uqp->uobj, cmd.user_handle,
SOL_UVERBS_UQP_UOBJ_TYPE);
rw_enter(&uqp->uobj.uo_lock, RW_WRITER);
llist_head_init(&uqp->mcast_list, NULL);
llist_head_init(&uqp->async_list, NULL);
uqp->async_events_reported = 0;
uqp->uctxt = uctxt;
uqp->disable_qp_mod = FALSE;
if (cmd.is_srq) {
usrq = uverbs_uobj_get_usrq_read(cmd.srq_handle);
uqp->uqp_rcq_srq_valid |= SOL_UVERBS_UQP_SRQ_VALID;
uqp->uqp_srq_hdl = cmd.srq_handle;
}
upd = uverbs_uobj_get_upd_read(cmd.pd_handle);
uqp->uqp_pd_hdl = cmd.pd_handle;
uscq = uverbs_uobj_get_ucq_read(cmd.send_cq_handle);
uqp->uqp_scq_hdl = cmd.send_cq_handle;
uqp->uqp_rcq_hdl = cmd.recv_cq_handle;
if (cmd.recv_cq_handle != cmd.send_cq_handle) {
urcq = uverbs_uobj_get_ucq_read(cmd.recv_cq_handle);
uqp->uqp_rcq_srq_valid |= SOL_UVERBS_UQP_RCQ_VALID;
} else
urcq = uscq;
if (!upd || !uscq || !urcq || (cmd.is_srq && !usrq)) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"create_qp(): Invalid resource handle");
rc = EINVAL;
goto err_put;
}
uqp->uqp_rcq = urcq;
uqp->uqp_scq = uscq;
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
"uqp %p, rcq %p. scq %p", uqp, urcq, uscq);
qp_attr.qp_pd_hdl = upd->pd;
if (usrq) {
qp_attr.qp_srq_hdl = usrq->srq;
}
qp_attr.qp_scq_hdl = uscq->cq;
qp_attr.qp_rcq_hdl = urcq->cq;
qp_attr.qp_sizes.cs_sq = cmd.max_send_wr;
qp_attr.qp_sizes.cs_rq = cmd.max_recv_wr;
qp_attr.qp_sizes.cs_sq_sgl = cmd.max_send_sge;
qp_attr.qp_sizes.cs_rq_sgl = cmd.max_recv_sge;
uqp->max_inline_data = cmd.max_inline_data;
uqp->ofa_qp_type = cmd.qp_type;
rc = ibt_alloc_qp(uctxt->hca->hdl, qp_type, &qp_attr, &qp_sizes,
&uqp->qp_num, &uqp->qp);
if (rc != IBT_SUCCESS) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"create_qp(): Error in ibt_alloc_qp() (rc=%d)", rc);
rc = sol_uverbs_ibt_to_kernel_status(rc);
uqp->uobj.uo_uobj_sz = sizeof (uverbs_uqp_uobj_t);
goto err_put;
}
ibt_set_qp_private(uqp->qp, uqp);
upd->active_qp_cnt++;
uscq->active_qp_cnt++;
if (cmd.recv_cq_handle != cmd.send_cq_handle)
urcq->active_qp_cnt++;
if (usrq)
usrq->active_qp_cnt++;
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
"\treq cs_sq=%d, actual cs_sq=%d",
qp_attr.qp_sizes.cs_sq, qp_sizes.cs_sq);
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
"\treq cs_sq_sgl=%d, actual cs_sg_sgl=%d",
qp_attr.qp_sizes.cs_sq_sgl, qp_sizes.cs_sq_sgl);
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
"\treq cs_rq=%d, actual cs_rq=%d",
qp_attr.qp_sizes.cs_rq, qp_sizes.cs_rq);
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
"\treq cs_rq_sgl=%d, actual cs_rq_sgl=%d",
qp_attr.qp_sizes.cs_rq_sgl, qp_sizes.cs_rq_sgl);
rc = ibt_ci_data_out(uctxt->hca->hdl, IBT_CI_NO_FLAGS, IBT_HDL_CHANNEL,
(void *)uqp->qp, &resp.drv_out, sizeof (resp.drv_out));
if (rc != IBT_SUCCESS) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"create_qp(): Error in ibt_ci_data_out() (rc=%d)", rc);
rc = EFAULT;
uqp->uobj.uo_uobj_sz = sizeof (uverbs_uqp_uobj_t);
goto err_qp_destroy;
}
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
"create_qp QP: ibt_ci_data_out:0x%016llx 0x%016llx",
resp.drv_out[0], resp.drv_out[1]);
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
" :0x%016llx 0x%016llx",
resp.drv_out[2], resp.drv_out[3]);
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
" :0x%016llx 0x%016llx",
resp.drv_out[4], resp.drv_out[5]);
if (sol_ofs_uobj_add(&uverbs_uqp_uo_tbl, &uqp->uobj) != 0) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"create_qp(): User object add failed (rc=%d)", rc);
rc = ENOMEM;
goto err_qp_destroy;
}
resp.qp_handle = uqp->uobj.uo_id;
resp.qpn = uqp->qp_num;
resp.max_send_wr = qp_sizes.cs_sq;
resp.max_send_sge = qp_sizes.cs_sq_sgl;
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "create_qp() : "
"resp.qp_handle=0x%08x, resp.qpn=0x%08x", resp.qp_handle, resp.qpn);
if (usrq) {
resp.max_recv_wr = cmd.max_recv_wr;
resp.max_recv_sge = cmd.max_recv_sge;
} else {
resp.max_recv_wr = qp_sizes.cs_rq;
resp.max_recv_sge = qp_sizes.cs_rq_sgl;
}
resp.max_inline_data = cmd.max_inline_data;
#ifdef _LP64
rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
#else
rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
#endif
if (rc != 0) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"create_qp(): Error writing resp data (rc=%d)", rc);
rc = EFAULT;
goto err_uo_delete;
}
mutex_enter(&uctxt->lock);
uqp->list_entry = add_genlist(&uctxt->qp_list, (uintptr_t)uqp,
(void*)uctxt);
mutex_exit(&uctxt->lock);
if (!uqp->list_entry) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"create_qp(): Error adding uqp to qp_list\n");
rc = ENOMEM;
goto err_uo_delete;
}
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
"create_qp() - uqp %p", uqp);
uqp->uobj.uo_live = 1;
sol_ofs_uobj_put(&upd->uobj);
sol_ofs_uobj_put(&uscq->uobj);
if (urcq != uscq) {
sol_ofs_uobj_put(&urcq->uobj);
}
if (usrq) {
sol_ofs_uobj_put(&usrq->uobj);
}
rw_exit(&uqp->uobj.uo_lock);
return (DDI_SUCCESS);
err_uo_delete:
uqp->uobj.uo_live = 1;
(void) sol_ofs_uobj_remove(&uverbs_uqp_uo_tbl, &uqp->uobj);
err_qp_destroy:
(void) ibt_free_qp(uqp->qp);
upd->active_qp_cnt--;
uscq->active_qp_cnt--;
if (cmd.recv_cq_handle != cmd.send_cq_handle)
urcq->active_qp_cnt--;
if (usrq)
usrq->active_qp_cnt--;
err_put:
if (upd) {
sol_ofs_uobj_put(&upd->uobj);
}
if (uscq) {
sol_ofs_uobj_put(&uscq->uobj);
}
if (urcq && urcq != uscq) {
sol_ofs_uobj_put(&urcq->uobj);
}
if (usrq) {
sol_ofs_uobj_put(&usrq->uobj);
}
rw_exit(&uqp->uobj.uo_lock);
sol_ofs_uobj_deref(&uqp->uobj, sol_ofs_uobj_free);
err_out:
return (rc);
}
static int
uverbs_uqp_rsrc_free(uverbs_uqp_uobj_t *uqp, uverbs_uctxt_uobj_t *uctxt)
{
uverbs_ucq_uobj_t *uscq = NULL, *urcq = NULL;
uverbs_usrq_uobj_t *usrq = NULL;
uverbs_upd_uobj_t *upd = NULL;
int ret, rc = -1;
upd = uverbs_uobj_get_upd_write(uqp->uqp_pd_hdl);
if (upd == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"uqp_rsrc_free: get_upd %d failed", uqp->uqp_pd_hdl);
goto err_free;
}
uscq = uverbs_uobj_get_ucq_write(uqp->uqp_scq_hdl);
if (uscq == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"uqp_rsrc_free: get_ucq %x failed", uqp->uqp_scq_hdl);
goto err_free;
}
if (uqp->uqp_rcq_srq_valid & SOL_UVERBS_UQP_RCQ_VALID) {
urcq = uverbs_uobj_get_ucq_write(uqp->uqp_rcq_hdl);
if (urcq == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"uqp_rsrc_free: get_ucq %x failed",
uqp->uqp_rcq_hdl);
goto err_free;
}
}
if (uqp->uqp_rcq_srq_valid & SOL_UVERBS_UQP_SRQ_VALID) {
usrq = uverbs_uobj_get_usrq_write(uqp->uqp_srq_hdl);
if (usrq == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"uqp_rsrc_free: get_srq %x failed",
uqp->uqp_srq_hdl);
goto err_free;
}
}
rc = 0;
upd->active_qp_cnt--;
uscq->active_qp_cnt--;
if (urcq)
urcq->active_qp_cnt--;
if (usrq)
usrq->active_qp_cnt--;
if (upd->active_qp_cnt == 0 && upd->free_pending) {
ret = uverbs_upd_free(upd, uctxt);
if (ret && rc == 0) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"uqp_rsrc_free: upd_free failed");
rc = ret;
}
} else if (upd)
sol_ofs_uobj_put(&upd->uobj);
if (uscq && uscq->active_qp_cnt == 0 && uscq->free_pending) {
ret = uverbs_ucq_free(uscq, uctxt);
if (ret && rc == 0) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"uqp_rsrc_free: ucq_free failed");
rc = ret;
}
} else if (uscq)
sol_ofs_uobj_put(&uscq->uobj);
if (urcq && urcq->active_qp_cnt == 0 && urcq->free_pending) {
ret = uverbs_ucq_free(urcq, uctxt);
if (ret && rc == 0) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"uqp_rsrc_free: ucq_free failed");
rc = ret;
}
} else if (urcq)
sol_ofs_uobj_put(&urcq->uobj);
if (usrq && usrq->active_qp_cnt == 0 && usrq->free_pending) {
ret = uverbs_usrq_free(usrq, uctxt);
if (ret && rc == 0) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"uqp_rsrc_free: usrq_free failed");
rc = ret;
}
} else if (usrq)
sol_ofs_uobj_put(&usrq->uobj);
return (rc);
err_free:
if (upd)
sol_ofs_uobj_put(&upd->uobj);
if (uscq)
sol_ofs_uobj_put(&uscq->uobj);
if (urcq)
sol_ofs_uobj_put(&urcq->uobj);
return (rc);
}
int
uverbs_uqp_free(uverbs_uqp_uobj_t *uqp, uverbs_uctxt_uobj_t *uctxt)
{
int rc;
ibt_status_t status;
uverbs_detach_uqp_mcast_entries(uqp);
if (!uqp->qp)
goto skip_ibt_free_qp;
status = ibt_free_qp(uqp->qp);
if (status != IBT_SUCCESS) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"uqp_free: ibt_free_qp failed %d", status);
sol_ofs_uobj_put(&uqp->uobj);
return (status);
}
uqp->qp = NULL;
skip_ibt_free_qp :
rc = uverbs_uqp_rsrc_free(uqp, uctxt);
if (rc) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"uqp_free: uqp_rcrc_free failed %d", rc);
sol_ofs_uobj_put(&uqp->uobj);
return (rc);
}
(void) sol_ofs_uobj_remove(&uverbs_uqp_uo_tbl, &uqp->uobj);
sol_ofs_uobj_put(&uqp->uobj);
if (uqp->list_entry) {
mutex_enter(&uctxt->lock);
delete_genlist(&uctxt->qp_list, uqp->list_entry);
uqp->list_entry = NULL;
mutex_exit(&uctxt->lock);
}
sol_ofs_uobj_deref(&uqp->uobj, sol_ofs_uobj_free);
if (uctxt->uctxt_free_pending && (uctxt->qp_list).count == 0) {
SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str,
"uqp_free: freeing uctxt %p", uctxt);
sol_ofs_uobj_deref(&uctxt->uobj, sol_ofs_uobj_free);
}
return (0);
}
int
sol_uverbs_destroy_qp(uverbs_uctxt_uobj_t *uctxt, char *buf,
int in_len, int out_len)
{
struct ib_uverbs_destroy_qp cmd;
struct ib_uverbs_destroy_qp_resp resp;
uverbs_uqp_uobj_t *uqp;
int rc;
(void) memcpy(&cmd, buf, sizeof (cmd));
(void) memset(&resp, 0, sizeof (resp));
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "DESTROY QP: entry "
"(qp_handle=%d)", cmd.qp_handle);
uqp = uverbs_uobj_get_uqp_write(cmd.qp_handle);
if (uqp == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"destroy_qp() : List lookup failure");
rc = EINVAL;
goto err_out;
}
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "DESTROY QP: qp_handle=%d, "
"uqp %p, qp_ptr %p", cmd.qp_handle, uqp, uqp->qp);
if (!llist_empty(&uqp->mcast_list)) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"destroy_qp() called with attached MC group(s)");
rc = EBUSY;
goto err_busy;
}
uverbs_release_uqp_uevents(uctxt->async_evfile, uqp);
resp.events_reported = uqp->async_events_reported;
if (uqp->uqp_free_state == SOL_UVERBS2UCMA_DISABLE_QP_FREE) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"destroy_qp() - UCMA disabled");
uqp->uqp_free_state = SOL_UVERBS2UCMA_FREE_PENDING;
sol_ofs_uobj_put(&uqp->uobj);
rc = 0;
goto report_qp_evts;
} else {
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
"destroy_qp() - freeing QP : %p", uqp);
rc = uverbs_uqp_free(uqp, uctxt);
}
if (rc) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"destroy_qp() - ibt_free_qp() fail %d", rc);
rc = sol_uverbs_ibt_to_kernel_status(rc);
goto err_out;
}
report_qp_evts:
#ifdef _LP64
rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
#else
rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
#endif
if (rc != 0) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"destroy_qp() : copyout failure %x", rc);
rc = EFAULT;
goto err_out;
}
return (DDI_SUCCESS);
err_busy:
sol_ofs_uobj_put(&uqp->uobj);
err_out:
return (rc);
}
static void
uverbs_copy_path_info_from_ibv(struct ib_uverbs_qp_dest *src_path,
ibt_cep_path_t *dest_path)
{
ASSERT(src_path != NULL);
ASSERT(dest_path != NULL);
(void) memcpy(&dest_path->cep_adds_vect.av_dgid,
&src_path->dgid[0], sizeof (src_path->dgid));
dest_path->cep_adds_vect.av_flow = src_path->flow_label;
dest_path->cep_adds_vect.av_dlid = src_path->dlid;
dest_path->cep_adds_vect.av_hop = src_path->hop_limit;
dest_path->cep_adds_vect.av_tclass = src_path->traffic_class;
dest_path->cep_adds_vect.av_srvl = src_path->sl & 0x0f;
dest_path->cep_adds_vect.av_port_num = src_path->port_num;
dest_path->cep_adds_vect.av_src_path = src_path->src_path_bits;
dest_path->cep_adds_vect.av_send_grh = src_path->is_global;
dest_path->cep_adds_vect.av_sgid_ix = src_path->sgid_index;
dest_path->cep_adds_vect.av_srate = src_path->static_rate;
}
static void
uverbs_modify_update(struct ib_uverbs_modify_qp *cmd,
enum ib_qp_state cur_state, enum ib_qp_state new_state,
ibt_qp_query_attr_t *qp_query_attr, ibt_cep_modify_flags_t *flags)
{
ibt_qp_info_t *qp_infop;
ibt_qp_rc_attr_t *rcp;
ibt_qp_uc_attr_t *ucp;
ibt_qp_ud_attr_t *udp;
*flags = IBT_CEP_SET_NOTHING;
qp_infop = &(qp_query_attr->qp_info);
rcp = &(qp_infop->qp_transport.rc);
ucp = &(qp_infop->qp_transport.uc);
udp = &(qp_infop->qp_transport.ud);
switch (cur_state) {
case IB_QPS_RESET:
qp_infop->qp_current_state = IBT_STATE_RESET;
break;
case IB_QPS_INIT:
qp_infop->qp_current_state = IBT_STATE_INIT;
break;
case IB_QPS_RTR:
qp_infop->qp_current_state = IBT_STATE_RTR;
break;
case IB_QPS_RTS:
qp_infop->qp_current_state = IBT_STATE_RTS;
break;
case IB_QPS_SQD:
qp_infop->qp_current_state = IBT_STATE_SQD;
break;
case IB_QPS_SQE:
qp_infop->qp_current_state = IBT_STATE_SQE;
break;
case IB_QPS_ERR:
qp_infop->qp_current_state = IBT_STATE_ERROR;
break;
}
if (cmd->attr_mask & IB_QP_STATE) {
switch (new_state) {
case IB_QPS_RESET:
qp_infop->qp_state = IBT_STATE_RESET;
*flags |= IBT_CEP_SET_STATE;
break;
case IB_QPS_INIT:
qp_infop->qp_state = IBT_STATE_INIT;
if (cur_state == IB_QPS_RESET) {
*flags |= IBT_CEP_SET_RESET_INIT;
} else {
*flags |= IBT_CEP_SET_STATE;
}
break;
case IB_QPS_RTR:
qp_infop->qp_state = IBT_STATE_RTR;
if (cur_state == IB_QPS_INIT) {
*flags |= IBT_CEP_SET_INIT_RTR;
} else {
*flags |= IBT_CEP_SET_STATE;
}
break;
case IB_QPS_RTS:
qp_infop->qp_state = IBT_STATE_RTS;
if (cur_state == IB_QPS_RTR) {
*flags |= IBT_CEP_SET_RTR_RTS;
} else {
ibt_cep_state_t *ibt_curr =
&qp_infop->qp_current_state;
switch (cur_state) {
case IB_QPS_RTS:
*ibt_curr = IBT_STATE_RTS;
break;
case IB_QPS_SQD:
*ibt_curr = IBT_STATE_SQD;
break;
case IB_QPS_SQE:
*ibt_curr = IBT_STATE_SQE;
break;
}
*flags |= IBT_CEP_SET_STATE;
}
break;
case IB_QPS_SQD:
qp_infop->qp_state = IBT_STATE_SQD;
*flags |= IBT_CEP_SET_STATE;
break;
case IB_QPS_SQE:
qp_infop->qp_state = IBT_STATE_SQE;
*flags |= IBT_CEP_SET_STATE;
break;
case IB_QPS_ERR:
qp_infop->qp_state = IBT_STATE_ERROR;
*flags |= IBT_CEP_SET_STATE;
break;
}
}
if (cmd->attr_mask & IB_QP_PKEY_INDEX) {
if (qp_infop->qp_trans == IBT_UD_SRV) {
udp->ud_pkey_ix = cmd->pkey_index;
} else if (qp_infop->qp_trans == IBT_RC_SRV) {
rcp->rc_path.cep_pkey_ix = cmd->pkey_index;
}
*flags |= IBT_CEP_SET_PKEY_IX;
}
if (cmd->attr_mask & IB_QP_AV) {
if (qp_infop->qp_trans == IBT_RC_SRV) {
uverbs_copy_path_info_from_ibv(&cmd->dest,
&rcp->rc_path);
}
*flags |= IBT_CEP_SET_ADDS_VECT;
}
if (qp_infop->qp_trans == IBT_RC_SRV) {
if (cmd->attr_mask & IB_QP_TIMEOUT) {
rcp->rc_path.cep_timeout = cmd->timeout;
*flags |= IBT_CEP_SET_TIMEOUT;
}
}
if (cmd->attr_mask & IB_QP_PORT) {
if (qp_infop->qp_trans == IBT_UD_SRV) {
udp->ud_port = cmd->port_num;
} else if (qp_infop->qp_trans == IBT_RC_SRV) {
rcp->rc_path.cep_hca_port_num = cmd->port_num;
}
*flags |= IBT_CEP_SET_PORT;
}
if (cmd->attr_mask & IB_QP_QKEY) {
if (qp_infop->qp_trans == IBT_UD_SRV) {
udp->ud_qkey = cmd->qkey;
}
if (qp_infop->qp_trans == IBT_RD_SRV) {
qp_infop->qp_transport.rd.rd_qkey = cmd->qkey;
}
*flags |= IBT_CEP_SET_QKEY;
}
if (cmd->attr_mask & IB_QP_PATH_MTU) {
if (qp_infop->qp_trans == IBT_UC_SRV) {
ucp->uc_path_mtu = cmd->path_mtu;
}
if (qp_infop->qp_trans == IBT_RC_SRV) {
rcp->rc_path_mtu = cmd->path_mtu;
}
}
if (cmd->attr_mask & IB_QP_RETRY_CNT) {
if (qp_infop->qp_trans == IBT_RC_SRV) {
rcp->rc_retry_cnt = cmd->retry_cnt & 0x7;
}
*flags |= IBT_CEP_SET_RETRY;
}
if (cmd->attr_mask & IB_QP_RNR_RETRY) {
if (qp_infop->qp_trans == IBT_RC_SRV) {
rcp->rc_rnr_retry_cnt = cmd->rnr_retry;
}
*flags |= IBT_CEP_SET_RNR_NAK_RETRY;
}
if (cmd->attr_mask & IB_QP_MIN_RNR_TIMER) {
if (qp_infop->qp_trans == IBT_RC_SRV) {
rcp->rc_min_rnr_nak = cmd->min_rnr_timer;
}
*flags |= IBT_CEP_SET_MIN_RNR_NAK;
}
if (cmd->attr_mask & IB_QP_RQ_PSN) {
if (qp_infop->qp_trans == IBT_RC_SRV) {
rcp->rc_rq_psn = cmd->rq_psn;
}
if (qp_infop->qp_trans == IBT_UC_SRV) {
ucp->uc_rq_psn = cmd->rq_psn;
}
}
if (cmd->attr_mask & IB_QP_ALT_PATH) {
if (qp_infop->qp_trans == IBT_RC_SRV) {
uverbs_copy_path_info_from_ibv(&cmd->alt_dest,
&rcp->rc_alt_path);
rcp->rc_alt_path.cep_hca_port_num = cmd->alt_port_num;
rcp->rc_alt_path.cep_timeout = cmd->alt_timeout;
}
if (qp_infop->qp_trans == IBT_UC_SRV) {
uverbs_copy_path_info_from_ibv(&cmd->alt_dest,
&ucp->uc_alt_path);
ucp->uc_alt_path.cep_hca_port_num = cmd->alt_port_num;
ucp->uc_alt_path.cep_timeout = cmd->alt_timeout;
}
*flags |= IBT_CEP_SET_ALT_PATH;
}
if (cmd->attr_mask & IB_QP_SQ_PSN) {
if (qp_infop->qp_trans == IBT_UD_SRV) {
udp->ud_sq_psn = cmd->sq_psn;
}
if (qp_infop->qp_trans == IBT_UC_SRV) {
ucp->uc_sq_psn = cmd->sq_psn;
}
if (qp_infop->qp_trans == IBT_RC_SRV) {
rcp->rc_sq_psn = cmd->sq_psn;
}
}
if (cmd->attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
if (qp_infop->qp_trans == IBT_RC_SRV) {
rcp->rc_rdma_ra_out = cmd->max_rd_atomic;
}
*flags |= IBT_CEP_SET_RDMARA_OUT | IBT_CEP_SET_STATE;
}
if (cmd->attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
if (qp_infop->qp_trans == IBT_RC_SRV) {
rcp->rc_rdma_ra_in = cmd->max_dest_rd_atomic;
}
*flags |= IBT_CEP_SET_RDMARA_IN | IBT_CEP_SET_STATE;
}
if (cmd->attr_mask & (IB_QP_ACCESS_FLAGS |
IB_QP_MAX_DEST_RD_ATOMIC)) {
if (qp_infop->qp_trans == IBT_RC_SRV) {
uint32_t access_flags = IBT_CEP_NO_FLAGS;
if (rcp->rc_rdma_ra_in) {
access_flags |= IBT_CEP_RDMA_WR;
*flags |= IBT_CEP_SET_RDMA_W;
}
if (cmd->attr_mask & IB_QP_ACCESS_FLAGS) {
if (cmd->qp_access_flags &
IB_ACCESS_REMOTE_WRITE) {
access_flags |= IBT_CEP_RDMA_WR;
*flags |= IBT_CEP_SET_RDMA_W;
}
if (cmd->qp_access_flags &
IB_ACCESS_REMOTE_READ) {
access_flags |= IBT_CEP_RDMA_RD;
*flags |= IBT_CEP_SET_RDMA_R;
}
if (cmd->qp_access_flags &
IB_ACCESS_REMOTE_ATOMIC) {
access_flags |= IBT_CEP_ATOMIC;
*flags |= IBT_CEP_SET_ATOMIC;
}
}
qp_infop->qp_flags &= ~(IBT_CEP_RDMA_WR |
IBT_CEP_RDMA_RD | IBT_CEP_ATOMIC);
qp_infop->qp_flags |= access_flags;
}
}
if (cmd->attr_mask & IB_QP_PATH_MIG_STATE) {
if (qp_infop->qp_trans == IBT_RC_SRV) {
if (cmd->path_mig_state == IB_MIG_MIGRATED) {
rcp->rc_mig_state = IBT_STATE_MIGRATED;
}
if (cmd->path_mig_state == IB_MIG_REARM) {
rcp->rc_mig_state = IBT_STATE_REARMED;
}
if (cmd->path_mig_state == IB_MIG_ARMED) {
rcp->rc_mig_state = IBT_STATE_ARMED;
}
}
if (qp_infop->qp_trans == IBT_UC_SRV) {
if (cmd->path_mig_state == IB_MIG_MIGRATED) {
ucp->uc_mig_state = IBT_STATE_MIGRATED;
}
if (cmd->path_mig_state == IB_MIG_REARM) {
ucp->uc_mig_state = IBT_STATE_REARMED;
}
if (cmd->path_mig_state == IB_MIG_ARMED) {
ucp->uc_mig_state = IBT_STATE_ARMED;
}
}
*flags |= IBT_CEP_SET_MIG;
}
if (cmd->attr_mask & IB_QP_DEST_QPN) {
if (qp_infop->qp_trans == IBT_RC_SRV) {
rcp->rc_dst_qpn = cmd->dest_qp_num;
}
if (qp_infop->qp_trans == IBT_UC_SRV) {
ucp->uc_dst_qpn = cmd->dest_qp_num;
}
}
}
static void
uverbs_qp_print_path(ibt_cep_path_t *pathp)
{
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "qp_print_pathp %p", pathp);
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "cep_pkey_ix %x, "
"cep_hca_port_num %x", pathp->cep_pkey_ix, pathp->cep_hca_port_num);
}
static void
uverbs_print_query_qp(ibt_qp_hdl_t qp_hdlp)
{
ibt_qp_query_attr_t qp_query_attr;
ibt_qp_info_t *qp_infop = &qp_query_attr.qp_info;
ibt_qp_rc_attr_t *rcp = &((qp_infop->qp_transport).rc);
ibt_status_t rc;
bzero(&qp_query_attr, sizeof (qp_query_attr));
rc = ibt_query_qp(qp_hdlp, &qp_query_attr);
if (rc != IBT_SUCCESS) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "print_query_qp -"
"ibt_query_qp() failed - rc=%d", rc);
return;
}
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "qp_print %p", qp_hdlp);
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "qp_sq_cq %p, qp_rq_cq %p, "
"qp_qpn %x, qp_sq_sgl %x, qp_rq_sgl %x, qp_srq %p, qp_flags %x",
qp_query_attr.qp_sq_cq, qp_query_attr.qp_rq_cq,
qp_query_attr.qp_qpn, qp_query_attr.qp_sq_sgl,
qp_query_attr.qp_rq_sgl, qp_query_attr.qp_srq,
qp_query_attr.qp_flags);
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "qp_sq_sz %x, qp_rq_sz %x, "
"qp_state %x, qp_current_state %x, qp_flags %x, qp_trans %x",
qp_infop->qp_sq_sz, qp_infop->qp_rq_sz, qp_infop->qp_state,
qp_infop->qp_current_state, qp_infop->qp_flags,
qp_infop->qp_trans);
if (qp_infop->qp_trans == IBT_RC_SRV) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "rc_sq_psn %x, rc_rq_psn %x, "
"rc_dst_qpn %x, rc_mig_state %x, rc_rnr_retry_cnt %x,"
"rc_retry_cnt %x rc_rdma_ra_out %x, rc_rdma_ra_in %x,"
"rc_min_rnr_nak %x, rc_path_mtu %x",
rcp->rc_sq_psn, rcp->rc_rq_psn, rcp->rc_dst_qpn, rcp->rc_mig_state,
rcp->rc_rnr_retry_cnt, rcp->rc_retry_cnt, rcp->rc_rdma_ra_out,
rcp->rc_rdma_ra_in, rcp->rc_min_rnr_nak, rcp->rc_path_mtu);
uverbs_qp_print_path(&rcp->rc_path);
uverbs_qp_print_path(&rcp->rc_alt_path);
}
}
int
sol_uverbs_modify_qp(uverbs_uctxt_uobj_t *uctxt, char *buf,
int in_len, int out_len)
{
struct ib_uverbs_modify_qp cmd;
uverbs_uqp_uobj_t *uqp;
ibt_qp_query_attr_t qp_query_attr;
ibt_cep_modify_flags_t flags;
ibt_queue_sizes_t size;
int rc;
enum ib_qp_state cur_state, new_state;
(void) memcpy(&cmd, buf, sizeof (cmd));
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "modify_qp - qp_hdl %d, "
"attr_mask %x", cmd.qp_handle, cmd.attr_mask);
uqp = uverbs_uobj_get_uqp_write(cmd.qp_handle);
if (uqp == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "modify_qp -"
"List lookup failure");
rc = EINVAL;
goto err_out;
}
if (uqp->disable_qp_mod == TRUE) {
SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str, "modify_qp -"
"qp_mod disabled");
goto done;
}
bzero(&qp_query_attr, sizeof (qp_query_attr));
rc = ibt_query_qp(uqp->qp, &qp_query_attr);
if (rc != IBT_SUCCESS) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "modify_qp -"
"ibt_query_qp() failed - rc=%d", rc);
rc = sol_uverbs_ibt_to_kernel_status(rc);
goto err_deref;
}
if (cmd.attr_mask & IB_QP_CUR_STATE) {
cur_state = cmd.cur_qp_state;
} else {
cur_state = IBT_TO_OFA_QP_STATE(qp_query_attr.qp_info.qp_state);
}
new_state = cmd.attr_mask & IB_QP_STATE ? cmd.qp_state : cur_state;
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "modify_qp: ibt qp %p, handle "
"%x, cur_state %x, new_state %x, qp_type %x, attr_mask %x", uqp->qp,
cmd.qp_handle, cur_state, new_state, uqp->ofa_qp_type,
cmd.attr_mask);
if (!uverbs_modify_qp_is_ok(cur_state, new_state, uqp->ofa_qp_type,
(enum ib_qp_attr_mask *)&cmd.attr_mask)) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "modify_qp() -"
"Failed modify OK test");
rc = EINVAL;
goto err_deref;
}
if (!cmd.attr_mask) {
SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str, "modify_qp() -"
"attr_mask after modify OK test is 0");
rc = 0;
goto done;
}
flags = 0;
switch (uqp->ofa_qp_type) {
case IB_QPT_UC:
qp_query_attr.qp_info.qp_trans = IBT_UC_SRV;
break;
case IB_QPT_UD:
qp_query_attr.qp_info.qp_trans = IBT_UD_SRV;
break;
case IB_QPT_RC:
qp_query_attr.qp_info.qp_trans = IBT_RC_SRV;
break;
default:
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"modify_qp: Invalid QP type");
rc = EINVAL;
goto err_deref;
}
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "modify_qp(): qp_info.qp_flags "
"before modify update = 0%08x", qp_query_attr.qp_info.qp_flags);
uverbs_modify_update(&cmd, cur_state, new_state, &qp_query_attr,
&flags);
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "modify_qp(): after "
"modify_update hdl flags = 0x%08x, qp_info.qp_flags = 0%08x",
flags, qp_query_attr.qp_info.qp_flags);
rc = ibt_modify_qp(uqp->qp, flags, &qp_query_attr.qp_info, &size);
if (rc != IBT_SUCCESS) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"modify_qp: Error in ibt_modify_qp() (rc=%d)", rc);
uverbs_print_query_qp(uqp->qp);
rc = sol_uverbs_ibt_to_kernel_status(rc);
goto err_deref;
}
done:
sol_ofs_uobj_put(&uqp->uobj);
return (DDI_SUCCESS);
err_deref:
sol_ofs_uobj_put(&uqp->uobj);
err_out:
return (rc);
}
static void
uverbs_copy_path_info_from_ibt(ibt_cep_path_t *src_path,
struct ib_uverbs_qp_dest *dest_path)
{
ASSERT(src_path != NULL);
ASSERT(dest_path != NULL);
(void) memcpy(&dest_path->dgid[0],
&src_path->cep_adds_vect.av_dgid, sizeof (dest_path->dgid));
dest_path->flow_label = src_path->cep_adds_vect.av_flow;
dest_path->dlid = src_path->cep_adds_vect.av_dlid;
dest_path->hop_limit = src_path->cep_adds_vect.av_hop;
dest_path->traffic_class = src_path->cep_adds_vect.av_tclass;
dest_path->sl = src_path->cep_adds_vect.av_srvl;
dest_path->port_num = src_path->cep_adds_vect.av_port_num;
dest_path->src_path_bits = src_path->cep_adds_vect.av_src_path;
dest_path->is_global = src_path->cep_adds_vect.av_send_grh;
dest_path->sgid_index = src_path->cep_adds_vect.av_sgid_ix;
dest_path->static_rate = src_path->cep_adds_vect.av_srate;
}
static void
uverbs_query_copy_rc(struct ib_uverbs_query_qp_resp *dest,
ibt_qp_rc_attr_t *src)
{
dest->sq_psn = src->rc_sq_psn;
dest->rq_psn = src->rc_rq_psn;
dest->dest_qp_num = src->rc_dst_qpn;
dest->rnr_retry = src->rc_rnr_retry_cnt;
dest->retry_cnt = src->rc_retry_cnt;
dest->max_dest_rd_atomic = src->rc_rdma_ra_in;
dest->max_rd_atomic = src->rc_rdma_ra_out;
dest->min_rnr_timer = src->rc_min_rnr_nak;
dest->path_mtu = src->rc_path_mtu;
dest->timeout = src->rc_path.cep_timeout;
dest->alt_timeout = src->rc_alt_path.cep_timeout;
dest->port_num = src->rc_path.cep_hca_port_num;
dest->alt_port_num = src->rc_alt_path.cep_hca_port_num;
if (src->rc_mig_state == IBT_STATE_MIGRATED) {
dest->path_mig_state = IB_MIG_MIGRATED;
}
if (src->rc_mig_state == IBT_STATE_REARMED) {
dest->path_mig_state = IB_MIG_REARM;
}
if (src->rc_mig_state == IBT_STATE_ARMED) {
dest->path_mig_state = IB_MIG_ARMED;
}
uverbs_copy_path_info_from_ibt(&src->rc_path, &dest->dest);
uverbs_copy_path_info_from_ibt(&src->rc_alt_path, &dest->alt_dest);
}
static void
uverbs_query_copy_uc(struct ib_uverbs_query_qp_resp *dest,
ibt_qp_uc_attr_t *src)
{
dest->sq_psn = src->uc_sq_psn;
dest->rq_psn = src->uc_rq_psn;
dest->dest_qp_num = src->uc_dst_qpn;
dest->path_mtu = src->uc_path_mtu;
if (src->uc_mig_state == IBT_STATE_MIGRATED) {
dest->path_mig_state = IB_MIG_MIGRATED;
}
if (src->uc_mig_state == IBT_STATE_REARMED) {
dest->path_mig_state = IB_MIG_REARM;
}
if (src->uc_mig_state == IBT_STATE_ARMED) {
dest->path_mig_state = IB_MIG_ARMED;
}
uverbs_copy_path_info_from_ibt(&src->uc_path, &dest->dest);
uverbs_copy_path_info_from_ibt(&src->uc_alt_path, &dest->alt_dest);
}
static void
uverbs_query_copy_rd(struct ib_uverbs_query_qp_resp *dest,
ibt_qp_rd_attr_t *src)
{
dest->qkey = src->rd_qkey;
dest->min_rnr_timer = src->rd_min_rnr_nak;
}
static void
uverbs_query_copy_ud(struct ib_uverbs_query_qp_resp *dest,
ibt_qp_ud_attr_t *src)
{
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
"query_copy_ud:entry - return UD info: qkey:%08X, "
"psn:%d, pkey_idx:%d, port:%d", src->ud_qkey, src->ud_sq_psn,
src->ud_pkey_ix, src->ud_port);
dest->qkey = src->ud_qkey;
dest->sq_psn = src->ud_sq_psn;
dest->pkey_index = src->ud_pkey_ix;
dest->port_num = src->ud_port;
}
static void
uverbs_query_copy_info(struct ib_uverbs_query_qp_resp *dest,
ibt_qp_info_t *src)
{
dest->max_send_wr = src->qp_sq_sz;
dest->max_recv_wr = src->qp_rq_sz;
dest->qp_access_flags = ibt_cep_flags2ibv(src->qp_flags);
switch (src->qp_state) {
case IBT_STATE_RESET:
dest->qp_state = IB_QPS_RESET;
break;
case IBT_STATE_INIT:
dest->qp_state = IB_QPS_INIT;
break;
case IBT_STATE_RTR:
dest->qp_state = IB_QPS_RTR;
break;
case IBT_STATE_RTS:
dest->qp_state = IB_QPS_RTS;
break;
case IBT_STATE_SQD:
dest->qp_state = IB_QPS_SQD;
break;
case IBT_STATE_SQE:
dest->qp_state = IB_QPS_SQE;
break;
case IBT_STATE_ERROR:
default:
dest->qp_state = IB_QPS_ERR;
break;
}
switch (src->qp_current_state) {
case IBT_STATE_RESET:
dest->cur_qp_state = IB_QPS_RESET;
break;
case IBT_STATE_INIT:
dest->cur_qp_state = IB_QPS_INIT;
break;
case IBT_STATE_RTR:
dest->cur_qp_state = IB_QPS_RTR;
break;
case IBT_STATE_RTS:
dest->cur_qp_state = IB_QPS_RTS;
break;
case IBT_STATE_SQD:
dest->cur_qp_state = IB_QPS_SQD;
break;
case IBT_STATE_SQE:
dest->cur_qp_state = IB_QPS_SQE;
break;
case IBT_STATE_ERROR:
default:
dest->cur_qp_state = IB_QPS_ERR;
break;
}
if ((src->qp_flags & IBT_ALL_SIGNALED) == IBT_ALL_SIGNALED) {
dest->sq_sig_all = 1;
}
}
static void
uverbs_query_copy_attr(struct ib_uverbs_query_qp_resp *dest,
ibt_qp_query_attr_t *src)
{
dest->max_send_sge = src->qp_sq_sgl;
dest->max_recv_sge = src->qp_rq_sgl;
}
int
sol_uverbs_query_qp(uverbs_uctxt_uobj_t *uctxt, char *buf,
int in_len, int out_len)
{
struct ib_uverbs_query_qp cmd;
struct ib_uverbs_query_qp_resp resp;
uverbs_uqp_uobj_t *uqp;
ibt_qp_query_attr_t qp_query_attr;
int rc;
(void) memset(&resp, 0, sizeof (resp));
(void) memcpy(&cmd, buf, sizeof (cmd));
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
"query_qp: entry (qp_handle=%d)", cmd.qp_handle);
uqp = uverbs_uobj_get_uqp_read(cmd.qp_handle);
if (uqp == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"query_qp(): List lookup failure");
rc = EINVAL;
goto err_out;
}
bzero(&qp_query_attr, sizeof (qp_query_attr));
rc = ibt_query_qp(uqp->qp, &qp_query_attr);
sol_ofs_uobj_put(&uqp->uobj);
if (rc != IBT_SUCCESS) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"query_qp: Error in ibt_query_qp() (rc=%d)", rc);
rc = sol_uverbs_ibt_to_kernel_status(rc);
goto err_out;
}
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
"query_qp(): qp_query_attr.qp_info.qp_trans = %d",
qp_query_attr.qp_info.qp_trans);
uverbs_query_copy_attr(&resp, &qp_query_attr);
uverbs_query_copy_info(&resp, &qp_query_attr.qp_info);
if (qp_query_attr.qp_info.qp_trans == IBT_RC_SRV) {
uverbs_query_copy_rc(&resp,
&qp_query_attr.qp_info.qp_transport.rc);
}
if (qp_query_attr.qp_info.qp_trans == IBT_UC_SRV) {
uverbs_query_copy_uc(&resp,
&qp_query_attr.qp_info.qp_transport.uc);
}
if (qp_query_attr.qp_info.qp_trans == IBT_RD_SRV) {
uverbs_query_copy_rd(&resp,
&qp_query_attr.qp_info.qp_transport.rd);
}
if (qp_query_attr.qp_info.qp_trans == IBT_UD_SRV) {
uverbs_query_copy_ud(&resp,
&qp_query_attr.qp_info.qp_transport.ud);
}
resp.max_inline_data = uqp->max_inline_data;
#ifdef _LP64
rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
#else
rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
#endif
if (rc != 0) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"query_qp(): Error writing resp data (rc=%d)", rc);
rc = EFAULT;
goto err_out;
}
return (DDI_SUCCESS);
err_out:
return (rc);
}
int
sol_uverbs_create_srq(uverbs_uctxt_uobj_t *uctxt, char *buf,
int in_len, int out_len)
{
struct ib_uverbs_create_srq cmd;
struct ib_uverbs_create_srq_resp resp;
uverbs_usrq_uobj_t *usrq;
uverbs_upd_uobj_t *upd;
ibt_srq_flags_t flags = IBT_SRQ_USER_MAP;
ibt_srq_sizes_t attr;
ibt_srq_sizes_t real_attr;
int rc;
(void) memcpy(&cmd, buf, sizeof (cmd));
(void) memset(&resp, 0, sizeof (resp));
(void) memset(&attr, 0, sizeof (attr));
attr.srq_wr_sz = cmd.max_wr;
attr.srq_sgl_sz = cmd.max_sge;
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "create_srq: "
"max_wr=%d, max_sge=%d, srq_limit=%d",
cmd.max_wr, cmd.max_sge, cmd.srq_limit);
if (!attr.srq_wr_sz) {
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
"create_srq(): Invalid args, invalid work "
"request size");
rc = EINVAL;
goto err_out;
}
if (attr.srq_wr_sz > uctxt->hca->attr.hca_max_srqs_sz ||
attr.srq_sgl_sz > uctxt->hca->attr.hca_max_srq_sgl) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"create_srq(): Invalid args, too large");
rc = EINVAL;
goto err_out;
}
usrq = kmem_zalloc(sizeof (*usrq), KM_NOSLEEP);
if (usrq == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"create_srq(): User object alloc failed");
rc = ENOMEM;
goto err_out;
}
sol_ofs_uobj_init(&usrq->uobj, cmd.user_handle,
SOL_UVERBS_USRQ_UOBJ_TYPE);
rw_enter(&usrq->uobj.uo_lock, RW_WRITER);
llist_head_init(&usrq->async_list, NULL);
usrq->async_events_reported = 0;
usrq->uctxt = uctxt;
upd = uverbs_uobj_get_upd_read(cmd.pd_handle);
if (upd == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"create_srq(): PD Invalid");
rc = EINVAL;
goto err_dealloc;
}
rc = ibt_alloc_srq(uctxt->hca->hdl, flags, upd->pd, &attr, &usrq->srq,
&real_attr);
if (rc != IBT_SUCCESS) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"create_srq(): Error in ibt_alloc_srq() (rc=%d)", rc);
usrq->srq = NULL;
rc = sol_uverbs_ibt_to_kernel_status(rc);
usrq->uobj.uo_uobj_sz = sizeof (uverbs_usrq_uobj_t);
goto err_release_pd;
}
ibt_set_srq_private(usrq->srq, usrq);
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
"create_srq(): ib_alloc_srq()real wqe_sz=%d, real_sg_sz=%d",
real_attr.srq_wr_sz, real_attr.srq_sgl_sz);
rc = ibt_ci_data_out(uctxt->hca->hdl, IBT_CI_NO_FLAGS, IBT_HDL_SRQ,
(void *)usrq->srq, &resp.drv_out, sizeof (resp.drv_out));
if (rc != IBT_SUCCESS) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"create_srq(): Error in ibt_ci_data_out() (rc=%d)", rc);
rc = EFAULT;
usrq->uobj.uo_uobj_sz = sizeof (uverbs_usrq_uobj_t);
goto err_srq_destroy;
}
if (sol_ofs_uobj_add(&uverbs_usrq_uo_tbl, &usrq->uobj) != 0) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"create_srq(): uobj add failed");
rc = ENOMEM;
goto err_srq_destroy;
}
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
"create_srq(): ibt_ci_data_out: 0x%16llx 0x%16llx 0x%16llx "
"0x%16llx", resp.drv_out[0], resp.drv_out[1], resp.drv_out[2],
resp.drv_out[3]);
resp.srq_handle = usrq->uobj.uo_id;
resp.max_wr = real_attr.srq_wr_sz;
resp.max_sge = real_attr.srq_sgl_sz;
#ifdef _LP64
rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
#else
rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
#endif
if (rc != 0) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"create_srq(): Error writing resp data (rc=%d)", rc);
rc = EFAULT;
goto err_uo_delete;
}
mutex_enter(&uctxt->lock);
usrq->list_entry = add_genlist(&uctxt->srq_list, (uintptr_t)usrq,
uctxt);
mutex_exit(&uctxt->lock);
if (!usrq->list_entry) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"create_srq() : Error adding usrq to srq_list failed");
rc = ENOMEM;
goto err_uo_delete;
}
usrq->uobj.uo_live = 1;
rw_exit(&usrq->uobj.uo_lock);
sol_ofs_uobj_put(&upd->uobj);
return (DDI_SUCCESS);
err_uo_delete:
usrq->uobj.uo_live = 1;
(void) sol_ofs_uobj_remove(&uverbs_usrq_uo_tbl, &usrq->uobj);
err_srq_destroy:
(void) ibt_free_srq(usrq->srq);
err_release_pd:
sol_ofs_uobj_put(&upd->uobj);
err_dealloc:
rw_exit(&usrq->uobj.uo_lock);
sol_ofs_uobj_deref(&usrq->uobj, sol_ofs_uobj_free);
err_out:
return (rc);
}
int
sol_uverbs_modify_srq(uverbs_uctxt_uobj_t *uctxt, char *buf,
int in_len, int out_len)
{
struct ib_uverbs_modify_srq cmd;
uverbs_usrq_uobj_t *usrq;
uint_t limit = 0;
uint_t size = 0;
uint_t real_size = 0;
ibt_srq_modify_flags_t flags = 0;
int rc;
(void) memcpy(&cmd, buf, sizeof (cmd));
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
"modify_srq(): entry (srq_handle=%d)", cmd.srq_handle);
usrq = uverbs_uobj_get_usrq_read(cmd.srq_handle);
if (usrq == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"modify_srq(): List lookup failure");
rc = EINVAL;
goto err_out;
}
if (cmd.attr_mask & IB_SRQ_MAX_WR) {
flags = IBT_SRQ_SET_SIZE;
size = cmd.max_wr;
}
if (cmd.attr_mask & IB_SRQ_LIMIT) {
flags |= IBT_SRQ_SET_LIMIT;
limit = cmd.srq_limit;
}
rc = ibt_modify_srq(usrq->srq, flags, size, limit, &real_size);
if (rc != IBT_SUCCESS) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"modify_srq(): Error in ibt_modify_srq() (rc=%d)", rc);
rc = sol_uverbs_ibt_to_kernel_status(rc);
goto err_deref;
}
sol_ofs_uobj_put(&usrq->uobj);
return (DDI_SUCCESS);
err_deref:
sol_ofs_uobj_put(&usrq->uobj);
err_out:
return (rc);
}
int
sol_uverbs_query_srq(uverbs_uctxt_uobj_t *uctxt, char *buf,
int in_len, int out_len)
{
struct ib_uverbs_query_srq cmd;
struct ib_uverbs_query_srq_resp resp;
uverbs_usrq_uobj_t *usrq;
ibt_pd_hdl_t pd;
int rc;
ibt_srq_sizes_t attr;
uint_t limit;
(void) memcpy(&cmd, buf, sizeof (cmd));
(void) memset(&resp, 0, sizeof (resp));
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
"query_srq(): entry (srq_handle=%d)", cmd.srq_handle);
usrq = uverbs_uobj_get_usrq_read(cmd.srq_handle);
if (usrq == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"query_srq(): Invalid handle: %d", cmd.srq_handle);
rc = EINVAL;
goto err_out;
}
rc = ibt_query_srq(usrq->srq, &pd, &attr, &limit);
sol_ofs_uobj_put(&usrq->uobj);
if (rc != IBT_SUCCESS) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"query_srq(): Error in ibt_query_srq() (rc=%d)", rc);
rc = sol_uverbs_ibt_to_kernel_status(rc);
goto err_out;
}
resp.max_wr = attr.srq_wr_sz;
resp.max_sge = attr.srq_sgl_sz;
resp.srq_limit = limit;
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "query_srq() - "
"max_wr=%d, max_sge=%d, limit=%d", resp.max_wr,
resp.max_sge, resp.srq_limit);
#ifdef _LP64
rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
#else
rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
#endif
if (rc != 0) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "query_srq() - "
"copyout failure %x", rc);
rc = EFAULT;
goto err_out;
}
return (DDI_SUCCESS);
err_out:
return (rc);
}
int
uverbs_usrq_free(uverbs_usrq_uobj_t *usrq, uverbs_uctxt_uobj_t *uctxt)
{
int rc;
if (!usrq->srq)
goto skip_ibt_free_srq;
rc = ibt_free_srq(usrq->srq);
if (rc != IBT_SUCCESS) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str, "usrq_free() - "
"Error in ibt_free_srq() (rc=%d)", rc);
rc = sol_uverbs_ibt_to_kernel_status(rc);
sol_ofs_uobj_put(&usrq->uobj);
return (rc);
}
usrq->srq = NULL;
skip_ibt_free_srq :
sol_ofs_uobj_put(&usrq->uobj);
if (usrq->list_entry) {
mutex_enter(&uctxt->lock);
delete_genlist(&uctxt->srq_list, usrq->list_entry);
mutex_exit(&uctxt->lock);
(void) sol_ofs_uobj_remove(&uverbs_usrq_uo_tbl, &usrq->uobj);
}
sol_ofs_uobj_deref(&usrq->uobj, sol_ofs_uobj_free);
return (0);
}
int
sol_uverbs_destroy_srq(uverbs_uctxt_uobj_t *uctxt, char *buf,
int in_len, int out_len)
{
struct ib_uverbs_destroy_srq cmd;
struct ib_uverbs_destroy_srq_resp resp;
uverbs_usrq_uobj_t *usrq;
int rc;
(void) memcpy(&cmd, buf, sizeof (cmd));
(void) memset(&resp, 0, sizeof (resp));
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "destroy_srq() - "
"srq_handle %d", cmd.srq_handle);
usrq = uverbs_uobj_get_usrq_write(cmd.srq_handle);
if (usrq == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"destroy_srq() : inavlid hdl %d", cmd.srq_handle);
rc = EINVAL;
goto err_out;
}
uverbs_release_usrq_uevents(uctxt->async_evfile, usrq);
resp.events_reported = usrq->async_events_reported;
if (usrq->active_qp_cnt) {
sol_ofs_uobj_put(&usrq->uobj);
return (EBUSY);
} else {
rc = uverbs_usrq_free(usrq, uctxt);
if (rc)
goto err_out;
}
#ifdef _LP64
rc = copyout((void*)&resp, (void*)cmd.response.r_laddr, sizeof (resp));
#else
rc = copyout((void*)&resp, (void*)cmd.response.r_addr, sizeof (resp));
#endif
if (rc != 0) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"destroy_srq() : copyout failure %x", rc);
rc = EFAULT;
goto err_out;
}
return (DDI_SUCCESS);
err_out:
return (rc);
}
int
sol_uverbs_attach_mcast(uverbs_uctxt_uobj_t *uctxt, char *buf,
int in_len, int out_len)
{
struct ib_uverbs_attach_mcast cmd;
uverbs_uqp_uobj_t *uqp;
uverbs_mcast_entry_t *mc;
llist_head_t *entry;
int rc;
ib_gid_t mc_gid;
(void) memcpy(&cmd, buf, sizeof (cmd));
mc_gid.gid_prefix = b2h64(*((uint64_t *)&cmd.gid[0]));
mc_gid.gid_guid = b2h64(*((uint64_t *)&cmd.gid[8]));
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str, "attach_mcast(qp_handle=%d, "
"mlid=0x%04x, gid=%016llx:%016llx", cmd.qp_handle, cmd.mlid,
mc_gid.gid_prefix, mc_gid.gid_guid);
uqp = uverbs_uobj_get_uqp_write(cmd.qp_handle);
if (uqp == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"attach_mcast QP not found");
rc = EINVAL;
goto err_out;
}
list_for_each(entry, &uqp->mcast_list) {
mc = (uverbs_mcast_entry_t *)entry->ptr;
if (cmd.mlid == mc->mcg.mc_adds_vect.av_dlid &&
!memcmp(&mc_gid.gid, &mc->mcg.mc_adds_vect.av_dgid,
sizeof (mc_gid.gid))) {
SOL_OFS_DPRINTF_L4(sol_uverbs_dbg_str,
"attach_mcast: match entry found");
rc = DDI_SUCCESS;
goto out_put;
}
}
mc = kmem_zalloc(sizeof (*mc), KM_NOSLEEP);
if (mc == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"attach_mcast: kmem_zalloc fail");
rc = ENOMEM;
goto out_put;
}
llist_head_init(&mc->list, mc);
mc->mcg.mc_adds_vect.av_dlid = cmd.mlid;
bcopy(&mc_gid, &(mc->mcg.mc_adds_vect.av_dgid), sizeof (mc_gid));
rc = ibt_attach_mcg(uqp->qp, &mc->mcg);
if (rc != IBT_SUCCESS) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"attach_mcast: ibt_attach_mcq failed (r=%d)", rc);
rc = sol_uverbs_ibt_to_kernel_status(rc);
goto err_free;
}
llist_add_tail(&mc->list, &uqp->mcast_list);
sol_ofs_uobj_put(&uqp->uobj);
return (DDI_SUCCESS);
err_free:
kmem_free(mc, sizeof (*mc));
out_put:
sol_ofs_uobj_put(&uqp->uobj);
err_out:
return (rc);
}
int
sol_uverbs_detach_mcast(uverbs_uctxt_uobj_t *uctxt, char *buf,
int in_len, int out_len)
{
struct ib_uverbs_detach_mcast cmd;
uverbs_uqp_uobj_t *uqp;
ibt_mcg_info_t mcg;
int rc;
uverbs_mcast_entry_t *mc;
llist_head_t *entry;
llist_head_t *temp;
ib_gid_t mc_gid;
(void) memcpy(&cmd, buf, sizeof (cmd));
mc_gid.gid_prefix = b2h64(*((uint64_t *)&cmd.gid[0]));
mc_gid.gid_guid = b2h64(*((uint64_t *)&cmd.gid[8]));
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
"detach_mcast: entry (qp_handle=%d, mlid=0x%04x,"
"gid=%016llx:%016llx", cmd.qp_handle, cmd.mlid, mc_gid.gid_prefix,
mc_gid.gid_guid);
(void) memset(&mcg, 0, sizeof (mcg));
uqp = uverbs_uobj_get_uqp_write(cmd.qp_handle);
if (uqp == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"detach_mcast(): QP hdl %x not found", cmd.qp_handle);
rc = EINVAL;
goto err_out;
}
mcg.mc_adds_vect.av_dlid = cmd.mlid;
mcg.mc_adds_vect.av_dgid = mc_gid;
rc = ibt_detach_mcg(uqp->qp, &mcg);
if (rc != IBT_SUCCESS) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"deatch_mcast(): ibt_attach_mcq failed (r=%d)", rc);
rc = sol_uverbs_ibt_to_kernel_status(rc);
goto err_put;
}
entry = uqp->mcast_list.nxt;
temp = entry->nxt;
while (entry != &uqp->mcast_list) {
ASSERT(entry);
mc = (uverbs_mcast_entry_t *)entry->ptr;
ASSERT(mc);
if (cmd.mlid == mc->mcg.mc_adds_vect.av_dlid &&
!memcmp(&mc_gid.gid, &mc->mcg.mc_adds_vect.av_dgid,
sizeof (mc_gid.gid))) {
llist_del(&mc->list);
kmem_free(mc, sizeof (*mc));
break;
}
entry = temp;
temp = entry->nxt;
}
sol_ofs_uobj_put(&uqp->uobj);
return (DDI_SUCCESS);
err_put:
sol_ofs_uobj_put(&uqp->uobj);
err_out:
return (rc);
}
void
uverbs_detach_uqp_mcast_entries(uverbs_uqp_uobj_t *uqp)
{
int rc;
uverbs_mcast_entry_t *mc;
llist_head_t *entry;
llist_head_t *temp;
entry = uqp->mcast_list.nxt;
temp = entry->nxt;
while (entry != &uqp->mcast_list) {
ASSERT(entry);
mc = (uverbs_mcast_entry_t *)entry->ptr;
ASSERT(mc);
rc = ibt_detach_mcg(uqp->qp, &mc->mcg);
if (rc != IBT_SUCCESS) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"detach_mcast() : "
"ibt_detach_mcq failed (r=%d)", rc);
}
llist_del(&mc->list);
entry = temp;
temp = entry->nxt;
}
}
ibt_qp_hdl_t
sol_uverbs_uqpid_to_ibt_handle(uint32_t uqpid)
{
uverbs_uqp_uobj_t *uqp;
void *qphdl;
uqp = uverbs_uobj_get_uqp_read(uqpid);
if (uqp == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"uqpid2ibthdl: QP lookup failure: id %d", uqpid);
return (NULL);
}
qphdl = (void *)uqp->qp;
sol_ofs_uobj_put(&uqp->uobj);
return (qphdl);
}
int
sol_uverbs_disable_user_qp_modify(uint32_t uqpid)
{
uverbs_uqp_uobj_t *uqp;
uqp = uverbs_uobj_get_uqp_write(uqpid);
if (uqp == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"disable_uqp_modify(%d) -lookup failure", uqpid);
return (EINVAL);
}
uqp->disable_qp_mod = TRUE;
sol_ofs_uobj_put(&uqp->uobj);
return (0);
}
int
sol_uverbs_enable_user_qp_modify(uint32_t uqpid)
{
uverbs_uqp_uobj_t *uqp;
uqp = uverbs_uobj_get_uqp_write(uqpid);
if (uqp == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"enable_uqp_modify(%d) -lookup failure", uqpid);
return (EINVAL);
}
uqp->disable_qp_mod = FALSE;
sol_ofs_uobj_put(&uqp->uobj);
return (0);
}
int
uverbs_uqpn_cq_ctrl(uint32_t uqpid, sol_uverbs_cq_ctrl_t ctrl)
{
uverbs_uqp_uobj_t *uqp;
uverbs_ucq_uobj_t *uscq;
uverbs_ucq_uobj_t *urcq;
uqp = uverbs_uobj_get_uqp_write(uqpid);
if (uqp == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"uqpn_cq_ctrl(%d) -lookup failure", uqpid);
return (EINVAL);
}
uscq = uqp->uqp_scq;
urcq = uqp->uqp_rcq;
SOL_OFS_DPRINTF_L5(sol_uverbs_dbg_str,
"ctrl - uqp %p, rcq %p. scq %p", uqp, urcq, uscq);
ASSERT(uscq);
ASSERT(urcq);
uverbs_cq_ctrl(uscq, ctrl);
if (uscq != urcq)
uverbs_cq_ctrl(urcq, ctrl);
sol_ofs_uobj_put(&uqp->uobj);
return (0);
}
extern uint32_t sol_uverbs_qpnum2uqpid(uint32_t);
void
sol_uverbs_flush_qp(uint32_t qpnum)
{
int32_t uqpid;
ibt_status_t status;
uverbs_uqp_uobj_t *uqp;
uqpid = sol_uverbs_qpnum2uqpid(qpnum);
if (uqpid == DDI_FAILURE) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"sol_uverbs_flush_qp(%x) - Invalid qpnum",
qpnum);
return;
}
uqp = uverbs_uobj_get_uqp_write(uqpid);
if (uqp == NULL) {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"sol_uverbs_flush_qp(%x) - Invalid "
"uqpid %x", qpnum, uqpid);
return;
}
if (uqp->qp) {
status = ibt_flush_qp(uqp->qp);
if (status != IBT_SUCCESS)
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"sol_uverbs_flush_qp(%x) - "
"ibt_flush_qp(%p) failed - status %d",
qpnum, uqp->qp, status);
sol_ofs_uobj_put(&uqp->uobj);
return;
} else {
SOL_OFS_DPRINTF_L2(sol_uverbs_dbg_str,
"sol_uverbs_flush_qp(%x), uqpid %x -"
"uqp->qp is NULL!!", qpnum, uqpid);
sol_ofs_uobj_put(&uqp->uobj);
return;
}
}
static uint32_t
ibt_cep_flags2ibv(ibt_cep_flags_t ibt_flags)
{
uint32_t ib_flags = 0;
if (ibt_flags & IBT_CEP_RDMA_WR)
ib_flags |= IB_ACCESS_REMOTE_WRITE;
if (ibt_flags & IBT_CEP_RDMA_RD)
ib_flags |= IB_ACCESS_REMOTE_READ;
if (ibt_flags & IBT_CEP_ATOMIC)
ib_flags |= IB_ACCESS_REMOTE_ATOMIC;
return (ib_flags);
}
static void
uverbs_cq_ctrl(uverbs_ucq_uobj_t *ucq, sol_uverbs_cq_ctrl_t ctrl)
{
uverbs_ufile_uobj_t *ufile;
ufile = ucq->comp_chan;
if (!ufile) {
SOL_OFS_DPRINTF_L3(sol_uverbs_dbg_str,
"cq_ctrl(%p), ufile NULL", ucq, ufile);
return;
}
mutex_enter(&ufile->lock);
ufile->ufile_notify_enabled = ctrl;
if (ctrl == SOL_UVERBS2UCMA_CQ_NOTIFY_ENABLE) {
if (!llist_empty(&ufile->event_list)) {
cv_signal(&ufile->poll_wait);
pollwakeup(&ufile->poll_head,
POLLIN | POLLRDNORM);
}
}
mutex_exit(&ufile->lock);
}