/*
* 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
*/
/*
*/
/*
*
* This file contains the IBTF module's initialization and
*/
/*
* Globals.
*/
/*
* ibtl_clnt_list:
*
* Head of the list of IBT Client Instances. The IBT Client List
* is modified by IBTF on an IBT client's ibt_attach/ibt_detach call.
*
* ibtl_hca_list:
*
* Head of the list of HCA devices. The HCA List is modified by IBTF on
* a CI's ibc_attach/ibc_detach call.
* The datap of the list elements points to an ibtl_hca_devinfo_s
* structure.
*
* (ibc_attach)
* ibtl_hca_list -> ibtl_hca_devinfo_t--> ... -->ibtl_hca_devinfo_t
* [per-hca_dev] | ^ {nth HCA Dev}
* | |
* | ibtl_hca_t (ibt_open_hca)
* | ^ |
* | | |
* v | V
* ibtl_clnt_list -> ibtl_clnt_t--> ...--> {n'th Module}
* [per-client_instance] (ibt_attach)
*
*/
/* Global List of IBT Client Instances, and associated mutex. */
/* Lock for the race between the client and CM to free QPs. */
/* Lock for the race between the client closing the HCA and QPN being freed. */
/* Global List of HCA Devices, and associated mutex. */
/* Well-known async handlers and associated client private. */
void *ibtl_cm_clnt_private;
void *ibtl_dm_clnt_private;
void *ibtl_ibma_clnt_private;
extern int ib_hw_status;
/*
* Misc Module Declarations.
*/
extern struct mod_ops mod_miscops;
&mod_miscops, /* Type of module - misc. */
"IB Transport Layer" /* Name of the Module. */
};
};
static void ibtl_kstat_init(ibtl_hca_devinfo_t *);
static void ibtl_kstat_fini(ibtl_hca_devinfo_t *);
extern kmutex_t ibtl_part_attr_mutex;
/*
* IBTF Loadable Module Routines.
*/
int
_init(void)
{
int rval;
return (rval);
/*
* initialize IBTL ib2usec table
*/
/*
* Initialize Logging
*/
/*
* Initialize the Alloc QP States.
*/
/*
* Initialize all Global Link Lists.
*/
return (rval);
}
int
_fini(void)
{
int rval;
return (rval);
}
/*
* Stop Logging
*/
return (rval);
}
int
{
/* Return the Module Information. */
}
/*
* IBTF Client Registration Routines.
*/
/*
* Function:
* ibt_attach
* Input:
* modinfop - Client Module info structure.
* arg - usually client's dip
* clnt_private - client's private data pointer.
* Output:
* ibt_hdl_p - pointer to client's specific IBT handle,
* which is opaque to clients.
* Returns:
* IBT_SUCCESS
* IBT_INVALID_PARAM
* Called by:
* IBTF Client module during its attach() to register its instance
* to IBTF.
* Description:
* Registers the IBTF client module instance and returns an opaque
* handler to the client to be used for future calls to IBTF.
* Adds this client module instance to ibtl_clnt_list list.
* Records well-known async handlers.
*/
{
"IB client needs to specify its name");
return (IBT_INVALID_PARAM);
}
/*
* Validate the Transport API version.
*/
return (IBT_NOT_SUPPORTED);
}
" provided an Asynchronous Event Handler.\n"
" This will be required soon.",
}
/*
* Check out Client's Class information. If it is not of mgmt class,
* we expect 'arg' to be Not NULL and point to client driver's
* device info struct.
*/
"arg not set with driver's dip.");
return (IBT_INVALID_PARAM);
}
"client %s is not a child of IB nexus driver.",
return (IBT_INVALID_PARAM);
}
}
if (ibtl_cm_async_handler != NULL) {
"CM is already attached.");
return (IBT_INVALID_PARAM);
}
if (ibtl_dm_async_handler != NULL) {
"DM is already attached.");
return (IBT_INVALID_PARAM);
}
if (ibtl_ibma_async_handler != NULL) {
"IBMF is already attached.");
return (IBT_INVALID_PARAM);
}
}
/* Allocate the memory for per-client-device info structure */
/* Update the Client info structure */
clntp->clnt_async_cnt = 0;
/* using a count of 7 below guarantees it is NULL terminated */
/*
* Update Client Device Instance List.
*/
/*
* The ibt_hdl_p is a opaque handle which is the address of
* ibt_clnt_t structure passed back to the clients.
* The client will pass on this handle in its future calls to IBTF.
*/
return (IBT_SUCCESS);
}
/*
* Function:
* ibt_detach
* Input:
* ibt_hdl - IBT Handle as returned during ibt_attach call.
* Output:
* none
* Returns:
* IBT_SUCCESS
* IBT_INVALID_PARAM.
* Called by:
* IBTF Client module during its detach() to de-register its instance
* from IBTF.
* Description:
* Deregisters the IBTF client module instance from the IBTF.
* All resources and any reference to this ibt_hdl will be removed.
*/
{
clntpp = &ibtl_clnt_list;
break;
ibt_hdl);
return (IBT_INVALID_PARAM);
}
/*
* Check out whether the client has freed all its resources.
* If not done, then fail the detach.
*
* viz. A client has to close all the HCA they have opened,
* i.e. the HCA List maintained for clients has to be empty.
* If this list is not empty, then the client has not performed
* complete clean-up, so fail the detach.
*/
"ERROR: Client '%s' has not closed all of its HCAs",
"freed by client '%s'\n",
return (IBT_HCA_RESOURCES_NOT_FREED);
}
if (ibt_hdl->clnt_srv_cnt != 0) {
"services or subnet_notices registered",
"freed by client '%s'\n",
return (IBT_HCA_RESOURCES_NOT_FREED);
}
/*
* Delete the entry of this module from the ibtl_clnt_list List.
*/
/* make sure asyncs complete before freeing */
}
/* Free up the memory of per-client info struct. */
return (IBT_SUCCESS);
}
static void
{
ib_hw_status++;
}
static void
{
ib_hw_status--;
}
/*
* Function:
* ibc_init
* Input:
* modlp - Pointer to IBC client module linkage structure
* Output:
* None
* Returns:
* 0 always for now
* Called by:
* CI client calls IBTF during its _init() to register HCA with
* Solaris I/O framework.
* Description:
* Initializes the CI clients module linkage structure with
* default bus_ops structure
*/
int
{
if (ibtl_ibnex_callback_routine) {
(void) ((*ibtl_ibnex_callback_routine)(&cb_args));
}
return (0);
}
/*
* Function:
* ibc_fini
* Input:
* modlp - Pointer to IBC client module linkage structure
* Output:
* None
* Returns:
* None
* Called by:
* CI client calls IBTF during its _fini() to remove HCA with
* Solaris I/O framework.
* Description:
* Undo what is done during ibc_init
*/
void
{
if (ibtl_ibnex_callback_routine) {
(void) ((*ibtl_ibnex_callback_routine)(&cb_args));
}
}
/*
* Function:
* ibc_attach
* Input:
* info_p - IBC HCA Info.
* Output:
* ibc_hdl_p - IBC Client's HCA Handle.
* Returns:
* IBC_SUCCESS
* IBC_FAILURE
* Called by:
* CI calls IBTF during its attach() to register HCA Device with IBTF.
* Description:
* Registers the presence of HCA device by providing the HCA device info
* structure and provides an opaque HCA handler for future calls to this
* HCA device.
*/
{
/* Validate the Transport API version */
return (IBC_FAILURE);
}
"HCA Attributes must be specified.");
return (IBC_FAILURE);
}
if (nports == 0) {
"Number of ports must be valid");
return (IBC_FAILURE);
}
"Number of Partitions must be at least 1");
return (IBC_FAILURE);
}
"HCA driver must support QP current state checking");
return (IBC_FAILURE);
}
"HCA driver must support PORT_UP async events");
return (IBC_FAILURE);
}
/*
* Install IB nexus driver (if not installed already)
*/
return (IBC_FAILURE);
}
/* Allocate the memory for per-client info structure */
/* Update HCA dev info structure */
if (status != IBT_SUCCESS) {
"failed: status = %d", status);
return (IBC_FAILURE);
}
/* Register the with MPxIO as PHCI */
return (IBC_FAILURE);
}
/* Initialize the Client List for this HCA. */
/* lock out asyncs until after we announce the new HCA */
/* init portinfo locking variables */
/*
* The ibc_hdl_p points to an opaque handle which is the address
* of ibt_hca_devinfo_t structure passed back to the CI.
* The CI will pass on this handle in its future upcalls to IBTF.
*/
return (IBC_SUCCESS);
}
/*
* Function:
* ibc_post_attach
* Input:
* ibc_hdl - IBC Client's HCA Handle.
* Returns:
* none
* Called by:
* CI calls IBTF during its attach() after a successful ibc_attach().
* Description:
* Announces to all known clients the existence of this HCA (by GUID).
*/
void
{
/*
* Update the HCA Device List.
*/
/* notify all IBT Client Device Instances of the new HCA Device */
}
/*
* Function:
* ibc_pre_detach
* Input:
* ibc_clnt_hdl - IBC HCA Handle as returned during ibc_attach call.
* cmd - DDI_DETACH/DDI_SUSPEND command.
* Output:
* none
* Returns:
* IBC_SUCCESS
* IBC_FAILURE.
* Called by:
* CI to try to get all IBTF clients to close the HCA device.
* Description:
* Attempts to deregister the HCA device entry from the IBTF.
* If all resources are freed by the IBTF clients and this HCA
* is closed, then IBC_SUCCESS is returned.
*/
{
/*
* Return failure, if command is not DDI_DETACH
*/
switch (cmd) {
case DDI_DETACH:
break;
default:
return (IBC_FAILURE); /* TBD: DDI_FAILURE */
}
/* Make sure this HCA is on the HCA Device List. */
break;
}
return (IBC_FAILURE);
}
/*
* Initially set the state to "Detaching".
*/
/*
* Try to detach all IBTI clients, and continue only if all
* of the detaches succeed.
*/
if (ibtl_detach_all_clients(hca_devp)) {
return (IBC_FAILURE);
}
/*
* Check to see if all clients closed this HCA, or not.
* We only succeed if all clients cooperated.
*/
"clients");
return (IBC_FAILURE);
}
/*
* mark this device as detached
*/
/* Delete the entry for this hca_devp from hca_head_list */
hcapp = &ibtl_hca_list;
break;
}
return (IBC_FAILURE);
}
return (IBC_FAILURE);
}
return (IBC_SUCCESS);
}
/*
* Function:
* ibc_detach
* Input:
* ibc_clnt_hdl - IBC HCA Handle as returned during ibc_attach call.
* Output:
* none
* Returns:
* None
* Called by:
* CI to detach the HCA device from IBTF.
* Description:
* Do the second step of detaching the HCA, which is required
* after a successful ibc_pre_detach.
*/
void
{
"pre-detached");
return;
}
/* Free up the memory of per-client info struct */
sizeof (ibtl_async_port_event_t));
}
/*
* Function:
* ibt_ci_data_in()
*
* Input:
* hca_hdl HCA Handle.
* flags IBT_COMPLETE_ALLOC - Finish a deferred alloc.
* object Identifies the type object pointed to by
* ibt_object_handle.
*
* ibt_object_handle The handle of the object to be associated with
*
* data_p Pointer data passed in to the CI. The buffer
* should be allocated by the caller.
*
* data_sz The size of the buffer pointed to by
* data_p.
* Output:
*
* Returns:
* IBT_SUCCESS
* IBT_NOT_SUPPORTED Feature not supported.
* IBT_INVALID_PARAM Invalid object type specified.
* IBT_HCA_HDL_INVALID
* IBT_CQ_HDL_INVALID
* IBT_EEC_HDL_INVALID
* IBT_RDD_HDL_INVALID
* IBT_MW_HDL_INVALID
* IBT_PD_HDL_INVALID
* IBT_SRQ_HDL_INVALID
*
* Description:
* Exchange CI private data for the specified CI object.
*/
{
void *ci_obj_hdl;
switch (object) {
case IBT_HDL_HCA:
ci_obj_hdl = (void *)
break;
case IBT_HDL_CHANNEL:
ci_obj_hdl = (void *)
break;
case IBT_HDL_CQ:
ci_obj_hdl = (void *)
break;
case IBT_HDL_EEC:
ci_obj_hdl = (void *)
break;
case IBT_HDL_UD_DEST:
ci_obj_hdl = (void *)
break;
case IBT_HDL_SRQ:
ci_obj_hdl = (void *)
break;
default:
break;
}
if (retval != IBT_SUCCESS) {
}
return (retval);
}
/*
* Function:
* ibt_ci_data_out()
*
* Input:
* hca_hdl HCA Handle.
* flags IBT_COMPLETE_ALLOC - Finish a deferred alloc.
* object Identifies the type object pointed to by
* ibt_object_handle.
*
* ibt_object_handle The handle of the object to be associated with
*
* data_p Pointer to a buffer in which to return the CI
* private data. The buffer should be allocated
* by the caller.
*
* data_sz The size of the buffer pointed to by
* data_p.
* Output:
*
* Returns:
* IBT_SUCCESS
* IBT_NOT_SUPPORTED Feature not supported.
* IBT_INSUFF_RESOURCE The buffer pointed to by data_p was too
* small to hold the data.
* IBT_INVALID_PARAM Invalid object type specified.
* IBT_HCA_HDL_INVALID
* IBT_CQ_HDL_INVALID
* IBT_EEC_HDL_INVALID
* IBT_RDD_HDL_INVALID
* IBT_MW_HDL_INVALID
* IBT_PD_HDL_INVALID
* IBT_SRQ_HDL_INVALID
*
* Description:
* Exchange CI private data for the specified CI object.
*/
{
void *ci_obj_hdl;
switch (object) {
case IBT_HDL_HCA:
ci_obj_hdl = (void *)
break;
case IBT_HDL_CHANNEL:
ci_obj_hdl = (void *)
break;
case IBT_HDL_CQ:
ci_obj_hdl = (void *)
break;
case IBT_HDL_EEC:
ci_obj_hdl = (void *)
break;
case IBT_HDL_UD_DEST:
ci_obj_hdl = (void *)
break;
case IBT_HDL_SRQ:
ci_obj_hdl = (void *)
break;
default:
break;
}
if (retval != IBT_SUCCESS) {
}
return (retval);
}
/*
* FMA Support functions.
*/
/*
* Function:
* ibt_get_module_failure()
*
* Input:
* type Identifies the failing IB module.
* ena '0' or the data for Fault Management
* Architecture (ENA).
*
* Returns:
* status Special IB failure status.
*
* Description:
* XXX Just stubbed out to return failures with no data for Fault
* Management Architecture (ENAs) at the moment XXX
*/
{
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:
break;
default:
ret = IBT_FAILURE;
}
return (ret);
}
/*
* Function:
* ibc_get_ci_failure()
*
* Input:
* ena '0' or the data for Fault Management
* Architecture (ENA).
*
* Returns:
* status Special CI failure status.
*
* Description:
* Just use the function above to do the job.
*/
{
}
/*
* ibt_check_failure()
* Function to test for special case failures.
*
* status An ibt_status_t returned from an IBTF function call.
*
* reserved_p NULL, or a pointer to where we store the data for
* Fault Management Architecture (ENA).
*
* Description:
* XXX Still need to determine the data for Fault Management Architecture
* (ENA), using 0 for now XXX
*/
{
/* XXX Need more work here... */
if (reserved_p != NULL)
*reserved_p = 0;
} else {
if (reserved_p != NULL)
*reserved_p = 0; /* No FMA Data Available. */
}
return (type);
}
/*
* Initialize and create kstats.
*
* We create the following kstats on all ports of the HCA:
* <hca_driver_name><instance_number>/port<port_num>/stats
* <hca_driver_name><instance_number>/port<port_num>/pkeys
*/
static void
{
int i;
sizeof (ibtl_hca_port_kstat_t) * nports;
}
}
/*
* Delete kstats on all ports of the HCA.
*/
static void
{
int i;
return;
if (pks->pks_stats_ksp)
if (pks->pks_pkeys_ksp) {
}
}
}
/*
* Update "stats" kstat.
* Called by kstat framework.
*/
static int
{
if (rw == KSTAT_WRITE)
return (EACCES);
/*
* Update the link_state kstat using the value from portinfo cache.
*/
return (0);
}
/*
* Create "stats" kstat for the specified HCA port in the form:
* <hca_driver_name><instance_number>/port<port_num>/stats
* At preset it contains only one named data of "link_state"
*/
static void
{
char *drv_name;
int drv_instance;
"ibtl_kstat_stats_create: kstat_create() failed");
return;
}
/* Install the kstat */
}
/*
* Update "pkeys" kstat.
*
* Called by kstat framework. Since ks_lock was set to ibtl_clnt_list_mutex
* at the time of the kstat creation, kstat framework will hold this lock
* while calling this function.
*/
static int
{
#ifndef __lock_lint
#endif
if (rw == KSTAT_WRITE)
return (EACCES);
/*
* Point kstat data to the pkey table in the portinfo cache.
*/
return (0);
}
/*
* Create "pkeys" kstat for the specified HCA port in the form:
* <hca_driver_name><instance_number>/port<port_num>/pkeys
*
* Currently kstat framework allows only some fixed data types as named
* data components under a named kstat. Due to this limitation it is not
* possible to add "pkeys" as a named data under the "stats" kstat.
*/
static void
{
char *drv_name;
int drv_instance;
"ibtl_kstat_pkeys_create: kstat_create() failed");
return;
}
/*
* We just go with the default_kstat_snapshot().
* So there is no need to set ks_snapshot field.
*/
/* Install the kstat */
}