sol_umad.c revision 448bf8594153765bb5fce82a8888e01e3f6c3bad
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
*/
/*
*
* ofuv user MAD kernel agent module
*
* Enables functionality of the OFED 1.3 Linux based MAD application code.
*/
#include <sys/sysmacros.h>
#define MAX_NAME_LEN 32
#if defined(DEBUG)
static char *sol_umad_dbg_str = "sol_umad";
#endif
/* Local definitions */
static void *umad_statep;
static struct cb_ops umad_cb_ops = {
.cb_close = umad_close,
.cb_strategy = nodev,
.cb_write = umad_write,
.cb_ioctl = umad_ioctl,
};
static struct dev_ops umad_dev_ops = {
.devo_refcnt = 0,
.devo_identify = nulldev,
.devo_probe = nulldev,
.devo_reset = nodev,
.devo_cb_ops = &umad_cb_ops,
.devo_bus_ops = NULL,
.devo_power = nodev,
};
static struct modldrv umad_modldrv = {
.drv_modops = &mod_driverops,
.drv_linkinfo = "Solaris IB user MAD kernel driver",
};
static struct modlinkage modlinkage = {
.ml_linkage = {
[0] = &umad_modldrv,
[1] = NULL,
}
};
static ibt_clnt_modinfo_t ibt_clnt_modinfo = {
.mi_reserved = NULL,
.mi_clnt_name = "sol_umad"
};
const struct ibmf_class_to_mad_type {
} ibmf_class_to_mad_types[] = {
0}},
{0,
{0}}
};
0, /* 0x00 Reserved */
SUBN_MANAGER, /* 0x01 CLASS_SUBN_LID_ROUTED */
0, /* 0x02 Reserved */
SUBN_ADM_AGENT, /* 0x03 CLASS_SUBN_ADM */
PERF_MANAGER, /* 0x04 CLASS_PERF_MGMT */
BM_AGENT, /* 0x05 CLASS_BM */
DEV_MGT_AGENT, /* 0x06 CLASS_DEVICE_MGMT */
COMM_MGT_MANAGER_AGENT, /* 0x07 CLASS_CM */
SNMP_MANAGER_AGENT, /* 0x08 CLASS_SNMP */
VENDOR_09_MANAGER_AGENT, /* 0x09 */
VENDOR_0A_MANAGER_AGENT, /* 0x0A */
VENDOR_0B_MANAGER_AGENT, /* 0x0B */
VENDOR_0C_MANAGER_AGENT, /* 0x0C */
VENDOR_0D_MANAGER_AGENT, /* 0x0D */
VENDOR_0E_MANAGER_AGENT, /* 0x0E */
VENDOR_0F_MANAGER_AGENT, /* 0x0F */
APPLICATION_10_MANAGER_AGENT, /* 0x10 */
APPLICATION_11_MANAGER_AGENT, /* 0x11 */
APPLICATION_12_MANAGER_AGENT, /* 0x12 */
APPLICATION_13_MANAGER_AGENT, /* 0x13 */
APPLICATION_14_MANAGER_AGENT, /* 0x14 */
APPLICATION_15_MANAGER_AGENT, /* 0x15 */
APPLICATION_16_MANAGER_AGENT, /* 0x16 */
APPLICATION_17_MANAGER_AGENT, /* 0x17 */
APPLICATION_18_MANAGER_AGENT, /* 0x18 */
APPLICATION_19_MANAGER_AGENT, /* 0x19 */
APPLICATION_1A_MANAGER_AGENT, /* 0x1A */
APPLICATION_1B_MANAGER_AGENT, /* 0x1B */
APPLICATION_1C_MANAGER_AGENT, /* 0x1C */
APPLICATION_1D_MANAGER_AGENT, /* 0x1D */
APPLICATION_1E_MANAGER_AGENT, /* 0x1E */
APPLICATION_1F_MANAGER_AGENT, /* 0x1F */
APPLICATION_20_MANAGER_AGENT, /* 0x20 */
APPLICATION_21_MANAGER_AGENT, /* 0x21 */
APPLICATION_22_MANAGER_AGENT, /* 0x22 */
APPLICATION_23_MANAGER_AGENT, /* 0x23 */
APPLICATION_24_MANAGER_AGENT, /* 0x24 */
APPLICATION_25_MANAGER_AGENT, /* 0x25 */
APPLICATION_26_MANAGER_AGENT, /* 0x26 */
APPLICATION_27_MANAGER_AGENT, /* 0x27 */
APPLICATION_28_MANAGER_AGENT, /* 0x28 */
APPLICATION_29_MANAGER_AGENT, /* 0x29 */
APPLICATION_2A_MANAGER_AGENT, /* 0x2A */
APPLICATION_2B_MANAGER_AGENT, /* 0x2B */
APPLICATION_2C_MANAGER_AGENT, /* 0x2C */
APPLICATION_2D_MANAGER_AGENT, /* 0x2D */
APPLICATION_2E_MANAGER_AGENT, /* 0x2E */
APPLICATION_2F_MANAGER_AGENT, /* 0x2F */
VENDOR_30_MANAGER_AGENT, /* 0x30 */
VENDOR_31_MANAGER_AGENT, /* 0x31 */
VENDOR_32_MANAGER_AGENT, /* 0x32 */
VENDOR_33_MANAGER_AGENT, /* 0x33 */
VENDOR_34_MANAGER_AGENT, /* 0x34 */
VENDOR_35_MANAGER_AGENT, /* 0x35 */
VENDOR_36_MANAGER_AGENT, /* 0x36 */
VENDOR_37_MANAGER_AGENT, /* 0x37 */
VENDOR_38_MANAGER_AGENT, /* 0x38 */
VENDOR_39_MANAGER_AGENT, /* 0x39 */
VENDOR_3A_MANAGER_AGENT, /* 0x3A */
VENDOR_3B_MANAGER_AGENT, /* 0x3B */
VENDOR_3C_MANAGER_AGENT, /* 0x3C */
VENDOR_3D_MANAGER_AGENT, /* 0x3D */
VENDOR_3E_MANAGER_AGENT, /* 0x3E */
VENDOR_3F_MANAGER_AGENT, /* 0x3F */
0, /* 0x50 Reserved */
0, /* 0x51 Reserved */
0, /* 0x52 Reserved */
0, /* 0x53 Reserved */
0, /* 0x54 Reserved */
0, /* 0x55 Reserved */
0, /* 0x56 Reserved */
0, /* 0x57 Reserved */
0, /* 0x58 Reserved */
0, /* 0x59 Reserved */
0, /* 0x5A Reserved */
0, /* 0x5B Reserved */
0, /* 0x5C Reserved */
0, /* 0x5D Reserved */
0, /* 0x5E Reserved */
0, /* 0x5F Reserved */
0, /* 0x60 Reserved */
0, /* 0x61 Reserved */
0, /* 0x62 Reserved */
0, /* 0x63 Reserved */
0, /* 0x64 Reserved */
0, /* 0x65 Reserved */
0, /* 0x66 Reserved */
0, /* 0x67 Reserved */
0, /* 0x68 Reserved */
0, /* 0x69 Reserved */
0, /* 0x6A Reserved */
0, /* 0x6B Reserved */
0, /* 0x6C Reserved */
0, /* 0x6D Reserved */
0, /* 0x6E Reserved */
0, /* 0x6F Reserved */
0, /* 0x70 Reserved */
0, /* 0x71 Reserved */
0, /* 0x72 Reserved */
0, /* 0x73 Reserved */
0, /* 0x74 Reserved */
0, /* 0x75 Reserved */
0, /* 0x76 Reserved */
0, /* 0x77 Reserved */
0, /* 0x78 Reserved */
0, /* 0x79 Reserved */
0, /* 0x7A Reserved */
0, /* 0x7B Reserved */
0, /* 0x7C Reserved */
0, /* 0x7D Reserved */
0, /* 0x7E Reserved */
0, /* 0x7F Reserved */
0, /* 0x80 Reserved */
SUBN_MANAGER, /* 0x81 CLASS_SUBN_DIRECT_ROUTE */
0, /* 0x82 Reserved */
0, /* 0x82 Reserved */
0, /* 0x84 Reserved */
0, /* 0x85 Reserved */
0, /* 0x86 Reserved */
0, /* 0x87 Reserved */
0, /* 0x88 Reserved */
0, /* 0x89 Reserved */
0, /* 0x8A Reserved */
0, /* 0x8B Reserved */
0, /* 0x8C Reserved */
0, /* 0x8D Reserved */
0, /* 0x8E Reserved */
0, /* 0x8f Reserved */
0, /* 0x90 Reserved */
0, /* 0x91 Reserved */
0, /* 0x92 Reserved */
0, /* 0x93 Reserved */
0, /* 0x94 Reserved */
0, /* 0x95 Reserved */
0, /* 0x96 Reserved */
0, /* 0x97 Reserved */
0, /* 0x98 Reserved */
0, /* 0x99 Reserved */
0, /* 0x9A Reserved */
0, /* 0x9B Reserved */
0, /* 0x9C Reserved */
0, /* 0x9D Reserved */
0, /* 0x9E Reserved */
0, /* 0x9F Reserved */
0, /* 0xA0 Reserved */
0, /* 0xA1 Reserved */
0, /* 0xA2 Reserved */
0, /* 0xA3 Reserved */
0, /* 0xA4 Reserved */
0, /* 0xA5 Reserved */
0, /* 0xA6 Reserved */
0, /* 0xA7 Reserved */
0, /* 0xA8 Reserved */
0, /* 0xA9 Reserved */
0, /* 0xAA Reserved */
0, /* 0xAB Reserved */
0, /* 0xAC Reserved */
0, /* 0xAD Reserved */
0, /* 0xAE Reserved */
0, /* 0xAF Reserved */
0, /* 0xB0 Reserved */
0, /* 0xB1 Reserved */
0, /* 0xB2 Reserved */
0, /* 0xB3 Reserved */
0, /* 0xB4 Reserved */
0, /* 0xB5 Reserved */
0, /* 0xB6 Reserved */
0, /* 0xB7 Reserved */
0, /* 0xB8 Reserved */
0, /* 0xB9 Reserved */
0, /* 0xBA Reserved */
0, /* 0xBB Reserved */
0, /* 0xBC Reserved */
0, /* 0xBD Reserved */
0, /* 0xBE Reserved */
0, /* 0xBF Reserved */
0, /* 0xC0 Reserved */
0, /* 0xC1 Reserved */
0, /* 0xC2 Reserved */
0, /* 0xC3 Reserved */
0, /* 0xC4 Reserved */
0, /* 0xC5 Reserved */
0, /* 0xC6 Reserved */
0, /* 0xC7 Reserved */
0, /* 0xC8 Reserved */
0, /* 0xC9 Reserved */
0, /* 0xCA Reserved */
0, /* 0xCB Reserved */
0, /* 0xCC Reserved */
0, /* 0xCD Reserved */
0, /* 0xCE Reserved */
0, /* 0xCF Reserved */
0, /* 0xD0 Reserved */
0, /* 0xD1 Reserved */
0, /* 0xD2 Reserved */
0, /* 0xD3 Reserved */
0, /* 0xD4 Reserved */
0, /* 0xD5 Reserved */
0, /* 0xD6 Reserved */
0, /* 0xD7 Reserved */
0, /* 0xD8 Reserved */
0, /* 0xD9 Reserved */
0, /* 0xDA Reserved */
0, /* 0xDB Reserved */
0, /* 0xDC Reserved */
0, /* 0xDD Reserved */
0, /* 0xDE Reserved */
0, /* 0xDF Reserved */
0, /* 0xE0 Reserved */
0, /* 0xE1 Reserved */
0, /* 0xE2 Reserved */
0, /* 0xE3 Reserved */
0, /* 0xE4 Reserved */
0, /* 0xE5 Reserved */
0, /* 0xE6 Reserved */
0, /* 0xE7 Reserved */
0, /* 0xE8 Reserved */
0, /* 0xE9 Reserved */
0, /* 0xEA Reserved */
0, /* 0xEB Reserved */
0, /* 0xEC Reserved */
0, /* 0xED Reserved */
0, /* 0xEE Reserved */
0, /* 0xEF Reserved */
0, /* 0xF0 Reserved */
0, /* 0xF1 Reserved */
0, /* 0xF2 Reserved */
0, /* 0xF3 Reserved */
0, /* 0xF4 Reserved */
0, /* 0xF5 Reserved */
0, /* 0xF6 Reserved */
0, /* 0xF7 Reserved */
0, /* 0xF8 Reserved */
0, /* 0xF9 Reserved */
0, /* 0xFA Reserved */
0, /* 0xFB Reserved */
0, /* 0xFC Reserved */
0, /* 0xFD Reserved */
0, /* 0xFE Reserved */
0, /* 0xFF Reserved */
};
/*
* Function:
* umad_init_port_info
* Input:
* info - driver info
* hca - hca info
* Output:
* port - port info
* Returns:
* None
* Called by:
* umad_init_hca_info
* Description:
* - Associates an hca to a port.
* - Initializes user context list for the port passed in
* - Initializes mutex to protect the user context list
*/
static void
{
}
/*
* Function:
* umad_release_hca_info
* Input:
* hca - hca info
* Output:
* Returns:
* None
* Called by:
* - umad_init_hca_info in case of error
* - umad_init_driver_info in case of error
* - umad_context_destroyed in normal case
* Description:
* - For every port associated with this hca destory the mutex assicated
* with the port and relese port info structure.
* - Closes hca handle and resets the GUID
*/
static void
{
unsigned int j;
#if defined(DEBUG)
#endif
for (j = 0; j < hca->hca_nports; j++) {
}
sizeof (umad_port_info_t));
}
if (hca->hca_handle) {
#if defined(DEBUG)
if (rc != IBT_SUCCESS) {
"umad_release_hca: ibt_close_hca() returned %d\n",
rc);
}
#else
#endif
hca->hca_handle = 0;
}
}
/*
* Function:
* umad_init_hca_info
* Input:
* info pointer to umad info instructure
* Output:
* hca handle associated with this hca
* Returns:
* IBT_SUCCESS
* IBT_HCA_IN_USE
* IBT_HCA_INVALID
* IBT_INVALID_PARAM
* IBT_HCA_INVALID
* Called by:
* - umad_init_driver_info in case of error
* Description:
* - It calls ibt_open_hca to get handle associated wit this hca
* - Determines how many port this hca has by calling ibt_query_hca
* - Allocates space for each port associated with this hca.
* - For every port it calls umad_init_port_info with the hca port
* structure.
* - It assigns port # index starting at 1 (1-N, zero is reserved, means
* it does not exist).
*/
static int
{
int rc;
unsigned int j;
if (rc != IBT_SUCCESS)
goto error;
if (rc != IBT_SUCCESS)
goto error;
/* Initialize ports structures. */
for (j = 0; j < hca->hca_nports; j++) {
/*
* Note: A port number different than 0 means the port has been
* initialized.
*/
}
if (rc)
return (rc);
}
/*
* Function:
* umad_init_driver_info
* Output:
* info - driver info
* Returns:
* IBT_SUCCESS
* IBT_INVALID_PARAM
* IBT_HCA_IN_USE
* IBT_HCA_INVALID
* IBT_INVALID_PARAM
* Called by:
* umad_attach
* Description:
* - Registers sol_umad instance with IBTF
* - Calls ibt_get_hca_list to get hca count
* - Allocates each hca and associate it with umad_info structure
* - For every hca it assign GUID which was returned by ibt_get_hca_list
* then calls umad_init_hca_info .
* - Error case undone what was done, which calls umad_release_hca_info
*/
static ibt_status_t
{
#if defined(DEBUG)
#endif
unsigned int i;
info->info_hca_count = 0;
&info->info_clnt_hdl);
if (rc != IBT_SUCCESS)
goto err1;
if (hca_count == 0) {
goto err2;
}
KM_SLEEP);
for (i = 0; i < hca_count; i++) {
/* Note: A non zero guid means the hca has been allocated. */
if (rc)
goto err3;
}
return (0);
err3:
for (i = 0; i < info->info_hca_count; i++) {
}
if (hca_guids)
err2:
#if defined(DEBUG)
if (rc2 != IBT_SUCCESS) {
"umad_init_driver_info: ibt_detach failed: %d\n", rc2);
}
#else
#endif
err1:
return (rc);
}
/*
* Function:
* umad_context_destroy
* Input:
* dip - device info
* info - driver info
* Output:
* None
* Returns:
* None
* Called by:
* umad_attach
* umad_detach
* Description:
* frees driver info resources
*/
static void
{
unsigned int i;
unsigned int j;
size_t n;
for (i = 0; i < info->info_hca_count; i++) {
continue;
for (j = 0; j < hca->hca_nports; j++) {
char name[MAX_NAME_LEN];
if (port->port_has_umad_minor_node) {
#if defined(DEBUG)
if (n > sizeof (name)) {
"umad_context_destroy:"
" minor name \"%s\": is longer than"
" %d characters!\n",
name, MAX_NAME_LEN);
}
#endif
}
if (port->port_has_issm_minor_node) {
#if defined(DEBUG)
if (n > sizeof (name)) {
"umad_context_destroy:"
" minor name \"%s\" is longer than"
" %d characters!\n",
name, MAX_NAME_LEN);
}
#endif
}
}
}
info->info_hca_count = 0;
}
}
}
/*
* Function:
* _init
* Input:
* None
* Output:
* None
* Returns:
* status
* Called by:
* Framework
* Description:
* driver initialization function
* inits debug tracing, river info and calls mod_install
*/
int
_init(void)
{
int rc;
if (rc != 0)
goto err;
if (rc != 0)
err:
return (rc);
}
/*
* Function:
* _info
* Input:
* None
* Output:
* modinfop Module information
* Returns:
* status
* Called by:
* Framework
* Description:
* Provides module information
*/
int
{
int rc;
return (rc);
}
/*
* Function:
* _fini
* Input:
* None
* Output:
* None
* Returns:
* status
* Called by:
* Framework
* Description:
* Cleans up upon module unloading
*/
int
_fini(void)
{
int rc;
return (rc);
}
/*
* Function:
* umad_attach
* Input:
* dip device info
* cmd DDI_ATTACH all others are invalid
* Output:
* None
* Returns:
* DDI_SUCCESS or DDI_FAILURE
* Called by:
* Framwork
* Description:
* Device attach routine
*/
static int
{
int rc;
unsigned int i;
unsigned int j;
char name[MAX_NAME_LEN];
unsigned int minor_name;
switch (cmd) {
case DDI_ATTACH:
!= DDI_SUCCESS)
goto err1;
goto err2;
/* initialize our data and per HCA info */
if (rc != 0)
goto err3;
"abi_version", IB_USER_MAD_ABI_VERSION);
if (rc != 0)
goto err3;
/*
* device names are consistent with OFA
* conventions, e.g. umad0 for port 1 on the first HCA.
*/
minor_name = 0;
for (i = 0; i < info->info_hca_count; i++) {
for (j = 0; j < hca.hca_nports; j++) {
size_t n;
#if defined(DEBUG)
if (n > sizeof (name)) {
"umad_attach: "
"name \"%s\" longer than %d!\n",
name, MAX_NAME_LEN);
}
#endif
GET_UMAD_MINOR(i, j), DDI_PSEUDO, 0);
if (rc != DDI_SUCCESS)
goto err3;
GET_UMAD_MINOR(i, j));
if (rc != DDI_SUCCESS)
goto err3;
if (rc != DDI_SUCCESS)
goto err3;
"hca-instance", i);
if (rc != DDI_SUCCESS)
goto err3;
"port", j + 1);
if (rc != DDI_SUCCESS)
goto err3;
#if defined(DEBUG)
if (n > sizeof (name)) {
"umad_attach: "
"name \"%s\" longer than %d!\n",
name, MAX_NAME_LEN);
}
#endif
GET_ISSM_MINOR(i, j), DDI_PSEUDO, 0);
if (rc != DDI_SUCCESS)
goto err3;
GET_ISSM_MINOR(i, j));
if (rc != DDI_SUCCESS)
goto err3;
if (rc != DDI_SUCCESS)
goto err3;
"hca-instance", i);
if (rc != DDI_SUCCESS)
goto err3;
"port", j + 1);
if (rc != DDI_SUCCESS)
goto err3;
minor_name++;
}
}
break;
default:
goto err1;
}
rc = DDI_SUCCESS;
return (rc);
err3:
err2:
err1:
rc = DDI_FAILURE;
return (rc);
}
/*
* Function:
* umad_detach
* Input:
* dip Device pointer
* cmd DDI_DETACH all others are an error
* Output:
* None
* Returns:
* DDI_SUCCESS or DDI_FAILURE
* Called by:
* Framework
* Description:
* Used when a device is removed
*/
static int
{
int rc = DDI_SUCCESS;
switch (cmd) {
case DDI_DETACH:
break;
default:
rc = DDI_FAILURE;
break;
}
return (rc);
}
/*
* Function:
* umad_getinfo
* Input:
* dip device pointer
* cmd DDI_INFO_DEVT2DEVINFO or DDI_INFO_DEV2INSTANCE
* arg Unused
* Output:
* resultp device pointer or device instance as per cmd
* Returns:
* status
* Called by:
* Framework
* Description:
* Gets information about specific device
*/
static int
{
int rc;
#if defined(__lint)
extern void dummy2(void *);
#endif
switch (cmd) {
case DDI_INFO_DEVT2DEVINFO:
break;
case DDI_INFO_DEVT2INSTANCE:
*resultp = (void *)UMAD_INSTANCE;
rc = DDI_SUCCESS;
break;
default:
rc = DDI_FAILURE;
break;
}
return (rc);
}
/*
* Function:
* umad_prop_op
* Input:
* dev device
* dip device pointer
* prop_op which property operation
* flags property flags
* name proper name
* Output:
* valuep - property value
* lengthp - propery length
* Returns:
* status
* Called by:
* Framework
* Description:
* Passes straight through to default ddi_prop_op()
*/
static int
int flags,
char *name,
int *lengthp)
{
int rc;
return (rc);
}
/* Returns an array of mad classes associated with IBMF class */
static const uint8_t *
{
const struct ibmf_class_to_mad_type *entry;
for (entry = &ibmf_class_to_mad_types[0];
entry->ibmf_class != 0;
++entry) {
}
return (NULL);
}
/* Returns an agent from its ID. */
static umad_agent_t *
{
/* Look for the agent */
return (agent);
}
return (NULL);
}
/* Returns an agent from its MAD class. */
static umad_agent_t *
{
/* Look for the agent */
return (agent);
}
return (NULL);
}
/*
* Register the agent with a class.
* mgmt_class is given from userspace.
*/
static int
{
int rc;
ibmf_register_info_t reg_info = {0, };
ibmf_impl_caps_t impl_caps = {0, };
const uint8_t *umad_types;
struct ibmf_reg_info *ibmf_info;
/*
* Map MAD class to IBMF class
*/
/*
* It is is reserved, bail
*/
if (ibmf_class == 0) {
goto done;
}
/* Check to see if any other mad classes also map to this IBMF class */
if (umad_types != NULL) {
struct umad_agent_s *other_agent;
for (; *umad_types != 0; ++umad_types) {
*umad_types);
if (other_agent != NULL) {
struct ibmf_reg_info *ibmf_reg;
if (other_agent->agent_flags
& UMAD_HANDLING_ASYNC) {
agent->agent_flags |=
}
while (ibmf_reg->ibmf_flags
}
return (0);
}
}
}
/*
* At this point we need to check if there is already an
* ibmf_info already associated with this HCA, port and ibmf
* class. If so, simply increment the reference count
* and set the agent's agent_reg field to point to the
* ibmf_info structure that was found. (under locking)
*/
break;
}
}
}
if (found) {
return (0);
}
if (rc != IBMF_SUCCESS) {
} else {
/* The client wants to receive some unsolicited MADs. */
(void *)ibmf_info, 0);
if (rc != IBMF_SUCCESS) {
} else {
}
}
done:
return (rc);
}
/*
* Function:
* umad_queue_mad_msg
* Input:
* port - handle to ibmf
* ibmf_msg - The incoming SM MAD
* Output:
* None
* Returns:
* 0 on success, otherwise error number
* Called by:
* umad_solicitied_cb and umad_unsolicited_cb
* Description:
* creates a umad_msg and adds it to the appropriate user's context
*/
static int
{
int rc;
goto err1;
}
goto err1;
}
goto err1;
}
rc = 0;
err1:
return (rc);
}
/* Frees up user context state */
static void
{
}
/*
* Function:
* umad_open
* Input:
* devp device pointer
* flag Unused
* otyp Open type (just validated)
* cred Unused
* Output:
* None
* Returns:
* status
* Called by:
* Device open framework
* Description:
* If this is the issm device, modify the port to indicate that this is
* a subnet manager. If regular umad device, allocate and initialize
* a new user context and connect it to the hca info. Return the new
* dev_t for the new minor.
*/
static int
{
int rc = DDI_SUCCESS;
#if defined(__lint)
extern void dummy(int);
#endif
if (rc != 0)
return (rc);
goto err1;
}
return (EINVAL);
/* lookup the node and port #s */
if (ISSM_MINOR(minor)) {
if (port->port_issm_open_cnt) {
goto err1;
}
IBT_PORT_SET_SM, 0);
if (rc) {
goto err1;
}
} else {
unsigned int uctx_num;
/* Find a free entry in uctx list */
break;
}
/* No room found */
goto err1;
}
}
err1:
return (rc);
}
/*
* Function:
* umad_close
* Input:
* dev device
* flag Unused
* otyp Unused
* cred Unused
* Output:
* None
* Returns:
* status
* Called by:
* Device close framework
* Description:
* Unwinds open while waiting for any pending I/O to complete.
*/
/* ARGSUSED1 */
static int
{
int rc = DDI_SUCCESS;
int port_num;
int node_id;
goto err1;
}
if (ISSM_MINOR(minor)) {
IBT_PORT_RESET_SM, 0);
} else {
/* Unregister the agents. Cancel the pending operations. */
}
}
err1:
return (rc);
}
/*
* return where optional header starts relative to the start
* of the transmited mad
*/
static int
{
switch (mgmt_class) {
case MAD_MGMT_CLASS_PERF:
case MAD_MGMT_CLASS_BM:
case MAD_MGMT_CLASS_DEV_MGT:
case MAD_MGMT_CLASS_COMM_MGT:
return (IB_MGMT_MAD_HDR);
case MAD_MGMT_CLASS_SUBN_ADM:
return (IB_MGMT_RMPP_HDR);
case MAD_MGMT_CLASS_SNMP:
return (IB_MGMT_SNMP_HDR);
default:
if (((mgmt_class >= MAD_MGMT_CLASS_VENDOR_START) &&
(mgmt_class <= MAD_MGMT_CLASS_VENDOR_END)) ||
return (IB_MGMT_MAD_HDR);
else if ((mgmt_class >= MAD_MGMT_CLASS_VENDOR2_START) &&
return (IB_MGMT_RMPP_HDR);
else {
#if defined(DEBUG)
"umad_get_mad_clhdr_offset:"
" got illegal management class %d", mgmt_class);
#endif
return (0); /* invalid mad */
}
}
}
/*
* return the offset of the mad data in the transmited mad
* following all headers
*/
static int
{
switch (mgmt_class) {
case MAD_MGMT_CLASS_PERF:
case MAD_MGMT_CLASS_BM:
case MAD_MGMT_CLASS_DEV_MGT:
case MAD_MGMT_CLASS_COMM_MGT:
return (IB_MGMT_MAD_HDR);
case MAD_MGMT_CLASS_SUBN_ADM:
return (IB_MGMT_SA_HDR);
case MAD_MGMT_CLASS_SNMP:
return (IB_MGMT_SNMP_DATA);
default:
if (((mgmt_class >= MAD_MGMT_CLASS_VENDOR_START) &&
(mgmt_class <= MAD_MGMT_CLASS_VENDOR_END)) ||
return (IB_MGMT_MAD_HDR);
else if ((mgmt_class >= MAD_MGMT_CLASS_VENDOR2_START) &&
return (IB_MGMT_VENDOR_HDR);
else {
#if defined(DEBUG)
"umad_get_mad_clhdr_offset:"
" got illegal management class %d", mgmt_class);
#endif
return (0); /* invalid mad */
}
}
}
/*
* Function:
* umad_read
* Input:
* dev device
* uiop User I/O pointer
* credp Unused
* Output:
* None
* Returns:
* status
* Called by:
* Device read framework
* Description:
* Cannot read from ISSM device. Read from UMAD device
* does usual checks for blocking and when data is present,
* removes message from user context receive list, fills in user
* space with message and frees kernel copy of the message.
*/
/* ARGSUSED2 */
static int
{
int minor;
int rc = 0;
struct umad_agent_s *agent;
goto err1;
}
if (ISSM_MINOR(minor)) {
goto err1;
}
/* Check to see if we are in blocking mode or not */
&uctx->uctx_recv_lock) == 0) {
return (EINTR);
}
}
/* Check for a short read */
return (0);
return (EAGAIN);
}
if (rc)
goto err2;
ib_mad_hdr = (ib_mad_hdr_t *)
data_len =
if (rc)
goto err2;
if (rc)
goto err2;
if (rc)
goto err2;
}
&ibmf_msg);
if (rc != IBMF_SUCCESS) {
#if defined(DEBUG)
"umad_read:"
" ibmf_free_msg failed %d", rc);
#endif
goto err1;
}
}
err2:
if (rc) {
&ibmf_msg);
if (rc != IBMF_SUCCESS) {
#if defined(DEBUG)
"umad_read:"
" ibmf_free_msg failed %d", rc);
#endif
}
}
err1:
return (rc);
}
/*
* Function:
* umad_solicited_cb
* Input:
* ibmf_handle - handle to ibmf
* msgp - The incoming SM MAD
* args - umad_port_info_t object that the MAD cam in on
* Output:
* None
* Returns:
* none
* Called by:
* Description:
* Callback function (ibmf_msg_cb_t) that is invoked when the
* ibmf receives a SM MAD for the given Port.
* This function copies the MAD into the port recv queue.
*/
static void
{
int rc;
#if defined(__lint)
ibmf_handle = 0;
#endif
if (agent->agent_outstanding_msgs == 0)
}
goto bad;
return;
bad:
}
/*
* Function:
* umad_write
* Input:
* dev device
* uiop User I/O pointer
* credp Unused
* Output:
* None
* Returns:
* status
* Called by:
* Device write framework
* Description:
* Cannot write to ISSM device. Allocate new umad_send structure
* and ibmf message and copy from user space into allocated message.
* Fill in required fields. If this is a request make sure
* umad_solicited_cb() is passed.
*/
/* ARGSUSED1 */
static int
{
int mad_offset, flags = 0;
int hdr_len;
goto err1;
}
/* lookup the node and port #s */
if (ISSM_MINOR(minor)) {
goto err1;
}
/* copy the MAD data in from user space */
/* data = user_mad + mad_hdrs + class_hdrs + class data */
/* LINTED */
if (rc != 0)
goto err3;
/* Look for the agent */
if (! agent) {
goto err3;
}
goto err3;
}
/* Allocate the msg buf for IBMF */
if (rc != IBMF_SUCCESS) {
goto err3;
}
/*
* build the IBMF msg from the mad data passed in
* construct the addr info
*/
#if defined(__FUTURE_FEATURE__)
/* TODO Proper GRH handling (non-smp traffic only) */
16);
// where can we get the GID??
}
#endif
/*
* Note: umad lid, qpn and qkey are in network order, so we need
* to revert them to give them to ibmf. See userspace
* umad_set_addr() and umad_set_addr_net().
*/
if (status != IBT_SUCCESS) {
#if defined(DEBUG)
"umad_write: ibt_index2pkey failed %d",
status);
#endif
}
else
/*
* This code is only correct for the cases of
* no headers beyond the MAD header or the case of
* MAD_MGMT_CLASS_SUBN_ADM (SA type) which has both
* an RMPP header and an SA header. Other header combinations
* are simply not dealt with correctly, but no applications
* utilize them either, so we should be ok.
*/
/* set use RMPP if UserAgent registered for it */
if (rmpp_hdr->rmpp_flags != 0)
}
/* construct the msg bufs */
/* Class headers and len, rmpp? */
(unsigned char *)user_mad +
(unsigned char *) user_mad + (sizeof (struct ib_user_mad) +
mad_retrans.retrans_rtv = 0;
mad_retrans.retrans_rttv = 0;
if (need_callback)
/* pass the MAD down to the IBMF layer */
if (! need_callback) {
&ibmf_msg);
if (rc != IBMF_SUCCESS) {
goto err3;
}
} else if (rc != IBMF_SUCCESS) {
if (agent->agent_outstanding_msgs == 0)
}
&ibmf_msg);
goto err3;
}
return (0);
err3:
err1:
return (rc);
}
/*
* Function:
* umad_async_handler
* Input:
* private Unused
* hca_hdl Unused
* code Unused
* event Unused
* Output:
* None
* Returns:
* None
* Called by:
* IBTL framework for asynchronous events.
* Description:
* No special event handling currently.
*/
/* ARGSUSED */
static void
void *private,
{
}
/*
* Need this ioctl to enable the newer interface (pkey_index and some
* reserved key). Since OFED changed the abi without changing the abi
* version. This resulted in wo abi interfaces (with and without the
* pkey_index and some reserved bytes, but one abi version number. The
* application then tries to do an ioctl() to enable the "newwer" interface
* and it that ioctl succeeds, the application code assumes the newer abi
* interface otherwise it assumes the older abi intrface (Uggggggg).
*/
static int
{
/* When we move to later releases of OFED, this will go away */
return (DDI_SUCCESS);
}
/*
* Function:
* umad_ioctl
* Input:
* dev device
* cmd IB_USER_MAD_ENABLE_PKEY, IB_USER_MAD_REGISTER_AGENT or
* IB_USER_MAD_UNREGISTER_AGENT
* arg which agent to register or unregister
* mode passed on to ddi_copyin()
* credp Unused
* rvalp Unused
* Output:
* None
* Returns:
* Error status
* Called by:
* Device ioctl framework
* Description:
* IB_USER_MAD_ENABLE_PKEY just allows the ioctl to succed to
* indicate that we are at ABI version 5+, not really 5.
* IB_USER_MAD_REGISTER_AGENT requests that a specific MAD class
* for this device be handled by this process.
* IB_USER_MAD_UNREGISTER_AGENT undoes the request above.
*/
/* ARGSUSED3 */
static int
int cmd,
int mode,
int *rvalp)
{
int rc = 0;
int minor;
struct ib_user_mad_reg_req req = {0};
goto err1;
}
/* lookup the node and port #s */
if (ISSM_MINOR(minor)) {
goto err1;
}
if (cmd == IB_USER_MAD_ENABLE_PKEY)
return (umad_pkey_enable());
goto err1;
}
switch (cmd) {
if (rc)
goto err1;
/* return agent ID to user */
if (rc) {
goto err1;
}
break;
break;
default:
rc = DDI_FAILURE;
}
err1:
return (rc);
}
/*
* Get a new unique agent ID. The agent list is already locked. The
* complexity is not ideal, but the number of agents should be small
* (ie 2 or 3) so it shouldn't matter.
*/
static int
{
unsigned int agent_id;
agent_id = 0;
for (;;) {
break;
}
}
if (! found)
break;
agent_id++;
}
return (agent_id);
}
/*
* Function:
* umad_register
* Input:
* req User registration request
* uctx User context
* Output:
* None
* Returns:
* status
* Called by:
* umad_ioctl
* Description:
* Handles the registration of user agents from userspace.
* Each call will result in the creation of a new agent object for
* error is raised.
*/
static int
{
int rc = IBMF_SUCCESS;
/* check for valid QP */
goto err1;
}
return (IBMF_PORT_IN_USE);
if (rc)
goto err1;
return (0);
err1:
if (rc) {
if (agent) {
}
}
return (rc);
}
/*
* Function:
* umad_unregister
* Input:
* req - user unregister request
* info - user context
* Output:
* None
* Returns:
* Status
* Called by:
* umad_ioct
* Description:
* Undoes registration. Waits for pending operations before completing.
*/
static int
{
int rc;
struct ibmf_reg_info *ibmf_info;
goto done;
}
while (agent->agent_outstanding_msgs != 0) {
}
/* Remove agent from the uctx list. */
/* Get the IBMF registration information */
/* Remove the pending received MADs. */
}
/* If no more references, tear down the ibmf registration */
if (--ibmf_info->ibmf_reg_refcnt == 0) {
/* Remove the callback */
#if defined(DEBUG)
if (rc) {
"umad_unregister: failed "
"ibmf_tear_down_async_cb() error %d\n", rc);
}
#endif
/* Remove the pending received MADs. */
&ibmf_msg);
}
/* unregister from IBMF */
#if defined(DEBUG)
if (rc) {
"umad_unregister: failed "
"ibmf_unregister() error %d\n", rc);
}
#endif
} else {
}
if (did_ibmf_unregister) {
#if defined(DEBUG)
#endif
if (ibmf_info == ibmf_entry) {
#if defined(DEBUG)
#endif
break;
}
}
/* Release the registration memory */
}
rc = 0;
done:
return (rc);
}
/*
* Function:
* umad_poll
* Input:
* dev device
* events which events
* anyyet any events yet?
* Output:
* reventsp return of which events
* phpp poll head pointer
* Returns:
* return 0 for success, or the appropriate error number
* Called by:
* Device poll framework
* Description:
* Fails for ISSM device. POLLOUT is always true. POLLIN or POLLRDNORM
* is true if a message has been queued for the user context receive list.
*/
static int
short events,
int anyyet,
short *reventsp,
{
int rc = 0;
int minor;
short revent = 0;
goto err1;
}
/* lookup the node and port #s */
if (ISSM_MINOR(minor)) {
goto err1;
}
/*
* Always signal ready for POLLOUT / POLLWRNORM.
* Signal for POLLIN / POLLRDNORM whenever there is something in
* the receive list.
*/
}
}
if (revent == 0) {
if (! anyyet)
}
err1:
return (rc);
}
/*
* Function:
* umad_unsolicited_cb
* Input:
* ibmf_handle - handle to ibmf
* msgp - The incoming SM MAD
* args - umad_port_info_t object that the MAD came in on
* Output:
* None
* Returns:
* none
* Called by:
* IBMF from below
* Description:
* Callback function (ibmf_msg_cb_t) that is invoked when the
* ibmf receives a response MAD and passes it up if requested.
* The message is tossed if no one wants it or queued if requested.
*/
static void
{
struct umad_agent_s *agent;
int rc;
#if defined(__lint)
ibmf_handle = 0;
#endif
/* Apply the filters to this MAD. */
/*
* Make sure the user context that was receiving the unsolicited
* messages is still present.
*/
goto reject;
goto reject;
goto reject;
goto reject;
goto reject;
return;
}
#if defined(__lint)
/*
* This is needed because rdma/ib_verbs.h and sol_ofs/sol_ofs_common.h
* both implement static functions. Not all of those functions are
* used by sol_umad, but lint doesn't like seeing static function that
* are defined but not used.
*/
void
{
(void) llist_is_last(a, b);
llist_add_tail(a, b);
(void) ib_width_enum_to_int(IB_WIDTH_1X);
}
#endif