#include <sys/sysmacros.h>
#include <sys/types.h>
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/modctl.h>
#include <sys/bitmap.h>
#include <sys/ib/adapters/hermon/hermon.h>
#include <sys/ib/ib_pkt_hdrs.h>
static int hermon_qp_reset2init(hermon_state_t *state, hermon_qphdl_t qp,
ibt_qp_info_t *info_p);
static int hermon_qp_init2init(hermon_state_t *state, hermon_qphdl_t qp,
ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
static int hermon_qp_init2rtr(hermon_state_t *state, hermon_qphdl_t qp,
ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
static int hermon_qp_rtr2rts(hermon_state_t *state, hermon_qphdl_t qp,
ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
static int hermon_qp_rts2rts(hermon_state_t *state, hermon_qphdl_t qp,
ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
#ifdef HERMON_NOTNOW
static int hermon_qp_rts2sqd(hermon_state_t *state, hermon_qphdl_t qp,
ibt_cep_modify_flags_t flags);
#endif
static int hermon_qp_sqd2rts(hermon_state_t *state, hermon_qphdl_t qp,
ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
static int hermon_qp_sqd2sqd(hermon_state_t *state, hermon_qphdl_t qp,
ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
static int hermon_qp_sqerr2rts(hermon_state_t *state, hermon_qphdl_t qp,
ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p);
static int hermon_qp_to_error(hermon_state_t *state, hermon_qphdl_t qp);
static int hermon_qp_reset2err(hermon_state_t *state, hermon_qphdl_t qp);
static uint_t hermon_check_rdma_enable_flags(ibt_cep_modify_flags_t flags,
ibt_qp_info_t *info_p, hermon_hw_qpc_t *qpc);
static int hermon_qp_validate_resp_rsrc(hermon_state_t *state,
ibt_qp_rc_attr_t *rc, uint_t *rra_max);
static int hermon_qp_validate_init_depth(hermon_state_t *state,
ibt_qp_rc_attr_t *rc, uint_t *sra_max);
static int hermon_qp_validate_mtu(hermon_state_t *state, uint_t mtu);
int
hermon_qp_modify(hermon_state_t *state, hermon_qphdl_t qp,
ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p,
ibt_queue_sizes_t *actual_sz)
{
ibt_cep_state_t cur_state, mod_state;
ibt_cep_modify_flags_t okflags;
int status;
mutex_enter(&qp->qp_lock);
if (!(HERMON_QP_TYPE_VALID(info_p->qp_trans, qp->qp_serv_type))) {
mutex_exit(&qp->qp_lock);
return (IBT_QP_SRV_TYPE_INVALID);
}
mod_state = info_p->qp_state;
if (flags & IBT_CEP_SET_RTR_RTS) {
cur_state = HERMON_QP_RTR;
} else if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_RTS)) {
switch (info_p->qp_current_state) {
case IBT_STATE_RTR:
cur_state = HERMON_QP_RTR;
break;
case IBT_STATE_RTS:
cur_state = HERMON_QP_RTS;
break;
case IBT_STATE_SQE:
cur_state = HERMON_QP_SQERR;
break;
case IBT_STATE_SQD:
cur_state = HERMON_QP_SQD;
break;
default:
mutex_exit(&qp->qp_lock);
return (IBT_QP_STATE_INVALID);
}
} else {
cur_state = qp->qp_state;
}
switch (cur_state) {
case HERMON_QP_RESET:
okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_RESET_INIT |
IBT_CEP_SET_RDMA_R | IBT_CEP_SET_RDMA_W |
IBT_CEP_SET_ATOMIC | IBT_CEP_SET_PKEY_IX |
IBT_CEP_SET_PORT | IBT_CEP_SET_QKEY);
if (flags & ~okflags) {
mutex_exit(&qp->qp_lock);
status = IBT_QP_ATTR_RO;
goto qpmod_fail;
}
if ((flags & IBT_CEP_SET_RESET_INIT) &&
(flags & IBT_CEP_SET_STATE) &&
(mod_state != IBT_STATE_INIT)) {
mutex_exit(&qp->qp_lock);
status = IBT_QP_STATE_INVALID;
goto qpmod_fail;
} else if ((flags & IBT_CEP_SET_RESET_INIT) ||
((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_INIT))) {
status = hermon_qp_reset2init(state, qp, info_p);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_INIT;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_INIT);
} else if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_RESET)) {
mutex_exit(&qp->qp_lock);
return (DDI_SUCCESS);
} else if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_ERROR)) {
status = hermon_qp_reset2err(state, qp);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_ERR;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
} else {
mutex_exit(&qp->qp_lock);
status = IBT_QP_STATE_INVALID;
goto qpmod_fail;
}
status = hermon_wrid_from_reset_handling(state, qp);
if (status != DDI_SUCCESS) {
if (hermon_qp_to_reset(state, qp) != DDI_SUCCESS) {
HERMON_WARNING(state, "failed to reset QP");
}
qp->qp_state = HERMON_QP_RESET;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
break;
case HERMON_QP_INIT:
okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_INIT_RTR |
IBT_CEP_SET_ADDS_VECT | IBT_CEP_SET_RDMARA_IN |
IBT_CEP_SET_MIN_RNR_NAK | IBT_CEP_SET_ALT_PATH |
IBT_CEP_SET_RDMA_R | IBT_CEP_SET_RDMA_W |
IBT_CEP_SET_ATOMIC | IBT_CEP_SET_PKEY_IX |
IBT_CEP_SET_QKEY | IBT_CEP_SET_PORT);
if (flags & ~okflags) {
mutex_exit(&qp->qp_lock);
status = IBT_QP_ATTR_RO;
goto qpmod_fail;
}
if ((flags & IBT_CEP_SET_INIT_RTR) &&
(flags & IBT_CEP_SET_STATE) &&
(mod_state != IBT_STATE_RTR)) {
mutex_exit(&qp->qp_lock);
status = IBT_QP_STATE_INVALID;
goto qpmod_fail;
} else if ((flags & IBT_CEP_SET_INIT_RTR) ||
((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_RTR))) {
status = hermon_qp_init2rtr(state, qp, flags, info_p);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_RTR;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTR);
} else if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_INIT)) {
status = hermon_qp_init2init(state, qp, flags, info_p);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_INIT;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_INIT);
} else if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_RESET)) {
status = hermon_qp_to_reset(state, qp);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_RESET;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
status = hermon_wrid_to_reset_handling(state, qp);
if (status != IBT_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
} else if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_ERROR)) {
status = hermon_qp_to_error(state, qp);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_ERR;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
} else {
mutex_exit(&qp->qp_lock);
status = IBT_QP_STATE_INVALID;
goto qpmod_fail;
}
break;
case HERMON_QP_RTR:
okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_RTR_RTS |
IBT_CEP_SET_TIMEOUT | IBT_CEP_SET_RETRY |
IBT_CEP_SET_RNR_NAK_RETRY | IBT_CEP_SET_RDMARA_OUT |
IBT_CEP_SET_RDMA_R | IBT_CEP_SET_RDMA_W |
IBT_CEP_SET_ATOMIC | IBT_CEP_SET_QKEY |
IBT_CEP_SET_ALT_PATH | IBT_CEP_SET_MIG |
IBT_CEP_SET_MIN_RNR_NAK);
if (flags & ~okflags) {
mutex_exit(&qp->qp_lock);
status = IBT_QP_ATTR_RO;
goto qpmod_fail;
}
if ((flags & IBT_CEP_SET_RTR_RTS) &&
(flags & IBT_CEP_SET_STATE) &&
(mod_state != IBT_STATE_RTS)) {
mutex_exit(&qp->qp_lock);
status = IBT_QP_STATE_INVALID;
goto qpmod_fail;
} else if ((flags & IBT_CEP_SET_RTR_RTS) ||
((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_RTS))) {
status = hermon_qp_rtr2rts(state, qp, flags, info_p);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_RTS;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTS);
} else if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_RESET)) {
status = hermon_qp_to_reset(state, qp);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_RESET;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
status = hermon_wrid_to_reset_handling(state, qp);
if (status != IBT_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
} else if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_ERROR)) {
status = hermon_qp_to_error(state, qp);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_ERR;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
} else {
mutex_exit(&qp->qp_lock);
status = IBT_QP_STATE_INVALID;
goto qpmod_fail;
}
break;
case HERMON_QP_RTS:
okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_RDMA_R |
IBT_CEP_SET_RDMA_W | IBT_CEP_SET_ATOMIC |
IBT_CEP_SET_QKEY | IBT_CEP_SET_ALT_PATH |
IBT_CEP_SET_MIG | IBT_CEP_SET_MIN_RNR_NAK |
IBT_CEP_SET_SQD_EVENT);
if (flags & ~okflags) {
mutex_exit(&qp->qp_lock);
status = IBT_QP_ATTR_RO;
goto qpmod_fail;
}
if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_RTS)) {
status = hermon_qp_rts2rts(state, qp, flags, info_p);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_RTS;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTS);
} else if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_SQD)) {
#ifdef HERMON_NOTNOW
status = hermon_qp_rts2sqd(state, qp, flags);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_SQD;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_SQD);
#else
mutex_exit(&qp->qp_lock);
status = IBT_QP_STATE_INVALID;
goto qpmod_fail;
#endif
} else if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_RESET)) {
status = hermon_qp_to_reset(state, qp);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_RESET;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
status = hermon_wrid_to_reset_handling(state, qp);
if (status != IBT_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
} else if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_ERROR)) {
status = hermon_qp_to_error(state, qp);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_ERR;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
} else {
mutex_exit(&qp->qp_lock);
status = IBT_QP_STATE_INVALID;
goto qpmod_fail;
}
break;
case HERMON_QP_SQERR:
okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_RDMA_R |
IBT_CEP_SET_RDMA_W | IBT_CEP_SET_ATOMIC |
IBT_CEP_SET_QKEY | IBT_CEP_SET_MIN_RNR_NAK);
if (flags & ~okflags) {
mutex_exit(&qp->qp_lock);
status = IBT_QP_ATTR_RO;
goto qpmod_fail;
}
if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_RTS)) {
status = hermon_qp_sqerr2rts(state, qp, flags, info_p);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_RTS;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTS);
} else if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_RESET)) {
status = hermon_qp_to_reset(state, qp);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_RESET;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
status = hermon_wrid_to_reset_handling(state, qp);
if (status != IBT_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
} else if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_ERROR)) {
status = hermon_qp_to_error(state, qp);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_ERR;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
} else {
mutex_exit(&qp->qp_lock);
status = IBT_QP_STATE_INVALID;
goto qpmod_fail;
}
break;
case HERMON_QP_SQD:
okflags = (IBT_CEP_SET_STATE | IBT_CEP_SET_ADDS_VECT |
IBT_CEP_SET_ALT_PATH | IBT_CEP_SET_MIG |
IBT_CEP_SET_RDMARA_OUT | IBT_CEP_SET_RDMARA_IN |
IBT_CEP_SET_QKEY | IBT_CEP_SET_PKEY_IX |
IBT_CEP_SET_TIMEOUT | IBT_CEP_SET_RETRY |
IBT_CEP_SET_RNR_NAK_RETRY | IBT_CEP_SET_PORT |
IBT_CEP_SET_MIN_RNR_NAK | IBT_CEP_SET_RDMA_R |
IBT_CEP_SET_RDMA_W | IBT_CEP_SET_ATOMIC);
if (flags & ~okflags) {
mutex_exit(&qp->qp_lock);
status = IBT_QP_ATTR_RO;
goto qpmod_fail;
}
if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_SQD)) {
status = hermon_qp_sqd2sqd(state, qp, flags, info_p);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_SQD;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_SQD);
} else if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_RTS)) {
if (qp->qp_sqd_still_draining) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
status = hermon_qp_sqd2sqd(state, qp, flags, info_p);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_SQD;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_SQD);
status = hermon_qp_sqd2rts(state, qp,
IBT_CEP_SET_STATE, info_p);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_RTS;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RTS);
} else if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_RESET)) {
status = hermon_qp_to_reset(state, qp);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_RESET;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
status = hermon_wrid_to_reset_handling(state, qp);
if (status != IBT_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
} else if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_ERROR)) {
status = hermon_qp_to_error(state, qp);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_ERR;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_ERR);
} else {
mutex_exit(&qp->qp_lock);
status = IBT_QP_STATE_INVALID;
goto qpmod_fail;
}
break;
case HERMON_QP_ERR:
if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_RESET)) {
status = hermon_qp_to_reset(state, qp);
if (status != DDI_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
qp->qp_state = HERMON_QP_RESET;
HERMON_SET_QP_POST_SEND_STATE(qp, HERMON_QP_RESET);
status = hermon_wrid_to_reset_handling(state, qp);
if (status != IBT_SUCCESS) {
mutex_exit(&qp->qp_lock);
goto qpmod_fail;
}
} else if ((flags & IBT_CEP_SET_STATE) &&
(mod_state == IBT_STATE_ERROR)) {
mutex_exit(&qp->qp_lock);
return (DDI_SUCCESS);
} else {
mutex_exit(&qp->qp_lock);
status = IBT_QP_STATE_INVALID;
goto qpmod_fail;
}
break;
default:
mutex_exit(&qp->qp_lock);
HERMON_WARNING(state, "unknown QP state in modify");
status = IBT_QP_STATE_INVALID;
goto qpmod_fail;
}
mutex_exit(&qp->qp_lock);
return (DDI_SUCCESS);
qpmod_fail:
return (status);
}
static int
hermon_qp_reset2init(hermon_state_t *state, hermon_qphdl_t qp,
ibt_qp_info_t *info_p)
{
hermon_hw_qpc_t *qpc;
ibt_qp_rc_attr_t *rc;
ibt_qp_ud_attr_t *ud;
ibt_qp_uc_attr_t *uc;
uint_t portnum, pkeyindx;
int status;
uint32_t cqnmask;
int qp_srq_en;
ASSERT(MUTEX_HELD(&qp->qp_lock));
qpc = &qp->qpc;
if (qp->qp_is_special) {
qpc->serv_type = HERMON_QP_MLX;
} else {
qpc->serv_type = qp->qp_serv_type;
}
qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
qpc->pd = qp->qp_pdhdl->pd_pdnum;
qpc->log_sq_stride = qp->qp_sq_log_wqesz - 4;
qpc->log_rq_stride = qp->qp_rq_log_wqesz - 4;
qpc->sq_no_prefetch = qp->qp_no_prefetch;
qpc->log_sq_size = highbit(qp->qp_sq_bufsz) - 1;
qpc->log_rq_size = highbit(qp->qp_rq_bufsz) - 1;
qpc->usr_page = qp->qp_uarpg;
cqnmask = (1 << state->hs_cfg_profile->cp_log_num_cq) - 1;
qpc->cqn_snd =
(qp->qp_sq_cqhdl == NULL) ? 0 : qp->qp_sq_cqhdl->cq_cqnum & cqnmask;
qpc->page_offs = qp->qp_wqinfo.qa_pgoffs >> 6;
qpc->cqn_rcv =
(qp->qp_rq_cqhdl == NULL) ? 0 : qp->qp_rq_cqhdl->cq_cqnum & cqnmask;
qpc->dbr_addrh = ((uint64_t)qp->qp_rq_pdbr >> 32);
qpc->dbr_addrl = ((uint64_t)qp->qp_rq_pdbr & 0xFFFFFFFC) >> 2;
qpc->sq_wqe_counter = 0;
qpc->rq_wqe_counter = 0;
qpc->log2_pgsz = qp->qp_mrhdl->mr_log2_pgsz;
qpc->mtt_base_addrl = (qp->qp_mrhdl->mr_mttaddr) >> 3;
qpc->mtt_base_addrh = (uint32_t)((qp->qp_mrhdl->mr_mttaddr >> 32) &
0xFF);
qp_srq_en = (qp->qp_alloc_flags & IBT_QP_USES_SRQ) != 0;
qpc->srq_en = qp_srq_en;
if (qp_srq_en) {
qpc->srq_number = qp->qp_srqhdl->srq_srqnum;
} else {
qpc->srq_number = 0;
}
qpc->fre = qp->qp_rlky;
qpc->rlky = qp->qp_rlky;
qpc->header_sep = 0;
qpc->rss = qp->qp_alloc_flags & IBT_QP_USES_RSS ? 1 : 0;
qpc->inline_scatter = 0;
if (qp->qp_type == IBT_UD_RQP) {
int my_fc_id_idx, exch_base;
ud = &info_p->qp_transport.ud;
qpc->qkey = ud->ud_qkey;
qpc->mtu = HERMON_MAX_MTU;
if (qp->qp_uses_lso)
qpc->msg_max = state->hs_devlim.log_max_gso_sz;
else if (qp->qp_is_special)
qpc->msg_max = HERMON_MAX_MTU + 6;
else
qpc->msg_max = HERMON_QP_LOG_MAX_MSGSZ;
portnum = ud->ud_port;
if (hermon_portnum_is_valid(state, portnum)) {
qp->qp_portnum = portnum - 1;
qpc->pri_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(portnum - 1,
0, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
pkeyindx = ud->ud_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->pri_addr_path.pkey_indx = pkeyindx;
qp->qp_pkeyindx = pkeyindx;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
if (qpc->rss) {
struct hermon_hw_rss_s *rssp;
ibt_rss_flags_t flags = ud->ud_rss.rss_flags;
rssp = (struct hermon_hw_rss_s *)&qpc->pri_addr_path;
rssp->log2_tbl_sz = ud->ud_rss.rss_log2_table;
rssp->base_qpn = ud->ud_rss.rss_base_qpn;
rssp->default_qpn = ud->ud_rss.rss_def_qpn;
if (flags & IBT_RSS_ALG_XOR)
rssp->hash_fn = 0;
else if (flags & IBT_RSS_ALG_TPL)
rssp->hash_fn = 1;
else
return (IBT_INVALID_PARAM);
rssp->ipv4 = (flags & IBT_RSS_HASH_IPV4) != 0;
rssp->tcp_ipv4 = (flags & IBT_RSS_HASH_TCP_IPV4) != 0;
rssp->ipv6 = (flags & IBT_RSS_HASH_IPV6) != 0;
rssp->tcp_ipv4 = (flags & IBT_RSS_HASH_TCP_IPV6) != 0;
bcopy(ud->ud_rss.rss_toe_key, rssp->rss_key, 40);
} else if (qp->qp_serv_type == HERMON_QP_RFCI) {
status = hermon_fcoib_set_id(state, portnum,
qp->qp_qpnum, ud->ud_fc.fc_src_id);
if (status != DDI_SUCCESS)
return (status);
qp->qp_fc_attr = ud->ud_fc;
} else if (qp->qp_serv_type == HERMON_QP_FEXCH) {
my_fc_id_idx = hermon_fcoib_get_id_idx(state,
portnum, &ud->ud_fc);
if (my_fc_id_idx == -1)
return (IBT_INVALID_PARAM);
qpc->my_fc_id_idx = my_fc_id_idx;
status = hermon_fcoib_fexch_mkey_init(state,
qp->qp_pdhdl, ud->ud_fc.fc_hca_port,
qp->qp_qpnum, HERMON_CMD_NOSLEEP_SPIN);
if (status != DDI_SUCCESS)
return (status);
qp->qp_fc_attr = ud->ud_fc;
} else if (qp->qp_serv_type == HERMON_QP_FCMND) {
my_fc_id_idx = hermon_fcoib_get_id_idx(state,
portnum, &ud->ud_fc);
if (my_fc_id_idx == -1)
return (IBT_INVALID_PARAM);
qpc->my_fc_id_idx = my_fc_id_idx;
exch_base = hermon_fcoib_check_exch_base_off(state,
portnum, &ud->ud_fc);
if (exch_base == -1)
return (IBT_INVALID_PARAM);
qpc->exch_base = exch_base;
qpc->exch_size = ud->ud_fc.fc_exch_log2_sz;
qp->qp_fc_attr = ud->ud_fc;
}
} else if (qp->qp_serv_type == HERMON_QP_RC) {
rc = &info_p->qp_transport.rc;
qpc->rre = (info_p->qp_flags & IBT_CEP_RDMA_RD) ? 1 : 0;
qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
qpc->rae = (info_p->qp_flags & IBT_CEP_ATOMIC) ? 1 : 0;
portnum = rc->rc_path.cep_hca_port_num;
if (hermon_portnum_is_valid(state, portnum)) {
qp->qp_portnum = portnum - 1;
qpc->pri_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(portnum - 1,
0, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
pkeyindx = rc->rc_path.cep_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->pri_addr_path.pkey_indx = pkeyindx;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
} else if (qp->qp_serv_type == HERMON_QP_UC) {
uc = &info_p->qp_transport.uc;
qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
portnum = uc->uc_path.cep_hca_port_num;
if (hermon_portnum_is_valid(state, portnum)) {
qp->qp_portnum = portnum - 1;
qpc->pri_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(portnum - 1,
0, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
pkeyindx = uc->uc_path.cep_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->pri_addr_path.pkey_indx = pkeyindx;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
} else {
HERMON_WARNING(state, "unknown QP transport type in rst2init");
return (ibc_get_ci_failure(0));
}
status = hermon_cmn_qp_cmd_post(state, RST2INIT_QP, qpc, qp->qp_qpnum,
0, HERMON_CMD_NOSLEEP_SPIN);
if (status != HERMON_CMD_SUCCESS) {
cmn_err(CE_NOTE, "hermon%d: RST2INIT_QP command failed: %08x\n",
state->hs_instance, status);
if (status == HERMON_CMD_INVALID_STATUS) {
hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
}
return (ibc_get_ci_failure(0));
}
return (DDI_SUCCESS);
}
static int
hermon_qp_init2init(hermon_state_t *state, hermon_qphdl_t qp,
ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
{
hermon_hw_qpc_t *qpc;
ibt_qp_rc_attr_t *rc;
ibt_qp_ud_attr_t *ud;
ibt_qp_uc_attr_t *uc;
uint_t portnum, pkeyindx;
uint32_t opmask = 0;
int status;
ASSERT(MUTEX_HELD(&qp->qp_lock));
qpc = &qp->qpc;
if (qp->qp_type == IBT_UD_RQP) {
ud = &info_p->qp_transport.ud;
if (flags & IBT_CEP_SET_PORT) {
portnum = ud->ud_port;
if (hermon_portnum_is_valid(state, portnum)) {
qp->qp_portnum = portnum - 1;
qpc->pri_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(portnum - 1,
0, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
}
if (flags & IBT_CEP_SET_PKEY_IX) {
pkeyindx = ud->ud_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->pri_addr_path.pkey_indx = pkeyindx;
opmask |= HERMON_CMD_OP_PKEYINDX;
qp->qp_pkeyindx = pkeyindx;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
}
if (flags & IBT_CEP_SET_QKEY) {
qpc->qkey = ud->ud_qkey;
opmask |= HERMON_CMD_OP_QKEY;
}
} else if (qp->qp_serv_type == HERMON_QP_RC) {
rc = &info_p->qp_transport.rc;
if (flags & IBT_CEP_SET_PORT) {
portnum = rc->rc_path.cep_hca_port_num;
if (hermon_portnum_is_valid(state, portnum)) {
qp->qp_portnum = portnum - 1;
qpc->pri_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(portnum - 1,
0, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
}
if (flags & IBT_CEP_SET_PKEY_IX) {
pkeyindx = rc->rc_path.cep_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->pri_addr_path.pkey_indx = pkeyindx;
opmask |= HERMON_CMD_OP_PKEYINDX;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
}
opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
} else if (qp->qp_serv_type == HERMON_QP_UC) {
uc = &info_p->qp_transport.uc;
if (flags & IBT_CEP_SET_PORT) {
portnum = uc->uc_path.cep_hca_port_num;
if (hermon_portnum_is_valid(state, portnum)) {
qp->qp_portnum = portnum - 1;
qpc->pri_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(portnum - 1,
0, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
}
if (flags & IBT_CEP_SET_PKEY_IX) {
pkeyindx = uc->uc_path.cep_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->pri_addr_path.pkey_indx = pkeyindx;
opmask |= HERMON_CMD_OP_PKEYINDX;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
}
if (flags & IBT_CEP_SET_RDMA_W) {
qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
opmask |= HERMON_CMD_OP_RWE;
}
} else {
HERMON_WARNING(state, "unknown QP transport type in init2init");
return (ibc_get_ci_failure(0));
}
status = hermon_cmn_qp_cmd_post(state, INIT2INIT_QP, qpc, qp->qp_qpnum,
opmask, HERMON_CMD_NOSLEEP_SPIN);
if (status != HERMON_CMD_SUCCESS) {
if (status != HERMON_CMD_BAD_QP_STATE) {
cmn_err(CE_NOTE, "hermon%d: INIT2INIT_QP command "
"failed: %08x\n", state->hs_instance, status);
if (status == HERMON_CMD_INVALID_STATUS) {
hermon_fm_ereport(state, HCA_SYS_ERR,
HCA_ERR_SRV_LOST);
}
return (ibc_get_ci_failure(0));
} else {
return (IBT_QP_STATE_INVALID);
}
}
return (DDI_SUCCESS);
}
static int
hermon_qp_init2rtr(hermon_state_t *state, hermon_qphdl_t qp,
ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
{
hermon_hw_qpc_t *qpc;
ibt_qp_rc_attr_t *rc;
ibt_qp_ud_attr_t *ud;
ibt_qp_uc_attr_t *uc;
hermon_hw_addr_path_t *qpc_path;
ibt_adds_vect_t *adds_vect;
uint_t portnum, pkeyindx, rra_max;
uint_t mtu;
uint32_t opmask = 0;
int status;
ASSERT(MUTEX_HELD(&qp->qp_lock));
qpc = &qp->qpc;
if (qp->qp_type == IBT_UD_RQP) {
ud = &info_p->qp_transport.ud;
qpc->mtu = HERMON_MAX_MTU;
if (qp->qp_uses_lso)
qpc->msg_max = state->hs_devlim.log_max_gso_sz;
else
qpc->msg_max = HERMON_QP_LOG_MAX_MSGSZ;
qp->qp_save_mtu = qpc->mtu;
if (flags & IBT_CEP_SET_PKEY_IX) {
pkeyindx = ud->ud_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->pri_addr_path.pkey_indx = pkeyindx;
opmask |= HERMON_CMD_OP_PKEYINDX;
qp->qp_pkeyindx = pkeyindx;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
}
if (flags & IBT_CEP_SET_QKEY) {
qpc->qkey = ud->ud_qkey;
opmask |= HERMON_CMD_OP_QKEY;
}
} else if (qp->qp_serv_type == HERMON_QP_RC) {
rc = &info_p->qp_transport.rc;
qpc_path = &qpc->pri_addr_path;
adds_vect = &rc->rc_path.cep_adds_vect;
status = hermon_set_addr_path(state, adds_vect, qpc_path,
HERMON_ADDRPATH_QP);
if (status != DDI_SUCCESS) {
return (status);
}
portnum = qp->qp_portnum + 1;
if (hermon_portnum_is_valid(state, portnum)) {
qpc->pri_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(qp->qp_portnum,
adds_vect->av_srvl, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
qpc->rnr_retry = rc->rc_rnr_retry_cnt;
qpc->retry_cnt = rc->rc_retry_cnt;
qpc_path->ack_timeout = rc->rc_path.cep_timeout;
qpc->rem_qpn = rc->rc_dst_qpn;
qpc->next_rcv_psn = rc->rc_rq_psn;
qpc->msg_max = HERMON_QP_LOG_MAX_MSGSZ;
qpc->ric = 0;
mtu = rc->rc_path_mtu;
if (hermon_qp_validate_mtu(state, mtu) != DDI_SUCCESS) {
return (IBT_HCA_PORT_MTU_EXCEEDED);
}
qpc->mtu = mtu;
qp->qp_save_mtu = qpc->mtu;
qpc->min_rnr_nak = rc->rc_min_rnr_nak;
opmask |= HERMON_CMD_OP_MINRNRNAK;
if (hermon_qp_validate_resp_rsrc(state, rc, &rra_max) !=
DDI_SUCCESS) {
return (IBT_INVALID_PARAM);
}
qpc->rra_max = rra_max;
if (flags & IBT_CEP_SET_PKEY_IX) {
pkeyindx = rc->rc_path.cep_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->pri_addr_path.pkey_indx = pkeyindx;
opmask |= HERMON_CMD_OP_PKEYINDX;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
}
opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
if (flags & IBT_CEP_SET_ALT_PATH) {
qpc_path = &qpc->alt_addr_path;
adds_vect = &rc->rc_alt_path.cep_adds_vect;
status = hermon_set_addr_path(state, adds_vect,
qpc_path, HERMON_ADDRPATH_QP);
if (status != DDI_SUCCESS) {
return (status);
}
qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
portnum = rc->rc_alt_path.cep_hca_port_num;
if (hermon_portnum_is_valid(state, portnum)) {
qp->qp_portnum_alt = portnum - 1;
qpc->alt_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(portnum - 1,
adds_vect->av_srvl, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
pkeyindx = rc->rc_alt_path.cep_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->alt_addr_path.pkey_indx = pkeyindx;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
opmask |= HERMON_CMD_OP_ALT_PATH;
}
} else if (qp->qp_serv_type == HERMON_QP_UC) {
uc = &info_p->qp_transport.uc;
qpc_path = &qpc->pri_addr_path;
adds_vect = &uc->uc_path.cep_adds_vect;
status = hermon_set_addr_path(state, adds_vect, qpc_path,
HERMON_ADDRPATH_QP);
if (status != DDI_SUCCESS) {
return (status);
}
portnum = qp->qp_portnum + 1;
if (hermon_portnum_is_valid(state, portnum)) {
qpc->pri_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(qp->qp_portnum,
adds_vect->av_srvl, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
qpc->rem_qpn = uc->uc_dst_qpn;
qpc->next_rcv_psn = uc->uc_rq_psn;
qpc->msg_max = HERMON_QP_LOG_MAX_MSGSZ;
mtu = uc->uc_path_mtu;
if (hermon_qp_validate_mtu(state, mtu) != DDI_SUCCESS) {
return (IBT_HCA_PORT_MTU_EXCEEDED);
}
qpc->mtu = mtu;
qp->qp_save_mtu = qpc->mtu;
if (flags & IBT_CEP_SET_PKEY_IX) {
pkeyindx = uc->uc_path.cep_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->pri_addr_path.pkey_indx = pkeyindx;
opmask |= HERMON_CMD_OP_PKEYINDX;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
}
if (flags & IBT_CEP_SET_RDMA_W) {
qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
opmask |= HERMON_CMD_OP_RWE;
}
if (flags & IBT_CEP_SET_ALT_PATH) {
qpc_path = &qpc->alt_addr_path;
adds_vect = &uc->uc_alt_path.cep_adds_vect;
status = hermon_set_addr_path(state, adds_vect,
qpc_path, HERMON_ADDRPATH_QP);
if (status != DDI_SUCCESS) {
return (status);
}
qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
portnum = uc->uc_alt_path.cep_hca_port_num;
if (hermon_portnum_is_valid(state, portnum)) {
qp->qp_portnum_alt = portnum - 1;
qpc->alt_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(portnum - 1,
adds_vect->av_srvl, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
pkeyindx = uc->uc_alt_path.cep_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->alt_addr_path.pkey_indx = pkeyindx;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
opmask |= HERMON_CMD_OP_ALT_PATH;
}
} else {
HERMON_WARNING(state, "unknown QP transport type in init2rtr");
return (ibc_get_ci_failure(0));
}
status = hermon_cmn_qp_cmd_post(state, INIT2RTR_QP, qpc, qp->qp_qpnum,
opmask, HERMON_CMD_NOSLEEP_SPIN);
if (status != HERMON_CMD_SUCCESS) {
if (status != HERMON_CMD_BAD_QP_STATE) {
cmn_err(CE_NOTE, "hermon%d: INIT2RTR_QP command "
"failed: %08x\n", state->hs_instance, status);
if (status == HERMON_CMD_INVALID_STATUS) {
hermon_fm_ereport(state, HCA_SYS_ERR,
HCA_ERR_SRV_LOST);
}
return (ibc_get_ci_failure(0));
} else {
return (IBT_QP_STATE_INVALID);
}
}
return (DDI_SUCCESS);
}
static int
hermon_qp_rtr2rts(hermon_state_t *state, hermon_qphdl_t qp,
ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
{
hermon_hw_qpc_t *qpc;
ibt_qp_rc_attr_t *rc;
ibt_qp_ud_attr_t *ud;
ibt_qp_uc_attr_t *uc;
hermon_hw_addr_path_t *qpc_path;
ibt_adds_vect_t *adds_vect;
uint_t portnum, pkeyindx, sra_max;
uint32_t opmask = 0;
int status;
ASSERT(MUTEX_HELD(&qp->qp_lock));
qpc = &qp->qpc;
if (qp->qp_type == IBT_UD_RQP) {
ud = &info_p->qp_transport.ud;
qpc->next_snd_psn = ud->ud_sq_psn;
if (flags & IBT_CEP_SET_QKEY) {
qpc->qkey = ud->ud_qkey;
opmask |= HERMON_CMD_OP_QKEY;
}
} else if (qp->qp_serv_type == HERMON_QP_RC) {
rc = &info_p->qp_transport.rc;
qpc_path = &qpc->pri_addr_path;
qpc->next_snd_psn = rc->rc_sq_psn;
qpc_path->ack_timeout = rc->rc_path.cep_timeout;
qpc->rnr_retry = rc->rc_rnr_retry_cnt;
qpc->retry_cnt = rc->rc_retry_cnt;
qpc->ack_req_freq = state->hs_cfg_profile->cp_ackreq_freq;
if (hermon_qp_validate_init_depth(state, rc, &sra_max) !=
DDI_SUCCESS) {
return (IBT_INVALID_PARAM);
}
qpc->sra_max = sra_max;
opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
if (flags & IBT_CEP_SET_MIG) {
if (rc->rc_mig_state == IBT_STATE_MIGRATED) {
qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
} else if (rc->rc_mig_state == IBT_STATE_REARMED) {
qpc->pm_state = HERMON_QP_PMSTATE_REARM;
} else {
return (IBT_QP_APM_STATE_INVALID);
}
opmask |= HERMON_CMD_OP_PM_STATE;
}
if (flags & IBT_CEP_SET_MIN_RNR_NAK) {
qpc->min_rnr_nak = rc->rc_min_rnr_nak;
opmask |= HERMON_CMD_OP_MINRNRNAK;
}
if (flags & IBT_CEP_SET_ALT_PATH) {
qpc_path = &qpc->alt_addr_path;
adds_vect = &rc->rc_alt_path.cep_adds_vect;
status = hermon_set_addr_path(state, adds_vect,
qpc_path, HERMON_ADDRPATH_QP);
if (status != DDI_SUCCESS) {
return (status);
}
qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
portnum = rc->rc_alt_path.cep_hca_port_num;
if (hermon_portnum_is_valid(state, portnum)) {
qp->qp_portnum_alt = portnum - 1;
qpc->alt_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(portnum - 1,
adds_vect->av_srvl, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
pkeyindx = rc->rc_alt_path.cep_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->alt_addr_path.pkey_indx = pkeyindx;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
opmask |= HERMON_CMD_OP_ALT_PATH;
}
} else if (qp->qp_serv_type == HERMON_QP_UC) {
uc = &info_p->qp_transport.uc;
qpc->next_snd_psn = uc->uc_sq_psn;
if (flags & IBT_CEP_SET_RDMA_W) {
qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
opmask |= HERMON_CMD_OP_RWE;
}
if (flags & IBT_CEP_SET_MIG) {
if (uc->uc_mig_state == IBT_STATE_MIGRATED) {
qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
} else if (uc->uc_mig_state == IBT_STATE_REARMED) {
qpc->pm_state = HERMON_QP_PMSTATE_REARM;
} else {
return (IBT_QP_APM_STATE_INVALID);
}
opmask |= HERMON_CMD_OP_PM_STATE;
}
if (flags & IBT_CEP_SET_ALT_PATH) {
qpc_path = &qpc->alt_addr_path;
adds_vect = &uc->uc_alt_path.cep_adds_vect;
status = hermon_set_addr_path(state, adds_vect,
qpc_path, HERMON_ADDRPATH_QP);
if (status != DDI_SUCCESS) {
return (status);
}
qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
portnum = uc->uc_alt_path.cep_hca_port_num;
if (hermon_portnum_is_valid(state, portnum)) {
qpc->alt_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(portnum - 1,
adds_vect->av_srvl, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
pkeyindx = uc->uc_alt_path.cep_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->alt_addr_path.pkey_indx = pkeyindx;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
opmask |= HERMON_CMD_OP_ALT_PATH;
}
} else {
HERMON_WARNING(state, "unknown QP transport type in rtr2rts");
return (ibc_get_ci_failure(0));
}
status = hermon_cmn_qp_cmd_post(state, RTR2RTS_QP, qpc, qp->qp_qpnum,
opmask, HERMON_CMD_NOSLEEP_SPIN);
if (status != HERMON_CMD_SUCCESS) {
if (status != HERMON_CMD_BAD_QP_STATE) {
cmn_err(CE_NOTE, "hermon%d: RTR2RTS_QP command failed: "
"%08x\n", state->hs_instance, status);
if (status == HERMON_CMD_INVALID_STATUS) {
hermon_fm_ereport(state, HCA_SYS_ERR,
HCA_ERR_SRV_LOST);
}
return (ibc_get_ci_failure(0));
} else {
return (IBT_QP_STATE_INVALID);
}
}
return (DDI_SUCCESS);
}
static int
hermon_qp_rts2rts(hermon_state_t *state, hermon_qphdl_t qp,
ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
{
hermon_hw_qpc_t *qpc;
ibt_qp_rc_attr_t *rc;
ibt_qp_ud_attr_t *ud;
ibt_qp_uc_attr_t *uc;
hermon_hw_addr_path_t *qpc_path;
ibt_adds_vect_t *adds_vect;
uint_t portnum, pkeyindx;
uint32_t opmask = 0;
int status;
ASSERT(MUTEX_HELD(&qp->qp_lock));
qpc = &qp->qpc;
if (qp->qp_type == IBT_UD_RQP) {
ud = &info_p->qp_transport.ud;
if (flags & IBT_CEP_SET_QKEY) {
qpc->qkey = ud->ud_qkey;
opmask |= HERMON_CMD_OP_QKEY;
}
} else if (qp->qp_serv_type == HERMON_QP_RC) {
rc = &info_p->qp_transport.rc;
opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
if (flags & IBT_CEP_SET_MIG) {
if (rc->rc_mig_state == IBT_STATE_MIGRATED) {
qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
} else if (rc->rc_mig_state == IBT_STATE_REARMED) {
qpc->pm_state = HERMON_QP_PMSTATE_REARM;
} else {
return (IBT_QP_APM_STATE_INVALID);
}
opmask |= HERMON_CMD_OP_PM_STATE;
}
if (flags & IBT_CEP_SET_MIN_RNR_NAK) {
qpc->min_rnr_nak = rc->rc_min_rnr_nak;
opmask |= HERMON_CMD_OP_MINRNRNAK;
}
if (flags & IBT_CEP_SET_ALT_PATH) {
qpc_path = &qpc->alt_addr_path;
adds_vect = &rc->rc_alt_path.cep_adds_vect;
status = hermon_set_addr_path(state, adds_vect,
qpc_path, HERMON_ADDRPATH_QP);
if (status != DDI_SUCCESS) {
return (status);
}
qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
portnum = rc->rc_alt_path.cep_hca_port_num;
if (hermon_portnum_is_valid(state, portnum)) {
qp->qp_portnum_alt = portnum - 1;
qpc->alt_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(portnum - 1,
adds_vect->av_srvl, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
pkeyindx = rc->rc_alt_path.cep_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->alt_addr_path.pkey_indx = pkeyindx;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
opmask |= HERMON_CMD_OP_ALT_PATH;
}
} else if (qp->qp_serv_type == HERMON_QP_UC) {
uc = &info_p->qp_transport.uc;
if (flags & IBT_CEP_SET_RDMA_W) {
qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
opmask |= HERMON_CMD_OP_RWE;
}
if (flags & IBT_CEP_SET_MIG) {
if (uc->uc_mig_state == IBT_STATE_MIGRATED) {
qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
} else if (uc->uc_mig_state == IBT_STATE_REARMED) {
qpc->pm_state = HERMON_QP_PMSTATE_REARM;
} else {
return (IBT_QP_APM_STATE_INVALID);
}
opmask |= HERMON_CMD_OP_PM_STATE;
}
if (flags & IBT_CEP_SET_ALT_PATH) {
qpc_path = &qpc->alt_addr_path;
adds_vect = &uc->uc_alt_path.cep_adds_vect;
status = hermon_set_addr_path(state, adds_vect,
qpc_path, HERMON_ADDRPATH_QP);
if (status != DDI_SUCCESS) {
return (status);
}
portnum = uc->uc_alt_path.cep_hca_port_num;
if (hermon_portnum_is_valid(state, portnum)) {
qp->qp_portnum_alt = portnum - 1;
qpc->alt_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(portnum - 1,
adds_vect->av_srvl, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
pkeyindx = uc->uc_alt_path.cep_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->alt_addr_path.pkey_indx = pkeyindx;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
opmask |= HERMON_CMD_OP_ALT_PATH;
}
} else {
HERMON_WARNING(state, "unknown QP transport type in rts2rts");
return (ibc_get_ci_failure(0));
}
status = hermon_cmn_qp_cmd_post(state, RTS2RTS_QP, qpc, qp->qp_qpnum,
opmask, HERMON_CMD_NOSLEEP_SPIN);
if (status != HERMON_CMD_SUCCESS) {
if (status != HERMON_CMD_BAD_QP_STATE) {
cmn_err(CE_NOTE, "hermon%d: RTS2RTS_QP command failed: "
"%08x\n", state->hs_instance, status);
if (status == HERMON_CMD_INVALID_STATUS) {
hermon_fm_ereport(state, HCA_SYS_ERR,
HCA_ERR_SRV_LOST);
}
return (ibc_get_ci_failure(0));
} else {
return (IBT_QP_STATE_INVALID);
}
}
return (DDI_SUCCESS);
}
#ifdef HERMON_NOTNOW
static int
hermon_qp_rts2sqd(hermon_state_t *state, hermon_qphdl_t qp,
ibt_cep_modify_flags_t flags)
{
int status;
ASSERT(MUTEX_HELD(&qp->qp_lock));
qp->qp_forward_sqd_event = (flags & IBT_CEP_SET_SQD_EVENT) ? 1 : 0;
status = hermon_cmn_qp_cmd_post(state, RTS2SQD_QP, NULL, qp->qp_qpnum,
0, HERMON_CMD_NOSLEEP_SPIN);
if (status != HERMON_CMD_SUCCESS) {
if (status != HERMON_CMD_BAD_QP_STATE) {
cmn_err(CE_NOTE, "hermon%d: RTS2SQD_QP command failed: "
"%08x\n", state->hs_instance, status);
if (status == HERMON_CMD_INVALID_STATUS) {
hermon_fm_ereport(state, HCA_SYS_ERR,
HCA_ERR_SRV_LOST);
}
return (ibc_get_ci_failure(0));
} else {
return (IBT_QP_STATE_INVALID);
}
}
qp->qp_sqd_still_draining = 1;
return (DDI_SUCCESS);
}
#endif
static int
hermon_qp_sqd2rts(hermon_state_t *state, hermon_qphdl_t qp,
ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
{
hermon_hw_qpc_t *qpc;
ibt_qp_rc_attr_t *rc;
ibt_qp_ud_attr_t *ud;
ibt_qp_uc_attr_t *uc;
hermon_hw_addr_path_t *qpc_path;
ibt_adds_vect_t *adds_vect;
uint_t portnum, pkeyindx;
uint_t rra_max, sra_max;
uint32_t opmask = 0;
int status;
ASSERT(MUTEX_HELD(&qp->qp_lock));
qpc = &qp->qpc;
if (qp->qp_type == IBT_UD_RQP) {
ud = &info_p->qp_transport.ud;
if (flags & IBT_CEP_SET_PORT) {
portnum = ud->ud_port;
if (hermon_portnum_is_valid(state, portnum)) {
qp->qp_portnum = portnum - 1;
qpc->pri_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(portnum - 1,
0, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
opmask |= HERMON_CMD_OP_PRIM_PORT;
}
if (flags & IBT_CEP_SET_PKEY_IX) {
pkeyindx = ud->ud_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->pri_addr_path.pkey_indx = pkeyindx;
opmask |= HERMON_CMD_OP_PKEYINDX;
qp->qp_pkeyindx = pkeyindx;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
}
if (flags & IBT_CEP_SET_QKEY) {
qpc->qkey = ud->ud_qkey;
opmask |= HERMON_CMD_OP_QKEY;
}
} else if (qp->qp_serv_type == HERMON_QP_RC) {
rc = &info_p->qp_transport.rc;
opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
qpc->retry_cnt = rc->rc_retry_cnt;
if (flags & IBT_CEP_SET_MIG) {
if (rc->rc_mig_state == IBT_STATE_MIGRATED) {
qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
} else if (rc->rc_mig_state == IBT_STATE_REARMED) {
qpc->pm_state = HERMON_QP_PMSTATE_REARM;
} else {
return (IBT_QP_APM_STATE_INVALID);
}
opmask |= HERMON_CMD_OP_PM_STATE;
}
if (flags & IBT_CEP_SET_ALT_PATH) {
qpc_path = &qpc->alt_addr_path;
adds_vect = &rc->rc_alt_path.cep_adds_vect;
status = hermon_set_addr_path(state, adds_vect,
qpc_path, HERMON_ADDRPATH_QP);
if (status != DDI_SUCCESS) {
return (status);
}
qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
portnum = rc->rc_alt_path.cep_hca_port_num;
if (hermon_portnum_is_valid(state, portnum)) {
qp->qp_portnum_alt = portnum - 1;
qpc->alt_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(portnum - 1,
adds_vect->av_srvl, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
pkeyindx = rc->rc_alt_path.cep_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->alt_addr_path.pkey_indx = pkeyindx;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
opmask |= HERMON_CMD_OP_ALT_PATH;
}
if (flags & IBT_CEP_SET_RDMARA_OUT) {
if (hermon_qp_validate_init_depth(state, rc,
&sra_max) != DDI_SUCCESS) {
return (IBT_INVALID_PARAM);
}
qpc->sra_max = sra_max;
opmask |= HERMON_CMD_OP_SRA_SET;
}
if (flags & IBT_CEP_SET_RDMARA_IN) {
if (hermon_qp_validate_resp_rsrc(state, rc,
&rra_max) != DDI_SUCCESS) {
return (IBT_INVALID_PARAM);
}
qpc->rra_max = rra_max;
opmask |= HERMON_CMD_OP_RRA_SET;
}
if (flags & IBT_CEP_SET_MIN_RNR_NAK) {
qpc->min_rnr_nak = rc->rc_min_rnr_nak;
opmask |= HERMON_CMD_OP_MINRNRNAK;
}
} else if (qp->qp_serv_type == HERMON_QP_UC) {
uc = &info_p->qp_transport.uc;
if (flags & IBT_CEP_SET_RDMA_W) {
qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
opmask |= HERMON_CMD_OP_RWE;
}
if (flags & IBT_CEP_SET_MIG) {
if (uc->uc_mig_state == IBT_STATE_MIGRATED) {
qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
} else if (uc->uc_mig_state == IBT_STATE_REARMED) {
qpc->pm_state = HERMON_QP_PMSTATE_REARM;
} else {
return (IBT_QP_APM_STATE_INVALID);
}
opmask |= HERMON_CMD_OP_PM_STATE;
}
if (flags & IBT_CEP_SET_ALT_PATH) {
qpc_path = &qpc->alt_addr_path;
adds_vect = &uc->uc_alt_path.cep_adds_vect;
status = hermon_set_addr_path(state, adds_vect,
qpc_path, HERMON_ADDRPATH_QP);
if (status != DDI_SUCCESS) {
return (status);
}
portnum = uc->uc_alt_path.cep_hca_port_num;
if (hermon_portnum_is_valid(state, portnum)) {
qp->qp_portnum_alt = portnum - 1;
qpc->alt_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(portnum - 1,
adds_vect->av_srvl, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
pkeyindx = uc->uc_alt_path.cep_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->alt_addr_path.pkey_indx = pkeyindx;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
opmask |= HERMON_CMD_OP_ALT_PATH;
}
} else {
HERMON_WARNING(state, "unknown QP transport type in sqd2rts");
return (ibc_get_ci_failure(0));
}
status = hermon_cmn_qp_cmd_post(state, SQD2RTS_QP, qpc, qp->qp_qpnum,
opmask, HERMON_CMD_NOSLEEP_SPIN);
if (status != HERMON_CMD_SUCCESS) {
if (status != HERMON_CMD_BAD_QP_STATE) {
cmn_err(CE_NOTE, "hermon%d: SQD2RTS_QP command failed: "
"%08x\n", state->hs_instance, status);
if (status == HERMON_CMD_INVALID_STATUS) {
hermon_fm_ereport(state, HCA_SYS_ERR,
HCA_ERR_SRV_LOST);
}
return (ibc_get_ci_failure(0));
} else {
return (IBT_QP_STATE_INVALID);
}
}
return (DDI_SUCCESS);
}
static int
hermon_qp_sqd2sqd(hermon_state_t *state, hermon_qphdl_t qp,
ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
{
hermon_hw_qpc_t *qpc;
ibt_qp_rc_attr_t *rc;
ibt_qp_ud_attr_t *ud;
ibt_qp_uc_attr_t *uc;
hermon_hw_addr_path_t *qpc_path;
ibt_adds_vect_t *adds_vect;
uint_t portnum, pkeyindx;
uint_t rra_max, sra_max;
uint32_t opmask = 0;
int status;
ASSERT(MUTEX_HELD(&qp->qp_lock));
qpc = &qp->qpc;
if (qp->qp_type == IBT_UD_RQP) {
ud = &info_p->qp_transport.ud;
if (flags & IBT_CEP_SET_PORT) {
portnum = ud->ud_port;
if (hermon_portnum_is_valid(state, portnum)) {
qp->qp_portnum = portnum - 1;
qpc->pri_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(portnum - 1,
0, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
opmask |= HERMON_CMD_OP_SCHEDQUEUE;
}
if (flags & IBT_CEP_SET_PKEY_IX) {
pkeyindx = ud->ud_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->pri_addr_path.pkey_indx = pkeyindx;
opmask |= HERMON_CMD_OP_PKEYINDX;
qp->qp_pkeyindx = pkeyindx;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
}
if (flags & IBT_CEP_SET_QKEY) {
qpc->qkey = ud->ud_qkey;
opmask |= HERMON_CMD_OP_QKEY;
}
} else if (qp->qp_serv_type == HERMON_QP_RC) {
rc = &info_p->qp_transport.rc;
opmask |= hermon_check_rdma_enable_flags(flags, info_p, qpc);
if (flags & IBT_CEP_SET_ADDS_VECT) {
qpc_path = &qpc->pri_addr_path;
adds_vect = &rc->rc_path.cep_adds_vect;
status = hermon_set_addr_path(state, adds_vect,
qpc_path, HERMON_ADDRPATH_QP);
if (status != DDI_SUCCESS) {
return (status);
}
qpc->rnr_retry = rc->rc_rnr_retry_cnt;
qpc_path->ack_timeout = rc->rc_path.cep_timeout;
qpc->retry_cnt = rc->rc_retry_cnt;
portnum = qp->qp_portnum + 1;
if (hermon_portnum_is_valid(state, portnum)) {
qpc->pri_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(qp->qp_portnum,
adds_vect->av_srvl, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
qpc->mtu = qp->qp_save_mtu;
opmask |= (HERMON_CMD_OP_PRIM_PATH |
HERMON_CMD_OP_RETRYCNT | HERMON_CMD_OP_ACKTIMEOUT |
HERMON_CMD_OP_PRIM_RNRRETRY);
}
if (flags & IBT_CEP_SET_MIG) {
if (rc->rc_mig_state == IBT_STATE_MIGRATED) {
qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
} else if (rc->rc_mig_state == IBT_STATE_REARMED) {
qpc->pm_state = HERMON_QP_PMSTATE_REARM;
} else {
return (IBT_QP_APM_STATE_INVALID);
}
opmask |= HERMON_CMD_OP_PM_STATE;
}
if (flags & IBT_CEP_SET_PKEY_IX) {
pkeyindx = rc->rc_path.cep_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->pri_addr_path.pkey_indx = pkeyindx;
opmask |= HERMON_CMD_OP_PKEYINDX;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
}
if (flags & IBT_CEP_SET_PORT) {
portnum = rc->rc_path.cep_hca_port_num;
if (hermon_portnum_is_valid(state, portnum)) {
qp->qp_portnum = portnum - 1;
qpc->pri_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(portnum - 1,
adds_vect->av_srvl, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
opmask |= HERMON_CMD_OP_SCHEDQUEUE;
}
if (flags & IBT_CEP_SET_ALT_PATH) {
qpc_path = &qpc->alt_addr_path;
adds_vect = &rc->rc_alt_path.cep_adds_vect;
status = hermon_set_addr_path(state, adds_vect,
qpc_path, HERMON_ADDRPATH_QP);
if (status != DDI_SUCCESS) {
return (status);
}
qpc_path->ack_timeout = rc->rc_alt_path.cep_timeout;
portnum = rc->rc_alt_path.cep_hca_port_num;
if (hermon_portnum_is_valid(state, portnum)) {
qp->qp_portnum_alt = portnum - 1;
qpc->alt_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(portnum - 1,
adds_vect->av_srvl, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
pkeyindx = rc->rc_alt_path.cep_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->alt_addr_path.pkey_indx = pkeyindx;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
opmask |= HERMON_CMD_OP_ALT_PATH;
}
if (flags & IBT_CEP_SET_RDMARA_OUT) {
if (hermon_qp_validate_init_depth(state, rc,
&sra_max) != DDI_SUCCESS) {
return (IBT_INVALID_PARAM);
}
qpc->sra_max = sra_max;
opmask |= HERMON_CMD_OP_SRA_SET;
}
if (flags & IBT_CEP_SET_RDMARA_IN) {
if (hermon_qp_validate_resp_rsrc(state, rc,
&rra_max) != DDI_SUCCESS) {
return (IBT_INVALID_PARAM);
}
qpc->rra_max = rra_max;
opmask |= HERMON_CMD_OP_RRA_SET;
}
if (flags & IBT_CEP_SET_TIMEOUT) {
qpc_path = &qpc->pri_addr_path;
qpc_path->ack_timeout = rc->rc_path.cep_timeout;
opmask |= HERMON_CMD_OP_ACKTIMEOUT;
}
if (flags & IBT_CEP_SET_RETRY) {
qpc->retry_cnt = rc->rc_retry_cnt;
opmask |= HERMON_CMD_OP_PRIM_RNRRETRY;
}
if (flags & IBT_CEP_SET_RNR_NAK_RETRY) {
qpc_path = &qpc->pri_addr_path;
qpc->rnr_retry = rc->rc_rnr_retry_cnt;
opmask |= HERMON_CMD_OP_RETRYCNT;
}
if (flags & IBT_CEP_SET_MIN_RNR_NAK) {
qpc->min_rnr_nak = rc->rc_min_rnr_nak;
opmask |= HERMON_CMD_OP_MINRNRNAK;
}
} else if (qp->qp_serv_type == HERMON_QP_UC) {
uc = &info_p->qp_transport.uc;
if (flags & IBT_CEP_SET_RDMA_W) {
qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
opmask |= HERMON_CMD_OP_RWE;
}
if (flags & IBT_CEP_SET_ADDS_VECT) {
qpc_path = &qpc->pri_addr_path;
adds_vect = &uc->uc_path.cep_adds_vect;
status = hermon_set_addr_path(state, adds_vect,
qpc_path, HERMON_ADDRPATH_QP);
if (status != DDI_SUCCESS) {
return (status);
}
portnum = qp->qp_portnum + 1;
if (hermon_portnum_is_valid(state, portnum)) {
qpc->pri_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(qp->qp_portnum,
adds_vect->av_srvl, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
qpc->mtu = qp->qp_save_mtu;
opmask |= HERMON_CMD_OP_PRIM_PATH;
}
if (flags & IBT_CEP_SET_MIG) {
if (uc->uc_mig_state == IBT_STATE_MIGRATED) {
qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
} else if (uc->uc_mig_state == IBT_STATE_REARMED) {
qpc->pm_state = HERMON_QP_PMSTATE_REARM;
} else {
return (IBT_QP_APM_STATE_INVALID);
}
opmask |= HERMON_CMD_OP_PM_STATE;
}
if (flags & IBT_CEP_SET_PKEY_IX) {
pkeyindx = uc->uc_path.cep_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->pri_addr_path.pkey_indx = pkeyindx;
opmask |= HERMON_CMD_OP_PKEYINDX;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
}
if (flags & IBT_CEP_SET_ALT_PATH) {
qpc_path = &qpc->alt_addr_path;
adds_vect = &uc->uc_alt_path.cep_adds_vect;
status = hermon_set_addr_path(state, adds_vect,
qpc_path, HERMON_ADDRPATH_QP);
if (status != DDI_SUCCESS) {
return (status);
}
portnum = uc->uc_alt_path.cep_hca_port_num;
if (hermon_portnum_is_valid(state, portnum)) {
qp->qp_portnum_alt = portnum - 1;
qpc->alt_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(portnum - 1,
adds_vect->av_srvl, qp->qp_is_special);
} else {
return (IBT_HCA_PORT_INVALID);
}
pkeyindx = uc->uc_alt_path.cep_pkey_ix;
if (hermon_pkeyindex_is_valid(state, pkeyindx)) {
qpc->alt_addr_path.pkey_indx = pkeyindx;
} else {
return (IBT_PKEY_IX_ILLEGAL);
}
opmask |= HERMON_CMD_OP_ALT_PATH;
}
} else {
HERMON_WARNING(state, "unknown QP transport type in sqd2sqd");
return (ibc_get_ci_failure(0));
}
status = hermon_cmn_qp_cmd_post(state, SQD2SQD_QP, qpc, qp->qp_qpnum,
opmask, HERMON_CMD_NOSLEEP_SPIN);
if (status != HERMON_CMD_SUCCESS) {
if (status != HERMON_CMD_BAD_QP_STATE) {
cmn_err(CE_NOTE, "hermon%d: SQD2SQD_QP command failed: "
"%08x\n", state->hs_instance, status);
if (status == HERMON_CMD_INVALID_STATUS) {
hermon_fm_ereport(state, HCA_SYS_ERR,
HCA_ERR_SRV_LOST);
}
return (ibc_get_ci_failure(0));
} else {
return (IBT_QP_STATE_INVALID);
}
}
return (DDI_SUCCESS);
}
static int
hermon_qp_sqerr2rts(hermon_state_t *state, hermon_qphdl_t qp,
ibt_cep_modify_flags_t flags, ibt_qp_info_t *info_p)
{
hermon_hw_qpc_t *qpc;
ibt_qp_ud_attr_t *ud;
uint32_t opmask = 0;
int status;
ASSERT(MUTEX_HELD(&qp->qp_lock));
qpc = &qp->qpc;
if (qp->qp_type == IBT_UD_RQP) {
ud = &info_p->qp_transport.ud;
if (flags & IBT_CEP_SET_QKEY) {
qpc->qkey = ud->ud_qkey;
opmask |= HERMON_CMD_OP_QKEY;
}
} else if (qp->qp_serv_type == HERMON_QP_UC) {
if (flags & IBT_CEP_SET_RDMA_W) {
qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
opmask |= HERMON_CMD_OP_RWE;
}
} else {
HERMON_WARNING(state, "unknown QP transport type in sqerr2rts");
return (ibc_get_ci_failure(0));
}
status = hermon_cmn_qp_cmd_post(state, SQERR2RTS_QP, qpc, qp->qp_qpnum,
opmask, HERMON_CMD_NOSLEEP_SPIN);
if (status != HERMON_CMD_SUCCESS) {
if (status != HERMON_CMD_BAD_QP_STATE) {
cmn_err(CE_NOTE, "hermon%d: SQERR2RTS_QP command "
"failed: %08x\n", state->hs_instance, status);
if (status == HERMON_CMD_INVALID_STATUS) {
hermon_fm_ereport(state, HCA_SYS_ERR,
HCA_ERR_SRV_LOST);
}
return (ibc_get_ci_failure(0));
} else {
return (IBT_QP_STATE_INVALID);
}
}
return (DDI_SUCCESS);
}
static int
hermon_qp_to_error(hermon_state_t *state, hermon_qphdl_t qp)
{
int status;
ASSERT(MUTEX_HELD(&qp->qp_lock));
status = hermon_cmn_qp_cmd_post(state, TOERR_QP, NULL, qp->qp_qpnum,
0, HERMON_CMD_NOSLEEP_SPIN);
if (status != HERMON_CMD_SUCCESS) {
cmn_err(CE_NOTE, "hermon%d: TOERR_QP command failed: %08x\n",
state->hs_instance, status);
if (status == HERMON_CMD_INVALID_STATUS) {
hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
}
return (ibc_get_ci_failure(0));
}
return (DDI_SUCCESS);
}
int
hermon_qp_to_reset(hermon_state_t *state, hermon_qphdl_t qp)
{
hermon_hw_qpc_t *qpc;
int status;
ASSERT(MUTEX_HELD(&qp->qp_lock));
qpc = &qp->qpc;
status = hermon_cmn_qp_cmd_post(state, TORST_QP, qpc, qp->qp_qpnum,
0, HERMON_CMD_NOSLEEP_SPIN);
if (status != HERMON_CMD_SUCCESS) {
cmn_err(CE_NOTE, "hermon%d: TORST_QP command failed: %08x\n",
state->hs_instance, status);
if (status == HERMON_CMD_INVALID_STATUS) {
hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
}
return (ibc_get_ci_failure(0));
}
if (qp->qp_serv_type == HERMON_QP_FEXCH) {
status = hermon_fcoib_fexch_mkey_fini(state, qp->qp_pdhdl,
qp->qp_qpnum, HERMON_CMD_NOSLEEP_SPIN);
if (status != DDI_SUCCESS)
cmn_err(CE_NOTE, "hermon%d: fexch_mkey_fini failed "
"%08x\n", state->hs_instance, status);
}
return (DDI_SUCCESS);
}
static int
hermon_qp_reset2err(hermon_state_t *state, hermon_qphdl_t qp)
{
hermon_hw_qpc_t *qpc;
int status;
uint32_t cqnmask;
ASSERT(MUTEX_HELD(&qp->qp_lock));
qpc = &qp->qpc;
if (qp->qp_is_special) {
qpc->serv_type = HERMON_QP_MLX;
} else {
qpc->serv_type = qp->qp_serv_type;
}
qpc->pm_state = HERMON_QP_PMSTATE_MIGRATED;
qpc->usr_page = qp->qp_uarpg;
qpc->dbr_addrh = ((uint64_t)qp->qp_rq_pdbr >> 32);
qpc->dbr_addrl = ((uint64_t)qp->qp_rq_pdbr & 0xFFFFFFFC) >> 2;
qpc->pd = qp->qp_pdhdl->pd_pdnum;
qpc->log2_pgsz = qp->qp_mrhdl->mr_log2_pgsz;
qpc->mtt_base_addrh = (qp->qp_mrhdl->mr_mttaddr) >> 32 & 0xFF;
qpc->mtt_base_addrl = (qp->qp_mrhdl->mr_mttaddr) >> 3 & 0xFFFFFFFF;
cqnmask = (1 << state->hs_cfg_profile->cp_log_num_cq) - 1;
qpc->cqn_snd =
(qp->qp_sq_cqhdl == NULL) ? 0 : qp->qp_sq_cqhdl->cq_cqnum & cqnmask;
qpc->page_offs = qp->qp_wqinfo.qa_pgoffs >> 6;
qpc->cqn_rcv =
(qp->qp_rq_cqhdl == NULL) ? 0 : qp->qp_rq_cqhdl->cq_cqnum & cqnmask;
qpc->sq_wqe_counter = 0;
qpc->rq_wqe_counter = 0;
qpc->log_sq_stride = qp->qp_sq_log_wqesz - 4;
qpc->log_rq_stride = qp->qp_rq_log_wqesz - 4;
qpc->log_sq_size = highbit(qp->qp_sq_bufsz) - 1;
qpc->log_rq_size = highbit(qp->qp_rq_bufsz) - 1;
qpc->srq_en = (qp->qp_alloc_flags & IBT_QP_USES_SRQ) != 0;
qpc->sq_no_prefetch = qp->qp_no_prefetch;
if (qp->qp_alloc_flags & IBT_QP_USES_SRQ) {
qpc->srq_number = qp->qp_srqhdl->srq_srqnum;
} else {
qpc->srq_number = 0;
}
qpc->fre = 0;
qpc->rlky = 0;
if (qp->qp_type == IBT_UD_RQP) {
qpc->qkey = 0;
qpc->pri_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(0, 0, qp->qp_is_special);
qpc->pri_addr_path.pkey_indx = 0;
} else if (qp->qp_serv_type == HERMON_QP_RC) {
qpc->rre = 0;
qpc->rwe = 0;
qpc->rae = 0;
qpc->alt_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(0, 0, qp->qp_is_special);
qpc->pri_addr_path.pkey_indx = 0;
} else if (qp->qp_serv_type == HERMON_QP_UC) {
qpc->rwe = 0;
qpc->alt_addr_path.sched_q =
HERMON_QP_SCHEDQ_GET(0, 0, qp->qp_is_special);
qpc->pri_addr_path.pkey_indx = 0;
} else {
HERMON_WARNING(state, "unknown QP transport type in rst2err");
return (ibc_get_ci_failure(0));
}
status = hermon_cmn_qp_cmd_post(state, RST2INIT_QP, qpc, qp->qp_qpnum,
0, HERMON_CMD_NOSLEEP_SPIN);
if (status != HERMON_CMD_SUCCESS) {
cmn_err(CE_NOTE, "hermon%d: RST2INIT_QP command failed: %08x\n",
state->hs_instance, status);
if (status == HERMON_CMD_INVALID_STATUS) {
hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
}
return (ibc_get_ci_failure(0));
}
status = hermon_cmn_qp_cmd_post(state, TOERR_QP, NULL, qp->qp_qpnum,
0, HERMON_CMD_NOSLEEP_SPIN);
if (status != HERMON_CMD_SUCCESS) {
cmn_err(CE_NOTE, "hermon%d: TOERR_QP command failed: %08x\n",
state->hs_instance, status);
if (status == HERMON_CMD_INVALID_STATUS) {
hermon_fm_ereport(state, HCA_SYS_ERR, HCA_ERR_SRV_LOST);
}
if (hermon_qp_to_reset(state, qp) != DDI_SUCCESS) {
HERMON_WARNING(state, "failed to reset QP context");
}
return (ibc_get_ci_failure(0));
}
return (DDI_SUCCESS);
}
static uint_t
hermon_check_rdma_enable_flags(ibt_cep_modify_flags_t flags,
ibt_qp_info_t *info_p, hermon_hw_qpc_t *qpc)
{
uint_t opmask = 0;
if (flags & IBT_CEP_SET_RDMA_R) {
qpc->rre = (info_p->qp_flags & IBT_CEP_RDMA_RD) ? 1 : 0;
opmask |= HERMON_CMD_OP_RRE;
}
if (flags & IBT_CEP_SET_RDMA_W) {
qpc->rwe = (info_p->qp_flags & IBT_CEP_RDMA_WR) ? 1 : 0;
opmask |= HERMON_CMD_OP_RWE;
}
if (flags & IBT_CEP_SET_ATOMIC) {
qpc->rae = (info_p->qp_flags & IBT_CEP_ATOMIC) ? 1 : 0;
opmask |= HERMON_CMD_OP_RAE;
}
return (opmask);
}
static int
hermon_qp_validate_resp_rsrc(hermon_state_t *state, ibt_qp_rc_attr_t *rc,
uint_t *rra_max)
{
uint_t rdma_ra_in;
rdma_ra_in = rc->rc_rdma_ra_in;
if (rdma_ra_in > state->hs_cfg_profile->cp_hca_max_rdma_in_qp) {
return (IBT_INVALID_PARAM);
}
if (rdma_ra_in == 0) {
rdma_ra_in = 1;
}
if (ISP2(rdma_ra_in)) {
*rra_max = highbit(rdma_ra_in) - 1;
} else {
*rra_max = highbit(rdma_ra_in);
}
return (DDI_SUCCESS);
}
static int
hermon_qp_validate_init_depth(hermon_state_t *state, ibt_qp_rc_attr_t *rc,
uint_t *sra_max)
{
uint_t rdma_ra_out;
rdma_ra_out = rc->rc_rdma_ra_out;
if (rdma_ra_out > state->hs_cfg_profile->cp_hca_max_rdma_out_qp) {
return (IBT_INVALID_PARAM);
}
if (rdma_ra_out == 0) {
rdma_ra_out = 1;
}
if (ISP2(rdma_ra_out)) {
*sra_max = highbit(rdma_ra_out) - 1;
} else {
*sra_max = highbit(rdma_ra_out);
}
return (DDI_SUCCESS);
}
static int
hermon_qp_validate_mtu(hermon_state_t *state, uint_t mtu)
{
if ((mtu == 0) || (mtu > state->hs_cfg_profile->cp_max_mtu)) {
return (IBT_HCA_PORT_MTU_EXCEEDED);
}
return (DDI_SUCCESS);
}