ibnex_ioctl.c revision 00a3eaf3896a33935e11fd5c5fb5c1714225c067
/*
* 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
*/
/*
* Copyright 2008 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* This file contains support required for IB cfgadm plugin.
*/
#include <sys/mdi_impldefs.h>
/*
* function prototypes
*/
int ibnex_offline_childdip(dev_info_t *);
static int ibnex_get_num_devices(void);
static int ibnex_get_snapshot(char **, size_t *, int);
void *);
static void ibnex_figure_ap_devstate(dev_info_t *,
static void ibnex_figure_ib_apid_devstate(devctl_ap_state_t *);
static char *ibnex_get_apid(struct devctl_iocdata *);
static int ibnex_get_dip_from_apid(char *, dev_info_t **,
ibnex_node_data_t **);
static ibnex_rval_t ibnex_handle_pseudo_configure(char *);
static ibnex_rval_t ibnex_handle_ioc_configure(char *);
static ibnex_rval_t ibnex_handle_commsvcnode_configure(char *);
static void ibnex_return_apid(dev_info_t *, char **);
static void ibnex_port_conf_entry_add(char *);
static void ibnex_vppa_conf_entry_add(char *);
static void ibnex_hcasvc_conf_entry_add(char *);
static int ibnex_port_conf_entry_delete(char *, char *);
static int ibnex_vppa_conf_entry_delete(char *, char *);
static int ibnex_hcasvc_conf_entry_delete(char *, char *);
extern uint64_t ibnex_str2hex(char *, int, int *);
extern int ibnex_ioc_initnode_all_pi(ibdm_ioc_info_t *);
ibdm_port_attr_t *, int, int, ib_pkey_t, int *,
int);
extern int ibnex_get_dip_from_guid(ib_guid_t, int,
ib_pkey_t, dev_info_t **);
extern void ibnex_reprobe_ioc_dev(void *arg);
extern void ibnex_reprobe_ioc_all();
extern int ibnex_pseudo_create_all_pi(ibnex_node_data_t *);
extern void ibnex_pseudo_initnodes(void);
/*
* ibnex_open()
*/
/* ARGSUSED */
int
{
return (0);
}
/*
* ibnex_close()
*/
/* ARGSUSED */
int
{
return (0);
}
/*
* ibnex_ioctl()
* Ioctl routine for cfgadm controls
* DEVCTL_AP_GETSTATE: returns attachment point state
* DEVCTL_AP_CONTROL: Does "ibnex" specific ioctls listed below
* IBNEX_NUM_DEVICE_NODES Gives how many device nodes exist?
* IBNEX_NUM_HCA_NODES Gives how many HCAs exist in the fabric
* IBNEX_UPDATE_PKEY_TBLS "-x update_pkey_tbls"
* IBNEX_GET_SNAPSHOT Gets the "snapshot" back to user-land
* IBNEX_SNAPSHOT_SIZE What is "snapshot" size
* IBNEX_DEVICE_PATH_SZ What is device-path size
* IBNEX_GET_DEVICE_PATH Gets the device path for Dynamic ap
* IBNEX_HCA_LIST_SZ "-x list" option size for the HCA ap_id
* IBNEX_HCA_LIST_INFO "-x list" option info for the HCA ap_id
* IBNEX_UNCFG_CLNTS_SZ "-x unconfig_client option size"
* IBNEX_UNCFG_CLNTS_INFO "-x unconfig_client data"
* IBNEX_CONF_ENTRY_ADD: "-x add_service"
* IBNEX_CONF_ENTRY_DEL: "-x delete_service"
* IBNEX_HCA_VERBOSE_SZ: "-alv hca_apid data size"
* IBNEX_HCA_VERBOSE_INFO: "-alv hca_apid actual data"
* IBNEX_UPDATE_IOC_CONF "-x update_ioc_conf"
* DEVCTL_AP_CONFIGURE: "configure" the attachment point
* DEVCTL_AP_UNCONFIGURE: "unconfigure" the attachment point
*/
/* ARGSUSED */
int
int *rvalp)
{
int circ;
char *msg;
char *guid_str;
size_t snapshot_sz = 0;
/* read devctl ioctl data */
if ((cmd != DEVCTL_AP_CONTROL) &&
IBTF_DPRINTF_L4("ibnex",
"\tioctl: ndi_dc_allochdl failed\n");
return (EFAULT);
}
switch (cmd) {
case DEVCTL_AP_GETSTATE:
msg = "\tioctl: DEVCTL_AP_GETSTATE";
if (*apid_n == '\0') {
IBTF_DPRINTF_L2("ibnex",
"%s: ibnex_get_apid failed", msg);
break;
}
} else {
/* if this apid is already seen by IBNEX, get the dip */
if (rv != IBNEX_DYN_APID) {
IBTF_DPRINTF_L2("ibnex",
"%s: ibnex_get_dip_from_apid failed", msg);
break;
}
if (apid_dip)
/* rv could be something undesirable, so reset it */
rv = 0;
}
/* copy the return-AP-state information to the user space */
IBTF_DPRINTF_L2("ibnex",
"%s: ndi_dc_return_ap_state failed", msg);
}
break;
case DEVCTL_AP_CONTROL:
{
int num_nodes = 0;
msg = "\tioctl: DEVCTL_AP_CONTROL";
#ifdef _MULTI_DATAMODEL
IBTF_DPRINTF_L2("ibnex",
"%s: ddi_copyin err 1", msg);
break;
}
}
#else
mode) != 0) {
IBTF_DPRINTF_L2("ibnex",
"%s: ddi_copyin 2 failed", msg);
break;
}
#endif /* _MULTI_DATAMODEL */
/*
* figure out ap_id name as passed from user-land
* NOTE: We don't need to figure out ap_id for these
* two sub-commands:-
* IBNEX_NUM_DEVICE_NODES, IBNEX_NUM_HCA_NODES
*
* Hence, In user-land, these two ioctls force "ap_id_len" to 0.
*/
IBTF_DPRINTF_L2("ibnex",
"%s: ddi_copyin err 3", msg);
break;
}
}
/* process sub-commands */
case IBNEX_NUM_DEVICE_NODES:
msg = "\tioctl: DEVCTL_AP_CONTROL: NUM_DEVICE_NODES";
/*
* figure out how many IOC, VPPA,
* Pseudo and Port nodes are present
*/
}
return (rv);
case IBNEX_NUM_HCA_NODES:
msg = "\tioctl: DEVCTL_AP_CONTROL: NUM_HCA_NODES";
/* figure out how many HCAs are present in the host */
}
return (rv);
case IBNEX_UPDATE_PKEY_TBLS:
msg = "\tioctl: DEVCTL_AP_CONTROL: UPDATE_PKEY_TBLS";
/*
* update P_Key tables:
* ibdm_ibnex_update_pkey_tbls() calls
* ibt_query_hca_ports_byguids() for all the
* HCAs that the IBDM has "seen" in the system.
* This ends up updating the IBTL P_Key database.
* NOTE: Changes in this area will break this
* assumption. Initially the plan was to call
* ibt_query_hca_ports_byguids() in IBTL but
* IBDM needs to call it as well. So, eliminating
* the first invocation.
*
* It next updates the DM P_Key database.
* Note that the DM P_Key database updating
* will always be driven through cfgadm.
*/
break;
case IBNEX_GET_SNAPSHOT:
case IBNEX_SNAPSHOT_SIZE:
"\tioctl: DEVCTL_AP_CONTROL: IBNEX_SNAPSHOT_SIZE" :
"\tioctl: DEVCTL_AP_CONTROL: IBNEX_GET_SNAPSHOT";
IBTF_DPRINTF_L2("ibnex",
"%s:\n\tibnex_get_snapshot failed", msg);
break;
}
/* ssiz needs to be reinitialized again */
ssiz = snapshot_sz;
IBTF_DPRINTF_L4("ibnex",
IBTF_DPRINTF_L2("ibnex",
"%s:\n\tddi_copyout 2 failed", msg);
}
} else {
IBTF_DPRINTF_L2("ibnex",
"%s:\n\tinvalid buffer size (%x %x)"
IBTF_DPRINTF_L2("ibnex",
"%s:\n\tddi_copyout 3 failed", msg);
}
}
break;
case IBNEX_DEVICE_PATH_SZ:
case IBNEX_GET_DEVICE_PATH:
{
char path[MAXPATHLEN];
"\tioctl:DEVCTL_AP_CONTROL: IBNEX_DEVICE_PATH_SZ" :
"\tioctl:DEVCTL_AP_CONTROL: IBNEX_GET_DEVICE_PATH";
/* if this apid is already seen by IBNEX, get the dip */
IBTF_DPRINTF_L2("ibnex",
"%s:\n\tget_dip_from_apid failed", msg);
break;
}
/* ddi_pathname doesn't supply /devices, so we do. */
IBTF_DPRINTF_L4("ibnex",
/* rv could be something undesirable, so reset it */
rv = 0;
IBTF_DPRINTF_L2("ibnex",
"%s: ddi_copyout 4 failed", msg);
}
} else {
IBTF_DPRINTF_L2("ibnex",
"%s: invalid size (%x, %x)",
"ddi_copyout 5 failed", msg);
}
}
break;
}
case IBNEX_HCA_LIST_SZ:
case IBNEX_HCA_LIST_INFO:
"DEVCTL_AP_CONTROL: IBNEX_HCA_LIST_SZ" :
"DEVCTL_AP_CONTROL: IBNEX_HCA_LIST_INFO";
break;
}
/* Get the GUID(hex value) from apid_n */
&ret);
if (ret != IBNEX_SUCCESS) {
"GUID string", msg);
break;
}
ibnex_return_apid) != IBT_SUCCESS) {
IBTF_DPRINTF_L2("ibnex",
"%s: get HCA consumers failed", msg);
break;
}
ssiz = snapshot_sz;
IBTF_DPRINTF_L2("ibnex",
"%s: ddi_copyout 6 failed", msg);
}
} else {
ssiz);
"ddi_copyout 7 failed", msg);
}
}
break;
case IBNEX_UNCFG_CLNTS_SZ:
case IBNEX_UNCFG_CLNTS_INFO:
"\tioctl:DEVCTL_AP_CONTROL: IBNEX_UNCFG_CLNTS_SZ" :
"\tioctl:DEVCTL_AP_CONTROL: IBNEX_UNCFG_CLNTS_INFO";
break;
}
/* Get the GUID(hex value) from apid_n */
&ret);
if (ret != IBNEX_SUCCESS) {
"GUID string passed", msg);
break;
}
IBTF_DPRINTF_L2("ibnex",
"%s: get HCA consumers failed", msg);
break;
}
/* ssiz needs to be reinitialized again */
ssiz = snapshot_sz;
IBTF_DPRINTF_L2("ibnex",
"%s: ddi_copyout 9 failed", msg);
}
} else {
IBTF_DPRINTF_L2("ibnex",
"%s: invalid size (%x, %x)",
"ddi_copyout 10 failed", msg);
}
}
break;
case IBNEX_CONF_ENTRY_ADD:
msg = "\tioctl: IBNEX_CONF_ENTRY_ADD: ";
/* read in the "service" name */
msg);
break;
}
/* read in the "service type" */
if (svc_type == IB_PORT_SERVICE) {
} else if (svc_type == IB_VPPA_SERVICE) {
} else if (svc_type == IB_HCASVC_SERVICE) {
}
break;
case IBNEX_CONF_ENTRY_DEL:
msg = "\tioctl:IBNEX_CONF_ENTRY_DEL: ";
/* read in the "service" name */
msg);
break;
}
/* read in the "service type" */
if (svc_type == IB_PORT_SERVICE) {
} else if (svc_type == IB_VPPA_SERVICE) {
} else if (svc_type == IB_HCASVC_SERVICE) {
service);
}
break;
case IBNEX_HCA_VERBOSE_SZ:
case IBNEX_HCA_VERBOSE_INFO:
"DEVCTL_AP_CONTROL: IBNEX_HCA_VERBOSE_SZ" :
"DEVCTL_AP_CONTROL: IBNEX_HCA_VERBOSE_INFO";
break;
}
/* Get the GUID(hex value) from apid_n */
&ret);
if (ret != IBNEX_SUCCESS) {
"string", msg);
break;
}
&snapshot_sz) != IBT_SUCCESS) {
"data failed", msg);
break;
}
ssiz = snapshot_sz;
IBTF_DPRINTF_L2("ibnex",
"%s: ddi_copyout 11 failed", msg);
}
} else {
IBTF_DPRINTF_L2("ibnex",
"%s: invalid size (%x, %x)",
} else if (ddi_copyout(snapshot,
"ddi_copyout 12 failed", msg);
}
}
break;
case IBNEX_UPDATE_IOC_CONF :
msg = "\tioctl:IBNEX_UPDATE_IOC_CONF: ";
/*
* If IB fabric APID, call ibnex_update_all
* If IOC APID, get the apid dip and call
* ibnex_update_ioc
*/
/*
* If reprobe is in progress or another reprobe
* is already waiting, wait.
*/
if (ibnex.ibnex_reprobe_state != 0) {
if (ibnex.ibnex_reprobe_state ==
while (ibnex.ibnex_reprobe_state) {
&ibnex.ibnex_mutex);
}
/*
* Pending reprobe all completed, return
*/
break;
}
/* Check if reprobe for any IOC is pending */
/* CONSTCOND */
while (1) {
ioc_reprobe_pending = 0;
if (scanp->node_reprobe_state
!= 0) {
1;
break;
}
}
if (ioc_reprobe_pending == 0) {
break;
}
&ibnex.ibnex_mutex);
}
/*
* Set the REPROBE_ALL_PROGRESS state &
* start reprobe
*/
&nodep);
/* Device unconfigured: return */
break;
/* Reset return value back to 0 */
rv = 0;
if (ibnex.ibnex_reprobe_state != 0 ||
nodep->node_reprobe_state != 0) {
while (ibnex.ibnex_reprobe_state != 0 &&
nodep->node_reprobe_state != 0) {
&ibnex.ibnex_mutex);
}
/* Pending reprobe completed, return */
break;
}
/* Set node_reprobe_state and start reprobe */
ibnex_reprobe_ioc_dev((void *)apid_dip);
} else {
}
break;
default:
IBTF_DPRINTF_L2("ibnex",
break;
}
}
break;
case DEVCTL_AP_UNCONFIGURE:
msg = "DEVCTL_AP_UNCONFIGURE";
/* Check for write permissions */
break;
}
IBTF_DPRINTF_L2("ibnex",
"%s: ibnex_get_apid failed", msg);
break;
}
/*
* If this apid is already seen by IBNEX, get the dip
* NOTE: ibnex_get_dip_from_apid() finds a valid dip
* and also does a ndi_devi_hold() on the child.
*/
break;
}
/* Check if it is a valid node type? */
if (!IBNEX_VALID_NODE_TYPE(nodep)) {
break;
}
/*
* continue unconfigure operation, only if device node
* is already configured. Return EBUSY if another
* configure/unconfigure operation is in progress.
*/
break;
}
/* do this before to avoid races */
/*
* Call devfs_clean first
* NOTE: The code so far is protected by holding ibnex_mutex
* and by doing a ndi_devi_hold() on the child.
*/
}
if (IBNEX_COMMSVC_NODE_TYPE(nodep)) {
/* unconfigure the IOC node */
/* unconfigure the pseudo node */
}
/* reset upon failure */
if (ret_val != IBNEX_SUCCESS) {
} else {
}
break;
case DEVCTL_AP_CONFIGURE:
msg = "DEVCTL_AP_CONFIGURE";
/* Check for write permissions */
break;
}
IBTF_DPRINTF_L2("ibnex",
"%s: ibnex_get_apid failed", msg);
break;
}
/*
* Let's get the node if it already exists.
* NOTE: ibnex_get_dip_from_apid() finds a valid dip
* and also does a ndi_devi_hold() on the child.
*/
/*
* We need the node_data but not the dip. If we get a dip for
* this apid, it means it's already configured. We need to
* return.
*/
rv = 0;
break;
}
/*
* A node exits for this apid but not a dip. So we must have
* unconfigured it earlier. Set the node_ap_state to configuring
* to allow configure operation.
*/
}
/*
* Five types of APIDs are supported:
* o HCA_GUID,0,service-name (HCA-SVC device)
* o IOC_GUID (IOC device)
* o PORT_GUID,0,service-name (Port device)
* o pseudo_name,unit-address, (Pseudo device)
* o PORT_GUID,P_Key,service-name (VPPA device)
* If the apid doesn't have "," then treat it as an IOC
* If the apid has one "," then it is Pseudo device
* If the apid has 2 ","s then it is one of the
* Port,VPPA,HCA_SVC devices
*/
} else {
char *second;
apid_n);
}
} /* end of else */
if (ret_val != IBNEX_SUCCESS) {
} else {
/*
* Get the newly created node and set the state to
* IBNEX_NODE_AP_CONFIGURED.
* NOTE: ibnex_get_dip_from_apid() finds a valid dip
* and also does a ndi_devi_hold() on the child.
*/
if (!nodep)
}
}
}
break;
default:
break;
}
}
if (dcp) {
}
return (rv);
}
/*
* ibnex_get_num_devices()
* Figure out how many IOC, VPPA, Pseudo, HCA_SVC and Port devices exist
*/
static int
ibnex_get_num_devices(void)
{
int j, k, l, hca_count;
int num_nodes = 0;
/* Get a count of HCAs, first. */
for (j = 0; j < ibnex.ibnex_nhcasvc_comm_svcs; j++)
num_nodes++;
for (k = 0; k < ibnex.ibnex_num_comm_svcs; k++)
num_nodes++;
pt_pkey))
continue;
for (l = 0; l < ibnex.ibnex_nvppa_comm_svcs;
l++, ++num_nodes)
;
} /* end of pa_npkeys */
} /* end of hl_nports */
} /* end of hca_list != NULL */
if (hcap)
/*
* Now figure out how many IOC nodes are present.
* Add count of configured "diconnected" IOCs
*/
/* Last: figure out how many Pseudo nodes are present. */
continue;
num_nodes++;
}
return (num_nodes);
}
/*
* ibnex_get_snapshot()
* Snapshot includes IBNEX_NODE_INFO_NVL, IBNEX_NODE_TYPE_NVL,
* IBNEX_NODE_RSTATE_NVL, IBNEX_NODE_OSTATE_NVL and
* IBNEX_NODE_COND_NVL
*/
static int
{
int i, j, k, l, hca_count;
*sz = 0;
if (!ibnex.ibnex_pseudo_inited) {
}
/* Go thru all the ports of all the HCAs and all the port-svc indices */
"fill in COMM service HCA_SVC nodes");
for (j = 0; j < ibnex.ibnex_nhcasvc_comm_svcs; j++) {
IBNEX_HCASVC_COMMSVC_NODE) != 0) {
IBTF_DPRINTF_L2("ibnex",
"ibnex_get_snapshot: failed to fill"
" HCA_SVC device (%x %x)", i, j);
return (-1);
}
}
"fill in COMM service Port nodes");
for (k = 0; k < ibnex.ibnex_num_comm_svcs; k++) {
IBNEX_PORT_COMMSVC_NODE) != 0) {
IBTF_DPRINTF_L2("ibnex",
"ibnex_get_snapshot: failed to fill"
" Port device (%x %x %x)", i, j, k);
return (-1);
}
} /* end of num_comm_svcs for loop */
"fill in VPPA service port nodes");
if (IBNEX_INVALID_PKEY(pkey))
continue;
for (k = 0; k < ibnex.ibnex_nvppa_comm_svcs;
k++) {
IBNEX_VPPA_COMMSVC_NODE) != 0) {
IBTF_DPRINTF_L2("ibnex",
"ibnex_get_snapshot: "
"failed to fill VPPA "
"device (%x %x %x % x)",
i, j, k, l);
return (-1);
}
} /* end of ibnex_nvppa_comm_svcs loop */
} /* end of pa_npkeys for loop */
} /* end of hl_nports for loop */
} /* end of hca_count for loop */
if (hcap)
/* save it to free up the entire list */
/*
* Say we have N IOCs and all were deleted from ibnex
* but not from IBDM
*/
"filling NVL data failed");
return (-1);
}
continue;
} else {
/* Check first, if we have already seen this IOC? */
break;
}
}
/* have we seen this IOC before? */
&ioc_listp->ioc_profile) != 0) {
IBTF_DPRINTF_L2("ibnex",
"ibnex_get_snapshot: filling NVL "
"for IOC node %p failed", nodep);
return (-1);
}
} else {
IBTF_DPRINTF_L2("ibnex",
"ibnex_get_snapshot: filling NVL "
"tmp for IOC node %p failed",
return (-1);
}
}
} /* end of else ibnex_ioc_node_head == NULL */
} /* end of external for */
/*
* Add list of "disconnected" IOCs, not unconfigured.
*/
IBTF_DPRINTF_L2("ibnex",
"ibnex_get_snapshot: filling NVL "
"for disconnected IOC node %p "
"failed", nodep);
return (-1);
}
}
}
/* lastly; pseudo nodes */
continue;
"filling NVL data for Pseudo %p failed", nodep);
return (-1);
}
}
/* pack the data into the buffer */
IBTF_DPRINTF_L2("ibnex",
"ibnex_get_snapshot: nvlist_pack failed");
return (-1);
}
return (0);
}
/*
* ibnex_get_commsvcnode_snapshot()
* HCA_SVCs seen even if they are not all configured by IBNEX.
*
* HCA_SVC snapshot. If none exists then it makes up a "temporary"
* node which will be displayed as "connected/unconfigured/unknown".
*
* For HCA_SVC node port_guid will be same as hca_guid.
*/
static int
{
int rval;
"HCA GUID: %llX Port GUID: %llX svc_index = %x pkey = %x "
/* check if this node was seen before? */
IBTF_DPRINTF_L2("ibnex",
"ibnex_get_commsvcnode_snapshot: failed to fill "
return (-1);
}
} else {
/* Fill P_Key only for VPPA nodes */
if (node_type == IBNEX_VPPA_COMMSVC_NODE) {
}
IBTF_DPRINTF_L2("ibnex",
"ibnex_get_commsvcnode_snapshot: failed to fill "
return (-1);
}
}
return (0);
}
/*
* ibnex_fill_ioc_tmp()
* A utility function to fill in a "dummy" IOC information.
* Cfgadm plugin will display all IOCs seen by IBDM even if they
* are configured or not by IBNEX.
*
* This function uses information from IBDM to fill up a
* dummy IOC information. It will be displayed as
* "connected/unconfigured/unknown".
*/
static int
{
"data for IOC node %p failed", nodep);
return (-1);
}
return (0);
}
/*
* ibnex_fill_nodeinfo()
* A utility function to fill in to the NVLIST information about
* to cfgadm utility for display. This information is used only
* for cfgadm -ll displays.
*
* Information that is filled in here is:-
* AP_ID_NAME
* AP_ID_INFO
* AP_ID_TYPE
* AP_ID_OCCUPANT_STATE
* AP_ID_RECEPTACLE_STATE
* AP_ID_CONDITION
*/
static int
{
char *svcname;
char *node_name;
char apid[IBTL_IBNEX_APID_LEN];
char info_data[MAXNAMELEN];
svcname);
/* Node APID */
"failed to fill %s", IBNEX_NODE_APID_NVL);
return (-1);
}
/* Node Info */
"failed to fill Port %s", IBNEX_NODE_INFO_NVL);
return (-1);
}
"Port %s = %s, %s = %s",
/* Node APID */
"failed to fill %s", IBNEX_NODE_APID_NVL);
return (-1);
}
/* Node Info */
"failed to fill VPPA %s", IBNEX_NODE_INFO_NVL);
return (-1);
}
"VPPA %s = %s, %s = %s",
svcname);
/* Node APID */
"failed to fill %s", IBNEX_NODE_APID_NVL);
return (-1);
}
/* Node Info */
"failed to fill Port %s", IBNEX_NODE_INFO_NVL);
return (-1);
}
"Port %s = %s, %s = %s",
/*
* get the IOC profile pointer from the args
*/
/* Node APID */
"failed to fill in %s", IBNEX_NODE_APID_NVL);
return (-1);
}
/*
* IOC "info" filed will display the following fields
* VendorID, IOCDeviceID, DeviceVersion, SubsystemVendorID,
* SubsystemID, Class, Subclass, Protocol, ProtocolVersion
*/
"VID: 0x%x DEVID: 0x%x VER: 0x%x SUBSYS_VID: 0x%x "
"SUBSYS_ID: 0x%x CLASS: 0x%x SUBCLASS: 0x%x PROTO: 0x%x "
(char *)profilep->ioc_id_string);
/* Node Info */
"failed to fill IOC %s", IBNEX_NODE_INFO_NVL);
return (-1);
}
/* Node APID */
"failed to fill in %s", IBNEX_NODE_APID_NVL);
return (-1);
}
/* Node Info */
"Pseudo Driver = \"%s\", Unit-address = \"%s\"",
"failed to fill Pseudo %s", IBNEX_NODE_INFO_NVL);
return (-1);
}
}
/* Node type */
node_datap->node_type)) {
"failed to fill in %s", IBNEX_NODE_TYPE_NVL);
return (-1);
}
/* figure out "ostate", "rstate" and "condition" */
"failed to fill in %s", IBNEX_NODE_RSTATE_NVL);
return (-1);
}
"failed to fill in %s", IBNEX_NODE_OSTATE_NVL);
return (-1);
}
"failed to fill in %s", IBNEX_NODE_COND_NVL);
return (-1);
}
return (0);
}
/*
* ibnex_figure_ap_devstate()
* Fills the "devctl_ap_state_t" for a given ap_id
*
* currently it assumes that we don't support "error_code" and
* "last_change" value.
*/
static void
{
} else {
} else {
}
}
ap_state->ap_error_code = 0;
ap_state->ap_in_transition = 0;
}
/*
* ibnex_figure_ib_apid_devstate()
* Fills the "devctl_ap_state_t" for a IB static ap_id
*/
static void
{
ap_state->ap_error_code = 0;
ap_state->ap_in_transition = 0;
}
/*
* ibnex_get_apid()
* Reads in the ap_id passed as an nvlist_string from user-land
*/
static char *
{
char *ap_id;
/* Get which ap_id to operate on. */
&ap_id) != 0) {
}
return (ap_id);
}
/*
* ibnex_get_dip_from_apid()
* exists as a "name" in the "ibnex" list
*
* NOTE: ap_id was on stack earlier and gets manipulated here. Since this
* function may be called twice; it is better to make a local copy of
* ap_id; if the ap_id were to be reused.
*/
static int
{
int index;
char *dyn;
char *ap_id;
char *first;
char *node_addr;
char name[100];
rv = IBNEX_DYN_APID;
} else { /* either static, hca or unknown */
rv = IBNEX_HCA_APID;
} else {
}
return (rv);
}
if (*dyn == '\0') {
return (IBNEX_UNKNOWN_APID);
}
/* APID */
/* Implies Port or VPPA or HCA_SVC Driver ap_id */
int str_len;
int pkey_val = 0;
/* dyn contains ,GUID,p_key,svc_name. Change it to GUID */
"Port / Node Guid %s", dyn);
/* figure out comm or vppa. figure out pkey */
++pkey_str; /* pkey_str used to point to ",p_key,svc_name" */
/* pkey_str contains p_key,svc_name. Change it to p_key */
/* convert the string P_KEY to hex value */
if (ret != IBNEX_SUCCESS) {
return (IBNEX_UNKNOWN_APID);
}
++svc_str; /* svc_str used to point to ",svc_name" */
/*
* Match P_Key, name string & service string:
* For COMM / HCA_SVC services these should be true:
* P_Key matches to 0, svc_str in comm_svc_names[]
* and name matches the dynamic part of the ap_id
* For VPPA services this should be true:
* P_Key != 0 & matches, svc_str in
* vppa_comm_svc_names[] and the name matches the
* dynamic part of the ap_id.
*/
/* pkey != 0, COMM / HCA_SVC service */
if (((pkey_val == 0) && (
/* Port Service */
/* HCA_SVC service */
!= NULL)))) ||
/* next the VPPA strings */
NULL))) {
*ret_node_datap = nodep;
return (rv);
}
}
} /* end of for */
/* pseudo ap_id */
== 1)
continue;
*ret_node_datap = nodep;
return (rv);
}
}
/* This is an IOC ap_id */
*ret_node_datap = nodep;
return (rv);
}
}
}
/* Could not find a matching IB device */
return (rv);
}
/*
* ibnex_handle_pseudo_configure()
* Do DEVCTL_AP_CONNECT processing for Pseudo devices only.
* The code also checks if the given ap_id is valid or not.
*/
static ibnex_rval_t
{
char *node_addr;
/* Check if the APID is valid first */
"invalid apid %s", apid);
return (retval);
}
/* find the matching entry and configure it */
continue;
continue;
/*
* Return BUSY if another configure
* operation is in progress
*/
if (nodep->node_state ==
return (IBNEX_BUSY);
else
return (IBNEX_SUCCESS);
}
/*
* Return BUSY if another unconfigure operation is
* in progress
*/
return (IBNEX_BUSY);
if (retval == NDI_SUCCESS) {
return (IBNEX_SUCCESS);
} else {
return (IBNEX_FAILURE);
}
}
retval);
return (retval);
}
/*
* ibnex_handle_ioc_configure()
* Do DEVCTL_AP_CONNECT processing for IOCs only.
* The code also checks if the given ap_id is valid or not.
*/
static ibnex_rval_t
ibnex_handle_ioc_configure(char *apid)
{
int ret;
/* Check if the APID is valid first */
IBTF_DPRINTF_L4("ibnex",
"\tibnex_handle_ioc_configure: invalid apid %s", apid);
return (retval);
}
/*
* Call into IBDM to get IOC information
*/
if (ret != IBNEX_SUCCESS)
return (ret);
IBTF_DPRINTF_L4("ibnex",
"\tibnex_handle_ioc_configure: IOC GUID = %llX", ioc_guid);
IBTF_DPRINTF_L2("ibnex",
"\tibnex_handle_ioc_configure: probe_iocguid failed");
return (retval);
}
"done retval = %d", retval);
return (retval);
}
/*
* ibnex_handle_commsvcnode_configure()
* Do DEVCTL_AP_CONNECT processing
* The code also checks if the given ap_id is valid or not.
*/
static ibnex_rval_t
{
int sndx;
int port_pkey = 0;
int node_type;
apid);
/* Check if the APID is valid first */
IBTF_DPRINTF_L4("ibnex",
"\tibnex_handle_commsvcnode_configure: "
"invalid apid %s", apid);
return (retval);
}
/* guid_str contains GUID,p_key,svc_name. Change it to GUID */
/* convert the string GUID to hex value */
if (ret == IBNEX_FAILURE)
return (ret);
"Port / Node Guid %llX", guid);
++pkey_str; /* pkey_str used to point to ",p_key,svc_name" */
/* pkey_str contains p_key,svc_name. Change it to P_Key */
"p_key %s", pkey_str);
/* convert the string P_Key to a hexadecimal value */
"PKEY num %x", port_pkey);
if (ret == IBNEX_FAILURE)
return (ret);
++svc_str; /* svc_str used to point to ",svc_name" */
/* find the service index */
if (port_pkey == 0) {
/* PORT Devices */
break;
}
}
/* HCA_SVC Devices */
sndx++) {
break;
}
}
}
} else {
break;
}
}
}
IBTF_DPRINTF_L2("ibnex",
"\tibnex_handle_commsvcnode_configure: "
"invalid service %s", svc_str);
return (retval);
}
/* get Port attributes structure */
if (is_hcasvc_node == B_FALSE) {
IBTF_DPRINTF_L2("ibnex",
"\tibnex_handle_commsvcnode_configure: "
"ibdm_ibnex_get_port_attrs failed");
return (retval);
}
} else {
IBTF_DPRINTF_L2("ibnex",
"\tibnex_handle_commsvcnode_configure: "
"ibdm_ibnex_get_hca_info_by_guid failed");
return (retval);
}
}
/* get HCA's dip */
IBTF_DPRINTF_L2("ibnex",
"\tibnex_handle_commsvcnode_configure: "
"no HCA present");
if (is_hcasvc_node == B_FALSE)
else
return (retval);
}
if (port_pkey == 0)
else
} else {
}
if (is_hcasvc_node == B_FALSE)
else
"done retval = %d", retval);
return (retval);
}
/*
* ibnex_return_apid()
* Construct the ap_id of a given IBTF client in kernel
*/
static void
{
"ib%s%llX,0,%s", DYN_SEP,
"ib%s%llX,0,%s", DYN_SEP,
"ib%s%llX,%x,%s", DYN_SEP,
"ib%s%llX", DYN_SEP,
} else {
}
}
/*
* ibnex_vppa_conf_entry_add()
* Add a new service to the ibnex data base of VPPA communication
* services.
*/
static void
ibnex_vppa_conf_entry_add(char *service)
{
int i, nsvcs;
char **service_name;
/* Allocate space for new "ibnex.ibnex_nvppa_comm_svcs + 1" */
/*
* Copy over the existing "ibnex.ibnex_vppa_comm_svc_names"
* array. Add the new service at the end.
*/
for (i = 0; i < nsvcs; i++)
/* Replace existing pointer to VPPA services w/ newly allocated one */
if (ibnex.ibnex_vppa_comm_svc_names) {
sizeof (char *));
}
}
/*
* ibnex_port_conf_entry_add()
* Add a new service to the ibnex data base of Port communication
* services.
*/
static void
ibnex_port_conf_entry_add(char *service)
{
int i, nsvcs;
char **service_name;
/* Allocate space for new "ibnex.ibnex_num_comm_svcs + 1" */
/*
* Copy over the existing "ibnex.ibnex_comm_svc_names" array.
* Add the new service to the end.
*/
for (i = 0; i < nsvcs; i++)
/* Replace existing pointer to Port services w/ newly allocated one */
if (ibnex.ibnex_comm_svc_names) {
}
}
/*
* ibnex_hcasvc_conf_entry_add()
* Add a new service to the ibnex data base of HCA_SVC communication
* services.
*/
static void
{
int i, nsvcs;
char **service_name;
/* Allocate space for new "ibnex.ibnex_nvppa_comm_svcs + 1" */
/*
* Copy over the existing "ibnex.ibnex_hcasvc_comm_svc_names"
* array. Add the new service at the end.
*/
for (i = 0; i < nsvcs; i++)
/*
* Replace existing pointer to HCA_SVC services w/ newly
* allocated one
*/
if (ibnex.ibnex_hcasvc_comm_svc_names) {
sizeof (char *));
}
}
/*
* ibnex_vppa_conf_entry_delete()
* Delete an existing service entry from ibnex data base of
* VPPA communication services.
*/
static int
{
int i, j, nsvcs;
int len;
int match_ndx;
char **service_name;
/* find matching index */
for (i = 0; i < nsvcs; i++) {
continue;
match_ndx = i;
break;
}
/* check for valid "nsvcs" */
return (EIO);
}
/* Check if service is in use; return failure if so */
node_datap->node_dip) {
return (EIO);
}
}
/* if nsvcs == 1, bailout early */
if (nsvcs == 1) {
/* free up that single entry */
return (0);
}
/* Allocate space for new "ibnex.ibnex_nvppa_comm_svcs - 1" */
/*
* Copy over the existing "ibnex.ibnex_vppa_comm_svc_names"
* array. Do not copy over the matching service.
*/
for (i = 0, j = 0; i < nsvcs; i++) {
if (i == match_ndx) {
/* free up that entry */
continue;
}
}
/* Replace existing pointer to VPPA services w/ newly adjusted one */
if (ibnex.ibnex_vppa_comm_svc_names) {
sizeof (char *));
}
return (0);
}
/*
* ibnex_port_conf_entry_delete()
* Delete an existing service entry from ibnex data base of
* Port communication services.
*/
static int
{
int i, j, nsvcs;
int match_ndx;
int len;
char **service_name;
/* find matching index */
for (i = 0; i < nsvcs; i++) {
continue;
match_ndx = i;
break;
}
/* check for valid "nsvcs" */
return (EIO);
}
/* Check if service is in use; return failure if so */
return (EIO);
}
/* if nsvcs == 1, bailout early */
if (nsvcs == 1) {
/* free up that single entry */
ibnex.ibnex_num_comm_svcs = 0;
return (0);
}
/* Allocate space for new "ibnex.ibnex_num_comm_svcs - 1" */
/*
* Copy over the existing "ibnex.ibnex_comm_svc_names" array.
* Skip the matching service.
*/
for (i = 0, j = 0; i < nsvcs; i++) {
if (i == match_ndx) {
/* free up that entry */
continue;
}
}
/* Replace existing pointer to Port services w/ newly adjusted one */
if (ibnex.ibnex_comm_svc_names) {
}
return (0);
}
/*
* ibnex_hcasvc_conf_entry_delete()
* Delete an existing service entry from ibnex data base of
* HCA_SVC communication services.
*/
static int
{
int i, j, nsvcs;
int len;
int match_ndx;
char **service_name;
/* find matching index */
for (i = 0; i < nsvcs; i++) {
continue;
match_ndx = i;
break;
}
/* check for valid "nsvcs" */
return (EIO);
}
/* Check if service is in use; return failure if so */
node_datap->node_dip) {
return (EIO);
}
}
/* if nsvcs == 1, bailout early */
if (nsvcs == 1) {
/* free up that single entry */
return (0);
}
/* Allocate space for new "ibnex.ibnex_nhcasvc_comm_svcs - 1" */
/*
* Copy over the existing "ibnex.ibnex_hcasvc_comm_svc_names"
* array. Do not copy over the matching service.
*/
for (i = 0, j = 0; i < nsvcs; i++) {
if (i == match_ndx) {
/* free up that entry */
continue;
}
}
/* Replace existing pointer to VPPA services w/ newly adjusted one */
if (ibnex.ibnex_hcasvc_comm_svc_names) {
sizeof (char *));
}
return (0);
}
/*
* ibnex_ioc_fininode()
* Un-initialize a child device node for IOC device node
* Returns IBNEX_SUCCESS/IBNEX_FAILURE
*/
static ibnex_rval_t
{
int rval = MDI_SUCCESS;
/*
* For a dis-connected IOC,
* Free the ioc_profile &&
* decrement ibnex_num_disconnect_iocs
*/
sizeof (ib_dm_ioc_ctrl_profile_t));
}
if (rval != MDI_SUCCESS) {
rval = NDI_FAILURE;
}
}
int
{
int rval = MDI_SUCCESS;
return (MDI_FAILURE);
}
"offling path %p", path);
if (rval != MDI_SUCCESS) {
"mdi_pi_offline failed %p", dip);
break;
}
(void) mdi_pi_free(temp, 0);
}
return (rval);
}
/*
* ibnex_commsvc_fininode()
*
* Un-initialize a child device node for HCA port / node GUID
* for a communication service.
* Returns IBNEX_SUCCESS/IBNEX_FAILURE
*/
static ibnex_rval_t
{
int rval = NDI_SUCCESS;
/*
* if the child hasn't been bound yet, we can
* just free the dip. This path is currently
* untested.
*/
(void) ddi_remove_child(dip, 0);
IBTF_DPRINTF_L4("ibnex",
"\tcommsvc_fininode: ddi_remove_child");
} else {
"Commsvc node");
if (rval != NDI_SUCCESS)
}
}
/*
* ibnex_pseudo_fininode()
* Un-initialize a child pseudo device node
* Returns IBNEX_SUCCESS/IBNEX_FAILURE
*/
static ibnex_rval_t
{
int rval = MDI_SUCCESS;
"pseudo device");
if (rval != MDI_SUCCESS) {
rval = NDI_FAILURE;
}
}