162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2004, 2005, 2006 Voltaire, Inc. All rights reserved. 362306a36Sopenharmony_ci * Copyright (c) 2005, 2006 Cisco Systems. All rights reserved. 462306a36Sopenharmony_ci * Copyright (c) 2013-2014 Mellanox Technologies. All rights reserved. 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * This software is available to you under a choice of one of two 762306a36Sopenharmony_ci * licenses. You may choose to be licensed under the terms of the GNU 862306a36Sopenharmony_ci * General Public License (GPL) Version 2, available from the file 962306a36Sopenharmony_ci * COPYING in the main directory of this source tree, or the 1062306a36Sopenharmony_ci * OpenIB.org BSD license below: 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * Redistribution and use in source and binary forms, with or 1362306a36Sopenharmony_ci * without modification, are permitted provided that the following 1462306a36Sopenharmony_ci * conditions are met: 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * - Redistributions of source code must retain the above 1762306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 1862306a36Sopenharmony_ci * disclaimer. 1962306a36Sopenharmony_ci * 2062306a36Sopenharmony_ci * - Redistributions in binary form must reproduce the above 2162306a36Sopenharmony_ci * copyright notice, this list of conditions and the following 2262306a36Sopenharmony_ci * disclaimer in the documentation and/or other materials 2362306a36Sopenharmony_ci * provided with the distribution. 2462306a36Sopenharmony_ci * 2562306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 2662306a36Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 2762306a36Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2862306a36Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 2962306a36Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 3062306a36Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 3162306a36Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 3262306a36Sopenharmony_ci * SOFTWARE. 3362306a36Sopenharmony_ci */ 3462306a36Sopenharmony_ci#include <linux/kernel.h> 3562306a36Sopenharmony_ci#include <linux/slab.h> 3662306a36Sopenharmony_ci#include <linux/delay.h> 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#include "iscsi_iser.h" 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic void iser_qp_event_callback(struct ib_event *cause, void *context) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci iser_err("qp event %s (%d)\n", 4362306a36Sopenharmony_ci ib_event_msg(cause->event), cause->event); 4462306a36Sopenharmony_ci} 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_cistatic void iser_event_handler(struct ib_event_handler *handler, 4762306a36Sopenharmony_ci struct ib_event *event) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci iser_err("async event %s (%d) on device %s port %d\n", 5062306a36Sopenharmony_ci ib_event_msg(event->event), event->event, 5162306a36Sopenharmony_ci dev_name(&event->device->dev), event->element.port_num); 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci/* 5562306a36Sopenharmony_ci * iser_create_device_ib_res - creates Protection Domain (PD), Completion 5662306a36Sopenharmony_ci * Queue (CQ), DMA Memory Region (DMA MR) with the device associated with 5762306a36Sopenharmony_ci * the adaptor. 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * Return: 0 on success, -1 on failure 6062306a36Sopenharmony_ci */ 6162306a36Sopenharmony_cistatic int iser_create_device_ib_res(struct iser_device *device) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci struct ib_device *ib_dev = device->ib_device; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (!(ib_dev->attrs.device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS)) { 6662306a36Sopenharmony_ci iser_err("IB device does not support memory registrations\n"); 6762306a36Sopenharmony_ci return -1; 6862306a36Sopenharmony_ci } 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci device->pd = ib_alloc_pd(ib_dev, 7162306a36Sopenharmony_ci iser_always_reg ? 0 : IB_PD_UNSAFE_GLOBAL_RKEY); 7262306a36Sopenharmony_ci if (IS_ERR(device->pd)) 7362306a36Sopenharmony_ci goto pd_err; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci INIT_IB_EVENT_HANDLER(&device->event_handler, ib_dev, 7662306a36Sopenharmony_ci iser_event_handler); 7762306a36Sopenharmony_ci ib_register_event_handler(&device->event_handler); 7862306a36Sopenharmony_ci return 0; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cipd_err: 8162306a36Sopenharmony_ci iser_err("failed to allocate an IB resource\n"); 8262306a36Sopenharmony_ci return -1; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci/* 8662306a36Sopenharmony_ci * iser_free_device_ib_res - destroy/dealloc/dereg the DMA MR, 8762306a36Sopenharmony_ci * CQ and PD created with the device associated with the adaptor. 8862306a36Sopenharmony_ci */ 8962306a36Sopenharmony_cistatic void iser_free_device_ib_res(struct iser_device *device) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci ib_unregister_event_handler(&device->event_handler); 9262306a36Sopenharmony_ci ib_dealloc_pd(device->pd); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci device->pd = NULL; 9562306a36Sopenharmony_ci} 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_cistatic struct iser_fr_desc * 9862306a36Sopenharmony_ciiser_create_fastreg_desc(struct iser_device *device, 9962306a36Sopenharmony_ci struct ib_pd *pd, 10062306a36Sopenharmony_ci bool pi_enable, 10162306a36Sopenharmony_ci unsigned int size) 10262306a36Sopenharmony_ci{ 10362306a36Sopenharmony_ci struct iser_fr_desc *desc; 10462306a36Sopenharmony_ci struct ib_device *ib_dev = device->ib_device; 10562306a36Sopenharmony_ci enum ib_mr_type mr_type; 10662306a36Sopenharmony_ci int ret; 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci desc = kzalloc(sizeof(*desc), GFP_KERNEL); 10962306a36Sopenharmony_ci if (!desc) 11062306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci if (ib_dev->attrs.kernel_cap_flags & IBK_SG_GAPS_REG) 11362306a36Sopenharmony_ci mr_type = IB_MR_TYPE_SG_GAPS; 11462306a36Sopenharmony_ci else 11562306a36Sopenharmony_ci mr_type = IB_MR_TYPE_MEM_REG; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci desc->rsc.mr = ib_alloc_mr(pd, mr_type, size); 11862306a36Sopenharmony_ci if (IS_ERR(desc->rsc.mr)) { 11962306a36Sopenharmony_ci ret = PTR_ERR(desc->rsc.mr); 12062306a36Sopenharmony_ci iser_err("Failed to allocate ib_fast_reg_mr err=%d\n", ret); 12162306a36Sopenharmony_ci goto err_alloc_mr; 12262306a36Sopenharmony_ci } 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci if (pi_enable) { 12562306a36Sopenharmony_ci desc->rsc.sig_mr = ib_alloc_mr_integrity(pd, size, size); 12662306a36Sopenharmony_ci if (IS_ERR(desc->rsc.sig_mr)) { 12762306a36Sopenharmony_ci ret = PTR_ERR(desc->rsc.sig_mr); 12862306a36Sopenharmony_ci iser_err("Failed to allocate sig_mr err=%d\n", ret); 12962306a36Sopenharmony_ci goto err_alloc_mr_integrity; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci } 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci return desc; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_cierr_alloc_mr_integrity: 13662306a36Sopenharmony_ci ib_dereg_mr(desc->rsc.mr); 13762306a36Sopenharmony_cierr_alloc_mr: 13862306a36Sopenharmony_ci kfree(desc); 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci return ERR_PTR(ret); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_cistatic void iser_destroy_fastreg_desc(struct iser_fr_desc *desc) 14462306a36Sopenharmony_ci{ 14562306a36Sopenharmony_ci struct iser_reg_resources *res = &desc->rsc; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci ib_dereg_mr(res->mr); 14862306a36Sopenharmony_ci if (res->sig_mr) { 14962306a36Sopenharmony_ci ib_dereg_mr(res->sig_mr); 15062306a36Sopenharmony_ci res->sig_mr = NULL; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci kfree(desc); 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci/** 15662306a36Sopenharmony_ci * iser_alloc_fastreg_pool - Creates pool of fast_reg descriptors 15762306a36Sopenharmony_ci * for fast registration work requests. 15862306a36Sopenharmony_ci * @ib_conn: connection RDMA resources 15962306a36Sopenharmony_ci * @cmds_max: max number of SCSI commands for this connection 16062306a36Sopenharmony_ci * @size: max number of pages per map request 16162306a36Sopenharmony_ci * 16262306a36Sopenharmony_ci * Return: 0 on success, or errno code on failure 16362306a36Sopenharmony_ci */ 16462306a36Sopenharmony_ciint iser_alloc_fastreg_pool(struct ib_conn *ib_conn, 16562306a36Sopenharmony_ci unsigned cmds_max, 16662306a36Sopenharmony_ci unsigned int size) 16762306a36Sopenharmony_ci{ 16862306a36Sopenharmony_ci struct iser_device *device = ib_conn->device; 16962306a36Sopenharmony_ci struct iser_fr_pool *fr_pool = &ib_conn->fr_pool; 17062306a36Sopenharmony_ci struct iser_fr_desc *desc; 17162306a36Sopenharmony_ci int i, ret; 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci INIT_LIST_HEAD(&fr_pool->list); 17462306a36Sopenharmony_ci INIT_LIST_HEAD(&fr_pool->all_list); 17562306a36Sopenharmony_ci spin_lock_init(&fr_pool->lock); 17662306a36Sopenharmony_ci fr_pool->size = 0; 17762306a36Sopenharmony_ci for (i = 0; i < cmds_max; i++) { 17862306a36Sopenharmony_ci desc = iser_create_fastreg_desc(device, device->pd, 17962306a36Sopenharmony_ci ib_conn->pi_support, size); 18062306a36Sopenharmony_ci if (IS_ERR(desc)) { 18162306a36Sopenharmony_ci ret = PTR_ERR(desc); 18262306a36Sopenharmony_ci goto err; 18362306a36Sopenharmony_ci } 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci list_add_tail(&desc->list, &fr_pool->list); 18662306a36Sopenharmony_ci list_add_tail(&desc->all_list, &fr_pool->all_list); 18762306a36Sopenharmony_ci fr_pool->size++; 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci return 0; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_cierr: 19362306a36Sopenharmony_ci iser_free_fastreg_pool(ib_conn); 19462306a36Sopenharmony_ci return ret; 19562306a36Sopenharmony_ci} 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci/** 19862306a36Sopenharmony_ci * iser_free_fastreg_pool - releases the pool of fast_reg descriptors 19962306a36Sopenharmony_ci * @ib_conn: connection RDMA resources 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_civoid iser_free_fastreg_pool(struct ib_conn *ib_conn) 20262306a36Sopenharmony_ci{ 20362306a36Sopenharmony_ci struct iser_fr_pool *fr_pool = &ib_conn->fr_pool; 20462306a36Sopenharmony_ci struct iser_fr_desc *desc, *tmp; 20562306a36Sopenharmony_ci int i = 0; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci if (list_empty(&fr_pool->all_list)) 20862306a36Sopenharmony_ci return; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci iser_info("freeing conn %p fr pool\n", ib_conn); 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci list_for_each_entry_safe(desc, tmp, &fr_pool->all_list, all_list) { 21362306a36Sopenharmony_ci list_del(&desc->all_list); 21462306a36Sopenharmony_ci iser_destroy_fastreg_desc(desc); 21562306a36Sopenharmony_ci ++i; 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci if (i < fr_pool->size) 21962306a36Sopenharmony_ci iser_warn("pool still has %d regions registered\n", 22062306a36Sopenharmony_ci fr_pool->size - i); 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci/* 22462306a36Sopenharmony_ci * iser_create_ib_conn_res - Queue-Pair (QP) 22562306a36Sopenharmony_ci * 22662306a36Sopenharmony_ci * Return: 0 on success, -1 on failure 22762306a36Sopenharmony_ci */ 22862306a36Sopenharmony_cistatic int iser_create_ib_conn_res(struct ib_conn *ib_conn) 22962306a36Sopenharmony_ci{ 23062306a36Sopenharmony_ci struct iser_conn *iser_conn = to_iser_conn(ib_conn); 23162306a36Sopenharmony_ci struct iser_device *device; 23262306a36Sopenharmony_ci struct ib_device *ib_dev; 23362306a36Sopenharmony_ci struct ib_qp_init_attr init_attr; 23462306a36Sopenharmony_ci int ret = -ENOMEM; 23562306a36Sopenharmony_ci unsigned int max_send_wr, cq_size; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci BUG_ON(ib_conn->device == NULL); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci device = ib_conn->device; 24062306a36Sopenharmony_ci ib_dev = device->ib_device; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci /* +1 for drain */ 24362306a36Sopenharmony_ci if (ib_conn->pi_support) 24462306a36Sopenharmony_ci max_send_wr = ISER_QP_SIG_MAX_REQ_DTOS + 1; 24562306a36Sopenharmony_ci else 24662306a36Sopenharmony_ci max_send_wr = ISER_QP_MAX_REQ_DTOS + 1; 24762306a36Sopenharmony_ci max_send_wr = min_t(unsigned int, max_send_wr, 24862306a36Sopenharmony_ci (unsigned int)ib_dev->attrs.max_qp_wr); 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci cq_size = max_send_wr + ISER_QP_MAX_RECV_DTOS; 25162306a36Sopenharmony_ci ib_conn->cq = ib_cq_pool_get(ib_dev, cq_size, -1, IB_POLL_SOFTIRQ); 25262306a36Sopenharmony_ci if (IS_ERR(ib_conn->cq)) { 25362306a36Sopenharmony_ci ret = PTR_ERR(ib_conn->cq); 25462306a36Sopenharmony_ci goto cq_err; 25562306a36Sopenharmony_ci } 25662306a36Sopenharmony_ci ib_conn->cq_size = cq_size; 25762306a36Sopenharmony_ci 25862306a36Sopenharmony_ci memset(&init_attr, 0, sizeof(init_attr)); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci init_attr.event_handler = iser_qp_event_callback; 26162306a36Sopenharmony_ci init_attr.qp_context = (void *)ib_conn; 26262306a36Sopenharmony_ci init_attr.send_cq = ib_conn->cq; 26362306a36Sopenharmony_ci init_attr.recv_cq = ib_conn->cq; 26462306a36Sopenharmony_ci /* +1 for drain */ 26562306a36Sopenharmony_ci init_attr.cap.max_recv_wr = ISER_QP_MAX_RECV_DTOS + 1; 26662306a36Sopenharmony_ci init_attr.cap.max_send_sge = 2; 26762306a36Sopenharmony_ci init_attr.cap.max_recv_sge = 1; 26862306a36Sopenharmony_ci init_attr.sq_sig_type = IB_SIGNAL_REQ_WR; 26962306a36Sopenharmony_ci init_attr.qp_type = IB_QPT_RC; 27062306a36Sopenharmony_ci init_attr.cap.max_send_wr = max_send_wr; 27162306a36Sopenharmony_ci if (ib_conn->pi_support) 27262306a36Sopenharmony_ci init_attr.create_flags |= IB_QP_CREATE_INTEGRITY_EN; 27362306a36Sopenharmony_ci iser_conn->max_cmds = ISER_GET_MAX_XMIT_CMDS(max_send_wr - 1); 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci ret = rdma_create_qp(ib_conn->cma_id, device->pd, &init_attr); 27662306a36Sopenharmony_ci if (ret) 27762306a36Sopenharmony_ci goto out_err; 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci ib_conn->qp = ib_conn->cma_id->qp; 28062306a36Sopenharmony_ci iser_info("setting conn %p cma_id %p qp %p max_send_wr %d\n", ib_conn, 28162306a36Sopenharmony_ci ib_conn->cma_id, ib_conn->cma_id->qp, max_send_wr); 28262306a36Sopenharmony_ci return ret; 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ciout_err: 28562306a36Sopenharmony_ci ib_cq_pool_put(ib_conn->cq, ib_conn->cq_size); 28662306a36Sopenharmony_cicq_err: 28762306a36Sopenharmony_ci iser_err("unable to alloc mem or create resource, err %d\n", ret); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci return ret; 29062306a36Sopenharmony_ci} 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci/* 29362306a36Sopenharmony_ci * based on the resolved device node GUID see if there already allocated 29462306a36Sopenharmony_ci * device for this device. If there's no such, create one. 29562306a36Sopenharmony_ci */ 29662306a36Sopenharmony_cistatic 29762306a36Sopenharmony_cistruct iser_device *iser_device_find_by_ib_device(struct rdma_cm_id *cma_id) 29862306a36Sopenharmony_ci{ 29962306a36Sopenharmony_ci struct iser_device *device; 30062306a36Sopenharmony_ci 30162306a36Sopenharmony_ci mutex_lock(&ig.device_list_mutex); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci list_for_each_entry(device, &ig.device_list, ig_list) 30462306a36Sopenharmony_ci /* find if there's a match using the node GUID */ 30562306a36Sopenharmony_ci if (device->ib_device->node_guid == cma_id->device->node_guid) 30662306a36Sopenharmony_ci goto inc_refcnt; 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_ci device = kzalloc(sizeof *device, GFP_KERNEL); 30962306a36Sopenharmony_ci if (!device) 31062306a36Sopenharmony_ci goto out; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* assign this device to the device */ 31362306a36Sopenharmony_ci device->ib_device = cma_id->device; 31462306a36Sopenharmony_ci /* init the device and link it into ig device list */ 31562306a36Sopenharmony_ci if (iser_create_device_ib_res(device)) { 31662306a36Sopenharmony_ci kfree(device); 31762306a36Sopenharmony_ci device = NULL; 31862306a36Sopenharmony_ci goto out; 31962306a36Sopenharmony_ci } 32062306a36Sopenharmony_ci list_add(&device->ig_list, &ig.device_list); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ciinc_refcnt: 32362306a36Sopenharmony_ci device->refcount++; 32462306a36Sopenharmony_ciout: 32562306a36Sopenharmony_ci mutex_unlock(&ig.device_list_mutex); 32662306a36Sopenharmony_ci return device; 32762306a36Sopenharmony_ci} 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci/* if there's no demand for this device, release it */ 33062306a36Sopenharmony_cistatic void iser_device_try_release(struct iser_device *device) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci mutex_lock(&ig.device_list_mutex); 33362306a36Sopenharmony_ci device->refcount--; 33462306a36Sopenharmony_ci iser_info("device %p refcount %d\n", device, device->refcount); 33562306a36Sopenharmony_ci if (!device->refcount) { 33662306a36Sopenharmony_ci iser_free_device_ib_res(device); 33762306a36Sopenharmony_ci list_del(&device->ig_list); 33862306a36Sopenharmony_ci kfree(device); 33962306a36Sopenharmony_ci } 34062306a36Sopenharmony_ci mutex_unlock(&ig.device_list_mutex); 34162306a36Sopenharmony_ci} 34262306a36Sopenharmony_ci 34362306a36Sopenharmony_civoid iser_release_work(struct work_struct *work) 34462306a36Sopenharmony_ci{ 34562306a36Sopenharmony_ci struct iser_conn *iser_conn; 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci iser_conn = container_of(work, struct iser_conn, release_work); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* Wait for conn_stop to complete */ 35062306a36Sopenharmony_ci wait_for_completion(&iser_conn->stop_completion); 35162306a36Sopenharmony_ci /* Wait for IB resouces cleanup to complete */ 35262306a36Sopenharmony_ci wait_for_completion(&iser_conn->ib_completion); 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci mutex_lock(&iser_conn->state_mutex); 35562306a36Sopenharmony_ci iser_conn->state = ISER_CONN_DOWN; 35662306a36Sopenharmony_ci mutex_unlock(&iser_conn->state_mutex); 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci iser_conn_release(iser_conn); 35962306a36Sopenharmony_ci} 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ci/** 36262306a36Sopenharmony_ci * iser_free_ib_conn_res - release IB related resources 36362306a36Sopenharmony_ci * @iser_conn: iser connection struct 36462306a36Sopenharmony_ci * @destroy: indicator if we need to try to release the 36562306a36Sopenharmony_ci * iser device and memory regoins pool (only iscsi 36662306a36Sopenharmony_ci * shutdown and DEVICE_REMOVAL will use this). 36762306a36Sopenharmony_ci * 36862306a36Sopenharmony_ci * This routine is called with the iser state mutex held 36962306a36Sopenharmony_ci * so the cm_id removal is out of here. It is Safe to 37062306a36Sopenharmony_ci * be invoked multiple times. 37162306a36Sopenharmony_ci */ 37262306a36Sopenharmony_cistatic void iser_free_ib_conn_res(struct iser_conn *iser_conn, bool destroy) 37362306a36Sopenharmony_ci{ 37462306a36Sopenharmony_ci struct ib_conn *ib_conn = &iser_conn->ib_conn; 37562306a36Sopenharmony_ci struct iser_device *device = ib_conn->device; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci iser_info("freeing conn %p cma_id %p qp %p\n", 37862306a36Sopenharmony_ci iser_conn, ib_conn->cma_id, ib_conn->qp); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci if (ib_conn->qp) { 38162306a36Sopenharmony_ci rdma_destroy_qp(ib_conn->cma_id); 38262306a36Sopenharmony_ci ib_cq_pool_put(ib_conn->cq, ib_conn->cq_size); 38362306a36Sopenharmony_ci ib_conn->qp = NULL; 38462306a36Sopenharmony_ci } 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci if (destroy) { 38762306a36Sopenharmony_ci if (iser_conn->rx_descs) 38862306a36Sopenharmony_ci iser_free_rx_descriptors(iser_conn); 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci if (device) { 39162306a36Sopenharmony_ci iser_device_try_release(device); 39262306a36Sopenharmony_ci ib_conn->device = NULL; 39362306a36Sopenharmony_ci } 39462306a36Sopenharmony_ci } 39562306a36Sopenharmony_ci} 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci/** 39862306a36Sopenharmony_ci * iser_conn_release - Frees all conn objects and deallocs conn descriptor 39962306a36Sopenharmony_ci * @iser_conn: iSER connection context 40062306a36Sopenharmony_ci */ 40162306a36Sopenharmony_civoid iser_conn_release(struct iser_conn *iser_conn) 40262306a36Sopenharmony_ci{ 40362306a36Sopenharmony_ci struct ib_conn *ib_conn = &iser_conn->ib_conn; 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci mutex_lock(&ig.connlist_mutex); 40662306a36Sopenharmony_ci list_del(&iser_conn->conn_list); 40762306a36Sopenharmony_ci mutex_unlock(&ig.connlist_mutex); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci mutex_lock(&iser_conn->state_mutex); 41062306a36Sopenharmony_ci /* In case we endup here without ep_disconnect being invoked. */ 41162306a36Sopenharmony_ci if (iser_conn->state != ISER_CONN_DOWN) { 41262306a36Sopenharmony_ci iser_warn("iser conn %p state %d, expected state down.\n", 41362306a36Sopenharmony_ci iser_conn, iser_conn->state); 41462306a36Sopenharmony_ci iscsi_destroy_endpoint(iser_conn->ep); 41562306a36Sopenharmony_ci iser_conn->state = ISER_CONN_DOWN; 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci /* 41862306a36Sopenharmony_ci * In case we never got to bind stage, we still need to 41962306a36Sopenharmony_ci * release IB resources (which is safe to call more than once). 42062306a36Sopenharmony_ci */ 42162306a36Sopenharmony_ci iser_free_ib_conn_res(iser_conn, true); 42262306a36Sopenharmony_ci mutex_unlock(&iser_conn->state_mutex); 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci if (ib_conn->cma_id) { 42562306a36Sopenharmony_ci rdma_destroy_id(ib_conn->cma_id); 42662306a36Sopenharmony_ci ib_conn->cma_id = NULL; 42762306a36Sopenharmony_ci } 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci kfree(iser_conn); 43062306a36Sopenharmony_ci} 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci/** 43362306a36Sopenharmony_ci * iser_conn_terminate - triggers start of the disconnect procedures and 43462306a36Sopenharmony_ci * waits for them to be done 43562306a36Sopenharmony_ci * @iser_conn: iSER connection context 43662306a36Sopenharmony_ci * 43762306a36Sopenharmony_ci * Called with state mutex held 43862306a36Sopenharmony_ci */ 43962306a36Sopenharmony_ciint iser_conn_terminate(struct iser_conn *iser_conn) 44062306a36Sopenharmony_ci{ 44162306a36Sopenharmony_ci struct ib_conn *ib_conn = &iser_conn->ib_conn; 44262306a36Sopenharmony_ci int err = 0; 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci lockdep_assert_held(&iser_conn->state_mutex); 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci /* terminate the iser conn only if the conn state is UP */ 44762306a36Sopenharmony_ci if (iser_conn->state != ISER_CONN_UP) 44862306a36Sopenharmony_ci return 0; 44962306a36Sopenharmony_ci 45062306a36Sopenharmony_ci iser_conn->state = ISER_CONN_TERMINATING; 45162306a36Sopenharmony_ci iser_info("iser_conn %p state %d\n", iser_conn, iser_conn->state); 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci /* suspend queuing of new iscsi commands */ 45462306a36Sopenharmony_ci if (iser_conn->iscsi_conn) 45562306a36Sopenharmony_ci iscsi_suspend_queue(iser_conn->iscsi_conn); 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci /* 45862306a36Sopenharmony_ci * In case we didn't already clean up the cma_id (peer initiated 45962306a36Sopenharmony_ci * a disconnection), we need to Cause the CMA to change the QP 46062306a36Sopenharmony_ci * state to ERROR. 46162306a36Sopenharmony_ci */ 46262306a36Sopenharmony_ci if (ib_conn->cma_id) { 46362306a36Sopenharmony_ci err = rdma_disconnect(ib_conn->cma_id); 46462306a36Sopenharmony_ci if (err) 46562306a36Sopenharmony_ci iser_err("Failed to disconnect, conn: 0x%p err %d\n", 46662306a36Sopenharmony_ci iser_conn, err); 46762306a36Sopenharmony_ci 46862306a36Sopenharmony_ci /* block until all flush errors are consumed */ 46962306a36Sopenharmony_ci ib_drain_qp(ib_conn->qp); 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci return 1; 47362306a36Sopenharmony_ci} 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ci/* 47662306a36Sopenharmony_ci * Called with state mutex held 47762306a36Sopenharmony_ci */ 47862306a36Sopenharmony_cistatic void iser_connect_error(struct rdma_cm_id *cma_id) 47962306a36Sopenharmony_ci{ 48062306a36Sopenharmony_ci struct iser_conn *iser_conn = cma_id->context; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci lockdep_assert_held(&iser_conn->state_mutex); 48362306a36Sopenharmony_ci 48462306a36Sopenharmony_ci iser_conn->state = ISER_CONN_TERMINATING; 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic void iser_calc_scsi_params(struct iser_conn *iser_conn, 48862306a36Sopenharmony_ci unsigned int max_sectors) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci struct iser_device *device = iser_conn->ib_conn.device; 49162306a36Sopenharmony_ci struct ib_device_attr *attr = &device->ib_device->attrs; 49262306a36Sopenharmony_ci unsigned short sg_tablesize, sup_sg_tablesize; 49362306a36Sopenharmony_ci unsigned short reserved_mr_pages; 49462306a36Sopenharmony_ci u32 max_num_sg; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci /* 49762306a36Sopenharmony_ci * FRs without SG_GAPS can only map up to a (device) page per entry, 49862306a36Sopenharmony_ci * but if the first entry is misaligned we'll end up using two entries 49962306a36Sopenharmony_ci * (head and tail) for a single page worth data, so one additional 50062306a36Sopenharmony_ci * entry is required. 50162306a36Sopenharmony_ci */ 50262306a36Sopenharmony_ci if (attr->kernel_cap_flags & IBK_SG_GAPS_REG) 50362306a36Sopenharmony_ci reserved_mr_pages = 0; 50462306a36Sopenharmony_ci else 50562306a36Sopenharmony_ci reserved_mr_pages = 1; 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci if (iser_conn->ib_conn.pi_support) 50862306a36Sopenharmony_ci max_num_sg = attr->max_pi_fast_reg_page_list_len; 50962306a36Sopenharmony_ci else 51062306a36Sopenharmony_ci max_num_sg = attr->max_fast_reg_page_list_len; 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci sg_tablesize = DIV_ROUND_UP(max_sectors * SECTOR_SIZE, SZ_4K); 51362306a36Sopenharmony_ci sup_sg_tablesize = min_t(uint, ISCSI_ISER_MAX_SG_TABLESIZE, 51462306a36Sopenharmony_ci max_num_sg - reserved_mr_pages); 51562306a36Sopenharmony_ci iser_conn->scsi_sg_tablesize = min(sg_tablesize, sup_sg_tablesize); 51662306a36Sopenharmony_ci iser_conn->pages_per_mr = 51762306a36Sopenharmony_ci iser_conn->scsi_sg_tablesize + reserved_mr_pages; 51862306a36Sopenharmony_ci} 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci/* 52162306a36Sopenharmony_ci * Called with state mutex held 52262306a36Sopenharmony_ci */ 52362306a36Sopenharmony_cistatic void iser_addr_handler(struct rdma_cm_id *cma_id) 52462306a36Sopenharmony_ci{ 52562306a36Sopenharmony_ci struct iser_conn *iser_conn = cma_id->context; 52662306a36Sopenharmony_ci struct iser_device *device; 52762306a36Sopenharmony_ci struct ib_conn *ib_conn; 52862306a36Sopenharmony_ci int ret; 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci lockdep_assert_held(&iser_conn->state_mutex); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci if (iser_conn->state != ISER_CONN_PENDING) 53362306a36Sopenharmony_ci /* bailout */ 53462306a36Sopenharmony_ci return; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci ib_conn = &iser_conn->ib_conn; 53762306a36Sopenharmony_ci device = iser_device_find_by_ib_device(cma_id); 53862306a36Sopenharmony_ci if (!device) { 53962306a36Sopenharmony_ci iser_err("device lookup/creation failed\n"); 54062306a36Sopenharmony_ci iser_connect_error(cma_id); 54162306a36Sopenharmony_ci return; 54262306a36Sopenharmony_ci } 54362306a36Sopenharmony_ci 54462306a36Sopenharmony_ci ib_conn->device = device; 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci /* connection T10-PI support */ 54762306a36Sopenharmony_ci if (iser_pi_enable) { 54862306a36Sopenharmony_ci if (!(device->ib_device->attrs.kernel_cap_flags & 54962306a36Sopenharmony_ci IBK_INTEGRITY_HANDOVER)) { 55062306a36Sopenharmony_ci iser_warn("T10-PI requested but not supported on %s, " 55162306a36Sopenharmony_ci "continue without T10-PI\n", 55262306a36Sopenharmony_ci dev_name(&ib_conn->device->ib_device->dev)); 55362306a36Sopenharmony_ci ib_conn->pi_support = false; 55462306a36Sopenharmony_ci } else { 55562306a36Sopenharmony_ci ib_conn->pi_support = true; 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci } 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci iser_calc_scsi_params(iser_conn, iser_max_sectors); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci ret = rdma_resolve_route(cma_id, 1000); 56262306a36Sopenharmony_ci if (ret) { 56362306a36Sopenharmony_ci iser_err("resolve route failed: %d\n", ret); 56462306a36Sopenharmony_ci iser_connect_error(cma_id); 56562306a36Sopenharmony_ci return; 56662306a36Sopenharmony_ci } 56762306a36Sopenharmony_ci} 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci/* 57062306a36Sopenharmony_ci * Called with state mutex held 57162306a36Sopenharmony_ci */ 57262306a36Sopenharmony_cistatic void iser_route_handler(struct rdma_cm_id *cma_id) 57362306a36Sopenharmony_ci{ 57462306a36Sopenharmony_ci struct rdma_conn_param conn_param; 57562306a36Sopenharmony_ci int ret; 57662306a36Sopenharmony_ci struct iser_cm_hdr req_hdr; 57762306a36Sopenharmony_ci struct iser_conn *iser_conn = cma_id->context; 57862306a36Sopenharmony_ci struct ib_conn *ib_conn = &iser_conn->ib_conn; 57962306a36Sopenharmony_ci struct ib_device *ib_dev = ib_conn->device->ib_device; 58062306a36Sopenharmony_ci 58162306a36Sopenharmony_ci lockdep_assert_held(&iser_conn->state_mutex); 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ci if (iser_conn->state != ISER_CONN_PENDING) 58462306a36Sopenharmony_ci /* bailout */ 58562306a36Sopenharmony_ci return; 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci ret = iser_create_ib_conn_res(ib_conn); 58862306a36Sopenharmony_ci if (ret) 58962306a36Sopenharmony_ci goto failure; 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci memset(&conn_param, 0, sizeof conn_param); 59262306a36Sopenharmony_ci conn_param.responder_resources = ib_dev->attrs.max_qp_rd_atom; 59362306a36Sopenharmony_ci conn_param.initiator_depth = 1; 59462306a36Sopenharmony_ci conn_param.retry_count = 7; 59562306a36Sopenharmony_ci conn_param.rnr_retry_count = 6; 59662306a36Sopenharmony_ci 59762306a36Sopenharmony_ci memset(&req_hdr, 0, sizeof(req_hdr)); 59862306a36Sopenharmony_ci req_hdr.flags = ISER_ZBVA_NOT_SUP; 59962306a36Sopenharmony_ci if (!iser_always_reg) 60062306a36Sopenharmony_ci req_hdr.flags |= ISER_SEND_W_INV_NOT_SUP; 60162306a36Sopenharmony_ci conn_param.private_data = (void *)&req_hdr; 60262306a36Sopenharmony_ci conn_param.private_data_len = sizeof(struct iser_cm_hdr); 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_ci ret = rdma_connect_locked(cma_id, &conn_param); 60562306a36Sopenharmony_ci if (ret) { 60662306a36Sopenharmony_ci iser_err("failure connecting: %d\n", ret); 60762306a36Sopenharmony_ci goto failure; 60862306a36Sopenharmony_ci } 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci return; 61162306a36Sopenharmony_cifailure: 61262306a36Sopenharmony_ci iser_connect_error(cma_id); 61362306a36Sopenharmony_ci} 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci/* 61662306a36Sopenharmony_ci * Called with state mutex held 61762306a36Sopenharmony_ci */ 61862306a36Sopenharmony_cistatic void iser_connected_handler(struct rdma_cm_id *cma_id, 61962306a36Sopenharmony_ci const void *private_data) 62062306a36Sopenharmony_ci{ 62162306a36Sopenharmony_ci struct iser_conn *iser_conn = cma_id->context; 62262306a36Sopenharmony_ci struct ib_qp_attr attr; 62362306a36Sopenharmony_ci struct ib_qp_init_attr init_attr; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci lockdep_assert_held(&iser_conn->state_mutex); 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci if (iser_conn->state != ISER_CONN_PENDING) 62862306a36Sopenharmony_ci /* bailout */ 62962306a36Sopenharmony_ci return; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci (void)ib_query_qp(cma_id->qp, &attr, ~0, &init_attr); 63262306a36Sopenharmony_ci iser_info("remote qpn:%x my qpn:%x\n", attr.dest_qp_num, cma_id->qp->qp_num); 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci if (private_data) { 63562306a36Sopenharmony_ci u8 flags = *(u8 *)private_data; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci iser_conn->snd_w_inv = !(flags & ISER_SEND_W_INV_NOT_SUP); 63862306a36Sopenharmony_ci } 63962306a36Sopenharmony_ci 64062306a36Sopenharmony_ci iser_info("conn %p: negotiated %s invalidation\n", 64162306a36Sopenharmony_ci iser_conn, iser_conn->snd_w_inv ? "remote" : "local"); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci iser_conn->state = ISER_CONN_UP; 64462306a36Sopenharmony_ci complete(&iser_conn->up_completion); 64562306a36Sopenharmony_ci} 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_ci/* 64862306a36Sopenharmony_ci * Called with state mutex held 64962306a36Sopenharmony_ci */ 65062306a36Sopenharmony_cistatic void iser_cleanup_handler(struct rdma_cm_id *cma_id, 65162306a36Sopenharmony_ci bool destroy) 65262306a36Sopenharmony_ci{ 65362306a36Sopenharmony_ci struct iser_conn *iser_conn = cma_id->context; 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_ci lockdep_assert_held(&iser_conn->state_mutex); 65662306a36Sopenharmony_ci /* 65762306a36Sopenharmony_ci * We are not guaranteed that we visited disconnected_handler 65862306a36Sopenharmony_ci * by now, call it here to be safe that we handle CM drep 65962306a36Sopenharmony_ci * and flush errors. 66062306a36Sopenharmony_ci */ 66162306a36Sopenharmony_ci if (iser_conn_terminate(iser_conn)) { 66262306a36Sopenharmony_ci if (iser_conn->iscsi_conn) 66362306a36Sopenharmony_ci iscsi_conn_failure(iser_conn->iscsi_conn, 66462306a36Sopenharmony_ci ISCSI_ERR_CONN_FAILED); 66562306a36Sopenharmony_ci else 66662306a36Sopenharmony_ci iser_err("iscsi_iser connection isn't bound\n"); 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci iser_free_ib_conn_res(iser_conn, destroy); 66962306a36Sopenharmony_ci complete(&iser_conn->ib_completion); 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_cistatic int iser_cma_handler(struct rdma_cm_id *cma_id, 67362306a36Sopenharmony_ci struct rdma_cm_event *event) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci struct iser_conn *iser_conn; 67662306a36Sopenharmony_ci int ret = 0; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci iser_conn = cma_id->context; 67962306a36Sopenharmony_ci iser_info("%s (%d): status %d conn %p id %p\n", 68062306a36Sopenharmony_ci rdma_event_msg(event->event), event->event, 68162306a36Sopenharmony_ci event->status, cma_id->context, cma_id); 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci mutex_lock(&iser_conn->state_mutex); 68462306a36Sopenharmony_ci switch (event->event) { 68562306a36Sopenharmony_ci case RDMA_CM_EVENT_ADDR_RESOLVED: 68662306a36Sopenharmony_ci iser_addr_handler(cma_id); 68762306a36Sopenharmony_ci break; 68862306a36Sopenharmony_ci case RDMA_CM_EVENT_ROUTE_RESOLVED: 68962306a36Sopenharmony_ci iser_route_handler(cma_id); 69062306a36Sopenharmony_ci break; 69162306a36Sopenharmony_ci case RDMA_CM_EVENT_ESTABLISHED: 69262306a36Sopenharmony_ci iser_connected_handler(cma_id, event->param.conn.private_data); 69362306a36Sopenharmony_ci break; 69462306a36Sopenharmony_ci case RDMA_CM_EVENT_REJECTED: 69562306a36Sopenharmony_ci iser_info("Connection rejected: %s\n", 69662306a36Sopenharmony_ci rdma_reject_msg(cma_id, event->status)); 69762306a36Sopenharmony_ci fallthrough; 69862306a36Sopenharmony_ci case RDMA_CM_EVENT_ADDR_ERROR: 69962306a36Sopenharmony_ci case RDMA_CM_EVENT_ROUTE_ERROR: 70062306a36Sopenharmony_ci case RDMA_CM_EVENT_CONNECT_ERROR: 70162306a36Sopenharmony_ci case RDMA_CM_EVENT_UNREACHABLE: 70262306a36Sopenharmony_ci iser_connect_error(cma_id); 70362306a36Sopenharmony_ci break; 70462306a36Sopenharmony_ci case RDMA_CM_EVENT_DISCONNECTED: 70562306a36Sopenharmony_ci case RDMA_CM_EVENT_ADDR_CHANGE: 70662306a36Sopenharmony_ci case RDMA_CM_EVENT_TIMEWAIT_EXIT: 70762306a36Sopenharmony_ci iser_cleanup_handler(cma_id, false); 70862306a36Sopenharmony_ci break; 70962306a36Sopenharmony_ci case RDMA_CM_EVENT_DEVICE_REMOVAL: 71062306a36Sopenharmony_ci /* 71162306a36Sopenharmony_ci * we *must* destroy the device as we cannot rely 71262306a36Sopenharmony_ci * on iscsid to be around to initiate error handling. 71362306a36Sopenharmony_ci * also if we are not in state DOWN implicitly destroy 71462306a36Sopenharmony_ci * the cma_id. 71562306a36Sopenharmony_ci */ 71662306a36Sopenharmony_ci iser_cleanup_handler(cma_id, true); 71762306a36Sopenharmony_ci if (iser_conn->state != ISER_CONN_DOWN) { 71862306a36Sopenharmony_ci iser_conn->ib_conn.cma_id = NULL; 71962306a36Sopenharmony_ci ret = 1; 72062306a36Sopenharmony_ci } 72162306a36Sopenharmony_ci break; 72262306a36Sopenharmony_ci default: 72362306a36Sopenharmony_ci iser_err("Unexpected RDMA CM event: %s (%d)\n", 72462306a36Sopenharmony_ci rdma_event_msg(event->event), event->event); 72562306a36Sopenharmony_ci break; 72662306a36Sopenharmony_ci } 72762306a36Sopenharmony_ci mutex_unlock(&iser_conn->state_mutex); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci return ret; 73062306a36Sopenharmony_ci} 73162306a36Sopenharmony_ci 73262306a36Sopenharmony_civoid iser_conn_init(struct iser_conn *iser_conn) 73362306a36Sopenharmony_ci{ 73462306a36Sopenharmony_ci struct ib_conn *ib_conn = &iser_conn->ib_conn; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci iser_conn->state = ISER_CONN_INIT; 73762306a36Sopenharmony_ci init_completion(&iser_conn->stop_completion); 73862306a36Sopenharmony_ci init_completion(&iser_conn->ib_completion); 73962306a36Sopenharmony_ci init_completion(&iser_conn->up_completion); 74062306a36Sopenharmony_ci INIT_LIST_HEAD(&iser_conn->conn_list); 74162306a36Sopenharmony_ci mutex_init(&iser_conn->state_mutex); 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci ib_conn->reg_cqe.done = iser_reg_comp; 74462306a36Sopenharmony_ci} 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci/* 74762306a36Sopenharmony_ci * starts the process of connecting to the target 74862306a36Sopenharmony_ci * sleeps until the connection is established or rejected 74962306a36Sopenharmony_ci */ 75062306a36Sopenharmony_ciint iser_connect(struct iser_conn *iser_conn, struct sockaddr *src_addr, 75162306a36Sopenharmony_ci struct sockaddr *dst_addr, int non_blocking) 75262306a36Sopenharmony_ci{ 75362306a36Sopenharmony_ci struct ib_conn *ib_conn = &iser_conn->ib_conn; 75462306a36Sopenharmony_ci int err = 0; 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci mutex_lock(&iser_conn->state_mutex); 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci sprintf(iser_conn->name, "%pISp", dst_addr); 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_ci iser_info("connecting to: %s\n", iser_conn->name); 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_ci /* the device is known only --after-- address resolution */ 76362306a36Sopenharmony_ci ib_conn->device = NULL; 76462306a36Sopenharmony_ci 76562306a36Sopenharmony_ci iser_conn->state = ISER_CONN_PENDING; 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_ci ib_conn->cma_id = rdma_create_id(&init_net, iser_cma_handler, 76862306a36Sopenharmony_ci iser_conn, RDMA_PS_TCP, IB_QPT_RC); 76962306a36Sopenharmony_ci if (IS_ERR(ib_conn->cma_id)) { 77062306a36Sopenharmony_ci err = PTR_ERR(ib_conn->cma_id); 77162306a36Sopenharmony_ci iser_err("rdma_create_id failed: %d\n", err); 77262306a36Sopenharmony_ci goto id_failure; 77362306a36Sopenharmony_ci } 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci err = rdma_resolve_addr(ib_conn->cma_id, src_addr, dst_addr, 1000); 77662306a36Sopenharmony_ci if (err) { 77762306a36Sopenharmony_ci iser_err("rdma_resolve_addr failed: %d\n", err); 77862306a36Sopenharmony_ci goto addr_failure; 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci if (!non_blocking) { 78262306a36Sopenharmony_ci wait_for_completion_interruptible(&iser_conn->up_completion); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci if (iser_conn->state != ISER_CONN_UP) { 78562306a36Sopenharmony_ci err = -EIO; 78662306a36Sopenharmony_ci goto connect_failure; 78762306a36Sopenharmony_ci } 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci mutex_unlock(&iser_conn->state_mutex); 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci mutex_lock(&ig.connlist_mutex); 79262306a36Sopenharmony_ci list_add(&iser_conn->conn_list, &ig.connlist); 79362306a36Sopenharmony_ci mutex_unlock(&ig.connlist_mutex); 79462306a36Sopenharmony_ci return 0; 79562306a36Sopenharmony_ci 79662306a36Sopenharmony_ciid_failure: 79762306a36Sopenharmony_ci ib_conn->cma_id = NULL; 79862306a36Sopenharmony_ciaddr_failure: 79962306a36Sopenharmony_ci iser_conn->state = ISER_CONN_DOWN; 80062306a36Sopenharmony_ciconnect_failure: 80162306a36Sopenharmony_ci mutex_unlock(&iser_conn->state_mutex); 80262306a36Sopenharmony_ci iser_conn_release(iser_conn); 80362306a36Sopenharmony_ci return err; 80462306a36Sopenharmony_ci} 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ciint iser_post_recvl(struct iser_conn *iser_conn) 80762306a36Sopenharmony_ci{ 80862306a36Sopenharmony_ci struct ib_conn *ib_conn = &iser_conn->ib_conn; 80962306a36Sopenharmony_ci struct iser_login_desc *desc = &iser_conn->login_desc; 81062306a36Sopenharmony_ci struct ib_recv_wr wr; 81162306a36Sopenharmony_ci int ret; 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci desc->sge.addr = desc->rsp_dma; 81462306a36Sopenharmony_ci desc->sge.length = ISER_RX_LOGIN_SIZE; 81562306a36Sopenharmony_ci desc->sge.lkey = ib_conn->device->pd->local_dma_lkey; 81662306a36Sopenharmony_ci 81762306a36Sopenharmony_ci desc->cqe.done = iser_login_rsp; 81862306a36Sopenharmony_ci wr.wr_cqe = &desc->cqe; 81962306a36Sopenharmony_ci wr.sg_list = &desc->sge; 82062306a36Sopenharmony_ci wr.num_sge = 1; 82162306a36Sopenharmony_ci wr.next = NULL; 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci ret = ib_post_recv(ib_conn->qp, &wr, NULL); 82462306a36Sopenharmony_ci if (unlikely(ret)) 82562306a36Sopenharmony_ci iser_err("ib_post_recv login failed ret=%d\n", ret); 82662306a36Sopenharmony_ci 82762306a36Sopenharmony_ci return ret; 82862306a36Sopenharmony_ci} 82962306a36Sopenharmony_ci 83062306a36Sopenharmony_ciint iser_post_recvm(struct iser_conn *iser_conn, struct iser_rx_desc *rx_desc) 83162306a36Sopenharmony_ci{ 83262306a36Sopenharmony_ci struct ib_conn *ib_conn = &iser_conn->ib_conn; 83362306a36Sopenharmony_ci struct ib_recv_wr wr; 83462306a36Sopenharmony_ci int ret; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci rx_desc->cqe.done = iser_task_rsp; 83762306a36Sopenharmony_ci wr.wr_cqe = &rx_desc->cqe; 83862306a36Sopenharmony_ci wr.sg_list = &rx_desc->rx_sg; 83962306a36Sopenharmony_ci wr.num_sge = 1; 84062306a36Sopenharmony_ci wr.next = NULL; 84162306a36Sopenharmony_ci 84262306a36Sopenharmony_ci ret = ib_post_recv(ib_conn->qp, &wr, NULL); 84362306a36Sopenharmony_ci if (unlikely(ret)) 84462306a36Sopenharmony_ci iser_err("ib_post_recv failed ret=%d\n", ret); 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci return ret; 84762306a36Sopenharmony_ci} 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci 85062306a36Sopenharmony_ci/** 85162306a36Sopenharmony_ci * iser_post_send - Initiate a Send DTO operation 85262306a36Sopenharmony_ci * @ib_conn: connection RDMA resources 85362306a36Sopenharmony_ci * @tx_desc: iSER TX descriptor 85462306a36Sopenharmony_ci * 85562306a36Sopenharmony_ci * Return: 0 on success, -1 on failure 85662306a36Sopenharmony_ci */ 85762306a36Sopenharmony_ciint iser_post_send(struct ib_conn *ib_conn, struct iser_tx_desc *tx_desc) 85862306a36Sopenharmony_ci{ 85962306a36Sopenharmony_ci struct ib_send_wr *wr = &tx_desc->send_wr; 86062306a36Sopenharmony_ci struct ib_send_wr *first_wr; 86162306a36Sopenharmony_ci int ret; 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci ib_dma_sync_single_for_device(ib_conn->device->ib_device, 86462306a36Sopenharmony_ci tx_desc->dma_addr, ISER_HEADERS_LEN, 86562306a36Sopenharmony_ci DMA_TO_DEVICE); 86662306a36Sopenharmony_ci 86762306a36Sopenharmony_ci wr->next = NULL; 86862306a36Sopenharmony_ci wr->wr_cqe = &tx_desc->cqe; 86962306a36Sopenharmony_ci wr->sg_list = tx_desc->tx_sg; 87062306a36Sopenharmony_ci wr->num_sge = tx_desc->num_sge; 87162306a36Sopenharmony_ci wr->opcode = IB_WR_SEND; 87262306a36Sopenharmony_ci wr->send_flags = IB_SEND_SIGNALED; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci if (tx_desc->inv_wr.next) 87562306a36Sopenharmony_ci first_wr = &tx_desc->inv_wr; 87662306a36Sopenharmony_ci else if (tx_desc->reg_wr.wr.next) 87762306a36Sopenharmony_ci first_wr = &tx_desc->reg_wr.wr; 87862306a36Sopenharmony_ci else 87962306a36Sopenharmony_ci first_wr = wr; 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci ret = ib_post_send(ib_conn->qp, first_wr, NULL); 88262306a36Sopenharmony_ci if (unlikely(ret)) 88362306a36Sopenharmony_ci iser_err("ib_post_send failed, ret:%d opcode:%d\n", 88462306a36Sopenharmony_ci ret, wr->opcode); 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_ci return ret; 88762306a36Sopenharmony_ci} 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ciu8 iser_check_task_pi_status(struct iscsi_iser_task *iser_task, 89062306a36Sopenharmony_ci enum iser_data_dir cmd_dir, sector_t *sector) 89162306a36Sopenharmony_ci{ 89262306a36Sopenharmony_ci struct iser_mem_reg *reg = &iser_task->rdma_reg[cmd_dir]; 89362306a36Sopenharmony_ci struct iser_fr_desc *desc = reg->desc; 89462306a36Sopenharmony_ci unsigned long sector_size = iser_task->sc->device->sector_size; 89562306a36Sopenharmony_ci struct ib_mr_status mr_status; 89662306a36Sopenharmony_ci int ret; 89762306a36Sopenharmony_ci 89862306a36Sopenharmony_ci if (desc && desc->sig_protected) { 89962306a36Sopenharmony_ci desc->sig_protected = false; 90062306a36Sopenharmony_ci ret = ib_check_mr_status(desc->rsc.sig_mr, 90162306a36Sopenharmony_ci IB_MR_CHECK_SIG_STATUS, &mr_status); 90262306a36Sopenharmony_ci if (ret) { 90362306a36Sopenharmony_ci iser_err("ib_check_mr_status failed, ret %d\n", ret); 90462306a36Sopenharmony_ci /* Not a lot we can do, return ambiguous guard error */ 90562306a36Sopenharmony_ci *sector = 0; 90662306a36Sopenharmony_ci return 0x1; 90762306a36Sopenharmony_ci } 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci if (mr_status.fail_status & IB_MR_CHECK_SIG_STATUS) { 91062306a36Sopenharmony_ci sector_t sector_off = mr_status.sig_err.sig_err_offset; 91162306a36Sopenharmony_ci 91262306a36Sopenharmony_ci sector_div(sector_off, sector_size + 8); 91362306a36Sopenharmony_ci *sector = scsi_get_sector(iser_task->sc) + sector_off; 91462306a36Sopenharmony_ci 91562306a36Sopenharmony_ci iser_err("PI error found type %d at sector %llx " 91662306a36Sopenharmony_ci "expected %x vs actual %x\n", 91762306a36Sopenharmony_ci mr_status.sig_err.err_type, 91862306a36Sopenharmony_ci (unsigned long long)*sector, 91962306a36Sopenharmony_ci mr_status.sig_err.expected, 92062306a36Sopenharmony_ci mr_status.sig_err.actual); 92162306a36Sopenharmony_ci 92262306a36Sopenharmony_ci switch (mr_status.sig_err.err_type) { 92362306a36Sopenharmony_ci case IB_SIG_BAD_GUARD: 92462306a36Sopenharmony_ci return 0x1; 92562306a36Sopenharmony_ci case IB_SIG_BAD_REFTAG: 92662306a36Sopenharmony_ci return 0x3; 92762306a36Sopenharmony_ci case IB_SIG_BAD_APPTAG: 92862306a36Sopenharmony_ci return 0x2; 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci } 93162306a36Sopenharmony_ci } 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci return 0; 93462306a36Sopenharmony_ci} 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_civoid iser_err_comp(struct ib_wc *wc, const char *type) 93762306a36Sopenharmony_ci{ 93862306a36Sopenharmony_ci if (wc->status != IB_WC_WR_FLUSH_ERR) { 93962306a36Sopenharmony_ci struct iser_conn *iser_conn = to_iser_conn(wc->qp->qp_context); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci iser_err("%s failure: %s (%d) vend_err %#x\n", type, 94262306a36Sopenharmony_ci ib_wc_status_msg(wc->status), wc->status, 94362306a36Sopenharmony_ci wc->vendor_err); 94462306a36Sopenharmony_ci 94562306a36Sopenharmony_ci if (iser_conn->iscsi_conn) 94662306a36Sopenharmony_ci iscsi_conn_failure(iser_conn->iscsi_conn, 94762306a36Sopenharmony_ci ISCSI_ERR_CONN_FAILED); 94862306a36Sopenharmony_ci } else { 94962306a36Sopenharmony_ci iser_dbg("%s failure: %s (%d)\n", type, 95062306a36Sopenharmony_ci ib_wc_status_msg(wc->status), wc->status); 95162306a36Sopenharmony_ci } 95262306a36Sopenharmony_ci} 953