#include <sys/modctl.h>
#include <sys/sunndi.h>
#include <sys/ib/ibtl/impl/ibtl.h>
#include <sys/ib/ibtl/impl/ibtl_ibnex.h>
static char ibtf[] = "ibtl_impl";
extern ibtl_ibnex_callback_t ibtl_ibnex_callback_routine;
struct ibtl_clnt_s *ibtl_clnt_list = NULL;
kmutex_t ibtl_clnt_list_mutex;
kmutex_t ibtl_free_qp_mutex;
kcondvar_t ibtl_close_hca_cv;
struct ibtl_hca_devinfo_s *ibtl_hca_list = NULL;
ibt_async_handler_t ibtl_cm_async_handler;
ibt_async_handler_t ibtl_dm_async_handler;
ibt_async_handler_t ibtl_ibma_async_handler;
void *ibtl_cm_clnt_private;
void *ibtl_dm_clnt_private;
void *ibtl_ibma_clnt_private;
extern int ib_hw_status;
_NOTE(SCHEME_PROTECTS_DATA("Scheme protects data", ib_hw_status))
extern struct mod_ops mod_miscops;
static struct modlmisc modlmisc = {
&mod_miscops,
"IB Transport Layer"
};
static struct modlinkage modlinkage = {
MODREV_1, (void *)&modlmisc, NULL
};
static void ibtl_kstat_init(ibtl_hca_devinfo_t *);
static void ibtl_kstat_fini(ibtl_hca_devinfo_t *);
static void ibtl_kstat_stats_create(ibtl_hca_devinfo_t *, uint_t);
static void ibtl_kstat_pkeys_create(ibtl_hca_devinfo_t *, uint_t);
extern kmutex_t ibtl_part_attr_mutex;
int
_init(void)
{
int rval;
if ((rval = mod_install(&modlinkage)) != 0)
return (rval);
ibtl_ib2usec_init();
ibtl_logging_initialization();
ibtl_init_cep_states();
mutex_init(&ibtl_clnt_list_mutex, NULL, MUTEX_DEFAULT, NULL);
mutex_init(&ibtl_free_qp_mutex, NULL, MUTEX_DEFAULT, NULL);
cv_init(&ibtl_close_hca_cv, NULL, CV_DEFAULT, NULL);
mutex_init(&ibtl_qp_mutex, NULL, MUTEX_DEFAULT, NULL);
cv_init(&ibtl_qp_cv, NULL, CV_DEFAULT, NULL);
mutex_init(&ibtl_part_attr_mutex, NULL, MUTEX_DEFAULT, NULL);
ibtl_thread_init();
return (rval);
}
int
_fini(void)
{
int rval;
if ((rval = mod_remove(&modlinkage)) != 0) {
return (rval);
}
ibtl_thread_fini();
mutex_destroy(&ibtl_clnt_list_mutex);
mutex_destroy(&ibtl_free_qp_mutex);
cv_destroy(&ibtl_close_hca_cv);
mutex_destroy(&ibtl_qp_mutex);
cv_destroy(&ibtl_qp_cv);
mutex_destroy(&ibtl_part_attr_mutex);
ibtl_logging_destroy();
return (rval);
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
ibt_status_t
ibt_attach(ibt_clnt_modinfo_t *mod_infop, dev_info_t *arg, void *clnt_private,
ibt_clnt_hdl_t *ibt_hdl_p)
{
dev_info_t *pdip;
ibtl_clnt_t *clntp;
IBTF_DPRINTF_L3(ibtf, "ibt_attach(%p, %p, %p)",
mod_infop, arg, clnt_private);
if (mod_infop->mi_clnt_name == NULL) {
IBTF_DPRINTF_L1(ibtf, "ibt_attach: "
"IB client needs to specify its name");
return (IBT_INVALID_PARAM);
}
if (mod_infop->mi_ibt_version != IBTI_V_CURR) {
IBTF_DPRINTF_L1(ibtf, "ibt_attach: IB client '%s' has an "
"invalid IB TI Version '%d'", mod_infop->mi_clnt_name,
mod_infop->mi_ibt_version);
return (IBT_NOT_SUPPORTED);
}
if (mod_infop->mi_async_handler == NULL) {
IBTF_DPRINTF_L2(ibtf, "ibt_attach: Client '%s' has not\n"
" provided an Asynchronous Event Handler.\n"
" This will be required soon.",
mod_infop->mi_clnt_name);
}
if ((!IBT_MISCMOD_CLIENTS(mod_infop->mi_clnt_class)) &&
(arg == NULL)) {
IBTF_DPRINTF_L1(ibtf, "ibt_attach: "
"arg not set with driver's dip.");
return (IBT_INVALID_PARAM);
}
if (!IBT_MISCMOD_CLIENTS(mod_infop->mi_clnt_class)) {
pdip = ddi_get_parent(arg);
if (pdip == NULL ||
ibtl_ibnex_valid_hca_parent(pdip) != IBT_SUCCESS) {
IBTF_DPRINTF_L2(ibtf, "ibt_attach: "
"client %s is not a child of IB nexus driver.",
ddi_driver_name(arg));
return (IBT_INVALID_PARAM);
}
}
mutex_enter(&ibtl_clnt_list_mutex);
if (mod_infop->mi_clnt_class == IBT_CM) {
if (ibtl_cm_async_handler != NULL) {
IBTF_DPRINTF_L1(ibtf, "ibt_attach: "
"CM is already attached.");
mutex_exit(&ibtl_clnt_list_mutex);
return (IBT_INVALID_PARAM);
}
ibtl_cm_async_handler = mod_infop->mi_async_handler;
ibtl_cm_clnt_private = clnt_private;
} else if (mod_infop->mi_clnt_class == IBT_DM) {
if (ibtl_dm_async_handler != NULL) {
IBTF_DPRINTF_L1(ibtf, "ibt_attach: "
"DM is already attached.");
mutex_exit(&ibtl_clnt_list_mutex);
return (IBT_INVALID_PARAM);
}
ibtl_dm_async_handler = mod_infop->mi_async_handler;
ibtl_dm_clnt_private = clnt_private;
} else if (mod_infop->mi_clnt_class == IBT_IBMA) {
if (ibtl_ibma_async_handler != NULL) {
IBTF_DPRINTF_L1(ibtf, "ibt_attach: "
"IBMF is already attached.");
mutex_exit(&ibtl_clnt_list_mutex);
return (IBT_INVALID_PARAM);
}
ibtl_ibma_async_handler = mod_infop->mi_async_handler;
ibtl_ibma_clnt_private = clnt_private;
}
clntp = kmem_zalloc(sizeof (ibtl_clnt_t), KM_SLEEP);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(clntp->clnt_modinfop,
clntp->clnt_dip, clntp->clnt_name, clntp->clnt_async_cnt,
clntp->clnt_private))
clntp->clnt_modinfop = mod_infop;
clntp->clnt_private = clnt_private;
clntp->clnt_dip = arg;
clntp->clnt_async_cnt = 0;
(void) strncpy(clntp->clnt_name, mod_infop->mi_clnt_name, 7);
_NOTE(NOW_VISIBLE_TO_OTHER_THREADS(clntp->clnt_modinfop,
clntp->clnt_dip, clntp->clnt_name, clntp->clnt_async_cnt,
clntp->clnt_private))
clntp->clnt_list_link = ibtl_clnt_list;
ibtl_clnt_list = clntp;
mutex_exit(&ibtl_clnt_list_mutex);
*ibt_hdl_p = clntp;
return (IBT_SUCCESS);
}
ibt_status_t
ibt_detach(ibt_clnt_hdl_t ibt_hdl)
{
ibtl_clnt_t **clntpp;
IBTF_DPRINTF_L3(ibtf, "ibt_detach(%p)", ibt_hdl);
mutex_enter(&ibtl_clnt_list_mutex);
clntpp = &ibtl_clnt_list;
for (; *clntpp != NULL; clntpp = &(*clntpp)->clnt_list_link)
if (*clntpp == ibt_hdl)
break;
if (*clntpp == NULL) {
IBTF_DPRINTF_L1(ibtf, "ibt_detach: Client @ %p Not Found",
ibt_hdl);
mutex_exit(&ibtl_clnt_list_mutex);
return (IBT_INVALID_PARAM);
}
if (ibt_hdl->clnt_hca_list != NULL) {
mutex_exit(&ibtl_clnt_list_mutex);
IBTF_DPRINTF_L2(ibtf, "ibt_detach: "
"ERROR: Client '%s' has not closed all of its HCAs",
ibt_hdl->clnt_modinfop->mi_clnt_name);
cmn_err(CE_CONT, "IBT DETACH failed: resources not yet "
"freed by client '%s'\n",
ibt_hdl->clnt_modinfop->mi_clnt_name);
return (IBT_HCA_RESOURCES_NOT_FREED);
}
if (ibt_hdl->clnt_srv_cnt != 0) {
mutex_exit(&ibtl_clnt_list_mutex);
IBTF_DPRINTF_L2(ibtf, "ibt_detach: client '%s' still has "
"services or subnet_notices registered",
ibt_hdl->clnt_modinfop->mi_clnt_name);
cmn_err(CE_CONT, "IBT DETACH failed: resources not yet "
"freed by client '%s'\n",
ibt_hdl->clnt_modinfop->mi_clnt_name);
return (IBT_HCA_RESOURCES_NOT_FREED);
}
*clntpp = ibt_hdl->clnt_list_link;
ibtl_free_clnt_async_check(ibt_hdl);
if (ibt_hdl->clnt_modinfop->mi_clnt_class == IBT_CM) {
ibtl_cm_async_handler = NULL;
ibtl_cm_clnt_private = NULL;
} else if (ibt_hdl->clnt_modinfop->mi_clnt_class == IBT_DM) {
ibtl_dm_async_handler = NULL;
ibtl_dm_clnt_private = NULL;
} else if (ibt_hdl->clnt_modinfop->mi_clnt_class == IBT_IBMA) {
ibtl_ibma_async_handler = NULL;
ibtl_ibma_clnt_private = NULL;
}
mutex_exit(&ibtl_clnt_list_mutex);
kmem_free(ibt_hdl, sizeof (ibtl_clnt_t));
return (IBT_SUCCESS);
}
static void
ibtl_set_ibhw_status()
{
ib_hw_status++;
}
static void
ibtl_clear_ibhw_status()
{
ib_hw_status--;
}
int
ibc_init(struct modlinkage *modlp)
{
ibtl_ibnex_cb_args_t cb_args;
mutex_enter(&ibtl_clnt_list_mutex);
cb_args.cb_flag = IBTL_IBNEX_IBC_INIT;
cb_args.cb_modlp = modlp;
if (ibtl_ibnex_callback_routine) {
(void) ((*ibtl_ibnex_callback_routine)(&cb_args));
}
mutex_exit(&ibtl_clnt_list_mutex);
return (0);
}
void
ibc_fini(struct modlinkage *modlp)
{
ibtl_ibnex_cb_args_t cb_args;
mutex_enter(&ibtl_clnt_list_mutex);
cb_args.cb_flag = IBTL_IBNEX_IBC_FINI;
cb_args.cb_modlp = modlp;
if (ibtl_ibnex_callback_routine) {
(void) ((*ibtl_ibnex_callback_routine)(&cb_args));
}
mutex_exit(&ibtl_clnt_list_mutex);
}
ibc_status_t
ibc_attach(ibc_clnt_hdl_t *ibc_hdl_p, ibc_hca_info_t *info_p)
{
ibtl_hca_devinfo_t *hca_devp;
uint_t nports;
ibt_status_t status;
IBTF_DPRINTF_L2(ibtf, "ibc_attach(%p, %p)", ibc_hdl_p, info_p);
if (info_p->hca_ci_vers != IBCI_V4) {
IBTF_DPRINTF_L1(ibtf, "ibc_attach: Invalid IB CI Version '%d'",
info_p->hca_ci_vers);
return (IBC_FAILURE);
}
if (info_p->hca_attr == NULL) {
IBTF_DPRINTF_L1(ibtf, "ibc_attach: "
"HCA Attributes must be specified.");
return (IBC_FAILURE);
}
nports = info_p->hca_attr->hca_nports;
if (nports == 0) {
IBTF_DPRINTF_L1(ibtf, "ibc_attach: "
"Number of ports must be valid");
return (IBC_FAILURE);
}
if (info_p->hca_attr->hca_max_port_pkey_tbl_sz == 0) {
IBTF_DPRINTF_L1(ibtf, "ibc_attach: "
"Number of Partitions must be at least 1");
return (IBC_FAILURE);
}
if ((info_p->hca_attr->hca_flags & IBT_HCA_CURRENT_QP_STATE) == 0) {
IBTF_DPRINTF_L1(ibtf, "ibc_attach: "
"HCA driver must support QP current state checking");
return (IBC_FAILURE);
}
if ((info_p->hca_attr->hca_flags & IBT_HCA_PORT_UP) == 0) {
IBTF_DPRINTF_L1(ibtf, "ibc_attach: "
"HCA driver must support PORT_UP async events");
return (IBC_FAILURE);
}
ibtl_set_ibhw_status();
if (ndi_devi_config_vhci("ib", 0) == NULL) {
IBTF_DPRINTF_L2(ibtf, "ibc_attach: IB nexus attach failed");
ibtl_clear_ibhw_status();
return (IBC_FAILURE);
}
ibtl_thread_init2();
hca_devp = kmem_zalloc(sizeof (ibtl_hca_devinfo_t) +
(nports - 1) * sizeof (ibtl_async_port_event_t), KM_SLEEP);
mutex_enter(&ibtl_clnt_list_mutex);
hca_devp->hd_ibc_hca_hdl = info_p->hca_handle;
hca_devp->hd_ibc_ops = info_p->hca_ops;
hca_devp->hd_hca_attr = info_p->hca_attr;
hca_devp->hd_hca_dip = info_p->hca_attr->hca_dip;
status = ibtl_init_hca_portinfo(hca_devp);
if (status != IBT_SUCCESS) {
mutex_exit(&ibtl_clnt_list_mutex);
IBTF_DPRINTF_L1(ibtf, "ibc_attach: call to ibc_query_hca_ports "
"failed: status = %d", status);
kmem_free(hca_devp, sizeof (ibtl_hca_devinfo_t) +
(nports - 1) * sizeof (ibtl_async_port_event_t));
return (IBC_FAILURE);
}
if (ibtl_ibnex_phci_register(hca_devp->hd_hca_dip) != IBT_SUCCESS) {
mutex_exit(&ibtl_clnt_list_mutex);
IBTF_DPRINTF_L1(ibtf, "ibc_attach: MPxIO register failed");
kmem_free(hca_devp, sizeof (ibtl_hca_devinfo_t) +
(nports - 1) * sizeof (ibtl_async_port_event_t));
return (IBC_FAILURE);
}
hca_devp->hd_state = IBTL_HCA_DEV_ATTACHED;
hca_devp->hd_async_busy = 1;
cv_init(&hca_devp->hd_async_task_cv, NULL, CV_DEFAULT, NULL);
cv_init(&hca_devp->hd_async_busy_cv, NULL, CV_DEFAULT, NULL);
hca_devp->hd_portinfo_locked_port = 0;
cv_init(&hca_devp->hd_portinfo_cv, NULL, CV_DEFAULT, NULL);
ibtl_kstat_init(hca_devp);
mutex_exit(&ibtl_clnt_list_mutex);
*ibc_hdl_p = hca_devp;
return (IBC_SUCCESS);
}
void
ibc_post_attach(ibc_clnt_hdl_t ibc_hdl)
{
IBTF_DPRINTF_L2(ibtf, "ibc_post_attach(%p)", ibc_hdl);
mutex_enter(&ibtl_clnt_list_mutex);
ibc_hdl->hd_hca_dev_link = ibtl_hca_list;
ibtl_hca_list = ibc_hdl;
mutex_exit(&ibtl_clnt_list_mutex);
ibtl_announce_new_hca(ibc_hdl);
}
ibc_status_t
ibc_pre_detach(ibc_clnt_hdl_t hca_devp, ddi_detach_cmd_t cmd)
{
ibtl_hca_devinfo_t **hcapp, *hcap;
IBTF_DPRINTF_L2(ibtf, "ibc_pre_detach(%p, 0x%x)", hca_devp, cmd);
switch (cmd) {
case DDI_DETACH:
break;
default:
return (IBC_FAILURE);
}
mutex_enter(&ibtl_clnt_list_mutex);
hcap = ibtl_hca_list;
while (hcap != NULL) {
if (hcap == hca_devp)
break;
hcap = hcap->hd_hca_dev_link;
}
if (hcap == NULL) {
mutex_exit(&ibtl_clnt_list_mutex);
return (IBC_FAILURE);
}
hca_devp->hd_state = IBTL_HCA_DEV_DETACHING;
if (ibtl_detach_all_clients(hca_devp)) {
hca_devp->hd_state = IBTL_HCA_DEV_ATTACHED;
mutex_exit(&ibtl_clnt_list_mutex);
return (IBC_FAILURE);
}
if (hca_devp->hd_clnt_list != NULL) {
hca_devp->hd_state = IBTL_HCA_DEV_ATTACHED;
mutex_exit(&ibtl_clnt_list_mutex);
IBTF_DPRINTF_L2(ibtf, "ibc_pre_detach: HCA still has attached "
"clients");
return (IBC_FAILURE);
}
hca_devp->hd_state = IBTL_HCA_DEV_DETACHED;
hcapp = &ibtl_hca_list;
while (*hcapp != NULL) {
if (*hcapp == hca_devp)
break;
hcapp = &(*hcapp)->hd_hca_dev_link;
}
if (ibtl_ibnex_phci_unregister(hca_devp->hd_hca_dip) != IBT_SUCCESS) {
hca_devp->hd_state = IBTL_HCA_DEV_ATTACHED;
mutex_exit(&ibtl_clnt_list_mutex);
IBTF_DPRINTF_L1(ibtf, "ibc_pre_detach: PHCI unregister failed");
return (IBC_FAILURE);
}
if (*hcapp == NULL) {
hca_devp->hd_state = IBTL_HCA_DEV_ATTACHED;
mutex_exit(&ibtl_clnt_list_mutex);
IBTF_DPRINTF_L1(ibtf, "ibc_pre_detach: HCA not attached");
return (IBC_FAILURE);
}
*hcapp = hca_devp->hd_hca_dev_link;
ibtl_fast_gid_cache_valid = B_FALSE;
mutex_exit(&ibtl_clnt_list_mutex);
return (IBC_SUCCESS);
}
void
ibc_detach(ibc_clnt_hdl_t hca_devp)
{
IBTF_DPRINTF_L2(ibtf, "ibc_detach(%p)", hca_devp);
mutex_enter(&ibtl_clnt_list_mutex);
if (hca_devp->hd_state != IBTL_HCA_DEV_DETACHED) {
mutex_exit(&ibtl_clnt_list_mutex);
IBTF_DPRINTF_L0(ibtf, "ibc_detach: HCA has not successfully "
"pre-detached");
return;
}
cv_destroy(&hca_devp->hd_async_task_cv);
cv_destroy(&hca_devp->hd_async_busy_cv);
cv_destroy(&hca_devp->hd_portinfo_cv);
kmem_free(hca_devp->hd_portinfop, hca_devp->hd_portinfo_len);
mutex_exit(&ibtl_clnt_list_mutex);
ibtl_kstat_fini(hca_devp);
kmem_free(hca_devp, sizeof (ibtl_hca_devinfo_t) +
(hca_devp->hd_hca_attr->hca_nports - 1) *
sizeof (ibtl_async_port_event_t));
ibtl_clear_ibhw_status();
}
ibt_status_t
ibt_ci_data_in(ibt_hca_hdl_t hca, ibt_ci_data_flags_t flags,
ibt_object_type_t object, void *ibt_object_handle, void *data_p,
size_t data_sz)
{
ibt_status_t retval;
void *ci_obj_hdl;
IBTF_DPRINTF_L3(ibtf, "ibt_ci_data_in(%p, %x, %d, %p, %p, %d)",
hca, flags, object, ibt_object_handle, data_p, data_sz);
switch (object) {
case IBT_HDL_HCA:
ci_obj_hdl = (void *)
(IBTL_HCA2CIHCA(((ibt_hca_hdl_t)ibt_object_handle)));
break;
case IBT_HDL_CHANNEL:
ci_obj_hdl = (void *)
(IBTL_CHAN2CIQP(((ibt_channel_hdl_t)ibt_object_handle)));
break;
case IBT_HDL_CQ:
ci_obj_hdl = (void *)
(((ibt_cq_hdl_t)(ibt_object_handle))->cq_ibc_cq_hdl);
break;
case IBT_HDL_EEC:
ci_obj_hdl = (void *)
(((ibt_eec_hdl_t)(ibt_object_handle))->eec_ibc_eec_hdl);
break;
case IBT_HDL_UD_DEST:
ci_obj_hdl = (void *)
(((ibt_ud_dest_hdl_t)(ibt_object_handle))->ud_ah);
break;
case IBT_HDL_SRQ:
ci_obj_hdl = (void *)
(((ibt_srq_hdl_t)(ibt_object_handle))->srq_ibc_srq_hdl);
break;
default:
ci_obj_hdl = ibt_object_handle;
break;
}
retval = (IBTL_HCA2CIHCAOPS_P(hca)->ibc_ci_data_in)(IBTL_HCA2CIHCA(hca),
flags, object, ci_obj_hdl, data_p, data_sz);
if (retval != IBT_SUCCESS) {
IBTF_DPRINTF_L2(ibtf, "ibt_ci_data_in: Failed : %d", retval);
}
return (retval);
}
ibt_status_t
ibt_ci_data_out(ibt_hca_hdl_t hca, ibt_ci_data_flags_t flags,
ibt_object_type_t object, void *ibt_object_handle, void *data_p,
size_t data_sz)
{
ibt_status_t retval;
void *ci_obj_hdl;
IBTF_DPRINTF_L3(ibtf, "ibt_ci_data_out(%p, %x, %d, %p, %p, %d)",
hca, flags, object, ibt_object_handle, data_p, data_sz);
switch (object) {
case IBT_HDL_HCA:
ci_obj_hdl = (void *)
(IBTL_HCA2CIHCA(((ibt_hca_hdl_t)ibt_object_handle)));
break;
case IBT_HDL_CHANNEL:
ci_obj_hdl = (void *)
(IBTL_CHAN2CIQP(((ibt_channel_hdl_t)ibt_object_handle)));
break;
case IBT_HDL_CQ:
ci_obj_hdl = (void *)
(((ibt_cq_hdl_t)(ibt_object_handle))->cq_ibc_cq_hdl);
break;
case IBT_HDL_EEC:
ci_obj_hdl = (void *)
(((ibt_eec_hdl_t)(ibt_object_handle))->eec_ibc_eec_hdl);
break;
case IBT_HDL_UD_DEST:
ci_obj_hdl = (void *)
(((ibt_ud_dest_hdl_t)(ibt_object_handle))->ud_ah);
break;
case IBT_HDL_SRQ:
ci_obj_hdl = (void *)
(((ibt_srq_hdl_t)(ibt_object_handle))->srq_ibc_srq_hdl);
break;
default:
ci_obj_hdl = ibt_object_handle;
break;
}
retval = (IBTL_HCA2CIHCAOPS_P(hca)->ibc_ci_data_out)
(IBTL_HCA2CIHCA(hca), flags, object, ci_obj_hdl, data_p, data_sz);
if (retval != IBT_SUCCESS) {
IBTF_DPRINTF_L2(ibtf, "ibt_ci_data_out: Failed : %d", retval);
}
return (retval);
}
#define IBTL_ENA_MASK 0xC0000000
#define IBTL_ENA_POSSIBLE 0x80000000
#define IBTL_TYPE_SHIFT 27
ibt_status_t
ibt_get_module_failure(ibt_failure_type_t type, uint64_t ena)
{
ibt_status_t ret;
IBTF_DPRINTF_L3(ibtf, "ibt_get_module_failure(%d, 0x%llX)", type, ena);
switch (type) {
case IBT_FAILURE_CI:
case IBT_FAILURE_IBMF:
case IBT_FAILURE_IBCM:
case IBT_FAILURE_IBDM:
case IBT_FAILURE_IBTL:
case IBT_FAILURE_IBSM:
ret = IBTL_ENA_POSSIBLE | (type << IBTL_TYPE_SHIFT);
break;
default:
ret = IBT_FAILURE;
}
IBTF_DPRINTF_L3(ibtf, "ibt_get_module_failure: ret = 0x%lX", ret);
return (ret);
}
ibt_status_t
ibc_get_ci_failure(uint64_t ena)
{
return (ibt_get_module_failure(IBT_FAILURE_CI, ena));
}
ibt_failure_type_t
ibt_check_failure(ibt_status_t status, uint64_t *reserved_p)
{
ibt_failure_type_t type;
IBTF_DPRINTF_L3(ibtf, "ibt_check_failure(%X)", status);
if ((status & IBTL_ENA_MASK) == IBTL_ENA_POSSIBLE) {
type = status & ~IBTL_ENA_POSSIBLE >> IBTL_TYPE_SHIFT;
if (reserved_p != NULL)
*reserved_p = 0;
} else {
type = IBT_FAILURE_STANDARD;
if (reserved_p != NULL)
*reserved_p = 0;
}
IBTF_DPRINTF_L3(ibtf, "ibt_check_failure: type = 0x%X", type);
return (type);
}
static void
ibtl_kstat_init(ibtl_hca_devinfo_t *hca_devp)
{
uint_t nports = hca_devp->hd_hca_attr->hca_nports;
ibtl_hca_port_kstat_t *pks;
int i;
IBTF_DPRINTF_L3(ibtf, "ibtl_kstat_init(hca_devp = 0x%p)", hca_devp);
hca_devp->hd_hca_port_ks_info_len =
sizeof (ibtl_hca_port_kstat_t) * nports;
pks = kmem_zalloc(hca_devp->hd_hca_port_ks_info_len, KM_SLEEP);
hca_devp->hd_hca_port_ks_info = pks;
for (i = 0; i < nports; i++, pks++) {
pks->pks_hca_devp = hca_devp;
pks->pks_port_num = i + 1;
ibtl_kstat_stats_create(hca_devp, i + 1);
ibtl_kstat_pkeys_create(hca_devp, i + 1);
}
}
static void
ibtl_kstat_fini(ibtl_hca_devinfo_t *hca_devp)
{
ibtl_hca_port_kstat_t *pks;
int i;
IBTF_DPRINTF_L3(ibtf, "ibtl_kstat_fini(hca_devp = 0x%p)", hca_devp);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*hca_devp))
pks = hca_devp->hd_hca_port_ks_info;
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*pks))
if (pks == NULL)
return;
for (i = 0; i < hca_devp->hd_hca_attr->hca_nports; i++, pks++) {
if (pks->pks_stats_ksp)
kstat_delete(pks->pks_stats_ksp);
if (pks->pks_pkeys_ksp) {
ASSERT(!MUTEX_HELD(&ibtl_clnt_list_mutex));
kstat_delete(pks->pks_pkeys_ksp);
}
}
kmem_free(hca_devp->hd_hca_port_ks_info,
hca_devp->hd_hca_port_ks_info_len);
}
static int
ibtl_kstat_stats_update(kstat_t *ksp, int rw)
{
ibtl_hca_port_kstat_t *pks;
ibtl_hca_devinfo_t *hca_devp;
ibt_hca_portinfo_t *p;
struct kstat_named *data;
IBTF_DPRINTF_L4(ibtf, "ibtl_kstat_stats_update(ksp = 0x%p, rw = %d)",
ksp, rw);
if (rw == KSTAT_WRITE)
return (EACCES);
mutex_enter(&ibtl_clnt_list_mutex);
pks = ksp->ks_private;
hca_devp = pks->pks_hca_devp;
data = (struct kstat_named *)(ksp->ks_data);
p = hca_devp->hd_portinfop + pks->pks_port_num - 1;
data[0].value.ui32 = (uint32_t)p->p_linkstate;
mutex_exit(&ibtl_clnt_list_mutex);
return (0);
}
static void
ibtl_kstat_stats_create(ibtl_hca_devinfo_t *hca_devp, uint_t port_num)
{
struct kstat *ksp;
struct kstat_named *named_data;
char *drv_name;
int drv_instance;
ibtl_hca_port_kstat_t *pks;
char kname[40];
IBTF_DPRINTF_L3(ibtf, "ibtl_kstat_stats_create(hca_devp = 0x%p, "
"port_num = 0x%u)", hca_devp, port_num);
drv_name = (char *)ddi_driver_name(hca_devp->hd_hca_dip);
drv_instance = ddi_get_instance(hca_devp->hd_hca_dip);
(void) snprintf(kname, sizeof (kname), "%s%d/port%d/stats",
drv_name, drv_instance, port_num);
ksp = kstat_create("ibtf", 0, kname, "ib", KSTAT_TYPE_NAMED, 1, 0);
if (ksp == NULL) {
IBTF_DPRINTF_L2(ibtf,
"ibtl_kstat_stats_create: kstat_create() failed");
return;
}
named_data = (struct kstat_named *)(ksp->ks_data);
kstat_named_init(&named_data[0], "link_state", KSTAT_DATA_UINT32);
pks = hca_devp->hd_hca_port_ks_info + port_num - 1;
pks->pks_stats_ksp = ksp;
ksp->ks_private = pks;
ksp->ks_update = ibtl_kstat_stats_update;
kstat_install(ksp);
}
static int
ibtl_kstat_pkeys_update(kstat_t *ksp, int rw)
{
ibtl_hca_port_kstat_t *pks;
ibtl_hca_devinfo_t *hca_devp;
ibt_hca_portinfo_t *p;
IBTF_DPRINTF_L4(ibtf, "ibtl_kstat_pkeys_update(ksp = 0x%p, rw = %d)",
ksp, rw);
#ifndef __lock_lint
ASSERT(MUTEX_HELD(&ibtl_clnt_list_mutex));
#endif
if (rw == KSTAT_WRITE)
return (EACCES);
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*ksp))
pks = ksp->ks_private;
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*pks))
hca_devp = pks->pks_hca_devp;
_NOTE(NOW_INVISIBLE_TO_OTHER_THREADS(*hca_devp))
p = hca_devp->hd_portinfop + pks->pks_port_num - 1;
ksp->ks_data = p->p_pkey_tbl;
ksp->ks_ndata = p->p_pkey_tbl_sz;
ksp->ks_data_size = p->p_pkey_tbl_sz * sizeof (ib_pkey_t);
return (0);
}
static void
ibtl_kstat_pkeys_create(ibtl_hca_devinfo_t *hca_devp, uint_t port_num)
{
struct kstat *ksp;
char *drv_name;
int drv_instance;
char kname[40];
ibtl_hca_port_kstat_t *pks;
IBTF_DPRINTF_L3(ibtf, "ibtl_kstat_stats_create(hca_devp = 0x%p, "
"port_num = 0x%u)", hca_devp, port_num);
drv_name = (char *)ddi_driver_name(hca_devp->hd_hca_dip);
drv_instance = ddi_get_instance(hca_devp->hd_hca_dip);
(void) snprintf(kname, sizeof (kname), "%s%d/port%d/pkeys",
drv_name, drv_instance, port_num);
ksp = kstat_create("ibtf", 0, kname, "ib", KSTAT_TYPE_RAW, 0,
KSTAT_FLAG_VAR_SIZE | KSTAT_FLAG_VIRTUAL);
if (ksp == NULL) {
IBTF_DPRINTF_L2(ibtf,
"ibtl_kstat_pkeys_create: kstat_create() failed");
return;
}
pks = hca_devp->hd_hca_port_ks_info + port_num - 1;
pks->pks_pkeys_ksp = ksp;
ksp->ks_private = pks;
ksp->ks_update = ibtl_kstat_pkeys_update;
ksp->ks_lock = &ibtl_clnt_list_mutex;
kstat_install(ksp);
}