162306a36Sopenharmony_ci/* QLogic qedr NIC Driver 262306a36Sopenharmony_ci * Copyright (c) 2015-2017 QLogic Corporation 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * This software is available to you under a choice of one of two 562306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 662306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 762306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 862306a36Sopenharmony_ci * OpenIB.org BSD license below: 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1162306a36Sopenharmony_ci * without modification, are permitted provided that the following 1262306a36Sopenharmony_ci * conditions are met: 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1562306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1662306a36Sopenharmony_ci * disclaimer. 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 1962306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2062306a36Sopenharmony_ci * disclaimer in the documentation and /or other materials 2162306a36Sopenharmony_ci * provided with the distribution. 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2462306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2562306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2662306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2762306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 2862306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 2962306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3062306a36Sopenharmony_ci * SOFTWARE. 3162306a36Sopenharmony_ci */ 3262306a36Sopenharmony_ci#include <net/ip.h> 3362306a36Sopenharmony_ci#include <net/ipv6.h> 3462306a36Sopenharmony_ci#include <net/udp.h> 3562306a36Sopenharmony_ci#include <net/addrconf.h> 3662306a36Sopenharmony_ci#include <net/route.h> 3762306a36Sopenharmony_ci#include <net/ip6_route.h> 3862306a36Sopenharmony_ci#include <net/flow.h> 3962306a36Sopenharmony_ci#include "qedr.h" 4062306a36Sopenharmony_ci#include "qedr_iw_cm.h" 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_cistatic inline void 4362306a36Sopenharmony_ciqedr_fill_sockaddr4(const struct qed_iwarp_cm_info *cm_info, 4462306a36Sopenharmony_ci struct iw_cm_event *event) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci struct sockaddr_in *laddr = (struct sockaddr_in *)&event->local_addr; 4762306a36Sopenharmony_ci struct sockaddr_in *raddr = (struct sockaddr_in *)&event->remote_addr; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci laddr->sin_family = AF_INET; 5062306a36Sopenharmony_ci raddr->sin_family = AF_INET; 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci laddr->sin_port = htons(cm_info->local_port); 5362306a36Sopenharmony_ci raddr->sin_port = htons(cm_info->remote_port); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci laddr->sin_addr.s_addr = htonl(cm_info->local_ip[0]); 5662306a36Sopenharmony_ci raddr->sin_addr.s_addr = htonl(cm_info->remote_ip[0]); 5762306a36Sopenharmony_ci} 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_cistatic inline void 6062306a36Sopenharmony_ciqedr_fill_sockaddr6(const struct qed_iwarp_cm_info *cm_info, 6162306a36Sopenharmony_ci struct iw_cm_event *event) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci struct sockaddr_in6 *laddr6 = (struct sockaddr_in6 *)&event->local_addr; 6462306a36Sopenharmony_ci struct sockaddr_in6 *raddr6 = 6562306a36Sopenharmony_ci (struct sockaddr_in6 *)&event->remote_addr; 6662306a36Sopenharmony_ci int i; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci laddr6->sin6_family = AF_INET6; 6962306a36Sopenharmony_ci raddr6->sin6_family = AF_INET6; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci laddr6->sin6_port = htons(cm_info->local_port); 7262306a36Sopenharmony_ci raddr6->sin6_port = htons(cm_info->remote_port); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 7562306a36Sopenharmony_ci laddr6->sin6_addr.in6_u.u6_addr32[i] = 7662306a36Sopenharmony_ci htonl(cm_info->local_ip[i]); 7762306a36Sopenharmony_ci raddr6->sin6_addr.in6_u.u6_addr32[i] = 7862306a36Sopenharmony_ci htonl(cm_info->remote_ip[i]); 7962306a36Sopenharmony_ci } 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic void qedr_iw_free_qp(struct kref *ref) 8362306a36Sopenharmony_ci{ 8462306a36Sopenharmony_ci struct qedr_qp *qp = container_of(ref, struct qedr_qp, refcnt); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci complete(&qp->qp_rel_comp); 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_cistatic void 9062306a36Sopenharmony_ciqedr_iw_free_ep(struct kref *ref) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci struct qedr_iw_ep *ep = container_of(ref, struct qedr_iw_ep, refcnt); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci if (ep->qp) 9562306a36Sopenharmony_ci kref_put(&ep->qp->refcnt, qedr_iw_free_qp); 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci if (ep->cm_id) 9862306a36Sopenharmony_ci ep->cm_id->rem_ref(ep->cm_id); 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci kfree(ep); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic void 10462306a36Sopenharmony_ciqedr_iw_mpa_request(void *context, struct qed_iwarp_cm_event_params *params) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci struct qedr_iw_listener *listener = (struct qedr_iw_listener *)context; 10762306a36Sopenharmony_ci struct qedr_dev *dev = listener->dev; 10862306a36Sopenharmony_ci struct iw_cm_event event; 10962306a36Sopenharmony_ci struct qedr_iw_ep *ep; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci ep = kzalloc(sizeof(*ep), GFP_ATOMIC); 11262306a36Sopenharmony_ci if (!ep) 11362306a36Sopenharmony_ci return; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci ep->dev = dev; 11662306a36Sopenharmony_ci ep->qed_context = params->ep_context; 11762306a36Sopenharmony_ci kref_init(&ep->refcnt); 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_ci memset(&event, 0, sizeof(event)); 12062306a36Sopenharmony_ci event.event = IW_CM_EVENT_CONNECT_REQUEST; 12162306a36Sopenharmony_ci event.status = params->status; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_IPV6) || 12462306a36Sopenharmony_ci params->cm_info->ip_version == QED_TCP_IPV4) 12562306a36Sopenharmony_ci qedr_fill_sockaddr4(params->cm_info, &event); 12662306a36Sopenharmony_ci else 12762306a36Sopenharmony_ci qedr_fill_sockaddr6(params->cm_info, &event); 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci event.provider_data = (void *)ep; 13062306a36Sopenharmony_ci event.private_data = (void *)params->cm_info->private_data; 13162306a36Sopenharmony_ci event.private_data_len = (u8)params->cm_info->private_data_len; 13262306a36Sopenharmony_ci event.ord = params->cm_info->ord; 13362306a36Sopenharmony_ci event.ird = params->cm_info->ird; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci listener->cm_id->event_handler(listener->cm_id, &event); 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_cistatic void 13962306a36Sopenharmony_ciqedr_iw_issue_event(void *context, 14062306a36Sopenharmony_ci struct qed_iwarp_cm_event_params *params, 14162306a36Sopenharmony_ci enum iw_cm_event_type event_type) 14262306a36Sopenharmony_ci{ 14362306a36Sopenharmony_ci struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context; 14462306a36Sopenharmony_ci struct iw_cm_event event; 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci memset(&event, 0, sizeof(event)); 14762306a36Sopenharmony_ci event.status = params->status; 14862306a36Sopenharmony_ci event.event = event_type; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci if (params->cm_info) { 15162306a36Sopenharmony_ci event.ird = params->cm_info->ird; 15262306a36Sopenharmony_ci event.ord = params->cm_info->ord; 15362306a36Sopenharmony_ci /* Only connect_request and reply have valid private data 15462306a36Sopenharmony_ci * the rest of the events this may be left overs from 15562306a36Sopenharmony_ci * connection establishment. CONNECT_REQUEST is issued via 15662306a36Sopenharmony_ci * qedr_iw_mpa_request 15762306a36Sopenharmony_ci */ 15862306a36Sopenharmony_ci if (event_type == IW_CM_EVENT_CONNECT_REPLY) { 15962306a36Sopenharmony_ci event.private_data_len = 16062306a36Sopenharmony_ci params->cm_info->private_data_len; 16162306a36Sopenharmony_ci event.private_data = 16262306a36Sopenharmony_ci (void *)params->cm_info->private_data; 16362306a36Sopenharmony_ci } 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci if (ep->cm_id) 16762306a36Sopenharmony_ci ep->cm_id->event_handler(ep->cm_id, &event); 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic void 17162306a36Sopenharmony_ciqedr_iw_close_event(void *context, struct qed_iwarp_cm_event_params *params) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context; 17462306a36Sopenharmony_ci 17562306a36Sopenharmony_ci if (ep->cm_id) 17662306a36Sopenharmony_ci qedr_iw_issue_event(context, params, IW_CM_EVENT_CLOSE); 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci kref_put(&ep->refcnt, qedr_iw_free_ep); 17962306a36Sopenharmony_ci} 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_cistatic void 18262306a36Sopenharmony_ciqedr_iw_qp_event(void *context, 18362306a36Sopenharmony_ci struct qed_iwarp_cm_event_params *params, 18462306a36Sopenharmony_ci enum ib_event_type ib_event, char *str) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context; 18762306a36Sopenharmony_ci struct qedr_dev *dev = ep->dev; 18862306a36Sopenharmony_ci struct ib_qp *ibqp = &ep->qp->ibqp; 18962306a36Sopenharmony_ci struct ib_event event; 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ci DP_NOTICE(dev, "QP error received: %s\n", str); 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci if (ibqp->event_handler) { 19462306a36Sopenharmony_ci event.event = ib_event; 19562306a36Sopenharmony_ci event.device = ibqp->device; 19662306a36Sopenharmony_ci event.element.qp = ibqp; 19762306a36Sopenharmony_ci ibqp->event_handler(&event, ibqp->qp_context); 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci} 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_cistruct qedr_discon_work { 20262306a36Sopenharmony_ci struct work_struct work; 20362306a36Sopenharmony_ci struct qedr_iw_ep *ep; 20462306a36Sopenharmony_ci enum qed_iwarp_event_type event; 20562306a36Sopenharmony_ci int status; 20662306a36Sopenharmony_ci}; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic void qedr_iw_disconnect_worker(struct work_struct *work) 20962306a36Sopenharmony_ci{ 21062306a36Sopenharmony_ci struct qedr_discon_work *dwork = 21162306a36Sopenharmony_ci container_of(work, struct qedr_discon_work, work); 21262306a36Sopenharmony_ci struct qed_rdma_modify_qp_in_params qp_params = { 0 }; 21362306a36Sopenharmony_ci struct qedr_iw_ep *ep = dwork->ep; 21462306a36Sopenharmony_ci struct qedr_dev *dev = ep->dev; 21562306a36Sopenharmony_ci struct qedr_qp *qp = ep->qp; 21662306a36Sopenharmony_ci struct iw_cm_event event; 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci /* The qp won't be released until we release the ep. 21962306a36Sopenharmony_ci * the ep's refcnt was increased before calling this 22062306a36Sopenharmony_ci * function, therefore it is safe to access qp 22162306a36Sopenharmony_ci */ 22262306a36Sopenharmony_ci if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_DISCONNECT, 22362306a36Sopenharmony_ci &qp->iwarp_cm_flags)) 22462306a36Sopenharmony_ci goto out; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci memset(&event, 0, sizeof(event)); 22762306a36Sopenharmony_ci event.status = dwork->status; 22862306a36Sopenharmony_ci event.event = IW_CM_EVENT_DISCONNECT; 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci /* Success means graceful disconnect was requested. modifying 23162306a36Sopenharmony_ci * to SQD is translated to graceful disconnect. O/w reset is sent 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ci if (dwork->status) 23462306a36Sopenharmony_ci qp_params.new_state = QED_ROCE_QP_STATE_ERR; 23562306a36Sopenharmony_ci else 23662306a36Sopenharmony_ci qp_params.new_state = QED_ROCE_QP_STATE_SQD; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci if (ep->cm_id) 24062306a36Sopenharmony_ci ep->cm_id->event_handler(ep->cm_id, &event); 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci SET_FIELD(qp_params.modify_flags, 24362306a36Sopenharmony_ci QED_RDMA_MODIFY_QP_VALID_NEW_STATE, 1); 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci dev->ops->rdma_modify_qp(dev->rdma_ctx, qp->qed_qp, &qp_params); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci complete(&ep->qp->iwarp_cm_comp); 24862306a36Sopenharmony_ciout: 24962306a36Sopenharmony_ci kfree(dwork); 25062306a36Sopenharmony_ci kref_put(&ep->refcnt, qedr_iw_free_ep); 25162306a36Sopenharmony_ci} 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_cistatic void 25462306a36Sopenharmony_ciqedr_iw_disconnect_event(void *context, 25562306a36Sopenharmony_ci struct qed_iwarp_cm_event_params *params) 25662306a36Sopenharmony_ci{ 25762306a36Sopenharmony_ci struct qedr_discon_work *work; 25862306a36Sopenharmony_ci struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context; 25962306a36Sopenharmony_ci struct qedr_dev *dev = ep->dev; 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci work = kzalloc(sizeof(*work), GFP_ATOMIC); 26262306a36Sopenharmony_ci if (!work) 26362306a36Sopenharmony_ci return; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci /* We can't get a close event before disconnect, but since 26662306a36Sopenharmony_ci * we're scheduling a work queue we need to make sure close 26762306a36Sopenharmony_ci * won't delete the ep, so we increase the refcnt 26862306a36Sopenharmony_ci */ 26962306a36Sopenharmony_ci kref_get(&ep->refcnt); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci work->ep = ep; 27262306a36Sopenharmony_ci work->event = params->event; 27362306a36Sopenharmony_ci work->status = params->status; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci INIT_WORK(&work->work, qedr_iw_disconnect_worker); 27662306a36Sopenharmony_ci queue_work(dev->iwarp_wq, &work->work); 27762306a36Sopenharmony_ci} 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic void 28062306a36Sopenharmony_ciqedr_iw_passive_complete(void *context, 28162306a36Sopenharmony_ci struct qed_iwarp_cm_event_params *params) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context; 28462306a36Sopenharmony_ci struct qedr_dev *dev = ep->dev; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci /* We will only reach the following state if MPA_REJECT was called on 28762306a36Sopenharmony_ci * passive. In this case there will be no associated QP. 28862306a36Sopenharmony_ci */ 28962306a36Sopenharmony_ci if ((params->status == -ECONNREFUSED) && (!ep->qp)) { 29062306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_IWARP, 29162306a36Sopenharmony_ci "PASSIVE connection refused releasing ep...\n"); 29262306a36Sopenharmony_ci kref_put(&ep->refcnt, qedr_iw_free_ep); 29362306a36Sopenharmony_ci return; 29462306a36Sopenharmony_ci } 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci complete(&ep->qp->iwarp_cm_comp); 29762306a36Sopenharmony_ci qedr_iw_issue_event(context, params, IW_CM_EVENT_ESTABLISHED); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (params->status < 0) 30062306a36Sopenharmony_ci qedr_iw_close_event(context, params); 30162306a36Sopenharmony_ci} 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_cistatic void 30462306a36Sopenharmony_ciqedr_iw_active_complete(void *context, 30562306a36Sopenharmony_ci struct qed_iwarp_cm_event_params *params) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci complete(&ep->qp->iwarp_cm_comp); 31062306a36Sopenharmony_ci qedr_iw_issue_event(context, params, IW_CM_EVENT_CONNECT_REPLY); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (params->status < 0) 31362306a36Sopenharmony_ci kref_put(&ep->refcnt, qedr_iw_free_ep); 31462306a36Sopenharmony_ci} 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_cistatic int 31762306a36Sopenharmony_ciqedr_iw_mpa_reply(void *context, struct qed_iwarp_cm_event_params *params) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context; 32062306a36Sopenharmony_ci struct qedr_dev *dev = ep->dev; 32162306a36Sopenharmony_ci struct qed_iwarp_send_rtr_in rtr_in; 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci rtr_in.ep_context = params->ep_context; 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci return dev->ops->iwarp_send_rtr(dev->rdma_ctx, &rtr_in); 32662306a36Sopenharmony_ci} 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic int 32962306a36Sopenharmony_ciqedr_iw_event_handler(void *context, struct qed_iwarp_cm_event_params *params) 33062306a36Sopenharmony_ci{ 33162306a36Sopenharmony_ci struct qedr_iw_ep *ep = (struct qedr_iw_ep *)context; 33262306a36Sopenharmony_ci struct qedr_dev *dev = ep->dev; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci switch (params->event) { 33562306a36Sopenharmony_ci case QED_IWARP_EVENT_MPA_REQUEST: 33662306a36Sopenharmony_ci qedr_iw_mpa_request(context, params); 33762306a36Sopenharmony_ci break; 33862306a36Sopenharmony_ci case QED_IWARP_EVENT_ACTIVE_MPA_REPLY: 33962306a36Sopenharmony_ci qedr_iw_mpa_reply(context, params); 34062306a36Sopenharmony_ci break; 34162306a36Sopenharmony_ci case QED_IWARP_EVENT_PASSIVE_COMPLETE: 34262306a36Sopenharmony_ci qedr_iw_passive_complete(context, params); 34362306a36Sopenharmony_ci break; 34462306a36Sopenharmony_ci case QED_IWARP_EVENT_ACTIVE_COMPLETE: 34562306a36Sopenharmony_ci qedr_iw_active_complete(context, params); 34662306a36Sopenharmony_ci break; 34762306a36Sopenharmony_ci case QED_IWARP_EVENT_DISCONNECT: 34862306a36Sopenharmony_ci qedr_iw_disconnect_event(context, params); 34962306a36Sopenharmony_ci break; 35062306a36Sopenharmony_ci case QED_IWARP_EVENT_CLOSE: 35162306a36Sopenharmony_ci qedr_iw_close_event(context, params); 35262306a36Sopenharmony_ci break; 35362306a36Sopenharmony_ci case QED_IWARP_EVENT_RQ_EMPTY: 35462306a36Sopenharmony_ci qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL, 35562306a36Sopenharmony_ci "QED_IWARP_EVENT_RQ_EMPTY"); 35662306a36Sopenharmony_ci break; 35762306a36Sopenharmony_ci case QED_IWARP_EVENT_IRQ_FULL: 35862306a36Sopenharmony_ci qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL, 35962306a36Sopenharmony_ci "QED_IWARP_EVENT_IRQ_FULL"); 36062306a36Sopenharmony_ci break; 36162306a36Sopenharmony_ci case QED_IWARP_EVENT_LLP_TIMEOUT: 36262306a36Sopenharmony_ci qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL, 36362306a36Sopenharmony_ci "QED_IWARP_EVENT_LLP_TIMEOUT"); 36462306a36Sopenharmony_ci break; 36562306a36Sopenharmony_ci case QED_IWARP_EVENT_REMOTE_PROTECTION_ERROR: 36662306a36Sopenharmony_ci qedr_iw_qp_event(context, params, IB_EVENT_QP_ACCESS_ERR, 36762306a36Sopenharmony_ci "QED_IWARP_EVENT_REMOTE_PROTECTION_ERROR"); 36862306a36Sopenharmony_ci break; 36962306a36Sopenharmony_ci case QED_IWARP_EVENT_CQ_OVERFLOW: 37062306a36Sopenharmony_ci qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL, 37162306a36Sopenharmony_ci "QED_IWARP_EVENT_CQ_OVERFLOW"); 37262306a36Sopenharmony_ci break; 37362306a36Sopenharmony_ci case QED_IWARP_EVENT_QP_CATASTROPHIC: 37462306a36Sopenharmony_ci qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL, 37562306a36Sopenharmony_ci "QED_IWARP_EVENT_QP_CATASTROPHIC"); 37662306a36Sopenharmony_ci break; 37762306a36Sopenharmony_ci case QED_IWARP_EVENT_LOCAL_ACCESS_ERROR: 37862306a36Sopenharmony_ci qedr_iw_qp_event(context, params, IB_EVENT_QP_ACCESS_ERR, 37962306a36Sopenharmony_ci "QED_IWARP_EVENT_LOCAL_ACCESS_ERROR"); 38062306a36Sopenharmony_ci break; 38162306a36Sopenharmony_ci case QED_IWARP_EVENT_REMOTE_OPERATION_ERROR: 38262306a36Sopenharmony_ci qedr_iw_qp_event(context, params, IB_EVENT_QP_FATAL, 38362306a36Sopenharmony_ci "QED_IWARP_EVENT_REMOTE_OPERATION_ERROR"); 38462306a36Sopenharmony_ci break; 38562306a36Sopenharmony_ci case QED_IWARP_EVENT_TERMINATE_RECEIVED: 38662306a36Sopenharmony_ci DP_NOTICE(dev, "Got terminate message\n"); 38762306a36Sopenharmony_ci break; 38862306a36Sopenharmony_ci default: 38962306a36Sopenharmony_ci DP_NOTICE(dev, "Unknown event received %d\n", params->event); 39062306a36Sopenharmony_ci break; 39162306a36Sopenharmony_ci } 39262306a36Sopenharmony_ci return 0; 39362306a36Sopenharmony_ci} 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_cistatic u16 qedr_iw_get_vlan_ipv4(struct qedr_dev *dev, u32 *addr) 39662306a36Sopenharmony_ci{ 39762306a36Sopenharmony_ci struct net_device *ndev; 39862306a36Sopenharmony_ci u16 vlan_id = 0; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci ndev = ip_dev_find(&init_net, htonl(addr[0])); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci if (ndev) { 40362306a36Sopenharmony_ci vlan_id = rdma_vlan_dev_vlan_id(ndev); 40462306a36Sopenharmony_ci dev_put(ndev); 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci if (vlan_id == 0xffff) 40762306a36Sopenharmony_ci vlan_id = 0; 40862306a36Sopenharmony_ci return vlan_id; 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic u16 qedr_iw_get_vlan_ipv6(u32 *addr) 41262306a36Sopenharmony_ci{ 41362306a36Sopenharmony_ci struct net_device *ndev = NULL; 41462306a36Sopenharmony_ci struct in6_addr laddr6; 41562306a36Sopenharmony_ci u16 vlan_id = 0; 41662306a36Sopenharmony_ci int i; 41762306a36Sopenharmony_ci 41862306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_IPV6)) 41962306a36Sopenharmony_ci return vlan_id; 42062306a36Sopenharmony_ci 42162306a36Sopenharmony_ci for (i = 0; i < 4; i++) 42262306a36Sopenharmony_ci laddr6.in6_u.u6_addr32[i] = htonl(addr[i]); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci rcu_read_lock(); 42562306a36Sopenharmony_ci for_each_netdev_rcu(&init_net, ndev) { 42662306a36Sopenharmony_ci if (ipv6_chk_addr(&init_net, &laddr6, ndev, 1)) { 42762306a36Sopenharmony_ci vlan_id = rdma_vlan_dev_vlan_id(ndev); 42862306a36Sopenharmony_ci break; 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci rcu_read_unlock(); 43362306a36Sopenharmony_ci if (vlan_id == 0xffff) 43462306a36Sopenharmony_ci vlan_id = 0; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return vlan_id; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_cistatic int 44062306a36Sopenharmony_ciqedr_addr4_resolve(struct qedr_dev *dev, 44162306a36Sopenharmony_ci struct sockaddr_in *src_in, 44262306a36Sopenharmony_ci struct sockaddr_in *dst_in, u8 *dst_mac) 44362306a36Sopenharmony_ci{ 44462306a36Sopenharmony_ci __be32 src_ip = src_in->sin_addr.s_addr; 44562306a36Sopenharmony_ci __be32 dst_ip = dst_in->sin_addr.s_addr; 44662306a36Sopenharmony_ci struct neighbour *neigh = NULL; 44762306a36Sopenharmony_ci struct rtable *rt = NULL; 44862306a36Sopenharmony_ci int rc = 0; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci rt = ip_route_output(&init_net, dst_ip, src_ip, 0, 0); 45162306a36Sopenharmony_ci if (IS_ERR(rt)) { 45262306a36Sopenharmony_ci DP_ERR(dev, "ip_route_output returned error\n"); 45362306a36Sopenharmony_ci return -EINVAL; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_ci neigh = dst_neigh_lookup(&rt->dst, &dst_ip); 45762306a36Sopenharmony_ci 45862306a36Sopenharmony_ci if (neigh) { 45962306a36Sopenharmony_ci rcu_read_lock(); 46062306a36Sopenharmony_ci if (neigh->nud_state & NUD_VALID) { 46162306a36Sopenharmony_ci ether_addr_copy(dst_mac, neigh->ha); 46262306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_QP, "mac_addr=[%pM]\n", dst_mac); 46362306a36Sopenharmony_ci } else { 46462306a36Sopenharmony_ci neigh_event_send(neigh, NULL); 46562306a36Sopenharmony_ci } 46662306a36Sopenharmony_ci rcu_read_unlock(); 46762306a36Sopenharmony_ci neigh_release(neigh); 46862306a36Sopenharmony_ci } 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci ip_rt_put(rt); 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci return rc; 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_cistatic int 47662306a36Sopenharmony_ciqedr_addr6_resolve(struct qedr_dev *dev, 47762306a36Sopenharmony_ci struct sockaddr_in6 *src_in, 47862306a36Sopenharmony_ci struct sockaddr_in6 *dst_in, u8 *dst_mac) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci struct neighbour *neigh = NULL; 48162306a36Sopenharmony_ci struct dst_entry *dst; 48262306a36Sopenharmony_ci struct flowi6 fl6; 48362306a36Sopenharmony_ci int rc = 0; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci memset(&fl6, 0, sizeof(fl6)); 48662306a36Sopenharmony_ci fl6.daddr = dst_in->sin6_addr; 48762306a36Sopenharmony_ci fl6.saddr = src_in->sin6_addr; 48862306a36Sopenharmony_ci 48962306a36Sopenharmony_ci dst = ip6_route_output(&init_net, NULL, &fl6); 49062306a36Sopenharmony_ci 49162306a36Sopenharmony_ci if ((!dst) || dst->error) { 49262306a36Sopenharmony_ci if (dst) { 49362306a36Sopenharmony_ci DP_ERR(dev, 49462306a36Sopenharmony_ci "ip6_route_output returned dst->error = %d\n", 49562306a36Sopenharmony_ci dst->error); 49662306a36Sopenharmony_ci dst_release(dst); 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci return -EINVAL; 49962306a36Sopenharmony_ci } 50062306a36Sopenharmony_ci neigh = dst_neigh_lookup(dst, &fl6.daddr); 50162306a36Sopenharmony_ci if (neigh) { 50262306a36Sopenharmony_ci rcu_read_lock(); 50362306a36Sopenharmony_ci if (neigh->nud_state & NUD_VALID) { 50462306a36Sopenharmony_ci ether_addr_copy(dst_mac, neigh->ha); 50562306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_QP, "mac_addr=[%pM]\n", dst_mac); 50662306a36Sopenharmony_ci } else { 50762306a36Sopenharmony_ci neigh_event_send(neigh, NULL); 50862306a36Sopenharmony_ci } 50962306a36Sopenharmony_ci rcu_read_unlock(); 51062306a36Sopenharmony_ci neigh_release(neigh); 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci dst_release(dst); 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci return rc; 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_cistatic struct qedr_qp *qedr_iw_load_qp(struct qedr_dev *dev, u32 qpn) 51962306a36Sopenharmony_ci{ 52062306a36Sopenharmony_ci struct qedr_qp *qp; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci xa_lock(&dev->qps); 52362306a36Sopenharmony_ci qp = xa_load(&dev->qps, qpn); 52462306a36Sopenharmony_ci if (qp) 52562306a36Sopenharmony_ci kref_get(&qp->refcnt); 52662306a36Sopenharmony_ci xa_unlock(&dev->qps); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci return qp; 52962306a36Sopenharmony_ci} 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ciint qedr_iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) 53262306a36Sopenharmony_ci{ 53362306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(cm_id->device); 53462306a36Sopenharmony_ci struct qed_iwarp_connect_out out_params; 53562306a36Sopenharmony_ci struct qed_iwarp_connect_in in_params; 53662306a36Sopenharmony_ci struct qed_iwarp_cm_info *cm_info; 53762306a36Sopenharmony_ci struct sockaddr_in6 *laddr6; 53862306a36Sopenharmony_ci struct sockaddr_in6 *raddr6; 53962306a36Sopenharmony_ci struct sockaddr_in *laddr; 54062306a36Sopenharmony_ci struct sockaddr_in *raddr; 54162306a36Sopenharmony_ci struct qedr_iw_ep *ep; 54262306a36Sopenharmony_ci struct qedr_qp *qp; 54362306a36Sopenharmony_ci int rc = 0; 54462306a36Sopenharmony_ci int i; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci laddr = (struct sockaddr_in *)&cm_id->m_local_addr; 54762306a36Sopenharmony_ci raddr = (struct sockaddr_in *)&cm_id->m_remote_addr; 54862306a36Sopenharmony_ci laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr; 54962306a36Sopenharmony_ci raddr6 = (struct sockaddr_in6 *)&cm_id->m_remote_addr; 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_IWARP, "MAPPED %d %d\n", 55262306a36Sopenharmony_ci ntohs(((struct sockaddr_in *)&cm_id->remote_addr)->sin_port), 55362306a36Sopenharmony_ci ntohs(raddr->sin_port)); 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_IWARP, 55662306a36Sopenharmony_ci "Connect source address: %pISpc, remote address: %pISpc\n", 55762306a36Sopenharmony_ci &cm_id->local_addr, &cm_id->remote_addr); 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci if (!laddr->sin_port || !raddr->sin_port) 56062306a36Sopenharmony_ci return -EINVAL; 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci ep = kzalloc(sizeof(*ep), GFP_KERNEL); 56362306a36Sopenharmony_ci if (!ep) 56462306a36Sopenharmony_ci return -ENOMEM; 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci ep->dev = dev; 56762306a36Sopenharmony_ci kref_init(&ep->refcnt); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci qp = qedr_iw_load_qp(dev, conn_param->qpn); 57062306a36Sopenharmony_ci if (!qp) { 57162306a36Sopenharmony_ci rc = -EINVAL; 57262306a36Sopenharmony_ci goto err; 57362306a36Sopenharmony_ci } 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci ep->qp = qp; 57662306a36Sopenharmony_ci cm_id->add_ref(cm_id); 57762306a36Sopenharmony_ci ep->cm_id = cm_id; 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci in_params.event_cb = qedr_iw_event_handler; 58062306a36Sopenharmony_ci in_params.cb_context = ep; 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci cm_info = &in_params.cm_info; 58362306a36Sopenharmony_ci memset(cm_info->local_ip, 0, sizeof(cm_info->local_ip)); 58462306a36Sopenharmony_ci memset(cm_info->remote_ip, 0, sizeof(cm_info->remote_ip)); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_IPV6) || 58762306a36Sopenharmony_ci cm_id->remote_addr.ss_family == AF_INET) { 58862306a36Sopenharmony_ci cm_info->ip_version = QED_TCP_IPV4; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci cm_info->remote_ip[0] = ntohl(raddr->sin_addr.s_addr); 59162306a36Sopenharmony_ci cm_info->local_ip[0] = ntohl(laddr->sin_addr.s_addr); 59262306a36Sopenharmony_ci cm_info->remote_port = ntohs(raddr->sin_port); 59362306a36Sopenharmony_ci cm_info->local_port = ntohs(laddr->sin_port); 59462306a36Sopenharmony_ci cm_info->vlan = qedr_iw_get_vlan_ipv4(dev, cm_info->local_ip); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci rc = qedr_addr4_resolve(dev, laddr, raddr, 59762306a36Sopenharmony_ci (u8 *)in_params.remote_mac_addr); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci in_params.mss = dev->iwarp_max_mtu - 60062306a36Sopenharmony_ci (sizeof(struct iphdr) + sizeof(struct tcphdr)); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci } else { 60362306a36Sopenharmony_ci in_params.cm_info.ip_version = QED_TCP_IPV6; 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 60662306a36Sopenharmony_ci cm_info->remote_ip[i] = 60762306a36Sopenharmony_ci ntohl(raddr6->sin6_addr.in6_u.u6_addr32[i]); 60862306a36Sopenharmony_ci cm_info->local_ip[i] = 60962306a36Sopenharmony_ci ntohl(laddr6->sin6_addr.in6_u.u6_addr32[i]); 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci cm_info->local_port = ntohs(laddr6->sin6_port); 61362306a36Sopenharmony_ci cm_info->remote_port = ntohs(raddr6->sin6_port); 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci in_params.mss = dev->iwarp_max_mtu - 61662306a36Sopenharmony_ci (sizeof(struct ipv6hdr) + sizeof(struct tcphdr)); 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci cm_info->vlan = qedr_iw_get_vlan_ipv6(cm_info->local_ip); 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci rc = qedr_addr6_resolve(dev, laddr6, raddr6, 62162306a36Sopenharmony_ci (u8 *)in_params.remote_mac_addr); 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci if (rc) 62462306a36Sopenharmony_ci goto err; 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_IWARP, 62762306a36Sopenharmony_ci "ord = %d ird=%d private_data=%p private_data_len=%d rq_psn=%d\n", 62862306a36Sopenharmony_ci conn_param->ord, conn_param->ird, conn_param->private_data, 62962306a36Sopenharmony_ci conn_param->private_data_len, qp->rq_psn); 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci cm_info->ord = conn_param->ord; 63262306a36Sopenharmony_ci cm_info->ird = conn_param->ird; 63362306a36Sopenharmony_ci cm_info->private_data = conn_param->private_data; 63462306a36Sopenharmony_ci cm_info->private_data_len = conn_param->private_data_len; 63562306a36Sopenharmony_ci in_params.qp = qp->qed_qp; 63662306a36Sopenharmony_ci memcpy(in_params.local_mac_addr, dev->ndev->dev_addr, ETH_ALEN); 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_CONNECT, 63962306a36Sopenharmony_ci &qp->iwarp_cm_flags)) { 64062306a36Sopenharmony_ci rc = -ENODEV; 64162306a36Sopenharmony_ci goto err; /* QP already being destroyed */ 64262306a36Sopenharmony_ci } 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci rc = dev->ops->iwarp_connect(dev->rdma_ctx, &in_params, &out_params); 64562306a36Sopenharmony_ci if (rc) { 64662306a36Sopenharmony_ci complete(&qp->iwarp_cm_comp); 64762306a36Sopenharmony_ci goto err; 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci return rc; 65162306a36Sopenharmony_ci 65262306a36Sopenharmony_cierr: 65362306a36Sopenharmony_ci kref_put(&ep->refcnt, qedr_iw_free_ep); 65462306a36Sopenharmony_ci return rc; 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ciint qedr_iw_create_listen(struct iw_cm_id *cm_id, int backlog) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(cm_id->device); 66062306a36Sopenharmony_ci struct qedr_iw_listener *listener; 66162306a36Sopenharmony_ci struct qed_iwarp_listen_in iparams; 66262306a36Sopenharmony_ci struct qed_iwarp_listen_out oparams; 66362306a36Sopenharmony_ci struct sockaddr_in *laddr; 66462306a36Sopenharmony_ci struct sockaddr_in6 *laddr6; 66562306a36Sopenharmony_ci int rc; 66662306a36Sopenharmony_ci int i; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci laddr = (struct sockaddr_in *)&cm_id->m_local_addr; 66962306a36Sopenharmony_ci laddr6 = (struct sockaddr_in6 *)&cm_id->m_local_addr; 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_IWARP, 67262306a36Sopenharmony_ci "Create Listener address: %pISpc\n", &cm_id->local_addr); 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci listener = kzalloc(sizeof(*listener), GFP_KERNEL); 67562306a36Sopenharmony_ci if (!listener) 67662306a36Sopenharmony_ci return -ENOMEM; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci listener->dev = dev; 67962306a36Sopenharmony_ci cm_id->add_ref(cm_id); 68062306a36Sopenharmony_ci listener->cm_id = cm_id; 68162306a36Sopenharmony_ci listener->backlog = backlog; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci iparams.cb_context = listener; 68462306a36Sopenharmony_ci iparams.event_cb = qedr_iw_event_handler; 68562306a36Sopenharmony_ci iparams.max_backlog = backlog; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (!IS_ENABLED(CONFIG_IPV6) || 68862306a36Sopenharmony_ci cm_id->local_addr.ss_family == AF_INET) { 68962306a36Sopenharmony_ci iparams.ip_version = QED_TCP_IPV4; 69062306a36Sopenharmony_ci memset(iparams.ip_addr, 0, sizeof(iparams.ip_addr)); 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci iparams.ip_addr[0] = ntohl(laddr->sin_addr.s_addr); 69362306a36Sopenharmony_ci iparams.port = ntohs(laddr->sin_port); 69462306a36Sopenharmony_ci iparams.vlan = qedr_iw_get_vlan_ipv4(dev, iparams.ip_addr); 69562306a36Sopenharmony_ci } else { 69662306a36Sopenharmony_ci iparams.ip_version = QED_TCP_IPV6; 69762306a36Sopenharmony_ci 69862306a36Sopenharmony_ci for (i = 0; i < 4; i++) { 69962306a36Sopenharmony_ci iparams.ip_addr[i] = 70062306a36Sopenharmony_ci ntohl(laddr6->sin6_addr.in6_u.u6_addr32[i]); 70162306a36Sopenharmony_ci } 70262306a36Sopenharmony_ci 70362306a36Sopenharmony_ci iparams.port = ntohs(laddr6->sin6_port); 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_ci iparams.vlan = qedr_iw_get_vlan_ipv6(iparams.ip_addr); 70662306a36Sopenharmony_ci } 70762306a36Sopenharmony_ci rc = dev->ops->iwarp_create_listen(dev->rdma_ctx, &iparams, &oparams); 70862306a36Sopenharmony_ci if (rc) 70962306a36Sopenharmony_ci goto err; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci listener->qed_handle = oparams.handle; 71262306a36Sopenharmony_ci cm_id->provider_data = listener; 71362306a36Sopenharmony_ci return rc; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_cierr: 71662306a36Sopenharmony_ci cm_id->rem_ref(cm_id); 71762306a36Sopenharmony_ci kfree(listener); 71862306a36Sopenharmony_ci return rc; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ciint qedr_iw_destroy_listen(struct iw_cm_id *cm_id) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci struct qedr_iw_listener *listener = cm_id->provider_data; 72462306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(cm_id->device); 72562306a36Sopenharmony_ci int rc = 0; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci if (listener->qed_handle) 72862306a36Sopenharmony_ci rc = dev->ops->iwarp_destroy_listen(dev->rdma_ctx, 72962306a36Sopenharmony_ci listener->qed_handle); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci cm_id->rem_ref(cm_id); 73262306a36Sopenharmony_ci kfree(listener); 73362306a36Sopenharmony_ci return rc; 73462306a36Sopenharmony_ci} 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ciint qedr_iw_accept(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param) 73762306a36Sopenharmony_ci{ 73862306a36Sopenharmony_ci struct qedr_iw_ep *ep = (struct qedr_iw_ep *)cm_id->provider_data; 73962306a36Sopenharmony_ci struct qedr_dev *dev = ep->dev; 74062306a36Sopenharmony_ci struct qedr_qp *qp; 74162306a36Sopenharmony_ci struct qed_iwarp_accept_in params; 74262306a36Sopenharmony_ci int rc; 74362306a36Sopenharmony_ci 74462306a36Sopenharmony_ci DP_DEBUG(dev, QEDR_MSG_IWARP, "Accept on qpid=%d\n", conn_param->qpn); 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci qp = qedr_iw_load_qp(dev, conn_param->qpn); 74762306a36Sopenharmony_ci if (!qp) { 74862306a36Sopenharmony_ci DP_ERR(dev, "Invalid QP number %d\n", conn_param->qpn); 74962306a36Sopenharmony_ci return -EINVAL; 75062306a36Sopenharmony_ci } 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci ep->qp = qp; 75362306a36Sopenharmony_ci cm_id->add_ref(cm_id); 75462306a36Sopenharmony_ci ep->cm_id = cm_id; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci params.ep_context = ep->qed_context; 75762306a36Sopenharmony_ci params.cb_context = ep; 75862306a36Sopenharmony_ci params.qp = ep->qp->qed_qp; 75962306a36Sopenharmony_ci params.private_data = conn_param->private_data; 76062306a36Sopenharmony_ci params.private_data_len = conn_param->private_data_len; 76162306a36Sopenharmony_ci params.ird = conn_param->ird; 76262306a36Sopenharmony_ci params.ord = conn_param->ord; 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci if (test_and_set_bit(QEDR_IWARP_CM_WAIT_FOR_CONNECT, 76562306a36Sopenharmony_ci &qp->iwarp_cm_flags)) { 76662306a36Sopenharmony_ci rc = -EINVAL; 76762306a36Sopenharmony_ci goto err; /* QP already destroyed */ 76862306a36Sopenharmony_ci } 76962306a36Sopenharmony_ci 77062306a36Sopenharmony_ci rc = dev->ops->iwarp_accept(dev->rdma_ctx, ¶ms); 77162306a36Sopenharmony_ci if (rc) { 77262306a36Sopenharmony_ci complete(&qp->iwarp_cm_comp); 77362306a36Sopenharmony_ci goto err; 77462306a36Sopenharmony_ci } 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci return rc; 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_cierr: 77962306a36Sopenharmony_ci kref_put(&ep->refcnt, qedr_iw_free_ep); 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci return rc; 78262306a36Sopenharmony_ci} 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ciint qedr_iw_reject(struct iw_cm_id *cm_id, const void *pdata, u8 pdata_len) 78562306a36Sopenharmony_ci{ 78662306a36Sopenharmony_ci struct qedr_iw_ep *ep = (struct qedr_iw_ep *)cm_id->provider_data; 78762306a36Sopenharmony_ci struct qedr_dev *dev = ep->dev; 78862306a36Sopenharmony_ci struct qed_iwarp_reject_in params; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci params.ep_context = ep->qed_context; 79162306a36Sopenharmony_ci params.cb_context = ep; 79262306a36Sopenharmony_ci params.private_data = pdata; 79362306a36Sopenharmony_ci params.private_data_len = pdata_len; 79462306a36Sopenharmony_ci ep->qp = NULL; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ci return dev->ops->iwarp_reject(dev->rdma_ctx, ¶ms); 79762306a36Sopenharmony_ci} 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_civoid qedr_iw_qp_add_ref(struct ib_qp *ibqp) 80062306a36Sopenharmony_ci{ 80162306a36Sopenharmony_ci struct qedr_qp *qp = get_qedr_qp(ibqp); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci kref_get(&qp->refcnt); 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_civoid qedr_iw_qp_rem_ref(struct ib_qp *ibqp) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci struct qedr_qp *qp = get_qedr_qp(ibqp); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci kref_put(&qp->refcnt, qedr_iw_free_qp); 81162306a36Sopenharmony_ci} 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_cistruct ib_qp *qedr_iw_get_qp(struct ib_device *ibdev, int qpn) 81462306a36Sopenharmony_ci{ 81562306a36Sopenharmony_ci struct qedr_dev *dev = get_qedr_dev(ibdev); 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci return xa_load(&dev->qps, qpn); 81862306a36Sopenharmony_ci} 819