#include <sys/types.h>
#include <sys/conf.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/modctl.h>
#include <sys/ib/adapters/tavor/tavor.h>
#include <sys/ib/mgt/ibmf/ibmf.h>
#include <sys/disp.h>
static void tavor_agent_request_cb(ibmf_handle_t ibmf_handle,
ibmf_msg_t *msgp, void *args);
static void tavor_agent_handle_req(void *cb_args);
static void tavor_agent_response_cb(ibmf_handle_t ibmf_handle,
ibmf_msg_t *msgp, void *args);
static int tavor_agent_list_init(tavor_state_t *state);
static void tavor_agent_list_fini(tavor_state_t *state);
static int tavor_agent_register_all(tavor_state_t *state);
static int tavor_agent_unregister_all(tavor_state_t *state, int num_reg);
static void tavor_agent_mad_resp_handling(tavor_state_t *state,
ibmf_msg_t *msgp, uint_t port);
int
tavor_agent_handlers_init(tavor_state_t *state)
{
int status;
char *rsrc_name;
if ((state->ts_cfg_profile->cp_qp0_agents_in_fw) &&
(state->ts_cfg_profile->cp_qp1_agents_in_fw)) {
return (DDI_SUCCESS);
}
rsrc_name = (char *)kmem_zalloc(TAVOR_RSRC_NAME_MAXLEN, KM_SLEEP);
TAVOR_RSRC_NAME(rsrc_name, TAVOR_TASKQ_NAME);
status = tavor_agent_list_init(state);
if (status != DDI_SUCCESS) {
goto agentsinit_fail;
}
state->ts_taskq_agents = ddi_taskq_create(state->ts_dip,
rsrc_name, TAVOR_TASKQ_NTHREADS, TASKQ_DEFAULTPRI, 0);
if (state->ts_taskq_agents == NULL) {
tavor_agent_list_fini(state);
goto agentsinit_fail;
}
status = tavor_agent_register_all(state);
if (status != DDI_SUCCESS) {
ddi_taskq_destroy(state->ts_taskq_agents);
tavor_agent_list_fini(state);
goto agentsinit_fail;
}
kmem_free(rsrc_name, TAVOR_RSRC_NAME_MAXLEN);
return (DDI_SUCCESS);
agentsinit_fail:
kmem_free(rsrc_name, TAVOR_RSRC_NAME_MAXLEN);
return (status);
}
int
tavor_agent_handlers_fini(tavor_state_t *state)
{
int status;
if ((state->ts_cfg_profile->cp_qp0_agents_in_fw) &&
(state->ts_cfg_profile->cp_qp1_agents_in_fw)) {
return (DDI_SUCCESS);
}
status = tavor_agent_unregister_all(state, state->ts_num_agents);
if (status != DDI_SUCCESS) {
return (DDI_FAILURE);
}
ddi_taskq_destroy(state->ts_taskq_agents);
tavor_agent_list_fini(state);
return (DDI_SUCCESS);
}
static void
tavor_agent_request_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
void *args)
{
tavor_agent_handler_arg_t *cb_args;
tavor_agent_list_t *curr;
tavor_state_t *state;
int status;
curr = (tavor_agent_list_t *)args;
state = curr->agl_state;
cb_args = (tavor_agent_handler_arg_t *)kmem_zalloc(
sizeof (tavor_agent_handler_arg_t), KM_NOSLEEP);
if (cb_args == NULL) {
(void) ibmf_free_msg(ibmf_handle, &msgp);
return;
}
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*cb_args))
cb_args->ahd_ibmfhdl = ibmf_handle;
cb_args->ahd_ibmfmsg = msgp;
cb_args->ahd_agentlist = args;
status = ddi_taskq_dispatch(state->ts_taskq_agents,
tavor_agent_handle_req, cb_args, DDI_NOSLEEP);
if (status == DDI_FAILURE) {
kmem_free(cb_args, sizeof (tavor_agent_handler_arg_t));
(void) ibmf_free_msg(ibmf_handle, &msgp);
}
}
static void
tavor_agent_handle_req(void *cb_args)
{
tavor_agent_handler_arg_t *agent_args;
tavor_agent_list_t *curr;
tavor_state_t *state;
ibmf_handle_t ibmf_handle;
ibmf_msg_t *msgp;
ibmf_msg_bufs_t *recv_msgbufp;
ibmf_msg_bufs_t *send_msgbufp;
ibmf_retrans_t retrans;
uint_t port;
int status;
agent_args = (tavor_agent_handler_arg_t *)cb_args;
ibmf_handle = agent_args->ahd_ibmfhdl;
msgp = agent_args->ahd_ibmfmsg;
curr = agent_args->ahd_agentlist;
state = curr->agl_state;
port = curr->agl_port;
recv_msgbufp = &msgp->im_msgbufs_recv;
send_msgbufp = &msgp->im_msgbufs_send;
bcopy(recv_msgbufp, send_msgbufp, sizeof (ibmf_msg_bufs_t));
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(msgp->im_local_addr))
if (TAVOR_IS_SPECIAL_TRAP_MAD(msgp)) {
msgp->im_local_addr.ia_remote_lid =
TAVOR_PORT_MASTERSMLID_GET(state, port - 1);
} else {
status = tavor_mad_ifc_cmd_post(state, port,
TAVOR_CMD_SLEEP_NOSPIN,
(uint32_t *)recv_msgbufp->im_bufs_mad_hdr,
(uint32_t *)send_msgbufp->im_bufs_mad_hdr);
if (status != TAVOR_CMD_SUCCESS) {
if ((status != TAVOR_CMD_BAD_PKT) &&
(status != TAVOR_CMD_INSUFF_RSRC)) {
cmn_err(CE_CONT, "Tavor: MAD_IFC (port %02d) "
"command failed: %08x\n", port, status);
}
goto tavor_agent_handle_req_skip_response;
}
}
if (TAVOR_IS_TRAP_REPRESS_MAD(msgp)) {
goto tavor_agent_handle_req_skip_response;
}
tavor_agent_mad_resp_handling(state, msgp, port);
status = ibmf_msg_transport(ibmf_handle, IBMF_QP_HANDLE_DEFAULT,
msgp, &retrans, tavor_agent_response_cb, state, 0);
if (status != IBMF_SUCCESS) {
goto tavor_agent_handle_req_skip_response;
}
kmem_free(agent_args, sizeof (tavor_agent_handler_arg_t));
return;
tavor_agent_handle_req_skip_response:
status = ibmf_free_msg(ibmf_handle, &msgp);
kmem_free(agent_args, sizeof (tavor_agent_handler_arg_t));
}
static void
tavor_agent_response_cb(ibmf_handle_t ibmf_handle, ibmf_msg_t *msgp,
void *args)
{
(void) ibmf_free_msg(ibmf_handle, &msgp);
}
static int
tavor_agent_list_init(tavor_state_t *state)
{
tavor_agent_list_t *curr;
uint_t num_ports, num_agents, num_agents_per_port;
uint_t num_sma_agents = 0;
uint_t num_pma_agents = 0;
uint_t num_bma_agents = 0;
uint_t do_qp0, do_qp1;
int i, j, indx;
num_ports = state->ts_cfg_profile->cp_num_ports;
num_agents = 0;
num_agents_per_port = 0;
do_qp0 = state->ts_cfg_profile->cp_qp0_agents_in_fw;
do_qp1 = state->ts_cfg_profile->cp_qp1_agents_in_fw;
if (do_qp0 == 0) {
num_agents += (num_ports * TAVOR_NUM_QP0_AGENTS_PER_PORT);
num_agents_per_port += TAVOR_NUM_QP0_AGENTS_PER_PORT;
num_sma_agents = num_ports;
}
if (do_qp1 == 0) {
num_agents += (num_ports * TAVOR_NUM_QP1_AGENTS_PER_PORT);
num_agents_per_port += TAVOR_NUM_QP1_AGENTS_PER_PORT;
num_pma_agents = num_ports;
}
state->ts_num_agents = num_agents;
state->ts_agents = (tavor_agent_list_t *)kmem_zalloc(num_agents *
sizeof (tavor_agent_list_t), KM_SLEEP);
if (state->ts_agents == NULL) {
return (DDI_FAILURE);
}
indx = 0;
for (i = 0; i < num_agents_per_port; i++) {
for (j = 0; j < num_ports; j++) {
curr = &state->ts_agents[indx];
curr->agl_state = state;
curr->agl_port = j + 1;
if ((do_qp0 == 0) && num_sma_agents) {
curr->agl_mgmtclass = SUBN_AGENT;
num_sma_agents--;
indx++;
} else if ((do_qp1 == 0) && (num_pma_agents)) {
curr->agl_mgmtclass = PERF_AGENT;
num_pma_agents--;
indx++;
} else if ((do_qp1 == 0) && (num_bma_agents)) {
curr->agl_mgmtclass = BM_AGENT;
num_bma_agents--;
indx++;
}
}
}
return (DDI_SUCCESS);
}
static void
tavor_agent_list_fini(tavor_state_t *state)
{
kmem_free(state->ts_agents,
state->ts_num_agents * sizeof (tavor_agent_list_t));
}
static int
tavor_agent_register_all(tavor_state_t *state)
{
tavor_agent_list_t *curr;
ibmf_register_info_t ibmf_reg;
ibmf_impl_caps_t impl_caps;
ib_guid_t nodeguid;
int i, status, num_registered;
nodeguid = state->ts_ibtfinfo.hca_attr->hca_node_guid;
num_registered = 0;
for (i = 0; i < state->ts_num_agents; i++) {
curr = &state->ts_agents[i];
ibmf_reg.ir_ci_guid = nodeguid;
ibmf_reg.ir_port_num = curr->agl_port;
ibmf_reg.ir_client_class = curr->agl_mgmtclass;
status = ibmf_register(&ibmf_reg, IBMF_VERSION, 0,
NULL, NULL, &curr->agl_ibmfhdl, &impl_caps);
if (status != IBMF_SUCCESS) {
goto agents_reg_fail;
}
status = ibmf_setup_async_cb(curr->agl_ibmfhdl,
IBMF_QP_HANDLE_DEFAULT, tavor_agent_request_cb, curr, 0);
if (status != IBMF_SUCCESS) {
(void) ibmf_unregister(&curr->agl_ibmfhdl, 0);
goto agents_reg_fail;
}
num_registered++;
}
return (DDI_SUCCESS);
agents_reg_fail:
(void) tavor_agent_unregister_all(state, num_registered);
return (DDI_FAILURE);
}
static int
tavor_agent_unregister_all(tavor_state_t *state, int num_reg)
{
tavor_agent_list_t *curr;
int i, status;
for (i = 0; i < num_reg; i++) {
curr = &state->ts_agents[i];
status = ibmf_tear_down_async_cb(curr->agl_ibmfhdl,
IBMF_QP_HANDLE_DEFAULT, 0);
if (status != IBMF_SUCCESS) {
return (DDI_FAILURE);
}
status = ibmf_unregister(&curr->agl_ibmfhdl, 0);
if (status != IBMF_SUCCESS) {
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
static void
tavor_agent_mad_resp_handling(tavor_state_t *state, ibmf_msg_t *msgp,
uint_t port)
{
ib_mad_hdr_t *rmadhdrp = msgp->im_msgbufs_recv.im_bufs_mad_hdr;
ib_mad_hdr_t *smadhdrp = msgp->im_msgbufs_send.im_bufs_mad_hdr;
uint_t hop_count, hop_point;
uchar_t *resp, *ret_path;
resp = (uchar_t *)msgp->im_msgbufs_send.im_bufs_cl_data;
if (TAVOR_MAD_IS_DR(rmadhdrp)) {
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*((sm_dr_mad_hdr_t *)rmadhdrp)))
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*((sm_dr_mad_hdr_t *)smadhdrp)))
TAVOR_DRMAD_SET_DIRECTION(rmadhdrp);
hop_count = TAVOR_DRMAD_GET_HOPCOUNT(rmadhdrp);
hop_point = TAVOR_DRMAD_GET_HOPPOINTER(rmadhdrp);
if ((hop_count != 0) && ((hop_point == hop_count) ||
(hop_point == hop_count + 1))) {
ret_path = &resp[TAVOR_DRMAD_RETURN_PATH_OFFSET];
ret_path[hop_point] = port;
}
hop_point++;
TAVOR_DRMAD_SET_HOPPOINTER(smadhdrp, hop_point);
}
}