Path: blob/master/drivers/infiniband/hw/amso1100/c2_cm.c
15112 views
/*1* Copyright (c) 2005 Ammasso, Inc. All rights reserved.2* Copyright (c) 2005 Open Grid Computing, Inc. All rights reserved.3*4* This software is available to you under a choice of one of two5* licenses. You may choose to be licensed under the terms of the GNU6* General Public License (GPL) Version 2, available from the file7* COPYING in the main directory of this source tree, or the8* OpenIB.org BSD license below:9*10* Redistribution and use in source and binary forms, with or11* without modification, are permitted provided that the following12* conditions are met:13*14* - Redistributions of source code must retain the above15* copyright notice, this list of conditions and the following16* disclaimer.17*18* - Redistributions in binary form must reproduce the above19* copyright notice, this list of conditions and the following20* disclaimer in the documentation and/or other materials21* provided with the distribution.22*23* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,24* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF25* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND26* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS27* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN28* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN29* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE30* SOFTWARE.31*32*/33#include <linux/slab.h>3435#include "c2.h"36#include "c2_wr.h"37#include "c2_vq.h"38#include <rdma/iw_cm.h>3940int c2_llp_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)41{42struct c2_dev *c2dev = to_c2dev(cm_id->device);43struct ib_qp *ibqp;44struct c2_qp *qp;45struct c2wr_qp_connect_req *wr; /* variable size needs a malloc. */46struct c2_vq_req *vq_req;47int err;4849ibqp = c2_get_qp(cm_id->device, iw_param->qpn);50if (!ibqp)51return -EINVAL;52qp = to_c2qp(ibqp);5354/* Associate QP <--> CM_ID */55cm_id->provider_data = qp;56cm_id->add_ref(cm_id);57qp->cm_id = cm_id;5859/*60* only support the max private_data length61*/62if (iw_param->private_data_len > C2_MAX_PRIVATE_DATA_SIZE) {63err = -EINVAL;64goto bail0;65}66/*67* Set the rdma read limits68*/69err = c2_qp_set_read_limits(c2dev, qp, iw_param->ord, iw_param->ird);70if (err)71goto bail0;7273/*74* Create and send a WR_QP_CONNECT...75*/76wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);77if (!wr) {78err = -ENOMEM;79goto bail0;80}8182vq_req = vq_req_alloc(c2dev);83if (!vq_req) {84err = -ENOMEM;85goto bail1;86}8788c2_wr_set_id(wr, CCWR_QP_CONNECT);89wr->hdr.context = 0;90wr->rnic_handle = c2dev->adapter_handle;91wr->qp_handle = qp->adapter_handle;9293wr->remote_addr = cm_id->remote_addr.sin_addr.s_addr;94wr->remote_port = cm_id->remote_addr.sin_port;9596/*97* Move any private data from the callers's buf into98* the WR.99*/100if (iw_param->private_data) {101wr->private_data_length =102cpu_to_be32(iw_param->private_data_len);103memcpy(&wr->private_data[0], iw_param->private_data,104iw_param->private_data_len);105} else106wr->private_data_length = 0;107108/*109* Send WR to adapter. NOTE: There is no synch reply from110* the adapter.111*/112err = vq_send_wr(c2dev, (union c2wr *) wr);113vq_req_free(c2dev, vq_req);114115bail1:116kfree(wr);117bail0:118if (err) {119/*120* If we fail, release reference on QP and121* disassociate QP from CM_ID122*/123cm_id->provider_data = NULL;124qp->cm_id = NULL;125cm_id->rem_ref(cm_id);126}127return err;128}129130int c2_llp_service_create(struct iw_cm_id *cm_id, int backlog)131{132struct c2_dev *c2dev;133struct c2wr_ep_listen_create_req wr;134struct c2wr_ep_listen_create_rep *reply;135struct c2_vq_req *vq_req;136int err;137138c2dev = to_c2dev(cm_id->device);139if (c2dev == NULL)140return -EINVAL;141142/*143* Allocate verbs request.144*/145vq_req = vq_req_alloc(c2dev);146if (!vq_req)147return -ENOMEM;148149/*150* Build the WR151*/152c2_wr_set_id(&wr, CCWR_EP_LISTEN_CREATE);153wr.hdr.context = (u64) (unsigned long) vq_req;154wr.rnic_handle = c2dev->adapter_handle;155wr.local_addr = cm_id->local_addr.sin_addr.s_addr;156wr.local_port = cm_id->local_addr.sin_port;157wr.backlog = cpu_to_be32(backlog);158wr.user_context = (u64) (unsigned long) cm_id;159160/*161* Reference the request struct. Dereferenced in the int handler.162*/163vq_req_get(c2dev, vq_req);164165/*166* Send WR to adapter167*/168err = vq_send_wr(c2dev, (union c2wr *) & wr);169if (err) {170vq_req_put(c2dev, vq_req);171goto bail0;172}173174/*175* Wait for reply from adapter176*/177err = vq_wait_for_reply(c2dev, vq_req);178if (err)179goto bail0;180181/*182* Process reply183*/184reply =185(struct c2wr_ep_listen_create_rep *) (unsigned long) vq_req->reply_msg;186if (!reply) {187err = -ENOMEM;188goto bail1;189}190191if ((err = c2_errno(reply)) != 0)192goto bail1;193194/*195* Keep the adapter handle. Used in subsequent destroy196*/197cm_id->provider_data = (void*)(unsigned long) reply->ep_handle;198199/*200* free vq stuff201*/202vq_repbuf_free(c2dev, reply);203vq_req_free(c2dev, vq_req);204205return 0;206207bail1:208vq_repbuf_free(c2dev, reply);209bail0:210vq_req_free(c2dev, vq_req);211return err;212}213214215int c2_llp_service_destroy(struct iw_cm_id *cm_id)216{217218struct c2_dev *c2dev;219struct c2wr_ep_listen_destroy_req wr;220struct c2wr_ep_listen_destroy_rep *reply;221struct c2_vq_req *vq_req;222int err;223224c2dev = to_c2dev(cm_id->device);225if (c2dev == NULL)226return -EINVAL;227228/*229* Allocate verbs request.230*/231vq_req = vq_req_alloc(c2dev);232if (!vq_req)233return -ENOMEM;234235/*236* Build the WR237*/238c2_wr_set_id(&wr, CCWR_EP_LISTEN_DESTROY);239wr.hdr.context = (unsigned long) vq_req;240wr.rnic_handle = c2dev->adapter_handle;241wr.ep_handle = (u32)(unsigned long)cm_id->provider_data;242243/*244* reference the request struct. dereferenced in the int handler.245*/246vq_req_get(c2dev, vq_req);247248/*249* Send WR to adapter250*/251err = vq_send_wr(c2dev, (union c2wr *) & wr);252if (err) {253vq_req_put(c2dev, vq_req);254goto bail0;255}256257/*258* Wait for reply from adapter259*/260err = vq_wait_for_reply(c2dev, vq_req);261if (err)262goto bail0;263264/*265* Process reply266*/267reply=(struct c2wr_ep_listen_destroy_rep *)(unsigned long)vq_req->reply_msg;268if (!reply) {269err = -ENOMEM;270goto bail0;271}272if ((err = c2_errno(reply)) != 0)273goto bail1;274275bail1:276vq_repbuf_free(c2dev, reply);277bail0:278vq_req_free(c2dev, vq_req);279return err;280}281282int c2_llp_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *iw_param)283{284struct c2_dev *c2dev = to_c2dev(cm_id->device);285struct c2_qp *qp;286struct ib_qp *ibqp;287struct c2wr_cr_accept_req *wr; /* variable length WR */288struct c2_vq_req *vq_req;289struct c2wr_cr_accept_rep *reply; /* VQ Reply msg ptr. */290int err;291292ibqp = c2_get_qp(cm_id->device, iw_param->qpn);293if (!ibqp)294return -EINVAL;295qp = to_c2qp(ibqp);296297/* Set the RDMA read limits */298err = c2_qp_set_read_limits(c2dev, qp, iw_param->ord, iw_param->ird);299if (err)300goto bail0;301302/* Allocate verbs request. */303vq_req = vq_req_alloc(c2dev);304if (!vq_req) {305err = -ENOMEM;306goto bail0;307}308vq_req->qp = qp;309vq_req->cm_id = cm_id;310vq_req->event = IW_CM_EVENT_ESTABLISHED;311312wr = kmalloc(c2dev->req_vq.msg_size, GFP_KERNEL);313if (!wr) {314err = -ENOMEM;315goto bail1;316}317318/* Build the WR */319c2_wr_set_id(wr, CCWR_CR_ACCEPT);320wr->hdr.context = (unsigned long) vq_req;321wr->rnic_handle = c2dev->adapter_handle;322wr->ep_handle = (u32) (unsigned long) cm_id->provider_data;323wr->qp_handle = qp->adapter_handle;324325/* Replace the cr_handle with the QP after accept */326cm_id->provider_data = qp;327cm_id->add_ref(cm_id);328qp->cm_id = cm_id;329330cm_id->provider_data = qp;331332/* Validate private_data length */333if (iw_param->private_data_len > C2_MAX_PRIVATE_DATA_SIZE) {334err = -EINVAL;335goto bail1;336}337338if (iw_param->private_data) {339wr->private_data_length = cpu_to_be32(iw_param->private_data_len);340memcpy(&wr->private_data[0],341iw_param->private_data, iw_param->private_data_len);342} else343wr->private_data_length = 0;344345/* Reference the request struct. Dereferenced in the int handler. */346vq_req_get(c2dev, vq_req);347348/* Send WR to adapter */349err = vq_send_wr(c2dev, (union c2wr *) wr);350if (err) {351vq_req_put(c2dev, vq_req);352goto bail1;353}354355/* Wait for reply from adapter */356err = vq_wait_for_reply(c2dev, vq_req);357if (err)358goto bail1;359360/* Check that reply is present */361reply = (struct c2wr_cr_accept_rep *) (unsigned long) vq_req->reply_msg;362if (!reply) {363err = -ENOMEM;364goto bail1;365}366367err = c2_errno(reply);368vq_repbuf_free(c2dev, reply);369370if (!err)371c2_set_qp_state(qp, C2_QP_STATE_RTS);372bail1:373kfree(wr);374vq_req_free(c2dev, vq_req);375bail0:376if (err) {377/*378* If we fail, release reference on QP and379* disassociate QP from CM_ID380*/381cm_id->provider_data = NULL;382qp->cm_id = NULL;383cm_id->rem_ref(cm_id);384}385return err;386}387388int c2_llp_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len)389{390struct c2_dev *c2dev;391struct c2wr_cr_reject_req wr;392struct c2_vq_req *vq_req;393struct c2wr_cr_reject_rep *reply;394int err;395396c2dev = to_c2dev(cm_id->device);397398/*399* Allocate verbs request.400*/401vq_req = vq_req_alloc(c2dev);402if (!vq_req)403return -ENOMEM;404405/*406* Build the WR407*/408c2_wr_set_id(&wr, CCWR_CR_REJECT);409wr.hdr.context = (unsigned long) vq_req;410wr.rnic_handle = c2dev->adapter_handle;411wr.ep_handle = (u32) (unsigned long) cm_id->provider_data;412413/*414* reference the request struct. dereferenced in the int handler.415*/416vq_req_get(c2dev, vq_req);417418/*419* Send WR to adapter420*/421err = vq_send_wr(c2dev, (union c2wr *) & wr);422if (err) {423vq_req_put(c2dev, vq_req);424goto bail0;425}426427/*428* Wait for reply from adapter429*/430err = vq_wait_for_reply(c2dev, vq_req);431if (err)432goto bail0;433434/*435* Process reply436*/437reply = (struct c2wr_cr_reject_rep *) (unsigned long)438vq_req->reply_msg;439if (!reply) {440err = -ENOMEM;441goto bail0;442}443err = c2_errno(reply);444/*445* free vq stuff446*/447vq_repbuf_free(c2dev, reply);448449bail0:450vq_req_free(c2dev, vq_req);451return err;452}453454455