ibnex_hca.c revision 1aae5cd0fbf4c2622e76b8be40ca23c7c1f78e2b
/*
* 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
*/
/*
*/
#include <sys/mdi_impldefs.h>
void ibnex_handle_hca_attach(void *);
static int ibnex_hca_bus_config_one(dev_info_t *, void *,
dev_info_t **, ibnex_node_type_t *);
static int ibnex_prom_devname_to_pkey_n_portnum(
extern int ibnex_busctl(dev_info_t *,
dev_info_t *, ddi_ctl_enum_t, void *, void *);
extern int ibnex_map_fault(dev_info_t *,
ddi_bus_config_op_t, void *, dev_info_t **);
static int ibnex_hca_bus_unconfig(dev_info_t *,
uint_t, ddi_bus_config_op_t, void *);
ddi_bus_config_op_t, void *, dev_info_t **, int *);
extern int ibnex_pseudo_config_one(
ibnex_node_data_t *, char *, dev_info_t *);
extern void ibnex_config_all_children(dev_info_t *);
extern void ibnex_pseudo_initnodes(void);
extern int ibnex_pseudo_mdi_config_one(int, void *, dev_info_t **,
char *, char *);
extern int ibnex_get_dip_from_guid(ib_guid_t, int,
ib_pkey_t, dev_info_t **);
ibdm_port_attr_t *, int, int, ib_pkey_t, int *,
int);
extern uint64_t ibnex_str2hex(char *, int, int *);
extern int ibnex_str2int(char *, int, int *);
extern void ibnex_create_hcasvc_nodes(
dev_info_t *, ibdm_port_attr_t *);
extern void ibnex_create_port_nodes(
dev_info_t *, ibdm_port_attr_t *);
extern void ibnex_create_vppa_nodes(
dev_info_t *, ibdm_port_attr_t *);
extern int ibnex_get_pkey_commsvc_index_portnum(
extern int ibnex_port_settling_time;
/*
* The bus_ops structure defines the capabilities of HCA nexus driver.
*/
struct bus_ops ibnex_ci_busops = {
nullbusmap, /* bus_map */
NULL, /* bus_get_intrspec */
NULL, /* bus_add_intrspec */
NULL, /* bus_remove_intrspec */
ibnex_map_fault, /* Map Fault */
ddi_no_dma_map, /* DMA related entry points */
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
ibnex_busctl, /* bus_ctl */
ddi_bus_prop_op, /* bus_prop_op */
NULL, /* bus_get_eventcookie */
NULL, /* bus_add_eventcall */
NULL, /* bus_remove_eventcall */
NULL, /* bus_post_event */
NULL,
ibnex_hca_bus_config, /* bus config */
ibnex_hca_bus_unconfig /* bus unconfig */
};
/*
* ibnex_hca_bus_config()
*
* BUS_CONFIG_ONE:
* Enumerate the exact instance of the driver. Use the device node name
* to locate the exact instance.
* Query IBDM to find whether the hardware exits for the instance of the
* driver. If exists, create a device node and return NDI_SUCCESS.
*
* BUS_CONFIG_ALL:
* Enumerate all the instances of all the possible children (seen before
* and never seen before).
*
* BUS_CONFIG_DRIVER:
* Enumerate all the instances of a particular driver.
*/
static int
{
/*
* In a normal case HCA is setup as a phci.
* If an HCA is in maintenance mode, its phci is not set up
* but the driver is attached to update the firmware. In this
* case, do not configure the MPxIO clients.
*/
return (NDI_SUCCESS);
else
return (NDI_FAILURE);
}
switch (op) {
case BUS_CONFIG_ONE:
"parent %p", parent);
break;
case BUS_CONFIG_OBP_ARGS:
if (cdip) {
/*
* Boot case.
* Special handling because the "devname"
* format for the enumerated device is
* different.
*/
srvname =
"ibport@%x,%x,%s",
}
} else {
"CONFIG_OBP_ARGS : invalid state!!");
ret = IBNEX_FAILURE;
}
break;
case BUS_CONFIG_ALL:
IBTF_DPRINTF_L4("ibnex",
"\thca_bus_config: CONFIG_ALL parent %p", parent);
break;
case BUS_CONFIG_DRIVER:
"CONFIG_DRIVER parent %p", parent);
break;
default:
ret = IBNEX_FAILURE;
break;
}
if (ret == IBNEX_SUCCESS) {
if (op == BUS_CONFIG_OBP_ARGS)
op = BUS_CONFIG_ONE;
"ndi_busop_bus_config : retval %d", ret);
return (ret);
}
return (NDI_FAILURE);
}
/*
* ibnex_hca_bus_unconfig()
*
* Unconfigure a particular device node or all instance of a device
* driver device or all children of IBnex
*/
static int
{
return (DDI_FAILURE);
(flag & NDI_UNCONFIG)) {
if (major == -1) {
/*
* HCA dip. When major number is -1 HCA is
* going away cleanup all the port nodes.
*/
ndp->node_state =
}
}
} else {
/*
* HCA dip. Cleanup only the port nodes that
* match the major number.
*/
parent) {
ndp->node_state =
}
}
}
}
return (DDI_SUCCESS);
}
/*
* ibnex_config_obp_args()
* Configures a particular port node for a IP over IB communication
* service.
* The format of the input string "devname" is
* port=x,pkey=y,protocol=ip,<wanboot options>
* Thr format of the node name created here is
* ibport@<Port#>,<pkey>,<service name>
* where pkey = 0 for port communication service nodes
* Returns "dev_info_t" of the "child" node just created
* NULL when failed to enumerate the child node
*
*/
static dev_info_t *
{
char *temp;
/* Is this OBP node for IPoIB ? */
do {
break;
break;
} else {
break;
}
temp++;
} while (temp);
return (NULL);
return (NULL);
}
"ipib") == 0) {
break;
}
}
if ((port_attr = ibdm_ibnex_probe_hcaport(
IBTF_DPRINTF_L2("ibnex",
"\tconfig_port_node: Port does not exist");
return (NULL);
}
/* Wait until "port is up" */
if ((port_attr = ibdm_ibnex_probe_hcaport(
return (NULL);
}
if (iter++ == 400) {
}
}
}
return (cdip);
}
IBTF_DPRINTF_L5("ibnex",
"\t ibnex_commsvc_initnode rval %x", rval);
break;
}
}
return (cdip);
}
/*
* ibnex_prom_devname_to_pkey_n_portnum()
* Parses the device node name and extracts "PKEY" and "port#"
* Returns IBNEX_SUCCESS/IBNEX_FAILURE
*/
static int
{
int ret = IBNEX_SUCCESS;
} else
ret = IBNEX_FAILURE;
if ((ret == IBNEX_SUCCESS) &&
} else
ret = IBNEX_FAILURE;
return (ret);
}
static ibnex_node_data_t *
{
int len;
IBTF_DPRINTF_L4("ibnex",
*type = IBNEX_IOC_NODE;
else
IBTF_DPRINTF_L4("ibnex",
if (*cdip)
return (node_data);
}
static int
{
int index;
IBTF_DPRINTF_L2("ibnex",
"\thca_bus_config: Invalid device node address");
return (IBNEX_FAILURE);
}
if (cdip) {
}
}
}
/*
* If child dip is present, just return
* from here.
*/
goto end;
}
switch (node_type) {
case IBNEX_IOC_NODE:
if (!need_bus_config) {
return (ret);
}
break;
case IBNEX_PSEUDO_NODE:
ret = IBNEX_SUCCESS;
break;
default:
IBTF_DPRINTF_L2("ibnex",
"\tconfig_port_node: Invalid Service Name");
return (IBNEX_FAILURE);
}
if (strcmp("ipib",
IBTF_DPRINTF_L2("ibnex",
"Skipping IBD devices... ");
break;
}
}
if (cdip)
ret = IBNEX_SUCCESS;
else
ret = IBNEX_FAILURE;
break;
}
end:
if (node_type == IBNEX_HCA_CHILD_NODE) {
/* Allows enumeration under PHCI */
*flag |= NDI_MDI_FALLBACK;
}
return (ret);
}
void
ibnex_handle_hca_attach(void *cb_arg)
{
/*
* Enumerate children of this HCA, port nodes,
* VPPA & HCA_SVC nodes. Use ndi_devi_enter() for
* locking. IB Nexus is enumerating the children
* of HCA, not MPXIO clients.
*/
return;
}
}
}