/*
* Copyright (c) 2004 Topspin Communications. All rights reserved.
* Copyright (c) 2005 Cisco Systems. All rights reserved.
* Copyright (c) 2005 Mellanox Technologies. All rights reserved.
* Copyright (c) 2004 Voltaire, Inc. All rights reserved.
* Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.
*
* This software is available to you under a choice of one of two
* licenses. You may choose to be licensed under the terms of the GNU
* General Public License (GPL) Version 2, available from the file
* COPYING in the main directory of this source tree, or the
* OpenIB.org BSD license below:
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above
* copyright notice, this list of conditions and the following
* disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
*/
#include <linux/delay.h>
#include <linux/gfp.h>
#include "c2.h"
#include "c2_vq.h"
#include "c2_status.h"
#define C2_MAX_ORD_PER_QP 128
#define C2_MAX_IRD_PER_QP 128
#define C2_HINT_MAKE(q_index, hint_count) (((q_index) << 16) | hint_count)
#define C2_HINT_GET_INDEX(hint) (((hint) & 0x7FFF0000) >> 16)
#define C2_HINT_GET_COUNT(hint) ((hint) & 0x0000FFFF)
#define NO_SUPPORT -1
static const u8 c2_opcode[] = {
[IB_WR_SEND] = C2_WR_TYPE_SEND,
[IB_WR_SEND_WITH_IMM] = NO_SUPPORT,
[IB_WR_RDMA_WRITE] = C2_WR_TYPE_RDMA_WRITE,
[IB_WR_RDMA_WRITE_WITH_IMM] = NO_SUPPORT,
[IB_WR_RDMA_READ] = C2_WR_TYPE_RDMA_READ,
[IB_WR_ATOMIC_CMP_AND_SWP] = NO_SUPPORT,
[IB_WR_ATOMIC_FETCH_AND_ADD] = NO_SUPPORT,
};
static int to_c2_state(enum ib_qp_state ib_state)
{
switch (ib_state) {
case IB_QPS_RESET:
return C2_QP_STATE_IDLE;
case IB_QPS_RTS:
return C2_QP_STATE_RTS;
case IB_QPS_SQD:
return C2_QP_STATE_CLOSING;
case IB_QPS_SQE:
return C2_QP_STATE_CLOSING;
case IB_QPS_ERR:
return C2_QP_STATE_ERROR;
default:
return -1;
}
}
static int to_ib_state(enum c2_qp_state c2_state)
{
switch (c2_state) {
case C2_QP_STATE_IDLE:
return IB_QPS_RESET;
case C2_QP_STATE_CONNECTING:
return IB_QPS_RTR;
case C2_QP_STATE_RTS:
return IB_QPS_RTS;
case C2_QP_STATE_CLOSING:
return IB_QPS_SQD;
case C2_QP_STATE_ERROR:
return IB_QPS_ERR;
case C2_QP_STATE_TERMINATE:
return IB_QPS_SQE;
default:
return -1;
}
}
static const char *to_ib_state_str(int ib_state)
{
static const char *state_str[] = {
"IB_QPS_RESET",
"IB_QPS_INIT",
"IB_QPS_RTR",
"IB_QPS_RTS",
"IB_QPS_SQD",
"IB_QPS_SQE",
"IB_QPS_ERR"
};
if (ib_state < IB_QPS_RESET ||
ib_state > IB_QPS_ERR)
return "<invalid IB QP state>";
ib_state -= IB_QPS_RESET;
return state_str[ib_state];
}
void c2_set_qp_state(struct c2_qp *qp, int c2_state)
{
int new_state = to_ib_state(c2_state);
pr_debug("%s: qp[%p] state modify %s --> %s\n",
__func__,
qp,
to_ib_state_str(qp->state),
to_ib_state_str(new_state));
qp->state = new_state;
}
#define C2_QP_NO_ATTR_CHANGE 0xFFFFFFFF
int c2_qp_modify(struct c2_dev *c2dev, struct c2_qp *qp,
struct ib_qp_attr *attr, int attr_mask)
{
struct c2wr_qp_modify_req wr;
struct c2wr_qp_modify_rep *reply;
struct c2_vq_req *vq_req;
unsigned long flags;
u8 next_state;
int err;
pr_debug("%s:%d qp=%p, %s --> %s\n",
__func__, __LINE__,
qp,
to_ib_state_str(qp->state),
to_ib_state_str(attr->qp_state));
vq_req = vq_req_alloc(c2dev);
if (!vq_req)
return -ENOMEM;
c2_wr_set_id(&wr, CCWR_QP_MODIFY);
wr.hdr.context = (unsigned long) vq_req;
wr.rnic_handle = c2dev->adapter_handle;
wr.qp_handle = qp->adapter_handle;
wr.ord = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
wr.ird = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
wr.sq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
wr.rq_depth = cpu_to_be32(C2_QP_NO_ATTR_CHANGE);
if (attr_mask & IB_QP_STATE) {
/* Ensure the state is valid */
if (attr->qp_state < 0 || attr->qp_state > IB_QPS_ERR) {
err = -EINVAL;
goto bail0;
}
wr.next_qp_state = cpu_to