sol_kverbs.c revision c0dd49bdd68c0d758a67d56f07826f3b45cfc664
/*
* 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
*/
/*
*/
/* Solaris Open Fabric kernel verbs */
static void *statep;
char *sol_kverbs_dbg_str = "sol_kverbs";
/*
* set ibt_client_t members. clnt->ib_client must be set before
* this func is called.
*/
static int
{
int namelen;
"alloc_ibt_client: client: 0x%p", clnt);
/*
* double-check the name string. if it's longer than MAXNAMELEN
* including the string terminator, assuming the name is invalid,
* return EINVAL.
*/
if (namelen >= MAXNAMELEN) {
"alloc_ibt_client: client: 0x%p => "
return (-EINVAL);
}
"alloc_ibt_client: client: 0x%p => "
"no sufficient memory", clnt);
return (-ENOMEM);
}
} else {
}
return (0);
}
static void
{
"free_ibt_client: client: 0x%p", clnt);
}
/*
* get_device() returns a pointer to struct ib_devcie with
* the same guid as one passed to the function.
*/
static ib_device_t *
{
"get_device: client: 0x%p, guid:0x%p",
return (device);
}
}
"get_device: client: 0x%p, guid:0x%p => no match guid",
return (NULL);
}
/*
* ofs_async_handler() is a delegated function to handle asynchrnonous events,
*/
static void
{
"ofs_async_handler: client: 0x%p, hca_hdl: 0x%p, code:0x%x, "
"event->qp: 0x%p, event->cq: 0x%p, event->srq: 0x%p "
"event->guid: 0x%p, event->port: 0x%x",
switch (code) {
case IBT_EVENT_PATH_MIGRATED:
return;
case IBT_EVENT_SQD:
return;
case IBT_EVENT_COM_EST:
return;
return;
return;
return;
return;
case IBT_EVENT_EMPTY_CHAN:
return;
case IBT_ERROR_CQ:
return;
case IBT_HCA_ATTACH_EVENT:
{
int rtn;
/* re-use the device once it was created */
/* add this HCA */
ofs_client->hca_num++;
}
device->local_dma_lkey = 0;
device->phys_port_cnt = 0;
/* open this HCA */
if (rtn == IBT_SUCCESS) {
if (rtn != IBT_SUCCESS) {
return;
}
/* invoke client's callback */
}
}
return;
}
case IBT_HCA_DETACH_EVENT:
{
/* invoke client's callback */
}
/* change the state only */
/* close this HCA */
}
return;
}
default:
"sol_ofs does not support this event(0x%x).\n"
"\t clntp=0x%p, hca_hdl=0x%p, code=%d, eventp=0x%p\n",
return;
}
}
/*
* ib_register_client - Register an IB client
* @client:Client to register
*
* Upper level users of the IB drivers can use ib_register_client() to
* register callbacks for IB device addition and removal. When an IB
* device is added, each registered client's add method will be called
* (in the order the clients were registered), and when a device is
* removed, each client's remove method will be called (in the reverse
* order that clients were registered). In addition, when
* ib_register_client() is called, the client will receive an add
* callback for all devices already registered.
*
* Note that struct ib_client should have a dip pointer to the client,
* which is different from the Linux implementation.
*/
int
{
int rtn;
"ib_register_client: client: 0x%p", client);
/* get the number of HCAs on this system */
"ib_register_client: client: 0x%p => no HCA", client);
return (-ENXIO);
}
/* allocate a new sol_ofs_client structure */
if (ofs_client == NULL) {
"ib_register_client: client: 0x%p => "
"no sufficient memory for ofs_client", client);
return (-ENOMEM);
}
/* set members */
"ib_register_client: client: 0x%p => "
return (rtn);
}
/* initialize IB client */
"ib_register_client: client: 0x%p => "
return (-EPERM);
}
/* attach this client to IBTF */
&ofs_client->ibt_hdl);
if (rtn != IBT_SUCCESS) {
"ib_register_client: client: 0x%p => "
return (-EINVAL);
}
/* link this client */
/* Open HCAs */
for (i = 0; i < ofs_client->hca_num; i++) {
/* allocate the ib_device structure */
"ib_register_client: client: 0x%p => "
"no sufficient memory for ib_device", client);
goto err;
}
if (rtn == IBT_SUCCESS) {
if (rtn != IBT_SUCCESS) {
"ib_register_client: client: 0x%p,"
"hca_hdl: 0x%p ==> "
"ibt_query_hca() failed w/ %d",
goto err;
}
/* invoke client's callback */
}
}
}
if (ofs_client->hca_open_num == 0) {
"ib_register_client: client: 0x%p => "
"no available HCA", client);
goto err;
}
return (0);
err:
/* first close all open HCAs */
/*
* If it's open already, close it after the remove
* callback.
*/
/* invoke client's callback */
}
}
}
/* then free the devices */
/* de-link and free the device */
ofs_client->hca_num--;
}
/* delink this client */
/* detach the client */
/* free sol_ofs_client */
return (rtn);
}
/*
* ib_unregister_client - Unregister an IB client
* @client:Client to unregister
*
* Upper level users use ib_unregister_client() to remove their client
* registration. When ib_unregister_client() is called, the client
* will receive a remove callback for each IB device still registered.
*/
void
{
"ib_unregister_client: client: 0x%p", client);
/* first close all open HCAs */
/*
* If it's open already, close it after the remove
* callback.
*/
/* invoke client's callback */
}
if (rtn != IBT_SUCCESS)
"ib_unregister_client(%p) - "
"ibt_close_hca failed %d",
}
}
/* then free the devices */
/* de-link and free the device */
ofs_client->hca_num--;
}
/* delink this client */
/* detach the client */
/* free sol_ofs_client */
}
/*
* ofs_lock_enter() and ofs_lock_exit() are used to avoid the recursive
* rwlock while the client callbacks are invoked.
*
* Note that the writer lock is used only in the client callback case,
* so that the kverb functions wanting to acquire the reader lock can
* safely ignore the reader lock if the writer lock is already held.
* The writer lock shouldn't be used in no other plances.
*/
static inline void
{
if (!RW_WRITE_HELD(lock)) {
}
}
static inline void
{
if (!RW_WRITE_HELD(lock)) {
}
}
/*
* ib_get_client_data - Get IB client context
* @device:Device to get context for
* @client:Client to get context for
*
* ib_get_client_data() returns client context set with
* ib_set_client_data() and returns NULL if it's not found.
*/
{
void *data;
if (ofs_client == 0) {
"ib_get_client_data: device: 0x%p, client: 0x%p => "
return (NULL);
}
break;
}
}
if (!found) {
"ib_get_client_data: device: 0x%p, client: 0x%p => "
return (NULL);
}
"ib_get_client_data: device: 0x%p, client: 0x%p",
return (data);
}
/*
* ib_set_client_data - Set IB client context
* @device:Device to set context for
* @client:Client to set context for
* @data:Context to set
*
* ib_set_client_data() sets client context that can be retrieved with
* ib_get_client_data(). If the specified device is not found, the function
* returns w/o any operations.
*/
void *data)
{
if (ofs_client == 0) {
return;
}
break;
}
}
if (!found) {
return;
}
"ib_set_client_data: device: 0x%p, client: 0x%p, "
}
/*
* ib_query_device - Query IB device attributes
* @device:Device to query
* @device_attr:Device attributes
*
* ib_query_device() returns the attributes of a device through the
* @device_attr pointer.
*/
int
{
int rtn;
"ib_query_device: device: 0x%p => "
return (-ENXIO);
}
"ib_query_device: device: 0x%p => "
return (-EIO);
}
"ib_query_device: device: 0x%p, attr: 0x%p, rtn: 0x%p",
/* OF order is major.micro.minor, so keep it here */
}
}
}
}
return (0);
}
/* Protection domains */
struct ib_pd *
{
int rtn;
"ib_alloc_pd: device: 0x%p => no sufficient memory",
device);
}
"ib_alloc_pd: device: 0x%p => invalid device state (%d)",
}
"ib_alloc_pd: device: 0x%p", device);
if (rtn == IBT_SUCCESS) {
"ib_alloc_pd: device: 0x%p, pd: 0x%p, ibt_pd: 0x%p, "
return (pd);
}
"ib_alloc_pd: device: 0x%p, pd: 0x%p, ibt_pd: 0x%p => "
switch (rtn) {
case IBT_INSUFF_RESOURCE:
case IBT_HCA_HDL_INVALID:
default:
}
}
int
{
int rtn;
"ib_dealloc_pd: pd: 0x%p => invalid device state (%d)",
return (-ENXIO);
}
"ib_dealloc_pd: pd: 0x%p", pd);
if (rtn == IBT_SUCCESS) {
"ib_dealloc_pd: pd: 0x%p, device: 0x%p, ibt_pd: 0x%p, "
return (0);
}
"ib_dealloc_pd: pd: 0x%p => ibt_free_pd failed w/ 0x%x",
switch (rtn) {
case IBT_PD_IN_USE:
return (-EBUSY);
case IBT_HCA_HDL_INVALID:
return (-EFAULT);
default:
return (-EIO);
}
}
/*
* ofs_cq_handler() is a delegated function to handle CQ events,
* which dispatches them to corresponding cq handlers registered
* with ib_create_cq().
*/
static void
{
"ofs_cq_handler: ibt_cq: 0x%p, ib_cq: 0x%p, comp_handler: 0x%p, "
if (cq->comp_handler) {
}
}
/*
* ib_create_cq - Creates a CQ on the specified device.
* @device: The device on which to create the CQ.
* @comp_handler: A user-specified callback that is invoked when a
* completion event occurs on the CQ.
* @event_handler: A user-specified callback that is invoked when an
* asynchronous event not associated with a completion occurs on the CQ.
* @cq_context: Context associated with the CQ returned to the user via
* the associated completion and event handlers.
* @cqe: The minimum size of the CQ.
* @comp_vector - Completion vector used to signal completion events.
* Must be >= 0 and < context->num_comp_vectors.
*
* Users can examine the cq structure to determine the actual CQ size.
*
* Note that comp_vector is not supported currently.
*/
struct ib_cq *
int cqe, int comp_vector)
{
int rtn;
"ib_create_cq: device: 0x%p, comp_handler: 0x%p, "
"event_handler: 0x%p, cq_context: 0x%p, cqe: 0x%x, "
"comp_vector: %d => no sufficient memory", device,
}
"ib_create_cq: device: 0x%p, comp_handler: 0x%p, "
"event_handler: 0x%p, cq_context: 0x%p, cqe: 0x%x, "
"comp_vector: %d => invalid device state (%d)", device,
}
"ib_create_cq: device: 0x%p, comp_handler: 0x%p, "
"event_handler: 0x%p, cq_context: 0x%p, cqe: 0x%x, "
if (rtn == IBT_SUCCESS) {
"ib_create_cq: device: 0x%p, cqe: 0x%x, ibt_cq: 0x%p, "
return (cq);
}
"ib_create_cq: device: 0x%p, cqe: 0x%x, ibt_cq: 0x%p => "
switch (rtn) {
case IBT_HCA_CQ_EXCEEDED:
case IBT_INVALID_PARAM:
case IBT_HCA_HDL_INVALID:
case IBT_INSUFF_RESOURCE:
default:
}
}
int
{
int rtn;
"ib_destroy_cq: cq: 0x%p => invalid device state (%d)",
return (-ENXIO);
}
"ib_destroy_cq: cq: 0x%p", cq);
/*
* if IBTL_ASYNC_PENDING is set, ibt_qp is not freed
* at this moment, but yet alive for a while. Then
* there is a possibility that this qp is used even after
* ib_destroy_cq() is called. To distinguish this case from
* others, clear ibt_qp here.
*/
if (rtn == IBT_SUCCESS) {
return (0);
}
switch (rtn) {
case IBT_CQ_BUSY:
return (-EBUSY);
case IBT_HCA_HDL_INVALID:
case IBT_CQ_HDL_INVALID:
return (-EINVAL);
default:
return (-EIO);
}
}
struct ib_qp *
{
int rtn;
/* sanity check */
"ib_create_qp: pd: 0x%p => invalid cqs "
"(send_cq=0x%p, recv_cq=0x%p)", pd,
}
/* UC, Raw IPv6 and Raw Ethernet are not supported */
"ib_create_qp: pd: 0x%p => invalid qp_type",
}
"ib_create_qp: pd: 0x%p, init_attr: 0x%p => "
}
"ib_create_qp: pd: 0x%p, init_attr: 0x%p => "
}
"ib_create_qp: pd: 0x%p, event_handler: 0x%p, qp_context: 0x%p, "
"send_cq: 0x%p, recv_cq: 0x%p, srq: 0x%p, max_send_wr: 0x%x, "
"max_recv_wr: 0x%x, max_send_sge: 0x%x, max_recv_sge: 0x%x, "
"max_inline_data: 0x%x, sq_sig_type: %d, qp_type: %d, "
"port_num: %d",
if (qp_init_attr->srq) {
}
}
switch (qp_init_attr->qp_type) {
case IB_QPT_RC:
break;
case IB_QPT_UD:
break;
case IB_QPT_SMI:
&ibt_qp);
break;
case IB_QPT_GSI:
&ibt_qp);
break;
default:
/* this should never happens */
}
if (rtn == IBT_SUCCESS) {
/* fill in ib_qp_cap w/ the real values */
/* max_inline_data is not supported */
/* fill in ib_qp */
"ib_create_qp: device: 0x%p, pd: 0x%x, init_attr: 0x%p, "
return (qp);
}
"ib_create_qp: device: 0x%p, pd: 0x%x, init_attr: 0x%p => "
qp_init_attr, rtn);
switch (rtn) {
case IBT_NOT_SUPPORTED:
case IBT_QP_SRV_TYPE_INVALID:
case IBT_CQ_HDL_INVALID:
case IBT_HCA_HDL_INVALID:
case IBT_INVALID_PARAM:
case IBT_SRQ_HDL_INVALID:
case IBT_PD_HDL_INVALID:
case IBT_HCA_SGL_EXCEEDED:
case IBT_HCA_WR_EXCEEDED:
case IBT_INSUFF_RESOURCE:
default:
}
}
int
{
int rtn;
"ib_destroy_qp: qp: 0x%p => invalid device state (%d)",
return (-ENXIO);
}
/*
* if IBTL_ASYNC_PENDING is set, ibt_qp is not freed
* at this moment, but yet alive for a while. Then
* there is a possibility that this qp is used even after
* ib_destroy_qp() is called. To distinguish this case from
* others, clear ibt_qp here.
*/
if (rtn == IBT_SUCCESS) {
return (0);
}
switch (rtn) {
case IBT_CHAN_STATE_INVALID:
case IBT_HCA_HDL_INVALID:
case IBT_QP_HDL_INVALID:
return (-EINVAL);
default:
return (-EIO);
}
}
/*
* ib_req_notify_cq - Request completion notification on a CQ.
* @cq: The CQ to generate an event for.
* @flags:
* Must contain exactly one of %IB_CQ_SOLICITED or %IB_CQ_NEXT_COMP
* to request an event on the next solicited event or next work
* completion at any type, respectively. %IB_CQ_REPORT_MISSED_EVENTS
* may also be |ed in to request a hint about missed events, as
* described below.
*
* Return Value:
* < 0 means an error occurred while requesting notification
* == 0 means notification was requested successfully, and if
* IB_CQ_REPORT_MISSED_EVENTS was passed in, then no events
* were missed and it is safe to wait for another event. In
* this case is it guaranteed that any work completions added
* to the CQ since the last CQ poll will trigger a completion
* notification event.
* > 0 is only returned if IB_CQ_REPORT_MISSED_EVENTS was passed
* in. It means that the consumer must poll the CQ again to
* make sure it is empty to avoid missing an event because of a
* race between requesting notification and an entry being
* added to the CQ. This return value means it is possible
* (but not guaranteed) that a work completion has been added
* to the CQ since the last poll without triggering a
* completion notification event.
*
* Note that IB_CQ_REPORT_MISSED_EVENTS is currently not supported.
*/
int
{
int rtn;
return (-ENXIO);
}
switch (flags & IB_CQ_SOLICITED_MASK) {
case IB_CQ_SOLICITED:
break;
case IB_CQ_NEXT_COMP:
break;
default:
/* Currently only two flags are supported */
"ib_req_notify_cq: cq: 0x%p, flag: 0x%x => invalid flag",
return (-EINVAL);
}
if (rtn == IBT_SUCCESS) {
"ib_req_notify_cq: cq: 0x%p, flag: 0x%x rtn: 0x%x",
return (0);
}
"ib_req_notify_cq: cq: 0x%p, flag: 0x%x => ibt_enable_cq_notify "
switch (rtn) {
case IBT_HCA_HDL_INVALID:
case IBT_CQ_HDL_INVALID:
return (-EINVAL);
default:
return (-EIO);
}
}
static const struct {
int valid;
[IB_QPS_RESET] = {
[IB_QPS_INIT] = {
.valid = 1,
.req_param = {
}
},
},
[IB_QPS_INIT] = {
[IB_QPS_INIT] = {
.valid = 1,
.opt_param = {
}
},
[IB_QPS_RTR] = {
.valid = 1,
.req_param = {
},
.opt_param = {
[IB_QPT_UC] = (IB_QP_ALT_PATH |
[IB_QPT_RC] = (IB_QP_ALT_PATH |
}
}
},
[IB_QPS_RTR] = {
[IB_QPS_RTS] = {
.valid = 1,
.req_param = {
[IB_QPT_UD] = IB_QP_SQ_PSN,
[IB_QPT_UC] = IB_QP_SQ_PSN,
[IB_QPT_RC] = (IB_QP_TIMEOUT |
[IB_QPT_SMI] = IB_QP_SQ_PSN,
[IB_QPT_GSI] = IB_QP_SQ_PSN,
},
.opt_param = {
[IB_QPT_UC] = (IB_QP_CUR_STATE |
[IB_QPT_RC] = (IB_QP_CUR_STATE |
}
}
},
[IB_QPS_RTS] = {
[IB_QPS_RTS] = {
.valid = 1,
.opt_param = {
[IB_QPT_UC] = (IB_QP_CUR_STATE |
[IB_QPT_RC] = (IB_QP_CUR_STATE |
}
},
[IB_QPS_SQD] = {
.valid = 1,
.opt_param = {
}
},
},
[IB_QPS_SQD] = {
[IB_QPS_RTS] = {
.valid = 1,
.opt_param = {
[IB_QPT_UC] = (IB_QP_CUR_STATE |
[IB_QPT_RC] = (IB_QP_CUR_STATE |
}
},
[IB_QPS_SQD] = {
.valid = 1,
.opt_param = {
}
}
},
[IB_QPS_SQE] = {
[IB_QPS_RTS] = {
.valid = 1,
.opt_param = {
[IB_QPT_UC] = (IB_QP_CUR_STATE |
}
}
},
[IB_QPS_ERR] = {
}
};
static inline int
{
"ib_modify_qp_is_ok: cur_state: %d, next_state: %d, "
"qp_type: %d, attr_mask: 0x%x => invalid state(1)",
return (0);
}
if (mask & IB_QP_CUR_STATE &&
"ib_modify_qp_is_ok: cur_state: %d, next_state: %d, "
"qp_type: %d, attr_mask: 0x%x => invalid state(2)",
return (0);
}
"ib_modify_qp_is_ok: cur_state: %d, next_state: %d, "
"qp_type: %d, attr_mask: 0x%x => state is not valid",
return (0);
}
"ib_modify_qp_is_ok: cur_state: %d, next_state: %d, "
"qp_type: %d, attr_mask: 0x%x => "
"required param doesn't match. req_param = 0x%x",
return (0);
}
"ib_modify_qp_is_ok: cur_state: %d, next_state: %d, "
"qp_type: %d, attr_mask: 0x%x => "
"unsupported options. req_param = 0x%x, opt_param = 0x%x",
return (0);
}
return (1);
}
static inline enum ib_qp_state
{
}
static inline ibt_tran_srv_t
{
switch (type) {
case IB_QPT_SMI:
case IB_QPT_GSI:
case IB_QPT_UD:
return (IBT_UD_SRV);
case IB_QPT_RC:
return (IBT_RC_SRV);
case IB_QPT_UC:
return (IBT_UC_SRV);
case IB_QPT_RAW_IPV6:
return (IBT_RAWIP_SRV);
case IB_QPT_RAW_ETY:
default:
return (IBT_RAWETHER_SRV);
}
}
static inline void
{
if (av->av_send_grh) {
}
}
int
{
int rtn;
"ib_modify_qp: qp: 0x%p => invalid device state (%d)",
return (-ENXIO);
}
if (rtn != IBT_SUCCESS) {
"ib_modify_qp: qp: 0x%p, hca_hdl: 0x%p => "
"ibt_query_hca() failed w/ %d",
return (-EIO);
}
/* only one thread per qp is allowed during the qp modification */
/* Get the current QP attributes first */
"ib_modify_qp: qp: 0x%p, attr: 0x%p, attr_mask: 0x%x => "
return (-EIO);
}
/* Get the current and new state for this QP */
/* Linux OF returns 0 in this case */
"ib_modify_qp: qp: 0x%p, attr: 0x%p, attr_mask: 0x%x => "
return (0);
}
/*
* Check if this modification request is supported with the new
*/
"ib_modify_qp: qp: 0x%p, attr: 0x%p, attr_mask: 0x%x => "
"invalid arguments",
return (-EINVAL);
}
/* Sanity checks */
"ib_modify_qp: qp: 0x%p, attr: 0x%p, attr_mask: 0x%x => "
"invalid attr->port_num(%d), max_nports(%d)",
return (-EINVAL);
}
if (attr_mask & IB_QP_PKEY_INDEX &&
"ib_modify_qp: qp: 0x%p, attr: 0x%p, attr_mask: 0x%x => "
"invalid attr->pkey_index(%d), max_pkey_index(%d)",
return (-EINVAL);
}
if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC &&
"ib_modify_qp: qp: 0x%p, attr: 0x%p, attr_mask: 0x%x => "
"invalid attr->max_rd_atomic(0x%x), max_rdma_out_qp(0x%x)",
return (-EINVAL);
}
if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC &&
"ib_modify_qp: qp: 0x%p, attr: 0x%p, attr_mask: 0x%x => "
"invalid attr->max_dest_rd_atomic(0x%x), "
return (-EINVAL);
}
/* copy the current setting */
/*
* Since it's already checked if the modification request matches
* modify_attr here. The current state is required if qp_state
* is RTR, but it's harmelss otherwise, so it's set always.
*/
/* Convert OF modification requests into IBTF ones */
if (cur_state == IB_QPS_RESET &&
new_state == IB_QPS_INIT) {
} else if (cur_state == IB_QPS_INIT &&
new_state == IB_QPS_RTR) {
} else if (cur_state == IB_QPS_RTR &&
new_state == IB_QPS_RTS) {
}
if (attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) {
}
if (attr_mask & IB_QP_ACCESS_FLAGS) {
}
}
}
}
if (attr_mask & IB_QP_PKEY_INDEX) {
case IB_QPT_SMI:
case IB_QPT_GSI:
case IB_QPT_UD:
break;
case IB_QPT_RC:
break;
case IB_QPT_UC:
break;
default:
/* This should never happen */
"ib_modify_qp(IB_QP_PKEY_INDEX): qp: 0x%p, "
"attr: 0x%p, attr_mask: 0x%x => "
"invalid qp->qp_type(%d)",
return (-EINVAL);
}
}
if (attr_mask & IB_QP_PORT) {
case IB_QPT_SMI:
case IB_QPT_GSI:
case IB_QPT_UD:
break;
case IB_QPT_RC:
break;
case IB_QPT_UC:
break;
default:
/* This should never happen */
"ib_modify_qp(IB_QP_PORT): qp: 0x%p, "
"attr: 0x%p, attr_mask: 0x%x => "
"invalid qp->qp_type(%d)",
return (-EINVAL);
}
}
if (attr_mask & IB_QP_QKEY) {
}
case IB_QPT_RC:
break;
case IB_QPT_UC:
break;
case IB_QPT_SMI:
case IB_QPT_GSI:
case IB_QPT_UD:
default:
/* This should never happen */
"ib_modify_qp(IB_QP_AV): qp: 0x%p, "
"attr: 0x%p, attr_mask: 0x%x => "
"invalid qp->qp_type(%d)",
return (-EINVAL);
}
}
if (attr_mask & IB_QP_PATH_MTU) {
case IB_QPT_RC:
break;
case IB_QPT_UC:
break;
case IB_QPT_SMI:
case IB_QPT_GSI:
case IB_QPT_UD:
default:
/* nothing to do */
break;
}
}
}
}
}
if (attr_mask & IB_QP_RQ_PSN) {
case IB_QPT_RC:
break;
case IB_QPT_UC:
break;
case IB_QPT_SMI:
case IB_QPT_GSI:
case IB_QPT_UD:
default:
/* nothing to do */
break;
}
}
if (attr->max_rd_atomic) {
}
}
if (attr_mask & IB_QP_ALT_PATH) {
/* Sanity checks */
if (attr->alt_port_num == 0 ||
"ib_modify_qp: qp: 0x%p, attr: 0x%p, "
"attr_mask: 0x%x => invalid attr->alt_port_num"
"(%d), max_nports(%d)",
return (-EINVAL);
}
"ib_modify_qp: qp: 0x%p, attr: 0x%p, "
"attr_mask: 0x%x => invalid attr->alt_pkey_index"
"(%d), max_port_key_index(%d)",
return (-EINVAL);
}
case IB_QPT_RC:
break;
case IB_QPT_UC:
break;
case IB_QPT_SMI:
case IB_QPT_GSI:
case IB_QPT_UD:
default:
/* This should never happen */
"ib_modify_qp(IB_QP_ALT_PATH): qp: 0x%p, "
"attr: 0x%p, attr_mask: 0x%x => "
"invalid qp->qp_type(%d)",
return (-EINVAL);
}
}
}
if (attr_mask & IB_QP_SQ_PSN) {
case IB_QPT_SMI:
case IB_QPT_GSI:
case IB_QPT_UD:
break;
case IB_QPT_RC:
break;
case IB_QPT_UC:
break;
default:
/* This should never happen */
"ib_modify_qp(IB_QP_SQ_PSN): qp: 0x%p, "
"attr: 0x%p, attr_mask: 0x%x => "
"invalid qp->qp_type(%d)",
return (-EINVAL);
}
}
/* Linux OF sets the value if max_dest_rd_atomic is not zero */
if (attr->max_dest_rd_atomic) {
}
}
if (attr_mask & IB_QP_PATH_MIG_STATE) {
flags |= IBT_CEP_SET_MIG;
case IB_QPT_RC:
break;
case IB_QPT_UC:
break;
case IB_QPT_SMI:
case IB_QPT_GSI:
case IB_QPT_UD:
default:
/* This should never happen */
"ib_modify_qp(IB_QP_PATH_MIG_STATE): qp: 0x%p, "
"attr: 0x%p, attr_mask: 0x%x => "
"invalid qp->qp_type(%d)",
return (-EINVAL);
}
}
/* IB_QP_CAP is not supported */
"ib_modify_qp: qp: 0x%p, attr: 0x%p, "
"attr_mask: 0x%x => IB_QP_CAP is not supported",
return (-EINVAL);
}
if (attr_mask & IB_QP_DEST_QPN) {
case IB_QPT_RC:
break;
case IB_QPT_UC:
break;
case IB_QPT_SMI:
case IB_QPT_GSI:
case IB_QPT_UD:
default:
/* This should never happen */
"ib_modify_qp(IB_QP_DEST_PSN): qp: 0x%p, "
"attr: 0x%p, attr_mask: 0x%x => "
"invalid qp->qp_type(%d)",
return (-EINVAL);
}
}
"ib_modify_qp: qp: 0x%p, attr: 0x%p, attr_mask: 0x%x, "
"flags: 0x%x, modify_attr: 0x%p",
/* Modify the QP attributes */
if (rtn == IBT_SUCCESS) {
return (0);
}
"ib_modify_qp: qp: 0x%p, attr: 0x%p, attr_mask: 0x%x => "
"ibt_modify_qp failed w/ %d, flags: 0x%x",
switch (rtn) {
case IBT_HCA_HDL_INVALID:
case IBT_QP_HDL_INVALID:
case IBT_QP_SRV_TYPE_INVALID:
case IBT_QP_STATE_INVALID:
case IBT_HCA_PORT_INVALID:
case IBT_PKEY_IX_ILLEGAL:
return (-EINVAL);
default:
return (-EIO);
}
}
static inline enum ib_wc_status
{
switch (status) {
case IBT_WC_LOCAL_LEN_ERR:
return (IB_WC_LOC_LEN_ERR);
case IBT_WC_LOCAL_CHAN_OP_ERR:
return (IB_WC_LOC_QP_OP_ERR);
case IBT_WC_LOCAL_PROTECT_ERR:
return (IB_WC_LOC_PROT_ERR);
case IBT_WC_WR_FLUSHED_ERR:
return (IB_WC_WR_FLUSH_ERR);
case IBT_WC_MEM_WIN_BIND_ERR:
return (IB_WC_MW_BIND_ERR);
case IBT_WC_BAD_RESPONSE_ERR:
return (IB_WC_BAD_RESP_ERR);
case IBT_WC_LOCAL_ACCESS_ERR:
return (IB_WC_LOC_ACCESS_ERR);
return (IB_WC_REM_INV_REQ_ERR);
case IBT_WC_REMOTE_ACCESS_ERR:
return (IB_WC_REM_ACCESS_ERR);
case IBT_WC_REMOTE_OP_ERR:
return (IB_WC_REM_OP_ERR);
case IBT_WC_TRANS_TIMEOUT_ERR:
return (IB_WC_RETRY_EXC_ERR);
return (IB_WC_RNR_RETRY_EXC_ERR);
case IBT_WC_SUCCESS:
default:
/* Hermon doesn't support EEC yet */
return (IB_WC_SUCCESS);
}
}
static inline enum ib_wc_opcode
{
switch (wc_type) {
case IBT_WRC_SEND:
return (IB_WC_SEND);
case IBT_WRC_RDMAR:
return (IB_WC_RDMA_READ);
case IBT_WRC_RDMAW:
return (IB_WC_RDMA_WRITE);
case IBT_WRC_CSWAP:
return (IB_WC_COMP_SWAP);
case IBT_WRC_FADD:
return (IB_WC_FETCH_ADD);
case IBT_WRC_BIND:
return (IB_WC_BIND_MW);
case IBT_WRC_RECV:
return (IB_WC_RECV);
case IBT_WRC_RECV_RDMAWI:
default:
return (IB_WC_RECV_RDMA_WITH_IMM);
}
}
static inline int
{
return (wc_flags & ~IBT_WC_CKSUM_OK);
}
static inline void
{
/* opcode can be undefined if status is not success */
}
}
/*
* ib_poll_cq - poll a CQ for completion(s)
* @cq:the CQ being polled
* @num_entries:maximum number of completions to return
* @wc:array of at least @num_entries &struct ib_wc where completions
* will be returned
*
* Poll a CQ for (possibly multiple) completions. If the return value
* is < 0, an error occurred. If the return value is >= 0, it is the
* number of completions returned. If the return value is
* non-negative and < num_entries, then the CQ was emptied.
*
* Note that three following memebers in struct ib_wc are not supported
* currently, and the values are always either 0 or NULL.
* u32 vendor_err;
* struct ib_qp *qp;
* u8 port_num;
*/
int
{
int npolled;
"ib_poll_cq: cq: 0x%p => invalid device state (%d)",
return (-ENXIO);
}
"ib_poll_cq: cq: 0x%p, num_entries: %d, wc: 0x%p, "
"ibt_cq: 0x%p, ibt_wc: 0x%p",
/* only one thread per cq is allowed during ibt_poll_cq() */
if (rtn != IBT_SUCCESS) {
break;
}
/* save this result to struct ib_wc */
}
return (npolled);
}
"ib_poll_cq: cq: 0x%p, num_entries: %d, wc: 0x%p => "
"ibt_poll_cq failed w/ %d, npolled = %d",
switch (rtn) {
case IBT_HCA_HDL_INVALID:
case IBT_CQ_HDL_INVALID:
case IBT_INVALID_PARAM:
return (-EINVAL);
default:
return (-EIO);
}
}
{
}
{
}