162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/******************************************************************************* 362306a36Sopenharmony_ci * This file contains iSCSI extentions for RDMA (iSER) Verbs 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * (c) Copyright 2013 Datera, Inc. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Nicholas A. Bellinger <nab@linux-iscsi.org> 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci ****************************************************************************/ 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include <linux/string.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/scatterlist.h> 1462306a36Sopenharmony_ci#include <linux/socket.h> 1562306a36Sopenharmony_ci#include <linux/in.h> 1662306a36Sopenharmony_ci#include <linux/in6.h> 1762306a36Sopenharmony_ci#include <rdma/ib_verbs.h> 1862306a36Sopenharmony_ci#include <rdma/ib_cm.h> 1962306a36Sopenharmony_ci#include <rdma/rdma_cm.h> 2062306a36Sopenharmony_ci#include <target/target_core_base.h> 2162306a36Sopenharmony_ci#include <target/target_core_fabric.h> 2262306a36Sopenharmony_ci#include <target/iscsi/iscsi_transport.h> 2362306a36Sopenharmony_ci#include <linux/semaphore.h> 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci#include "ib_isert.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic int isert_debug_level; 2862306a36Sopenharmony_cimodule_param_named(debug_level, isert_debug_level, int, 0644); 2962306a36Sopenharmony_ciMODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0 (default:0)"); 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic int isert_sg_tablesize_set(const char *val, 3262306a36Sopenharmony_ci const struct kernel_param *kp); 3362306a36Sopenharmony_cistatic const struct kernel_param_ops sg_tablesize_ops = { 3462306a36Sopenharmony_ci .set = isert_sg_tablesize_set, 3562306a36Sopenharmony_ci .get = param_get_int, 3662306a36Sopenharmony_ci}; 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_cistatic int isert_sg_tablesize = ISCSI_ISER_MIN_SG_TABLESIZE; 3962306a36Sopenharmony_cimodule_param_cb(sg_tablesize, &sg_tablesize_ops, &isert_sg_tablesize, 0644); 4062306a36Sopenharmony_ciMODULE_PARM_DESC(sg_tablesize, 4162306a36Sopenharmony_ci "Number of gather/scatter entries in a single scsi command, should >= 128 (default: 128, max: 4096)"); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_cistatic DEFINE_MUTEX(device_list_mutex); 4462306a36Sopenharmony_cistatic LIST_HEAD(device_list); 4562306a36Sopenharmony_cistatic struct workqueue_struct *isert_login_wq; 4662306a36Sopenharmony_cistatic struct workqueue_struct *isert_comp_wq; 4762306a36Sopenharmony_cistatic struct workqueue_struct *isert_release_wq; 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_cistatic int 5062306a36Sopenharmony_ciisert_put_response(struct iscsit_conn *conn, struct iscsit_cmd *cmd); 5162306a36Sopenharmony_cistatic int 5262306a36Sopenharmony_ciisert_login_post_recv(struct isert_conn *isert_conn); 5362306a36Sopenharmony_cistatic int 5462306a36Sopenharmony_ciisert_rdma_accept(struct isert_conn *isert_conn); 5562306a36Sopenharmony_cistruct rdma_cm_id *isert_setup_id(struct isert_np *isert_np); 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_cistatic void isert_release_work(struct work_struct *work); 5862306a36Sopenharmony_cistatic void isert_recv_done(struct ib_cq *cq, struct ib_wc *wc); 5962306a36Sopenharmony_cistatic void isert_send_done(struct ib_cq *cq, struct ib_wc *wc); 6062306a36Sopenharmony_cistatic void isert_login_recv_done(struct ib_cq *cq, struct ib_wc *wc); 6162306a36Sopenharmony_cistatic void isert_login_send_done(struct ib_cq *cq, struct ib_wc *wc); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic int isert_sg_tablesize_set(const char *val, const struct kernel_param *kp) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci int n = 0, ret; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci ret = kstrtoint(val, 10, &n); 6862306a36Sopenharmony_ci if (ret != 0 || n < ISCSI_ISER_MIN_SG_TABLESIZE || 6962306a36Sopenharmony_ci n > ISCSI_ISER_MAX_SG_TABLESIZE) 7062306a36Sopenharmony_ci return -EINVAL; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci return param_set_int(val, kp); 7362306a36Sopenharmony_ci} 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_cistatic inline bool 7662306a36Sopenharmony_ciisert_prot_cmd(struct isert_conn *conn, struct se_cmd *cmd) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci return (conn->pi_support && 7962306a36Sopenharmony_ci cmd->prot_op != TARGET_PROT_NORMAL); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_cistatic void 8362306a36Sopenharmony_ciisert_qp_event_callback(struct ib_event *e, void *context) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct isert_conn *isert_conn = context; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci isert_err("%s (%d): conn %p\n", 8862306a36Sopenharmony_ci ib_event_msg(e->event), e->event, isert_conn); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci switch (e->event) { 9162306a36Sopenharmony_ci case IB_EVENT_COMM_EST: 9262306a36Sopenharmony_ci rdma_notify(isert_conn->cm_id, IB_EVENT_COMM_EST); 9362306a36Sopenharmony_ci break; 9462306a36Sopenharmony_ci case IB_EVENT_QP_LAST_WQE_REACHED: 9562306a36Sopenharmony_ci isert_warn("Reached TX IB_EVENT_QP_LAST_WQE_REACHED\n"); 9662306a36Sopenharmony_ci break; 9762306a36Sopenharmony_ci default: 9862306a36Sopenharmony_ci break; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci} 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_cistatic struct ib_qp * 10362306a36Sopenharmony_ciisert_create_qp(struct isert_conn *isert_conn, 10462306a36Sopenharmony_ci struct rdma_cm_id *cma_id) 10562306a36Sopenharmony_ci{ 10662306a36Sopenharmony_ci u32 cq_size = ISERT_QP_MAX_REQ_DTOS + ISERT_QP_MAX_RECV_DTOS + 2; 10762306a36Sopenharmony_ci struct isert_device *device = isert_conn->device; 10862306a36Sopenharmony_ci struct ib_device *ib_dev = device->ib_device; 10962306a36Sopenharmony_ci struct ib_qp_init_attr attr; 11062306a36Sopenharmony_ci int ret, factor; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci isert_conn->cq = ib_cq_pool_get(ib_dev, cq_size, -1, IB_POLL_WORKQUEUE); 11362306a36Sopenharmony_ci if (IS_ERR(isert_conn->cq)) { 11462306a36Sopenharmony_ci isert_err("Unable to allocate cq\n"); 11562306a36Sopenharmony_ci ret = PTR_ERR(isert_conn->cq); 11662306a36Sopenharmony_ci return ERR_PTR(ret); 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci isert_conn->cq_size = cq_size; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci memset(&attr, 0, sizeof(struct ib_qp_init_attr)); 12162306a36Sopenharmony_ci attr.event_handler = isert_qp_event_callback; 12262306a36Sopenharmony_ci attr.qp_context = isert_conn; 12362306a36Sopenharmony_ci attr.send_cq = isert_conn->cq; 12462306a36Sopenharmony_ci attr.recv_cq = isert_conn->cq; 12562306a36Sopenharmony_ci attr.cap.max_send_wr = ISERT_QP_MAX_REQ_DTOS + 1; 12662306a36Sopenharmony_ci attr.cap.max_recv_wr = ISERT_QP_MAX_RECV_DTOS + 1; 12762306a36Sopenharmony_ci factor = rdma_rw_mr_factor(device->ib_device, cma_id->port_num, 12862306a36Sopenharmony_ci isert_sg_tablesize); 12962306a36Sopenharmony_ci attr.cap.max_rdma_ctxs = ISCSI_DEF_XMIT_CMDS_MAX * factor; 13062306a36Sopenharmony_ci attr.cap.max_send_sge = device->ib_device->attrs.max_send_sge; 13162306a36Sopenharmony_ci attr.cap.max_recv_sge = 1; 13262306a36Sopenharmony_ci attr.sq_sig_type = IB_SIGNAL_REQ_WR; 13362306a36Sopenharmony_ci attr.qp_type = IB_QPT_RC; 13462306a36Sopenharmony_ci if (device->pi_capable) 13562306a36Sopenharmony_ci attr.create_flags |= IB_QP_CREATE_INTEGRITY_EN; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci ret = rdma_create_qp(cma_id, device->pd, &attr); 13862306a36Sopenharmony_ci if (ret) { 13962306a36Sopenharmony_ci isert_err("rdma_create_qp failed for cma_id %d\n", ret); 14062306a36Sopenharmony_ci ib_cq_pool_put(isert_conn->cq, isert_conn->cq_size); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci return ERR_PTR(ret); 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci return cma_id->qp; 14662306a36Sopenharmony_ci} 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_cistatic int 14962306a36Sopenharmony_ciisert_alloc_rx_descriptors(struct isert_conn *isert_conn) 15062306a36Sopenharmony_ci{ 15162306a36Sopenharmony_ci struct isert_device *device = isert_conn->device; 15262306a36Sopenharmony_ci struct ib_device *ib_dev = device->ib_device; 15362306a36Sopenharmony_ci struct iser_rx_desc *rx_desc; 15462306a36Sopenharmony_ci struct ib_sge *rx_sg; 15562306a36Sopenharmony_ci u64 dma_addr; 15662306a36Sopenharmony_ci int i, j; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_ci isert_conn->rx_descs = kcalloc(ISERT_QP_MAX_RECV_DTOS, 15962306a36Sopenharmony_ci sizeof(struct iser_rx_desc), 16062306a36Sopenharmony_ci GFP_KERNEL); 16162306a36Sopenharmony_ci if (!isert_conn->rx_descs) 16262306a36Sopenharmony_ci return -ENOMEM; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci rx_desc = isert_conn->rx_descs; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci for (i = 0; i < ISERT_QP_MAX_RECV_DTOS; i++, rx_desc++) { 16762306a36Sopenharmony_ci dma_addr = ib_dma_map_single(ib_dev, rx_desc->buf, 16862306a36Sopenharmony_ci ISER_RX_SIZE, DMA_FROM_DEVICE); 16962306a36Sopenharmony_ci if (ib_dma_mapping_error(ib_dev, dma_addr)) 17062306a36Sopenharmony_ci goto dma_map_fail; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci rx_desc->dma_addr = dma_addr; 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci rx_sg = &rx_desc->rx_sg; 17562306a36Sopenharmony_ci rx_sg->addr = rx_desc->dma_addr + isert_get_hdr_offset(rx_desc); 17662306a36Sopenharmony_ci rx_sg->length = ISER_RX_PAYLOAD_SIZE; 17762306a36Sopenharmony_ci rx_sg->lkey = device->pd->local_dma_lkey; 17862306a36Sopenharmony_ci rx_desc->rx_cqe.done = isert_recv_done; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return 0; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cidma_map_fail: 18462306a36Sopenharmony_ci rx_desc = isert_conn->rx_descs; 18562306a36Sopenharmony_ci for (j = 0; j < i; j++, rx_desc++) { 18662306a36Sopenharmony_ci ib_dma_unmap_single(ib_dev, rx_desc->dma_addr, 18762306a36Sopenharmony_ci ISER_RX_SIZE, DMA_FROM_DEVICE); 18862306a36Sopenharmony_ci } 18962306a36Sopenharmony_ci kfree(isert_conn->rx_descs); 19062306a36Sopenharmony_ci isert_conn->rx_descs = NULL; 19162306a36Sopenharmony_ci isert_err("conn %p failed to allocate rx descriptors\n", isert_conn); 19262306a36Sopenharmony_ci return -ENOMEM; 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic void 19662306a36Sopenharmony_ciisert_free_rx_descriptors(struct isert_conn *isert_conn) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci struct ib_device *ib_dev = isert_conn->device->ib_device; 19962306a36Sopenharmony_ci struct iser_rx_desc *rx_desc; 20062306a36Sopenharmony_ci int i; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (!isert_conn->rx_descs) 20362306a36Sopenharmony_ci return; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci rx_desc = isert_conn->rx_descs; 20662306a36Sopenharmony_ci for (i = 0; i < ISERT_QP_MAX_RECV_DTOS; i++, rx_desc++) { 20762306a36Sopenharmony_ci ib_dma_unmap_single(ib_dev, rx_desc->dma_addr, 20862306a36Sopenharmony_ci ISER_RX_SIZE, DMA_FROM_DEVICE); 20962306a36Sopenharmony_ci } 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci kfree(isert_conn->rx_descs); 21262306a36Sopenharmony_ci isert_conn->rx_descs = NULL; 21362306a36Sopenharmony_ci} 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_cistatic int 21662306a36Sopenharmony_ciisert_create_device_ib_res(struct isert_device *device) 21762306a36Sopenharmony_ci{ 21862306a36Sopenharmony_ci struct ib_device *ib_dev = device->ib_device; 21962306a36Sopenharmony_ci int ret; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci isert_dbg("devattr->max_send_sge: %d devattr->max_recv_sge %d\n", 22262306a36Sopenharmony_ci ib_dev->attrs.max_send_sge, ib_dev->attrs.max_recv_sge); 22362306a36Sopenharmony_ci isert_dbg("devattr->max_sge_rd: %d\n", ib_dev->attrs.max_sge_rd); 22462306a36Sopenharmony_ci 22562306a36Sopenharmony_ci device->pd = ib_alloc_pd(ib_dev, 0); 22662306a36Sopenharmony_ci if (IS_ERR(device->pd)) { 22762306a36Sopenharmony_ci ret = PTR_ERR(device->pd); 22862306a36Sopenharmony_ci isert_err("failed to allocate pd, device %p, ret=%d\n", 22962306a36Sopenharmony_ci device, ret); 23062306a36Sopenharmony_ci return ret; 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci /* Check signature cap */ 23462306a36Sopenharmony_ci if (ib_dev->attrs.kernel_cap_flags & IBK_INTEGRITY_HANDOVER) 23562306a36Sopenharmony_ci device->pi_capable = true; 23662306a36Sopenharmony_ci else 23762306a36Sopenharmony_ci device->pi_capable = false; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci return 0; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_cistatic void 24362306a36Sopenharmony_ciisert_free_device_ib_res(struct isert_device *device) 24462306a36Sopenharmony_ci{ 24562306a36Sopenharmony_ci isert_info("device %p\n", device); 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_ci ib_dealloc_pd(device->pd); 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistatic void 25162306a36Sopenharmony_ciisert_device_put(struct isert_device *device) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci mutex_lock(&device_list_mutex); 25462306a36Sopenharmony_ci device->refcount--; 25562306a36Sopenharmony_ci isert_info("device %p refcount %d\n", device, device->refcount); 25662306a36Sopenharmony_ci if (!device->refcount) { 25762306a36Sopenharmony_ci isert_free_device_ib_res(device); 25862306a36Sopenharmony_ci list_del(&device->dev_node); 25962306a36Sopenharmony_ci kfree(device); 26062306a36Sopenharmony_ci } 26162306a36Sopenharmony_ci mutex_unlock(&device_list_mutex); 26262306a36Sopenharmony_ci} 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_cistatic struct isert_device * 26562306a36Sopenharmony_ciisert_device_get(struct rdma_cm_id *cma_id) 26662306a36Sopenharmony_ci{ 26762306a36Sopenharmony_ci struct isert_device *device; 26862306a36Sopenharmony_ci int ret; 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci mutex_lock(&device_list_mutex); 27162306a36Sopenharmony_ci list_for_each_entry(device, &device_list, dev_node) { 27262306a36Sopenharmony_ci if (device->ib_device->node_guid == cma_id->device->node_guid) { 27362306a36Sopenharmony_ci device->refcount++; 27462306a36Sopenharmony_ci isert_info("Found iser device %p refcount %d\n", 27562306a36Sopenharmony_ci device, device->refcount); 27662306a36Sopenharmony_ci mutex_unlock(&device_list_mutex); 27762306a36Sopenharmony_ci return device; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci device = kzalloc(sizeof(struct isert_device), GFP_KERNEL); 28262306a36Sopenharmony_ci if (!device) { 28362306a36Sopenharmony_ci mutex_unlock(&device_list_mutex); 28462306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci INIT_LIST_HEAD(&device->dev_node); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci device->ib_device = cma_id->device; 29062306a36Sopenharmony_ci ret = isert_create_device_ib_res(device); 29162306a36Sopenharmony_ci if (ret) { 29262306a36Sopenharmony_ci kfree(device); 29362306a36Sopenharmony_ci mutex_unlock(&device_list_mutex); 29462306a36Sopenharmony_ci return ERR_PTR(ret); 29562306a36Sopenharmony_ci } 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci device->refcount++; 29862306a36Sopenharmony_ci list_add_tail(&device->dev_node, &device_list); 29962306a36Sopenharmony_ci isert_info("Created a new iser device %p refcount %d\n", 30062306a36Sopenharmony_ci device, device->refcount); 30162306a36Sopenharmony_ci mutex_unlock(&device_list_mutex); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci return device; 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistatic void 30762306a36Sopenharmony_ciisert_init_conn(struct isert_conn *isert_conn) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci isert_conn->state = ISER_CONN_INIT; 31062306a36Sopenharmony_ci INIT_LIST_HEAD(&isert_conn->node); 31162306a36Sopenharmony_ci init_completion(&isert_conn->login_comp); 31262306a36Sopenharmony_ci init_completion(&isert_conn->login_req_comp); 31362306a36Sopenharmony_ci init_waitqueue_head(&isert_conn->rem_wait); 31462306a36Sopenharmony_ci kref_init(&isert_conn->kref); 31562306a36Sopenharmony_ci mutex_init(&isert_conn->mutex); 31662306a36Sopenharmony_ci INIT_WORK(&isert_conn->release_work, isert_release_work); 31762306a36Sopenharmony_ci} 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_cistatic void 32062306a36Sopenharmony_ciisert_free_login_buf(struct isert_conn *isert_conn) 32162306a36Sopenharmony_ci{ 32262306a36Sopenharmony_ci struct ib_device *ib_dev = isert_conn->device->ib_device; 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci ib_dma_unmap_single(ib_dev, isert_conn->login_rsp_dma, 32562306a36Sopenharmony_ci ISER_RX_PAYLOAD_SIZE, DMA_TO_DEVICE); 32662306a36Sopenharmony_ci kfree(isert_conn->login_rsp_buf); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci ib_dma_unmap_single(ib_dev, isert_conn->login_desc->dma_addr, 32962306a36Sopenharmony_ci ISER_RX_SIZE, DMA_FROM_DEVICE); 33062306a36Sopenharmony_ci kfree(isert_conn->login_desc); 33162306a36Sopenharmony_ci} 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_cistatic int 33462306a36Sopenharmony_ciisert_alloc_login_buf(struct isert_conn *isert_conn, 33562306a36Sopenharmony_ci struct ib_device *ib_dev) 33662306a36Sopenharmony_ci{ 33762306a36Sopenharmony_ci int ret; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci isert_conn->login_desc = kzalloc(sizeof(*isert_conn->login_desc), 34062306a36Sopenharmony_ci GFP_KERNEL); 34162306a36Sopenharmony_ci if (!isert_conn->login_desc) 34262306a36Sopenharmony_ci return -ENOMEM; 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci isert_conn->login_desc->dma_addr = ib_dma_map_single(ib_dev, 34562306a36Sopenharmony_ci isert_conn->login_desc->buf, 34662306a36Sopenharmony_ci ISER_RX_SIZE, DMA_FROM_DEVICE); 34762306a36Sopenharmony_ci ret = ib_dma_mapping_error(ib_dev, isert_conn->login_desc->dma_addr); 34862306a36Sopenharmony_ci if (ret) { 34962306a36Sopenharmony_ci isert_err("login_desc dma mapping error: %d\n", ret); 35062306a36Sopenharmony_ci isert_conn->login_desc->dma_addr = 0; 35162306a36Sopenharmony_ci goto out_free_login_desc; 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci isert_conn->login_rsp_buf = kzalloc(ISER_RX_PAYLOAD_SIZE, GFP_KERNEL); 35562306a36Sopenharmony_ci if (!isert_conn->login_rsp_buf) { 35662306a36Sopenharmony_ci ret = -ENOMEM; 35762306a36Sopenharmony_ci goto out_unmap_login_desc; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci isert_conn->login_rsp_dma = ib_dma_map_single(ib_dev, 36162306a36Sopenharmony_ci isert_conn->login_rsp_buf, 36262306a36Sopenharmony_ci ISER_RX_PAYLOAD_SIZE, DMA_TO_DEVICE); 36362306a36Sopenharmony_ci ret = ib_dma_mapping_error(ib_dev, isert_conn->login_rsp_dma); 36462306a36Sopenharmony_ci if (ret) { 36562306a36Sopenharmony_ci isert_err("login_rsp_dma mapping error: %d\n", ret); 36662306a36Sopenharmony_ci isert_conn->login_rsp_dma = 0; 36762306a36Sopenharmony_ci goto out_free_login_rsp_buf; 36862306a36Sopenharmony_ci } 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci return 0; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_ciout_free_login_rsp_buf: 37362306a36Sopenharmony_ci kfree(isert_conn->login_rsp_buf); 37462306a36Sopenharmony_ciout_unmap_login_desc: 37562306a36Sopenharmony_ci ib_dma_unmap_single(ib_dev, isert_conn->login_desc->dma_addr, 37662306a36Sopenharmony_ci ISER_RX_SIZE, DMA_FROM_DEVICE); 37762306a36Sopenharmony_ciout_free_login_desc: 37862306a36Sopenharmony_ci kfree(isert_conn->login_desc); 37962306a36Sopenharmony_ci return ret; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic void 38362306a36Sopenharmony_ciisert_set_nego_params(struct isert_conn *isert_conn, 38462306a36Sopenharmony_ci struct rdma_conn_param *param) 38562306a36Sopenharmony_ci{ 38662306a36Sopenharmony_ci struct ib_device_attr *attr = &isert_conn->device->ib_device->attrs; 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci /* Set max inflight RDMA READ requests */ 38962306a36Sopenharmony_ci isert_conn->initiator_depth = min_t(u8, param->initiator_depth, 39062306a36Sopenharmony_ci attr->max_qp_init_rd_atom); 39162306a36Sopenharmony_ci isert_dbg("Using initiator_depth: %u\n", isert_conn->initiator_depth); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci if (param->private_data) { 39462306a36Sopenharmony_ci u8 flags = *(u8 *)param->private_data; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* 39762306a36Sopenharmony_ci * use remote invalidation if the both initiator 39862306a36Sopenharmony_ci * and the HCA support it 39962306a36Sopenharmony_ci */ 40062306a36Sopenharmony_ci isert_conn->snd_w_inv = !(flags & ISER_SEND_W_INV_NOT_SUP) && 40162306a36Sopenharmony_ci (attr->device_cap_flags & 40262306a36Sopenharmony_ci IB_DEVICE_MEM_MGT_EXTENSIONS); 40362306a36Sopenharmony_ci if (isert_conn->snd_w_inv) 40462306a36Sopenharmony_ci isert_info("Using remote invalidation\n"); 40562306a36Sopenharmony_ci } 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_cistatic void 40962306a36Sopenharmony_ciisert_destroy_qp(struct isert_conn *isert_conn) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci ib_destroy_qp(isert_conn->qp); 41262306a36Sopenharmony_ci ib_cq_pool_put(isert_conn->cq, isert_conn->cq_size); 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_cistatic int 41662306a36Sopenharmony_ciisert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci struct isert_np *isert_np = cma_id->context; 41962306a36Sopenharmony_ci struct iscsi_np *np = isert_np->np; 42062306a36Sopenharmony_ci struct isert_conn *isert_conn; 42162306a36Sopenharmony_ci struct isert_device *device; 42262306a36Sopenharmony_ci int ret = 0; 42362306a36Sopenharmony_ci 42462306a36Sopenharmony_ci spin_lock_bh(&np->np_thread_lock); 42562306a36Sopenharmony_ci if (!np->enabled) { 42662306a36Sopenharmony_ci spin_unlock_bh(&np->np_thread_lock); 42762306a36Sopenharmony_ci isert_dbg("iscsi_np is not enabled, reject connect request\n"); 42862306a36Sopenharmony_ci return rdma_reject(cma_id, NULL, 0, IB_CM_REJ_CONSUMER_DEFINED); 42962306a36Sopenharmony_ci } 43062306a36Sopenharmony_ci spin_unlock_bh(&np->np_thread_lock); 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci isert_dbg("cma_id: %p, portal: %p\n", 43362306a36Sopenharmony_ci cma_id, cma_id->context); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci isert_conn = kzalloc(sizeof(struct isert_conn), GFP_KERNEL); 43662306a36Sopenharmony_ci if (!isert_conn) 43762306a36Sopenharmony_ci return -ENOMEM; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci isert_init_conn(isert_conn); 44062306a36Sopenharmony_ci isert_conn->cm_id = cma_id; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci device = isert_device_get(cma_id); 44362306a36Sopenharmony_ci if (IS_ERR(device)) { 44462306a36Sopenharmony_ci ret = PTR_ERR(device); 44562306a36Sopenharmony_ci goto out; 44662306a36Sopenharmony_ci } 44762306a36Sopenharmony_ci isert_conn->device = device; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci ret = isert_alloc_login_buf(isert_conn, cma_id->device); 45062306a36Sopenharmony_ci if (ret) 45162306a36Sopenharmony_ci goto out_conn_dev; 45262306a36Sopenharmony_ci 45362306a36Sopenharmony_ci isert_set_nego_params(isert_conn, &event->param.conn); 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_ci isert_conn->qp = isert_create_qp(isert_conn, cma_id); 45662306a36Sopenharmony_ci if (IS_ERR(isert_conn->qp)) { 45762306a36Sopenharmony_ci ret = PTR_ERR(isert_conn->qp); 45862306a36Sopenharmony_ci goto out_rsp_dma_map; 45962306a36Sopenharmony_ci } 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci ret = isert_login_post_recv(isert_conn); 46262306a36Sopenharmony_ci if (ret) 46362306a36Sopenharmony_ci goto out_destroy_qp; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci ret = isert_rdma_accept(isert_conn); 46662306a36Sopenharmony_ci if (ret) 46762306a36Sopenharmony_ci goto out_destroy_qp; 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci mutex_lock(&isert_np->mutex); 47062306a36Sopenharmony_ci list_add_tail(&isert_conn->node, &isert_np->accepted); 47162306a36Sopenharmony_ci mutex_unlock(&isert_np->mutex); 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci return 0; 47462306a36Sopenharmony_ci 47562306a36Sopenharmony_ciout_destroy_qp: 47662306a36Sopenharmony_ci isert_destroy_qp(isert_conn); 47762306a36Sopenharmony_ciout_rsp_dma_map: 47862306a36Sopenharmony_ci isert_free_login_buf(isert_conn); 47962306a36Sopenharmony_ciout_conn_dev: 48062306a36Sopenharmony_ci isert_device_put(device); 48162306a36Sopenharmony_ciout: 48262306a36Sopenharmony_ci kfree(isert_conn); 48362306a36Sopenharmony_ci rdma_reject(cma_id, NULL, 0, IB_CM_REJ_CONSUMER_DEFINED); 48462306a36Sopenharmony_ci return ret; 48562306a36Sopenharmony_ci} 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_cistatic void 48862306a36Sopenharmony_ciisert_connect_release(struct isert_conn *isert_conn) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci struct isert_device *device = isert_conn->device; 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci isert_dbg("conn %p\n", isert_conn); 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci BUG_ON(!device); 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci isert_free_rx_descriptors(isert_conn); 49762306a36Sopenharmony_ci if (isert_conn->cm_id && 49862306a36Sopenharmony_ci !isert_conn->dev_removed) 49962306a36Sopenharmony_ci rdma_destroy_id(isert_conn->cm_id); 50062306a36Sopenharmony_ci 50162306a36Sopenharmony_ci if (isert_conn->qp) 50262306a36Sopenharmony_ci isert_destroy_qp(isert_conn); 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci if (isert_conn->login_desc) 50562306a36Sopenharmony_ci isert_free_login_buf(isert_conn); 50662306a36Sopenharmony_ci 50762306a36Sopenharmony_ci isert_device_put(device); 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (isert_conn->dev_removed) 51062306a36Sopenharmony_ci wake_up_interruptible(&isert_conn->rem_wait); 51162306a36Sopenharmony_ci else 51262306a36Sopenharmony_ci kfree(isert_conn); 51362306a36Sopenharmony_ci} 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_cistatic void 51662306a36Sopenharmony_ciisert_connected_handler(struct rdma_cm_id *cma_id) 51762306a36Sopenharmony_ci{ 51862306a36Sopenharmony_ci struct isert_conn *isert_conn = cma_id->qp->qp_context; 51962306a36Sopenharmony_ci struct isert_np *isert_np = cma_id->context; 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci isert_info("conn %p\n", isert_conn); 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci mutex_lock(&isert_conn->mutex); 52462306a36Sopenharmony_ci isert_conn->state = ISER_CONN_UP; 52562306a36Sopenharmony_ci kref_get(&isert_conn->kref); 52662306a36Sopenharmony_ci mutex_unlock(&isert_conn->mutex); 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci mutex_lock(&isert_np->mutex); 52962306a36Sopenharmony_ci list_move_tail(&isert_conn->node, &isert_np->pending); 53062306a36Sopenharmony_ci mutex_unlock(&isert_np->mutex); 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci isert_info("np %p: Allow accept_np to continue\n", isert_np); 53362306a36Sopenharmony_ci up(&isert_np->sem); 53462306a36Sopenharmony_ci} 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_cistatic void 53762306a36Sopenharmony_ciisert_release_kref(struct kref *kref) 53862306a36Sopenharmony_ci{ 53962306a36Sopenharmony_ci struct isert_conn *isert_conn = container_of(kref, 54062306a36Sopenharmony_ci struct isert_conn, kref); 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci isert_info("conn %p final kref %s/%d\n", isert_conn, current->comm, 54362306a36Sopenharmony_ci current->pid); 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci isert_connect_release(isert_conn); 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_cistatic void 54962306a36Sopenharmony_ciisert_put_conn(struct isert_conn *isert_conn) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci kref_put(&isert_conn->kref, isert_release_kref); 55262306a36Sopenharmony_ci} 55362306a36Sopenharmony_ci 55462306a36Sopenharmony_cistatic void 55562306a36Sopenharmony_ciisert_handle_unbound_conn(struct isert_conn *isert_conn) 55662306a36Sopenharmony_ci{ 55762306a36Sopenharmony_ci struct isert_np *isert_np = isert_conn->cm_id->context; 55862306a36Sopenharmony_ci 55962306a36Sopenharmony_ci mutex_lock(&isert_np->mutex); 56062306a36Sopenharmony_ci if (!list_empty(&isert_conn->node)) { 56162306a36Sopenharmony_ci /* 56262306a36Sopenharmony_ci * This means iscsi doesn't know this connection 56362306a36Sopenharmony_ci * so schedule a cleanup ourselves 56462306a36Sopenharmony_ci */ 56562306a36Sopenharmony_ci list_del_init(&isert_conn->node); 56662306a36Sopenharmony_ci isert_put_conn(isert_conn); 56762306a36Sopenharmony_ci queue_work(isert_release_wq, &isert_conn->release_work); 56862306a36Sopenharmony_ci } 56962306a36Sopenharmony_ci mutex_unlock(&isert_np->mutex); 57062306a36Sopenharmony_ci} 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci/** 57362306a36Sopenharmony_ci * isert_conn_terminate() - Initiate connection termination 57462306a36Sopenharmony_ci * @isert_conn: isert connection struct 57562306a36Sopenharmony_ci * 57662306a36Sopenharmony_ci * Notes: 57762306a36Sopenharmony_ci * In case the connection state is BOUND, move state 57862306a36Sopenharmony_ci * to TEMINATING and start teardown sequence (rdma_disconnect). 57962306a36Sopenharmony_ci * In case the connection state is UP, complete flush as well. 58062306a36Sopenharmony_ci * 58162306a36Sopenharmony_ci * This routine must be called with mutex held. Thus it is 58262306a36Sopenharmony_ci * safe to call multiple times. 58362306a36Sopenharmony_ci */ 58462306a36Sopenharmony_cistatic void 58562306a36Sopenharmony_ciisert_conn_terminate(struct isert_conn *isert_conn) 58662306a36Sopenharmony_ci{ 58762306a36Sopenharmony_ci int err; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci if (isert_conn->state >= ISER_CONN_TERMINATING) 59062306a36Sopenharmony_ci return; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci isert_info("Terminating conn %p state %d\n", 59362306a36Sopenharmony_ci isert_conn, isert_conn->state); 59462306a36Sopenharmony_ci isert_conn->state = ISER_CONN_TERMINATING; 59562306a36Sopenharmony_ci err = rdma_disconnect(isert_conn->cm_id); 59662306a36Sopenharmony_ci if (err) 59762306a36Sopenharmony_ci isert_warn("Failed rdma_disconnect isert_conn %p\n", 59862306a36Sopenharmony_ci isert_conn); 59962306a36Sopenharmony_ci} 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_cistatic int 60262306a36Sopenharmony_ciisert_np_cma_handler(struct isert_np *isert_np, 60362306a36Sopenharmony_ci enum rdma_cm_event_type event) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci isert_dbg("%s (%d): isert np %p\n", 60662306a36Sopenharmony_ci rdma_event_msg(event), event, isert_np); 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci switch (event) { 60962306a36Sopenharmony_ci case RDMA_CM_EVENT_DEVICE_REMOVAL: 61062306a36Sopenharmony_ci isert_np->cm_id = NULL; 61162306a36Sopenharmony_ci break; 61262306a36Sopenharmony_ci case RDMA_CM_EVENT_ADDR_CHANGE: 61362306a36Sopenharmony_ci isert_np->cm_id = isert_setup_id(isert_np); 61462306a36Sopenharmony_ci if (IS_ERR(isert_np->cm_id)) { 61562306a36Sopenharmony_ci isert_err("isert np %p setup id failed: %ld\n", 61662306a36Sopenharmony_ci isert_np, PTR_ERR(isert_np->cm_id)); 61762306a36Sopenharmony_ci isert_np->cm_id = NULL; 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci break; 62062306a36Sopenharmony_ci default: 62162306a36Sopenharmony_ci isert_err("isert np %p Unexpected event %d\n", 62262306a36Sopenharmony_ci isert_np, event); 62362306a36Sopenharmony_ci } 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci return -1; 62662306a36Sopenharmony_ci} 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_cistatic int 62962306a36Sopenharmony_ciisert_disconnected_handler(struct rdma_cm_id *cma_id, 63062306a36Sopenharmony_ci enum rdma_cm_event_type event) 63162306a36Sopenharmony_ci{ 63262306a36Sopenharmony_ci struct isert_conn *isert_conn = cma_id->qp->qp_context; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci mutex_lock(&isert_conn->mutex); 63562306a36Sopenharmony_ci switch (isert_conn->state) { 63662306a36Sopenharmony_ci case ISER_CONN_TERMINATING: 63762306a36Sopenharmony_ci break; 63862306a36Sopenharmony_ci case ISER_CONN_UP: 63962306a36Sopenharmony_ci isert_conn_terminate(isert_conn); 64062306a36Sopenharmony_ci ib_drain_qp(isert_conn->qp); 64162306a36Sopenharmony_ci isert_handle_unbound_conn(isert_conn); 64262306a36Sopenharmony_ci break; 64362306a36Sopenharmony_ci case ISER_CONN_BOUND: 64462306a36Sopenharmony_ci case ISER_CONN_FULL_FEATURE: /* FALLTHRU */ 64562306a36Sopenharmony_ci iscsit_cause_connection_reinstatement(isert_conn->conn, 0); 64662306a36Sopenharmony_ci break; 64762306a36Sopenharmony_ci default: 64862306a36Sopenharmony_ci isert_warn("conn %p terminating in state %d\n", 64962306a36Sopenharmony_ci isert_conn, isert_conn->state); 65062306a36Sopenharmony_ci } 65162306a36Sopenharmony_ci mutex_unlock(&isert_conn->mutex); 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci return 0; 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic int 65762306a36Sopenharmony_ciisert_connect_error(struct rdma_cm_id *cma_id) 65862306a36Sopenharmony_ci{ 65962306a36Sopenharmony_ci struct isert_conn *isert_conn = cma_id->qp->qp_context; 66062306a36Sopenharmony_ci struct isert_np *isert_np = cma_id->context; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci ib_drain_qp(isert_conn->qp); 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci mutex_lock(&isert_np->mutex); 66562306a36Sopenharmony_ci list_del_init(&isert_conn->node); 66662306a36Sopenharmony_ci mutex_unlock(&isert_np->mutex); 66762306a36Sopenharmony_ci isert_conn->cm_id = NULL; 66862306a36Sopenharmony_ci isert_put_conn(isert_conn); 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ci return -1; 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic int 67462306a36Sopenharmony_ciisert_cma_handler(struct rdma_cm_id *cma_id, struct rdma_cm_event *event) 67562306a36Sopenharmony_ci{ 67662306a36Sopenharmony_ci struct isert_np *isert_np = cma_id->context; 67762306a36Sopenharmony_ci struct isert_conn *isert_conn; 67862306a36Sopenharmony_ci int ret = 0; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci isert_info("%s (%d): status %d id %p np %p\n", 68162306a36Sopenharmony_ci rdma_event_msg(event->event), event->event, 68262306a36Sopenharmony_ci event->status, cma_id, cma_id->context); 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci if (isert_np->cm_id == cma_id) 68562306a36Sopenharmony_ci return isert_np_cma_handler(cma_id->context, event->event); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci switch (event->event) { 68862306a36Sopenharmony_ci case RDMA_CM_EVENT_CONNECT_REQUEST: 68962306a36Sopenharmony_ci ret = isert_connect_request(cma_id, event); 69062306a36Sopenharmony_ci if (ret) 69162306a36Sopenharmony_ci isert_err("failed handle connect request %d\n", ret); 69262306a36Sopenharmony_ci break; 69362306a36Sopenharmony_ci case RDMA_CM_EVENT_ESTABLISHED: 69462306a36Sopenharmony_ci isert_connected_handler(cma_id); 69562306a36Sopenharmony_ci break; 69662306a36Sopenharmony_ci case RDMA_CM_EVENT_ADDR_CHANGE: 69762306a36Sopenharmony_ci case RDMA_CM_EVENT_DISCONNECTED: 69862306a36Sopenharmony_ci case RDMA_CM_EVENT_TIMEWAIT_EXIT: /* FALLTHRU */ 69962306a36Sopenharmony_ci ret = isert_disconnected_handler(cma_id, event->event); 70062306a36Sopenharmony_ci break; 70162306a36Sopenharmony_ci case RDMA_CM_EVENT_DEVICE_REMOVAL: 70262306a36Sopenharmony_ci isert_conn = cma_id->qp->qp_context; 70362306a36Sopenharmony_ci isert_conn->dev_removed = true; 70462306a36Sopenharmony_ci isert_disconnected_handler(cma_id, event->event); 70562306a36Sopenharmony_ci wait_event_interruptible(isert_conn->rem_wait, 70662306a36Sopenharmony_ci isert_conn->state == ISER_CONN_DOWN); 70762306a36Sopenharmony_ci kfree(isert_conn); 70862306a36Sopenharmony_ci /* 70962306a36Sopenharmony_ci * return non-zero from the callback to destroy 71062306a36Sopenharmony_ci * the rdma cm id 71162306a36Sopenharmony_ci */ 71262306a36Sopenharmony_ci return 1; 71362306a36Sopenharmony_ci case RDMA_CM_EVENT_REJECTED: 71462306a36Sopenharmony_ci isert_info("Connection rejected: %s\n", 71562306a36Sopenharmony_ci rdma_reject_msg(cma_id, event->status)); 71662306a36Sopenharmony_ci fallthrough; 71762306a36Sopenharmony_ci case RDMA_CM_EVENT_UNREACHABLE: 71862306a36Sopenharmony_ci case RDMA_CM_EVENT_CONNECT_ERROR: 71962306a36Sopenharmony_ci ret = isert_connect_error(cma_id); 72062306a36Sopenharmony_ci break; 72162306a36Sopenharmony_ci default: 72262306a36Sopenharmony_ci isert_err("Unhandled RDMA CMA event: %d\n", event->event); 72362306a36Sopenharmony_ci break; 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_ci return ret; 72762306a36Sopenharmony_ci} 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_cistatic int 73062306a36Sopenharmony_ciisert_post_recvm(struct isert_conn *isert_conn, u32 count) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci struct ib_recv_wr *rx_wr; 73362306a36Sopenharmony_ci int i, ret; 73462306a36Sopenharmony_ci struct iser_rx_desc *rx_desc; 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci for (rx_wr = isert_conn->rx_wr, i = 0; i < count; i++, rx_wr++) { 73762306a36Sopenharmony_ci rx_desc = &isert_conn->rx_descs[i]; 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci rx_wr->wr_cqe = &rx_desc->rx_cqe; 74062306a36Sopenharmony_ci rx_wr->sg_list = &rx_desc->rx_sg; 74162306a36Sopenharmony_ci rx_wr->num_sge = 1; 74262306a36Sopenharmony_ci rx_wr->next = rx_wr + 1; 74362306a36Sopenharmony_ci rx_desc->in_use = false; 74462306a36Sopenharmony_ci } 74562306a36Sopenharmony_ci rx_wr--; 74662306a36Sopenharmony_ci rx_wr->next = NULL; /* mark end of work requests list */ 74762306a36Sopenharmony_ci 74862306a36Sopenharmony_ci ret = ib_post_recv(isert_conn->qp, isert_conn->rx_wr, NULL); 74962306a36Sopenharmony_ci if (ret) 75062306a36Sopenharmony_ci isert_err("ib_post_recv() failed with ret: %d\n", ret); 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci return ret; 75362306a36Sopenharmony_ci} 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_cistatic int 75662306a36Sopenharmony_ciisert_post_recv(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc) 75762306a36Sopenharmony_ci{ 75862306a36Sopenharmony_ci struct ib_recv_wr rx_wr; 75962306a36Sopenharmony_ci int ret; 76062306a36Sopenharmony_ci 76162306a36Sopenharmony_ci if (!rx_desc->in_use) { 76262306a36Sopenharmony_ci /* 76362306a36Sopenharmony_ci * if the descriptor is not in-use we already reposted it 76462306a36Sopenharmony_ci * for recv, so just silently return 76562306a36Sopenharmony_ci */ 76662306a36Sopenharmony_ci return 0; 76762306a36Sopenharmony_ci } 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci rx_desc->in_use = false; 77062306a36Sopenharmony_ci rx_wr.wr_cqe = &rx_desc->rx_cqe; 77162306a36Sopenharmony_ci rx_wr.sg_list = &rx_desc->rx_sg; 77262306a36Sopenharmony_ci rx_wr.num_sge = 1; 77362306a36Sopenharmony_ci rx_wr.next = NULL; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci ret = ib_post_recv(isert_conn->qp, &rx_wr, NULL); 77662306a36Sopenharmony_ci if (ret) 77762306a36Sopenharmony_ci isert_err("ib_post_recv() failed with ret: %d\n", ret); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci return ret; 78062306a36Sopenharmony_ci} 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_cistatic int 78362306a36Sopenharmony_ciisert_login_post_send(struct isert_conn *isert_conn, struct iser_tx_desc *tx_desc) 78462306a36Sopenharmony_ci{ 78562306a36Sopenharmony_ci struct ib_device *ib_dev = isert_conn->cm_id->device; 78662306a36Sopenharmony_ci struct ib_send_wr send_wr; 78762306a36Sopenharmony_ci int ret; 78862306a36Sopenharmony_ci 78962306a36Sopenharmony_ci ib_dma_sync_single_for_device(ib_dev, tx_desc->dma_addr, 79062306a36Sopenharmony_ci ISER_HEADERS_LEN, DMA_TO_DEVICE); 79162306a36Sopenharmony_ci 79262306a36Sopenharmony_ci tx_desc->tx_cqe.done = isert_login_send_done; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci send_wr.next = NULL; 79562306a36Sopenharmony_ci send_wr.wr_cqe = &tx_desc->tx_cqe; 79662306a36Sopenharmony_ci send_wr.sg_list = tx_desc->tx_sg; 79762306a36Sopenharmony_ci send_wr.num_sge = tx_desc->num_sge; 79862306a36Sopenharmony_ci send_wr.opcode = IB_WR_SEND; 79962306a36Sopenharmony_ci send_wr.send_flags = IB_SEND_SIGNALED; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci ret = ib_post_send(isert_conn->qp, &send_wr, NULL); 80262306a36Sopenharmony_ci if (ret) 80362306a36Sopenharmony_ci isert_err("ib_post_send() failed, ret: %d\n", ret); 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_ci return ret; 80662306a36Sopenharmony_ci} 80762306a36Sopenharmony_ci 80862306a36Sopenharmony_cistatic void 80962306a36Sopenharmony_ci__isert_create_send_desc(struct isert_device *device, 81062306a36Sopenharmony_ci struct iser_tx_desc *tx_desc) 81162306a36Sopenharmony_ci{ 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci memset(&tx_desc->iser_header, 0, sizeof(struct iser_ctrl)); 81462306a36Sopenharmony_ci tx_desc->iser_header.flags = ISCSI_CTRL; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci tx_desc->num_sge = 1; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci if (tx_desc->tx_sg[0].lkey != device->pd->local_dma_lkey) { 81962306a36Sopenharmony_ci tx_desc->tx_sg[0].lkey = device->pd->local_dma_lkey; 82062306a36Sopenharmony_ci isert_dbg("tx_desc %p lkey mismatch, fixing\n", tx_desc); 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_cistatic void 82562306a36Sopenharmony_ciisert_create_send_desc(struct isert_conn *isert_conn, 82662306a36Sopenharmony_ci struct isert_cmd *isert_cmd, 82762306a36Sopenharmony_ci struct iser_tx_desc *tx_desc) 82862306a36Sopenharmony_ci{ 82962306a36Sopenharmony_ci struct isert_device *device = isert_conn->device; 83062306a36Sopenharmony_ci struct ib_device *ib_dev = device->ib_device; 83162306a36Sopenharmony_ci 83262306a36Sopenharmony_ci ib_dma_sync_single_for_cpu(ib_dev, tx_desc->dma_addr, 83362306a36Sopenharmony_ci ISER_HEADERS_LEN, DMA_TO_DEVICE); 83462306a36Sopenharmony_ci 83562306a36Sopenharmony_ci __isert_create_send_desc(device, tx_desc); 83662306a36Sopenharmony_ci} 83762306a36Sopenharmony_ci 83862306a36Sopenharmony_cistatic int 83962306a36Sopenharmony_ciisert_init_tx_hdrs(struct isert_conn *isert_conn, 84062306a36Sopenharmony_ci struct iser_tx_desc *tx_desc) 84162306a36Sopenharmony_ci{ 84262306a36Sopenharmony_ci struct isert_device *device = isert_conn->device; 84362306a36Sopenharmony_ci struct ib_device *ib_dev = device->ib_device; 84462306a36Sopenharmony_ci u64 dma_addr; 84562306a36Sopenharmony_ci 84662306a36Sopenharmony_ci dma_addr = ib_dma_map_single(ib_dev, (void *)tx_desc, 84762306a36Sopenharmony_ci ISER_HEADERS_LEN, DMA_TO_DEVICE); 84862306a36Sopenharmony_ci if (ib_dma_mapping_error(ib_dev, dma_addr)) { 84962306a36Sopenharmony_ci isert_err("ib_dma_mapping_error() failed\n"); 85062306a36Sopenharmony_ci return -ENOMEM; 85162306a36Sopenharmony_ci } 85262306a36Sopenharmony_ci 85362306a36Sopenharmony_ci tx_desc->dma_addr = dma_addr; 85462306a36Sopenharmony_ci tx_desc->tx_sg[0].addr = tx_desc->dma_addr; 85562306a36Sopenharmony_ci tx_desc->tx_sg[0].length = ISER_HEADERS_LEN; 85662306a36Sopenharmony_ci tx_desc->tx_sg[0].lkey = device->pd->local_dma_lkey; 85762306a36Sopenharmony_ci 85862306a36Sopenharmony_ci isert_dbg("Setup tx_sg[0].addr: 0x%llx length: %u lkey: 0x%x\n", 85962306a36Sopenharmony_ci tx_desc->tx_sg[0].addr, tx_desc->tx_sg[0].length, 86062306a36Sopenharmony_ci tx_desc->tx_sg[0].lkey); 86162306a36Sopenharmony_ci 86262306a36Sopenharmony_ci return 0; 86362306a36Sopenharmony_ci} 86462306a36Sopenharmony_ci 86562306a36Sopenharmony_cistatic void 86662306a36Sopenharmony_ciisert_init_send_wr(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd, 86762306a36Sopenharmony_ci struct ib_send_wr *send_wr) 86862306a36Sopenharmony_ci{ 86962306a36Sopenharmony_ci struct iser_tx_desc *tx_desc = &isert_cmd->tx_desc; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci tx_desc->tx_cqe.done = isert_send_done; 87262306a36Sopenharmony_ci send_wr->wr_cqe = &tx_desc->tx_cqe; 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci if (isert_conn->snd_w_inv && isert_cmd->inv_rkey) { 87562306a36Sopenharmony_ci send_wr->opcode = IB_WR_SEND_WITH_INV; 87662306a36Sopenharmony_ci send_wr->ex.invalidate_rkey = isert_cmd->inv_rkey; 87762306a36Sopenharmony_ci } else { 87862306a36Sopenharmony_ci send_wr->opcode = IB_WR_SEND; 87962306a36Sopenharmony_ci } 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_ci send_wr->sg_list = &tx_desc->tx_sg[0]; 88262306a36Sopenharmony_ci send_wr->num_sge = isert_cmd->tx_desc.num_sge; 88362306a36Sopenharmony_ci send_wr->send_flags = IB_SEND_SIGNALED; 88462306a36Sopenharmony_ci} 88562306a36Sopenharmony_ci 88662306a36Sopenharmony_cistatic int 88762306a36Sopenharmony_ciisert_login_post_recv(struct isert_conn *isert_conn) 88862306a36Sopenharmony_ci{ 88962306a36Sopenharmony_ci struct ib_recv_wr rx_wr; 89062306a36Sopenharmony_ci struct ib_sge sge; 89162306a36Sopenharmony_ci int ret; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci memset(&sge, 0, sizeof(struct ib_sge)); 89462306a36Sopenharmony_ci sge.addr = isert_conn->login_desc->dma_addr + 89562306a36Sopenharmony_ci isert_get_hdr_offset(isert_conn->login_desc); 89662306a36Sopenharmony_ci sge.length = ISER_RX_PAYLOAD_SIZE; 89762306a36Sopenharmony_ci sge.lkey = isert_conn->device->pd->local_dma_lkey; 89862306a36Sopenharmony_ci 89962306a36Sopenharmony_ci isert_dbg("Setup sge: addr: %llx length: %d 0x%08x\n", 90062306a36Sopenharmony_ci sge.addr, sge.length, sge.lkey); 90162306a36Sopenharmony_ci 90262306a36Sopenharmony_ci isert_conn->login_desc->rx_cqe.done = isert_login_recv_done; 90362306a36Sopenharmony_ci 90462306a36Sopenharmony_ci memset(&rx_wr, 0, sizeof(struct ib_recv_wr)); 90562306a36Sopenharmony_ci rx_wr.wr_cqe = &isert_conn->login_desc->rx_cqe; 90662306a36Sopenharmony_ci rx_wr.sg_list = &sge; 90762306a36Sopenharmony_ci rx_wr.num_sge = 1; 90862306a36Sopenharmony_ci 90962306a36Sopenharmony_ci ret = ib_post_recv(isert_conn->qp, &rx_wr, NULL); 91062306a36Sopenharmony_ci if (ret) 91162306a36Sopenharmony_ci isert_err("ib_post_recv() failed: %d\n", ret); 91262306a36Sopenharmony_ci 91362306a36Sopenharmony_ci return ret; 91462306a36Sopenharmony_ci} 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_cistatic int 91762306a36Sopenharmony_ciisert_put_login_tx(struct iscsit_conn *conn, struct iscsi_login *login, 91862306a36Sopenharmony_ci u32 length) 91962306a36Sopenharmony_ci{ 92062306a36Sopenharmony_ci struct isert_conn *isert_conn = conn->context; 92162306a36Sopenharmony_ci struct isert_device *device = isert_conn->device; 92262306a36Sopenharmony_ci struct ib_device *ib_dev = device->ib_device; 92362306a36Sopenharmony_ci struct iser_tx_desc *tx_desc = &isert_conn->login_tx_desc; 92462306a36Sopenharmony_ci int ret; 92562306a36Sopenharmony_ci 92662306a36Sopenharmony_ci __isert_create_send_desc(device, tx_desc); 92762306a36Sopenharmony_ci 92862306a36Sopenharmony_ci memcpy(&tx_desc->iscsi_header, &login->rsp[0], 92962306a36Sopenharmony_ci sizeof(struct iscsi_hdr)); 93062306a36Sopenharmony_ci 93162306a36Sopenharmony_ci isert_init_tx_hdrs(isert_conn, tx_desc); 93262306a36Sopenharmony_ci 93362306a36Sopenharmony_ci if (length > 0) { 93462306a36Sopenharmony_ci struct ib_sge *tx_dsg = &tx_desc->tx_sg[1]; 93562306a36Sopenharmony_ci 93662306a36Sopenharmony_ci ib_dma_sync_single_for_cpu(ib_dev, isert_conn->login_rsp_dma, 93762306a36Sopenharmony_ci length, DMA_TO_DEVICE); 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci memcpy(isert_conn->login_rsp_buf, login->rsp_buf, length); 94062306a36Sopenharmony_ci 94162306a36Sopenharmony_ci ib_dma_sync_single_for_device(ib_dev, isert_conn->login_rsp_dma, 94262306a36Sopenharmony_ci length, DMA_TO_DEVICE); 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci tx_dsg->addr = isert_conn->login_rsp_dma; 94562306a36Sopenharmony_ci tx_dsg->length = length; 94662306a36Sopenharmony_ci tx_dsg->lkey = isert_conn->device->pd->local_dma_lkey; 94762306a36Sopenharmony_ci tx_desc->num_sge = 2; 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci if (!login->login_failed) { 95062306a36Sopenharmony_ci if (login->login_complete) { 95162306a36Sopenharmony_ci ret = isert_alloc_rx_descriptors(isert_conn); 95262306a36Sopenharmony_ci if (ret) 95362306a36Sopenharmony_ci return ret; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci ret = isert_post_recvm(isert_conn, 95662306a36Sopenharmony_ci ISERT_QP_MAX_RECV_DTOS); 95762306a36Sopenharmony_ci if (ret) 95862306a36Sopenharmony_ci return ret; 95962306a36Sopenharmony_ci 96062306a36Sopenharmony_ci /* Now we are in FULL_FEATURE phase */ 96162306a36Sopenharmony_ci mutex_lock(&isert_conn->mutex); 96262306a36Sopenharmony_ci isert_conn->state = ISER_CONN_FULL_FEATURE; 96362306a36Sopenharmony_ci mutex_unlock(&isert_conn->mutex); 96462306a36Sopenharmony_ci goto post_send; 96562306a36Sopenharmony_ci } 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci ret = isert_login_post_recv(isert_conn); 96862306a36Sopenharmony_ci if (ret) 96962306a36Sopenharmony_ci return ret; 97062306a36Sopenharmony_ci } 97162306a36Sopenharmony_cipost_send: 97262306a36Sopenharmony_ci ret = isert_login_post_send(isert_conn, tx_desc); 97362306a36Sopenharmony_ci if (ret) 97462306a36Sopenharmony_ci return ret; 97562306a36Sopenharmony_ci 97662306a36Sopenharmony_ci return 0; 97762306a36Sopenharmony_ci} 97862306a36Sopenharmony_ci 97962306a36Sopenharmony_cistatic void 98062306a36Sopenharmony_ciisert_rx_login_req(struct isert_conn *isert_conn) 98162306a36Sopenharmony_ci{ 98262306a36Sopenharmony_ci struct iser_rx_desc *rx_desc = isert_conn->login_desc; 98362306a36Sopenharmony_ci int rx_buflen = isert_conn->login_req_len; 98462306a36Sopenharmony_ci struct iscsit_conn *conn = isert_conn->conn; 98562306a36Sopenharmony_ci struct iscsi_login *login = conn->conn_login; 98662306a36Sopenharmony_ci int size; 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci isert_info("conn %p\n", isert_conn); 98962306a36Sopenharmony_ci 99062306a36Sopenharmony_ci WARN_ON_ONCE(!login); 99162306a36Sopenharmony_ci 99262306a36Sopenharmony_ci if (login->first_request) { 99362306a36Sopenharmony_ci struct iscsi_login_req *login_req = 99462306a36Sopenharmony_ci (struct iscsi_login_req *)isert_get_iscsi_hdr(rx_desc); 99562306a36Sopenharmony_ci /* 99662306a36Sopenharmony_ci * Setup the initial iscsi_login values from the leading 99762306a36Sopenharmony_ci * login request PDU. 99862306a36Sopenharmony_ci */ 99962306a36Sopenharmony_ci login->leading_connection = (!login_req->tsih) ? 1 : 0; 100062306a36Sopenharmony_ci login->current_stage = ISCSI_LOGIN_CURRENT_STAGE( 100162306a36Sopenharmony_ci login_req->flags); 100262306a36Sopenharmony_ci login->version_min = login_req->min_version; 100362306a36Sopenharmony_ci login->version_max = login_req->max_version; 100462306a36Sopenharmony_ci memcpy(login->isid, login_req->isid, 6); 100562306a36Sopenharmony_ci login->cmd_sn = be32_to_cpu(login_req->cmdsn); 100662306a36Sopenharmony_ci login->init_task_tag = login_req->itt; 100762306a36Sopenharmony_ci login->initial_exp_statsn = be32_to_cpu(login_req->exp_statsn); 100862306a36Sopenharmony_ci login->cid = be16_to_cpu(login_req->cid); 100962306a36Sopenharmony_ci login->tsih = be16_to_cpu(login_req->tsih); 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci memcpy(&login->req[0], isert_get_iscsi_hdr(rx_desc), ISCSI_HDR_LEN); 101362306a36Sopenharmony_ci 101462306a36Sopenharmony_ci size = min(rx_buflen, MAX_KEY_VALUE_PAIRS); 101562306a36Sopenharmony_ci isert_dbg("Using login payload size: %d, rx_buflen: %d " 101662306a36Sopenharmony_ci "MAX_KEY_VALUE_PAIRS: %d\n", size, rx_buflen, 101762306a36Sopenharmony_ci MAX_KEY_VALUE_PAIRS); 101862306a36Sopenharmony_ci memcpy(login->req_buf, isert_get_data(rx_desc), size); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci if (login->first_request) { 102162306a36Sopenharmony_ci complete(&isert_conn->login_comp); 102262306a36Sopenharmony_ci return; 102362306a36Sopenharmony_ci } 102462306a36Sopenharmony_ci queue_delayed_work(isert_login_wq, &conn->login_work, 0); 102562306a36Sopenharmony_ci} 102662306a36Sopenharmony_ci 102762306a36Sopenharmony_cistatic struct iscsit_cmd 102862306a36Sopenharmony_ci*isert_allocate_cmd(struct iscsit_conn *conn, struct iser_rx_desc *rx_desc) 102962306a36Sopenharmony_ci{ 103062306a36Sopenharmony_ci struct isert_conn *isert_conn = conn->context; 103162306a36Sopenharmony_ci struct isert_cmd *isert_cmd; 103262306a36Sopenharmony_ci struct iscsit_cmd *cmd; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE); 103562306a36Sopenharmony_ci if (!cmd) { 103662306a36Sopenharmony_ci isert_err("Unable to allocate iscsit_cmd + isert_cmd\n"); 103762306a36Sopenharmony_ci return NULL; 103862306a36Sopenharmony_ci } 103962306a36Sopenharmony_ci isert_cmd = iscsit_priv_cmd(cmd); 104062306a36Sopenharmony_ci isert_cmd->conn = isert_conn; 104162306a36Sopenharmony_ci isert_cmd->iscsit_cmd = cmd; 104262306a36Sopenharmony_ci isert_cmd->rx_desc = rx_desc; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci return cmd; 104562306a36Sopenharmony_ci} 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_cistatic int 104862306a36Sopenharmony_ciisert_handle_scsi_cmd(struct isert_conn *isert_conn, 104962306a36Sopenharmony_ci struct isert_cmd *isert_cmd, struct iscsit_cmd *cmd, 105062306a36Sopenharmony_ci struct iser_rx_desc *rx_desc, unsigned char *buf) 105162306a36Sopenharmony_ci{ 105262306a36Sopenharmony_ci struct iscsit_conn *conn = isert_conn->conn; 105362306a36Sopenharmony_ci struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)buf; 105462306a36Sopenharmony_ci int imm_data, imm_data_len, unsol_data, sg_nents, rc; 105562306a36Sopenharmony_ci bool dump_payload = false; 105662306a36Sopenharmony_ci unsigned int data_len; 105762306a36Sopenharmony_ci 105862306a36Sopenharmony_ci rc = iscsit_setup_scsi_cmd(conn, cmd, buf); 105962306a36Sopenharmony_ci if (rc < 0) 106062306a36Sopenharmony_ci return rc; 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci imm_data = cmd->immediate_data; 106362306a36Sopenharmony_ci imm_data_len = cmd->first_burst_len; 106462306a36Sopenharmony_ci unsol_data = cmd->unsolicited_data; 106562306a36Sopenharmony_ci data_len = cmd->se_cmd.data_length; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_ci if (imm_data && imm_data_len == data_len) 106862306a36Sopenharmony_ci cmd->se_cmd.se_cmd_flags |= SCF_PASSTHROUGH_SG_TO_MEM_NOALLOC; 106962306a36Sopenharmony_ci rc = iscsit_process_scsi_cmd(conn, cmd, hdr); 107062306a36Sopenharmony_ci if (rc < 0) { 107162306a36Sopenharmony_ci return 0; 107262306a36Sopenharmony_ci } else if (rc > 0) { 107362306a36Sopenharmony_ci dump_payload = true; 107462306a36Sopenharmony_ci goto sequence_cmd; 107562306a36Sopenharmony_ci } 107662306a36Sopenharmony_ci 107762306a36Sopenharmony_ci if (!imm_data) 107862306a36Sopenharmony_ci return 0; 107962306a36Sopenharmony_ci 108062306a36Sopenharmony_ci if (imm_data_len != data_len) { 108162306a36Sopenharmony_ci sg_nents = max(1UL, DIV_ROUND_UP(imm_data_len, PAGE_SIZE)); 108262306a36Sopenharmony_ci sg_copy_from_buffer(cmd->se_cmd.t_data_sg, sg_nents, 108362306a36Sopenharmony_ci isert_get_data(rx_desc), imm_data_len); 108462306a36Sopenharmony_ci isert_dbg("Copy Immediate sg_nents: %u imm_data_len: %d\n", 108562306a36Sopenharmony_ci sg_nents, imm_data_len); 108662306a36Sopenharmony_ci } else { 108762306a36Sopenharmony_ci sg_init_table(&isert_cmd->sg, 1); 108862306a36Sopenharmony_ci cmd->se_cmd.t_data_sg = &isert_cmd->sg; 108962306a36Sopenharmony_ci cmd->se_cmd.t_data_nents = 1; 109062306a36Sopenharmony_ci sg_set_buf(&isert_cmd->sg, isert_get_data(rx_desc), 109162306a36Sopenharmony_ci imm_data_len); 109262306a36Sopenharmony_ci isert_dbg("Transfer Immediate imm_data_len: %d\n", 109362306a36Sopenharmony_ci imm_data_len); 109462306a36Sopenharmony_ci } 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_ci cmd->write_data_done += imm_data_len; 109762306a36Sopenharmony_ci 109862306a36Sopenharmony_ci if (cmd->write_data_done == cmd->se_cmd.data_length) { 109962306a36Sopenharmony_ci spin_lock_bh(&cmd->istate_lock); 110062306a36Sopenharmony_ci cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT; 110162306a36Sopenharmony_ci cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT; 110262306a36Sopenharmony_ci spin_unlock_bh(&cmd->istate_lock); 110362306a36Sopenharmony_ci } 110462306a36Sopenharmony_ci 110562306a36Sopenharmony_cisequence_cmd: 110662306a36Sopenharmony_ci rc = iscsit_sequence_cmd(conn, cmd, buf, hdr->cmdsn); 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci if (!rc && !dump_payload && unsol_data) 110962306a36Sopenharmony_ci iscsit_set_unsolicited_dataout(cmd); 111062306a36Sopenharmony_ci else if (dump_payload && imm_data) 111162306a36Sopenharmony_ci target_put_sess_cmd(&cmd->se_cmd); 111262306a36Sopenharmony_ci 111362306a36Sopenharmony_ci return 0; 111462306a36Sopenharmony_ci} 111562306a36Sopenharmony_ci 111662306a36Sopenharmony_cistatic int 111762306a36Sopenharmony_ciisert_handle_iscsi_dataout(struct isert_conn *isert_conn, 111862306a36Sopenharmony_ci struct iser_rx_desc *rx_desc, unsigned char *buf) 111962306a36Sopenharmony_ci{ 112062306a36Sopenharmony_ci struct scatterlist *sg_start; 112162306a36Sopenharmony_ci struct iscsit_conn *conn = isert_conn->conn; 112262306a36Sopenharmony_ci struct iscsit_cmd *cmd = NULL; 112362306a36Sopenharmony_ci struct iscsi_data *hdr = (struct iscsi_data *)buf; 112462306a36Sopenharmony_ci u32 unsol_data_len = ntoh24(hdr->dlength); 112562306a36Sopenharmony_ci int rc, sg_nents, sg_off, page_off; 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci rc = iscsit_check_dataout_hdr(conn, buf, &cmd); 112862306a36Sopenharmony_ci if (rc < 0) 112962306a36Sopenharmony_ci return rc; 113062306a36Sopenharmony_ci else if (!cmd) 113162306a36Sopenharmony_ci return 0; 113262306a36Sopenharmony_ci /* 113362306a36Sopenharmony_ci * FIXME: Unexpected unsolicited_data out 113462306a36Sopenharmony_ci */ 113562306a36Sopenharmony_ci if (!cmd->unsolicited_data) { 113662306a36Sopenharmony_ci isert_err("Received unexpected solicited data payload\n"); 113762306a36Sopenharmony_ci dump_stack(); 113862306a36Sopenharmony_ci return -1; 113962306a36Sopenharmony_ci } 114062306a36Sopenharmony_ci 114162306a36Sopenharmony_ci isert_dbg("Unsolicited DataOut unsol_data_len: %u, " 114262306a36Sopenharmony_ci "write_data_done: %u, data_length: %u\n", 114362306a36Sopenharmony_ci unsol_data_len, cmd->write_data_done, 114462306a36Sopenharmony_ci cmd->se_cmd.data_length); 114562306a36Sopenharmony_ci 114662306a36Sopenharmony_ci sg_off = cmd->write_data_done / PAGE_SIZE; 114762306a36Sopenharmony_ci sg_start = &cmd->se_cmd.t_data_sg[sg_off]; 114862306a36Sopenharmony_ci sg_nents = max(1UL, DIV_ROUND_UP(unsol_data_len, PAGE_SIZE)); 114962306a36Sopenharmony_ci page_off = cmd->write_data_done % PAGE_SIZE; 115062306a36Sopenharmony_ci /* 115162306a36Sopenharmony_ci * FIXME: Non page-aligned unsolicited_data out 115262306a36Sopenharmony_ci */ 115362306a36Sopenharmony_ci if (page_off) { 115462306a36Sopenharmony_ci isert_err("unexpected non-page aligned data payload\n"); 115562306a36Sopenharmony_ci dump_stack(); 115662306a36Sopenharmony_ci return -1; 115762306a36Sopenharmony_ci } 115862306a36Sopenharmony_ci isert_dbg("Copying DataOut: sg_start: %p, sg_off: %u " 115962306a36Sopenharmony_ci "sg_nents: %u from %p %u\n", sg_start, sg_off, 116062306a36Sopenharmony_ci sg_nents, isert_get_data(rx_desc), unsol_data_len); 116162306a36Sopenharmony_ci 116262306a36Sopenharmony_ci sg_copy_from_buffer(sg_start, sg_nents, isert_get_data(rx_desc), 116362306a36Sopenharmony_ci unsol_data_len); 116462306a36Sopenharmony_ci 116562306a36Sopenharmony_ci rc = iscsit_check_dataout_payload(cmd, hdr, false); 116662306a36Sopenharmony_ci if (rc < 0) 116762306a36Sopenharmony_ci return rc; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci /* 117062306a36Sopenharmony_ci * multiple data-outs on the same command can arrive - 117162306a36Sopenharmony_ci * so post the buffer before hand 117262306a36Sopenharmony_ci */ 117362306a36Sopenharmony_ci return isert_post_recv(isert_conn, rx_desc); 117462306a36Sopenharmony_ci} 117562306a36Sopenharmony_ci 117662306a36Sopenharmony_cistatic int 117762306a36Sopenharmony_ciisert_handle_nop_out(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd, 117862306a36Sopenharmony_ci struct iscsit_cmd *cmd, struct iser_rx_desc *rx_desc, 117962306a36Sopenharmony_ci unsigned char *buf) 118062306a36Sopenharmony_ci{ 118162306a36Sopenharmony_ci struct iscsit_conn *conn = isert_conn->conn; 118262306a36Sopenharmony_ci struct iscsi_nopout *hdr = (struct iscsi_nopout *)buf; 118362306a36Sopenharmony_ci int rc; 118462306a36Sopenharmony_ci 118562306a36Sopenharmony_ci rc = iscsit_setup_nop_out(conn, cmd, hdr); 118662306a36Sopenharmony_ci if (rc < 0) 118762306a36Sopenharmony_ci return rc; 118862306a36Sopenharmony_ci /* 118962306a36Sopenharmony_ci * FIXME: Add support for NOPOUT payload using unsolicited RDMA payload 119062306a36Sopenharmony_ci */ 119162306a36Sopenharmony_ci 119262306a36Sopenharmony_ci return iscsit_process_nop_out(conn, cmd, hdr); 119362306a36Sopenharmony_ci} 119462306a36Sopenharmony_ci 119562306a36Sopenharmony_cistatic int 119662306a36Sopenharmony_ciisert_handle_text_cmd(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd, 119762306a36Sopenharmony_ci struct iscsit_cmd *cmd, struct iser_rx_desc *rx_desc, 119862306a36Sopenharmony_ci struct iscsi_text *hdr) 119962306a36Sopenharmony_ci{ 120062306a36Sopenharmony_ci struct iscsit_conn *conn = isert_conn->conn; 120162306a36Sopenharmony_ci u32 payload_length = ntoh24(hdr->dlength); 120262306a36Sopenharmony_ci int rc; 120362306a36Sopenharmony_ci unsigned char *text_in = NULL; 120462306a36Sopenharmony_ci 120562306a36Sopenharmony_ci rc = iscsit_setup_text_cmd(conn, cmd, hdr); 120662306a36Sopenharmony_ci if (rc < 0) 120762306a36Sopenharmony_ci return rc; 120862306a36Sopenharmony_ci 120962306a36Sopenharmony_ci if (payload_length) { 121062306a36Sopenharmony_ci text_in = kzalloc(payload_length, GFP_KERNEL); 121162306a36Sopenharmony_ci if (!text_in) 121262306a36Sopenharmony_ci return -ENOMEM; 121362306a36Sopenharmony_ci } 121462306a36Sopenharmony_ci cmd->text_in_ptr = text_in; 121562306a36Sopenharmony_ci 121662306a36Sopenharmony_ci memcpy(cmd->text_in_ptr, isert_get_data(rx_desc), payload_length); 121762306a36Sopenharmony_ci 121862306a36Sopenharmony_ci return iscsit_process_text_cmd(conn, cmd, hdr); 121962306a36Sopenharmony_ci} 122062306a36Sopenharmony_ci 122162306a36Sopenharmony_cistatic int 122262306a36Sopenharmony_ciisert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc, 122362306a36Sopenharmony_ci uint32_t read_stag, uint64_t read_va, 122462306a36Sopenharmony_ci uint32_t write_stag, uint64_t write_va) 122562306a36Sopenharmony_ci{ 122662306a36Sopenharmony_ci struct iscsi_hdr *hdr = isert_get_iscsi_hdr(rx_desc); 122762306a36Sopenharmony_ci struct iscsit_conn *conn = isert_conn->conn; 122862306a36Sopenharmony_ci struct iscsit_cmd *cmd; 122962306a36Sopenharmony_ci struct isert_cmd *isert_cmd; 123062306a36Sopenharmony_ci int ret = -EINVAL; 123162306a36Sopenharmony_ci u8 opcode = (hdr->opcode & ISCSI_OPCODE_MASK); 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci if (conn->sess->sess_ops->SessionType && 123462306a36Sopenharmony_ci (!(opcode & ISCSI_OP_TEXT) || !(opcode & ISCSI_OP_LOGOUT))) { 123562306a36Sopenharmony_ci isert_err("Got illegal opcode: 0x%02x in SessionType=Discovery," 123662306a36Sopenharmony_ci " ignoring\n", opcode); 123762306a36Sopenharmony_ci return 0; 123862306a36Sopenharmony_ci } 123962306a36Sopenharmony_ci 124062306a36Sopenharmony_ci switch (opcode) { 124162306a36Sopenharmony_ci case ISCSI_OP_SCSI_CMD: 124262306a36Sopenharmony_ci cmd = isert_allocate_cmd(conn, rx_desc); 124362306a36Sopenharmony_ci if (!cmd) 124462306a36Sopenharmony_ci break; 124562306a36Sopenharmony_ci 124662306a36Sopenharmony_ci isert_cmd = iscsit_priv_cmd(cmd); 124762306a36Sopenharmony_ci isert_cmd->read_stag = read_stag; 124862306a36Sopenharmony_ci isert_cmd->read_va = read_va; 124962306a36Sopenharmony_ci isert_cmd->write_stag = write_stag; 125062306a36Sopenharmony_ci isert_cmd->write_va = write_va; 125162306a36Sopenharmony_ci isert_cmd->inv_rkey = read_stag ? read_stag : write_stag; 125262306a36Sopenharmony_ci 125362306a36Sopenharmony_ci ret = isert_handle_scsi_cmd(isert_conn, isert_cmd, cmd, 125462306a36Sopenharmony_ci rx_desc, (unsigned char *)hdr); 125562306a36Sopenharmony_ci break; 125662306a36Sopenharmony_ci case ISCSI_OP_NOOP_OUT: 125762306a36Sopenharmony_ci cmd = isert_allocate_cmd(conn, rx_desc); 125862306a36Sopenharmony_ci if (!cmd) 125962306a36Sopenharmony_ci break; 126062306a36Sopenharmony_ci 126162306a36Sopenharmony_ci isert_cmd = iscsit_priv_cmd(cmd); 126262306a36Sopenharmony_ci ret = isert_handle_nop_out(isert_conn, isert_cmd, cmd, 126362306a36Sopenharmony_ci rx_desc, (unsigned char *)hdr); 126462306a36Sopenharmony_ci break; 126562306a36Sopenharmony_ci case ISCSI_OP_SCSI_DATA_OUT: 126662306a36Sopenharmony_ci ret = isert_handle_iscsi_dataout(isert_conn, rx_desc, 126762306a36Sopenharmony_ci (unsigned char *)hdr); 126862306a36Sopenharmony_ci break; 126962306a36Sopenharmony_ci case ISCSI_OP_SCSI_TMFUNC: 127062306a36Sopenharmony_ci cmd = isert_allocate_cmd(conn, rx_desc); 127162306a36Sopenharmony_ci if (!cmd) 127262306a36Sopenharmony_ci break; 127362306a36Sopenharmony_ci 127462306a36Sopenharmony_ci ret = iscsit_handle_task_mgt_cmd(conn, cmd, 127562306a36Sopenharmony_ci (unsigned char *)hdr); 127662306a36Sopenharmony_ci break; 127762306a36Sopenharmony_ci case ISCSI_OP_LOGOUT: 127862306a36Sopenharmony_ci cmd = isert_allocate_cmd(conn, rx_desc); 127962306a36Sopenharmony_ci if (!cmd) 128062306a36Sopenharmony_ci break; 128162306a36Sopenharmony_ci 128262306a36Sopenharmony_ci ret = iscsit_handle_logout_cmd(conn, cmd, (unsigned char *)hdr); 128362306a36Sopenharmony_ci break; 128462306a36Sopenharmony_ci case ISCSI_OP_TEXT: 128562306a36Sopenharmony_ci if (be32_to_cpu(hdr->ttt) != 0xFFFFFFFF) 128662306a36Sopenharmony_ci cmd = iscsit_find_cmd_from_itt(conn, hdr->itt); 128762306a36Sopenharmony_ci else 128862306a36Sopenharmony_ci cmd = isert_allocate_cmd(conn, rx_desc); 128962306a36Sopenharmony_ci 129062306a36Sopenharmony_ci if (!cmd) 129162306a36Sopenharmony_ci break; 129262306a36Sopenharmony_ci 129362306a36Sopenharmony_ci isert_cmd = iscsit_priv_cmd(cmd); 129462306a36Sopenharmony_ci ret = isert_handle_text_cmd(isert_conn, isert_cmd, cmd, 129562306a36Sopenharmony_ci rx_desc, (struct iscsi_text *)hdr); 129662306a36Sopenharmony_ci break; 129762306a36Sopenharmony_ci default: 129862306a36Sopenharmony_ci isert_err("Got unknown iSCSI OpCode: 0x%02x\n", opcode); 129962306a36Sopenharmony_ci dump_stack(); 130062306a36Sopenharmony_ci break; 130162306a36Sopenharmony_ci } 130262306a36Sopenharmony_ci 130362306a36Sopenharmony_ci return ret; 130462306a36Sopenharmony_ci} 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_cistatic void 130762306a36Sopenharmony_ciisert_print_wc(struct ib_wc *wc, const char *type) 130862306a36Sopenharmony_ci{ 130962306a36Sopenharmony_ci if (wc->status != IB_WC_WR_FLUSH_ERR) 131062306a36Sopenharmony_ci isert_err("%s failure: %s (%d) vend_err %x\n", type, 131162306a36Sopenharmony_ci ib_wc_status_msg(wc->status), wc->status, 131262306a36Sopenharmony_ci wc->vendor_err); 131362306a36Sopenharmony_ci else 131462306a36Sopenharmony_ci isert_dbg("%s failure: %s (%d)\n", type, 131562306a36Sopenharmony_ci ib_wc_status_msg(wc->status), wc->status); 131662306a36Sopenharmony_ci} 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_cistatic void 131962306a36Sopenharmony_ciisert_recv_done(struct ib_cq *cq, struct ib_wc *wc) 132062306a36Sopenharmony_ci{ 132162306a36Sopenharmony_ci struct isert_conn *isert_conn = wc->qp->qp_context; 132262306a36Sopenharmony_ci struct ib_device *ib_dev = isert_conn->cm_id->device; 132362306a36Sopenharmony_ci struct iser_rx_desc *rx_desc = cqe_to_rx_desc(wc->wr_cqe); 132462306a36Sopenharmony_ci struct iscsi_hdr *hdr = isert_get_iscsi_hdr(rx_desc); 132562306a36Sopenharmony_ci struct iser_ctrl *iser_ctrl = isert_get_iser_hdr(rx_desc); 132662306a36Sopenharmony_ci uint64_t read_va = 0, write_va = 0; 132762306a36Sopenharmony_ci uint32_t read_stag = 0, write_stag = 0; 132862306a36Sopenharmony_ci 132962306a36Sopenharmony_ci if (unlikely(wc->status != IB_WC_SUCCESS)) { 133062306a36Sopenharmony_ci isert_print_wc(wc, "recv"); 133162306a36Sopenharmony_ci if (wc->status != IB_WC_WR_FLUSH_ERR) 133262306a36Sopenharmony_ci iscsit_cause_connection_reinstatement(isert_conn->conn, 0); 133362306a36Sopenharmony_ci return; 133462306a36Sopenharmony_ci } 133562306a36Sopenharmony_ci 133662306a36Sopenharmony_ci rx_desc->in_use = true; 133762306a36Sopenharmony_ci 133862306a36Sopenharmony_ci ib_dma_sync_single_for_cpu(ib_dev, rx_desc->dma_addr, 133962306a36Sopenharmony_ci ISER_RX_SIZE, DMA_FROM_DEVICE); 134062306a36Sopenharmony_ci 134162306a36Sopenharmony_ci isert_dbg("DMA: 0x%llx, iSCSI opcode: 0x%02x, ITT: 0x%08x, flags: 0x%02x dlen: %d\n", 134262306a36Sopenharmony_ci rx_desc->dma_addr, hdr->opcode, hdr->itt, hdr->flags, 134362306a36Sopenharmony_ci (int)(wc->byte_len - ISER_HEADERS_LEN)); 134462306a36Sopenharmony_ci 134562306a36Sopenharmony_ci switch (iser_ctrl->flags & 0xF0) { 134662306a36Sopenharmony_ci case ISCSI_CTRL: 134762306a36Sopenharmony_ci if (iser_ctrl->flags & ISER_RSV) { 134862306a36Sopenharmony_ci read_stag = be32_to_cpu(iser_ctrl->read_stag); 134962306a36Sopenharmony_ci read_va = be64_to_cpu(iser_ctrl->read_va); 135062306a36Sopenharmony_ci isert_dbg("ISER_RSV: read_stag: 0x%x read_va: 0x%llx\n", 135162306a36Sopenharmony_ci read_stag, (unsigned long long)read_va); 135262306a36Sopenharmony_ci } 135362306a36Sopenharmony_ci if (iser_ctrl->flags & ISER_WSV) { 135462306a36Sopenharmony_ci write_stag = be32_to_cpu(iser_ctrl->write_stag); 135562306a36Sopenharmony_ci write_va = be64_to_cpu(iser_ctrl->write_va); 135662306a36Sopenharmony_ci isert_dbg("ISER_WSV: write_stag: 0x%x write_va: 0x%llx\n", 135762306a36Sopenharmony_ci write_stag, (unsigned long long)write_va); 135862306a36Sopenharmony_ci } 135962306a36Sopenharmony_ci 136062306a36Sopenharmony_ci isert_dbg("ISER ISCSI_CTRL PDU\n"); 136162306a36Sopenharmony_ci break; 136262306a36Sopenharmony_ci case ISER_HELLO: 136362306a36Sopenharmony_ci isert_err("iSER Hello message\n"); 136462306a36Sopenharmony_ci break; 136562306a36Sopenharmony_ci default: 136662306a36Sopenharmony_ci isert_warn("Unknown iSER hdr flags: 0x%02x\n", iser_ctrl->flags); 136762306a36Sopenharmony_ci break; 136862306a36Sopenharmony_ci } 136962306a36Sopenharmony_ci 137062306a36Sopenharmony_ci isert_rx_opcode(isert_conn, rx_desc, 137162306a36Sopenharmony_ci read_stag, read_va, write_stag, write_va); 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci ib_dma_sync_single_for_device(ib_dev, rx_desc->dma_addr, 137462306a36Sopenharmony_ci ISER_RX_SIZE, DMA_FROM_DEVICE); 137562306a36Sopenharmony_ci} 137662306a36Sopenharmony_ci 137762306a36Sopenharmony_cistatic void 137862306a36Sopenharmony_ciisert_login_recv_done(struct ib_cq *cq, struct ib_wc *wc) 137962306a36Sopenharmony_ci{ 138062306a36Sopenharmony_ci struct isert_conn *isert_conn = wc->qp->qp_context; 138162306a36Sopenharmony_ci struct ib_device *ib_dev = isert_conn->device->ib_device; 138262306a36Sopenharmony_ci 138362306a36Sopenharmony_ci if (unlikely(wc->status != IB_WC_SUCCESS)) { 138462306a36Sopenharmony_ci isert_print_wc(wc, "login recv"); 138562306a36Sopenharmony_ci return; 138662306a36Sopenharmony_ci } 138762306a36Sopenharmony_ci 138862306a36Sopenharmony_ci ib_dma_sync_single_for_cpu(ib_dev, isert_conn->login_desc->dma_addr, 138962306a36Sopenharmony_ci ISER_RX_SIZE, DMA_FROM_DEVICE); 139062306a36Sopenharmony_ci 139162306a36Sopenharmony_ci isert_conn->login_req_len = wc->byte_len - ISER_HEADERS_LEN; 139262306a36Sopenharmony_ci 139362306a36Sopenharmony_ci if (isert_conn->conn) { 139462306a36Sopenharmony_ci struct iscsi_login *login = isert_conn->conn->conn_login; 139562306a36Sopenharmony_ci 139662306a36Sopenharmony_ci if (login && !login->first_request) 139762306a36Sopenharmony_ci isert_rx_login_req(isert_conn); 139862306a36Sopenharmony_ci } 139962306a36Sopenharmony_ci 140062306a36Sopenharmony_ci mutex_lock(&isert_conn->mutex); 140162306a36Sopenharmony_ci complete(&isert_conn->login_req_comp); 140262306a36Sopenharmony_ci mutex_unlock(&isert_conn->mutex); 140362306a36Sopenharmony_ci 140462306a36Sopenharmony_ci ib_dma_sync_single_for_device(ib_dev, isert_conn->login_desc->dma_addr, 140562306a36Sopenharmony_ci ISER_RX_SIZE, DMA_FROM_DEVICE); 140662306a36Sopenharmony_ci} 140762306a36Sopenharmony_ci 140862306a36Sopenharmony_cistatic void 140962306a36Sopenharmony_ciisert_rdma_rw_ctx_destroy(struct isert_cmd *cmd, struct isert_conn *conn) 141062306a36Sopenharmony_ci{ 141162306a36Sopenharmony_ci struct se_cmd *se_cmd = &cmd->iscsit_cmd->se_cmd; 141262306a36Sopenharmony_ci enum dma_data_direction dir = target_reverse_dma_direction(se_cmd); 141362306a36Sopenharmony_ci 141462306a36Sopenharmony_ci if (!cmd->rw.nr_ops) 141562306a36Sopenharmony_ci return; 141662306a36Sopenharmony_ci 141762306a36Sopenharmony_ci if (isert_prot_cmd(conn, se_cmd)) { 141862306a36Sopenharmony_ci rdma_rw_ctx_destroy_signature(&cmd->rw, conn->qp, 141962306a36Sopenharmony_ci conn->cm_id->port_num, se_cmd->t_data_sg, 142062306a36Sopenharmony_ci se_cmd->t_data_nents, se_cmd->t_prot_sg, 142162306a36Sopenharmony_ci se_cmd->t_prot_nents, dir); 142262306a36Sopenharmony_ci } else { 142362306a36Sopenharmony_ci rdma_rw_ctx_destroy(&cmd->rw, conn->qp, conn->cm_id->port_num, 142462306a36Sopenharmony_ci se_cmd->t_data_sg, se_cmd->t_data_nents, dir); 142562306a36Sopenharmony_ci } 142662306a36Sopenharmony_ci 142762306a36Sopenharmony_ci cmd->rw.nr_ops = 0; 142862306a36Sopenharmony_ci} 142962306a36Sopenharmony_ci 143062306a36Sopenharmony_cistatic void 143162306a36Sopenharmony_ciisert_put_cmd(struct isert_cmd *isert_cmd, bool comp_err) 143262306a36Sopenharmony_ci{ 143362306a36Sopenharmony_ci struct iscsit_cmd *cmd = isert_cmd->iscsit_cmd; 143462306a36Sopenharmony_ci struct isert_conn *isert_conn = isert_cmd->conn; 143562306a36Sopenharmony_ci struct iscsit_conn *conn = isert_conn->conn; 143662306a36Sopenharmony_ci struct iscsi_text_rsp *hdr; 143762306a36Sopenharmony_ci 143862306a36Sopenharmony_ci isert_dbg("Cmd %p\n", isert_cmd); 143962306a36Sopenharmony_ci 144062306a36Sopenharmony_ci switch (cmd->iscsi_opcode) { 144162306a36Sopenharmony_ci case ISCSI_OP_SCSI_CMD: 144262306a36Sopenharmony_ci spin_lock_bh(&conn->cmd_lock); 144362306a36Sopenharmony_ci if (!list_empty(&cmd->i_conn_node)) 144462306a36Sopenharmony_ci list_del_init(&cmd->i_conn_node); 144562306a36Sopenharmony_ci spin_unlock_bh(&conn->cmd_lock); 144662306a36Sopenharmony_ci 144762306a36Sopenharmony_ci if (cmd->data_direction == DMA_TO_DEVICE) { 144862306a36Sopenharmony_ci iscsit_stop_dataout_timer(cmd); 144962306a36Sopenharmony_ci /* 145062306a36Sopenharmony_ci * Check for special case during comp_err where 145162306a36Sopenharmony_ci * WRITE_PENDING has been handed off from core, 145262306a36Sopenharmony_ci * but requires an extra target_put_sess_cmd() 145362306a36Sopenharmony_ci * before transport_generic_free_cmd() below. 145462306a36Sopenharmony_ci */ 145562306a36Sopenharmony_ci if (comp_err && 145662306a36Sopenharmony_ci cmd->se_cmd.t_state == TRANSPORT_WRITE_PENDING) { 145762306a36Sopenharmony_ci struct se_cmd *se_cmd = &cmd->se_cmd; 145862306a36Sopenharmony_ci 145962306a36Sopenharmony_ci target_put_sess_cmd(se_cmd); 146062306a36Sopenharmony_ci } 146162306a36Sopenharmony_ci } 146262306a36Sopenharmony_ci 146362306a36Sopenharmony_ci isert_rdma_rw_ctx_destroy(isert_cmd, isert_conn); 146462306a36Sopenharmony_ci transport_generic_free_cmd(&cmd->se_cmd, 0); 146562306a36Sopenharmony_ci break; 146662306a36Sopenharmony_ci case ISCSI_OP_SCSI_TMFUNC: 146762306a36Sopenharmony_ci spin_lock_bh(&conn->cmd_lock); 146862306a36Sopenharmony_ci if (!list_empty(&cmd->i_conn_node)) 146962306a36Sopenharmony_ci list_del_init(&cmd->i_conn_node); 147062306a36Sopenharmony_ci spin_unlock_bh(&conn->cmd_lock); 147162306a36Sopenharmony_ci 147262306a36Sopenharmony_ci transport_generic_free_cmd(&cmd->se_cmd, 0); 147362306a36Sopenharmony_ci break; 147462306a36Sopenharmony_ci case ISCSI_OP_REJECT: 147562306a36Sopenharmony_ci case ISCSI_OP_NOOP_OUT: 147662306a36Sopenharmony_ci case ISCSI_OP_TEXT: 147762306a36Sopenharmony_ci hdr = (struct iscsi_text_rsp *)&isert_cmd->tx_desc.iscsi_header; 147862306a36Sopenharmony_ci /* If the continue bit is on, keep the command alive */ 147962306a36Sopenharmony_ci if (hdr->flags & ISCSI_FLAG_TEXT_CONTINUE) 148062306a36Sopenharmony_ci break; 148162306a36Sopenharmony_ci 148262306a36Sopenharmony_ci spin_lock_bh(&conn->cmd_lock); 148362306a36Sopenharmony_ci if (!list_empty(&cmd->i_conn_node)) 148462306a36Sopenharmony_ci list_del_init(&cmd->i_conn_node); 148562306a36Sopenharmony_ci spin_unlock_bh(&conn->cmd_lock); 148662306a36Sopenharmony_ci 148762306a36Sopenharmony_ci /* 148862306a36Sopenharmony_ci * Handle special case for REJECT when iscsi_add_reject*() has 148962306a36Sopenharmony_ci * overwritten the original iscsi_opcode assignment, and the 149062306a36Sopenharmony_ci * associated cmd->se_cmd needs to be released. 149162306a36Sopenharmony_ci */ 149262306a36Sopenharmony_ci if (cmd->se_cmd.se_tfo != NULL) { 149362306a36Sopenharmony_ci isert_dbg("Calling transport_generic_free_cmd for 0x%02x\n", 149462306a36Sopenharmony_ci cmd->iscsi_opcode); 149562306a36Sopenharmony_ci transport_generic_free_cmd(&cmd->se_cmd, 0); 149662306a36Sopenharmony_ci break; 149762306a36Sopenharmony_ci } 149862306a36Sopenharmony_ci fallthrough; 149962306a36Sopenharmony_ci default: 150062306a36Sopenharmony_ci iscsit_release_cmd(cmd); 150162306a36Sopenharmony_ci break; 150262306a36Sopenharmony_ci } 150362306a36Sopenharmony_ci} 150462306a36Sopenharmony_ci 150562306a36Sopenharmony_cistatic void 150662306a36Sopenharmony_ciisert_unmap_tx_desc(struct iser_tx_desc *tx_desc, struct ib_device *ib_dev) 150762306a36Sopenharmony_ci{ 150862306a36Sopenharmony_ci if (tx_desc->dma_addr != 0) { 150962306a36Sopenharmony_ci isert_dbg("unmap single for tx_desc->dma_addr\n"); 151062306a36Sopenharmony_ci ib_dma_unmap_single(ib_dev, tx_desc->dma_addr, 151162306a36Sopenharmony_ci ISER_HEADERS_LEN, DMA_TO_DEVICE); 151262306a36Sopenharmony_ci tx_desc->dma_addr = 0; 151362306a36Sopenharmony_ci } 151462306a36Sopenharmony_ci} 151562306a36Sopenharmony_ci 151662306a36Sopenharmony_cistatic void 151762306a36Sopenharmony_ciisert_completion_put(struct iser_tx_desc *tx_desc, struct isert_cmd *isert_cmd, 151862306a36Sopenharmony_ci struct ib_device *ib_dev, bool comp_err) 151962306a36Sopenharmony_ci{ 152062306a36Sopenharmony_ci if (isert_cmd->pdu_buf_dma != 0) { 152162306a36Sopenharmony_ci isert_dbg("unmap single for isert_cmd->pdu_buf_dma\n"); 152262306a36Sopenharmony_ci ib_dma_unmap_single(ib_dev, isert_cmd->pdu_buf_dma, 152362306a36Sopenharmony_ci isert_cmd->pdu_buf_len, DMA_TO_DEVICE); 152462306a36Sopenharmony_ci isert_cmd->pdu_buf_dma = 0; 152562306a36Sopenharmony_ci } 152662306a36Sopenharmony_ci 152762306a36Sopenharmony_ci isert_unmap_tx_desc(tx_desc, ib_dev); 152862306a36Sopenharmony_ci isert_put_cmd(isert_cmd, comp_err); 152962306a36Sopenharmony_ci} 153062306a36Sopenharmony_ci 153162306a36Sopenharmony_cistatic int 153262306a36Sopenharmony_ciisert_check_pi_status(struct se_cmd *se_cmd, struct ib_mr *sig_mr) 153362306a36Sopenharmony_ci{ 153462306a36Sopenharmony_ci struct ib_mr_status mr_status; 153562306a36Sopenharmony_ci int ret; 153662306a36Sopenharmony_ci 153762306a36Sopenharmony_ci ret = ib_check_mr_status(sig_mr, IB_MR_CHECK_SIG_STATUS, &mr_status); 153862306a36Sopenharmony_ci if (ret) { 153962306a36Sopenharmony_ci isert_err("ib_check_mr_status failed, ret %d\n", ret); 154062306a36Sopenharmony_ci goto fail_mr_status; 154162306a36Sopenharmony_ci } 154262306a36Sopenharmony_ci 154362306a36Sopenharmony_ci if (mr_status.fail_status & IB_MR_CHECK_SIG_STATUS) { 154462306a36Sopenharmony_ci u64 sec_offset_err; 154562306a36Sopenharmony_ci u32 block_size = se_cmd->se_dev->dev_attrib.block_size + 8; 154662306a36Sopenharmony_ci 154762306a36Sopenharmony_ci switch (mr_status.sig_err.err_type) { 154862306a36Sopenharmony_ci case IB_SIG_BAD_GUARD: 154962306a36Sopenharmony_ci se_cmd->pi_err = TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED; 155062306a36Sopenharmony_ci break; 155162306a36Sopenharmony_ci case IB_SIG_BAD_REFTAG: 155262306a36Sopenharmony_ci se_cmd->pi_err = TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED; 155362306a36Sopenharmony_ci break; 155462306a36Sopenharmony_ci case IB_SIG_BAD_APPTAG: 155562306a36Sopenharmony_ci se_cmd->pi_err = TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED; 155662306a36Sopenharmony_ci break; 155762306a36Sopenharmony_ci } 155862306a36Sopenharmony_ci sec_offset_err = mr_status.sig_err.sig_err_offset; 155962306a36Sopenharmony_ci do_div(sec_offset_err, block_size); 156062306a36Sopenharmony_ci se_cmd->sense_info = sec_offset_err + se_cmd->t_task_lba; 156162306a36Sopenharmony_ci 156262306a36Sopenharmony_ci isert_err("PI error found type %d at sector 0x%llx " 156362306a36Sopenharmony_ci "expected 0x%x vs actual 0x%x\n", 156462306a36Sopenharmony_ci mr_status.sig_err.err_type, 156562306a36Sopenharmony_ci (unsigned long long)se_cmd->sense_info, 156662306a36Sopenharmony_ci mr_status.sig_err.expected, 156762306a36Sopenharmony_ci mr_status.sig_err.actual); 156862306a36Sopenharmony_ci ret = 1; 156962306a36Sopenharmony_ci } 157062306a36Sopenharmony_ci 157162306a36Sopenharmony_cifail_mr_status: 157262306a36Sopenharmony_ci return ret; 157362306a36Sopenharmony_ci} 157462306a36Sopenharmony_ci 157562306a36Sopenharmony_cistatic void 157662306a36Sopenharmony_ciisert_rdma_write_done(struct ib_cq *cq, struct ib_wc *wc) 157762306a36Sopenharmony_ci{ 157862306a36Sopenharmony_ci struct isert_conn *isert_conn = wc->qp->qp_context; 157962306a36Sopenharmony_ci struct isert_device *device = isert_conn->device; 158062306a36Sopenharmony_ci struct iser_tx_desc *desc = cqe_to_tx_desc(wc->wr_cqe); 158162306a36Sopenharmony_ci struct isert_cmd *isert_cmd = tx_desc_to_cmd(desc); 158262306a36Sopenharmony_ci struct se_cmd *cmd = &isert_cmd->iscsit_cmd->se_cmd; 158362306a36Sopenharmony_ci int ret = 0; 158462306a36Sopenharmony_ci 158562306a36Sopenharmony_ci if (unlikely(wc->status != IB_WC_SUCCESS)) { 158662306a36Sopenharmony_ci isert_print_wc(wc, "rdma write"); 158762306a36Sopenharmony_ci if (wc->status != IB_WC_WR_FLUSH_ERR) 158862306a36Sopenharmony_ci iscsit_cause_connection_reinstatement(isert_conn->conn, 0); 158962306a36Sopenharmony_ci isert_completion_put(desc, isert_cmd, device->ib_device, true); 159062306a36Sopenharmony_ci return; 159162306a36Sopenharmony_ci } 159262306a36Sopenharmony_ci 159362306a36Sopenharmony_ci isert_dbg("Cmd %p\n", isert_cmd); 159462306a36Sopenharmony_ci 159562306a36Sopenharmony_ci ret = isert_check_pi_status(cmd, isert_cmd->rw.reg->mr); 159662306a36Sopenharmony_ci isert_rdma_rw_ctx_destroy(isert_cmd, isert_conn); 159762306a36Sopenharmony_ci 159862306a36Sopenharmony_ci if (ret) { 159962306a36Sopenharmony_ci /* 160062306a36Sopenharmony_ci * transport_generic_request_failure() expects to have 160162306a36Sopenharmony_ci * plus two references to handle queue-full, so re-add 160262306a36Sopenharmony_ci * one here as target-core will have already dropped 160362306a36Sopenharmony_ci * it after the first isert_put_datain() callback. 160462306a36Sopenharmony_ci */ 160562306a36Sopenharmony_ci kref_get(&cmd->cmd_kref); 160662306a36Sopenharmony_ci transport_generic_request_failure(cmd, cmd->pi_err); 160762306a36Sopenharmony_ci } else { 160862306a36Sopenharmony_ci /* 160962306a36Sopenharmony_ci * XXX: isert_put_response() failure is not retried. 161062306a36Sopenharmony_ci */ 161162306a36Sopenharmony_ci ret = isert_put_response(isert_conn->conn, isert_cmd->iscsit_cmd); 161262306a36Sopenharmony_ci if (ret) 161362306a36Sopenharmony_ci pr_warn_ratelimited("isert_put_response() ret: %d\n", ret); 161462306a36Sopenharmony_ci } 161562306a36Sopenharmony_ci} 161662306a36Sopenharmony_ci 161762306a36Sopenharmony_cistatic void 161862306a36Sopenharmony_ciisert_rdma_read_done(struct ib_cq *cq, struct ib_wc *wc) 161962306a36Sopenharmony_ci{ 162062306a36Sopenharmony_ci struct isert_conn *isert_conn = wc->qp->qp_context; 162162306a36Sopenharmony_ci struct isert_device *device = isert_conn->device; 162262306a36Sopenharmony_ci struct iser_tx_desc *desc = cqe_to_tx_desc(wc->wr_cqe); 162362306a36Sopenharmony_ci struct isert_cmd *isert_cmd = tx_desc_to_cmd(desc); 162462306a36Sopenharmony_ci struct iscsit_cmd *cmd = isert_cmd->iscsit_cmd; 162562306a36Sopenharmony_ci struct se_cmd *se_cmd = &cmd->se_cmd; 162662306a36Sopenharmony_ci int ret = 0; 162762306a36Sopenharmony_ci 162862306a36Sopenharmony_ci if (unlikely(wc->status != IB_WC_SUCCESS)) { 162962306a36Sopenharmony_ci isert_print_wc(wc, "rdma read"); 163062306a36Sopenharmony_ci if (wc->status != IB_WC_WR_FLUSH_ERR) 163162306a36Sopenharmony_ci iscsit_cause_connection_reinstatement(isert_conn->conn, 0); 163262306a36Sopenharmony_ci isert_completion_put(desc, isert_cmd, device->ib_device, true); 163362306a36Sopenharmony_ci return; 163462306a36Sopenharmony_ci } 163562306a36Sopenharmony_ci 163662306a36Sopenharmony_ci isert_dbg("Cmd %p\n", isert_cmd); 163762306a36Sopenharmony_ci 163862306a36Sopenharmony_ci iscsit_stop_dataout_timer(cmd); 163962306a36Sopenharmony_ci 164062306a36Sopenharmony_ci if (isert_prot_cmd(isert_conn, se_cmd)) 164162306a36Sopenharmony_ci ret = isert_check_pi_status(se_cmd, isert_cmd->rw.reg->mr); 164262306a36Sopenharmony_ci isert_rdma_rw_ctx_destroy(isert_cmd, isert_conn); 164362306a36Sopenharmony_ci cmd->write_data_done = 0; 164462306a36Sopenharmony_ci 164562306a36Sopenharmony_ci isert_dbg("Cmd: %p RDMA_READ comp calling execute_cmd\n", isert_cmd); 164662306a36Sopenharmony_ci spin_lock_bh(&cmd->istate_lock); 164762306a36Sopenharmony_ci cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT; 164862306a36Sopenharmony_ci cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT; 164962306a36Sopenharmony_ci spin_unlock_bh(&cmd->istate_lock); 165062306a36Sopenharmony_ci 165162306a36Sopenharmony_ci /* 165262306a36Sopenharmony_ci * transport_generic_request_failure() will drop the extra 165362306a36Sopenharmony_ci * se_cmd->cmd_kref reference after T10-PI error, and handle 165462306a36Sopenharmony_ci * any non-zero ->queue_status() callback error retries. 165562306a36Sopenharmony_ci */ 165662306a36Sopenharmony_ci if (ret) 165762306a36Sopenharmony_ci transport_generic_request_failure(se_cmd, se_cmd->pi_err); 165862306a36Sopenharmony_ci else 165962306a36Sopenharmony_ci target_execute_cmd(se_cmd); 166062306a36Sopenharmony_ci} 166162306a36Sopenharmony_ci 166262306a36Sopenharmony_cistatic void 166362306a36Sopenharmony_ciisert_do_control_comp(struct work_struct *work) 166462306a36Sopenharmony_ci{ 166562306a36Sopenharmony_ci struct isert_cmd *isert_cmd = container_of(work, 166662306a36Sopenharmony_ci struct isert_cmd, comp_work); 166762306a36Sopenharmony_ci struct isert_conn *isert_conn = isert_cmd->conn; 166862306a36Sopenharmony_ci struct ib_device *ib_dev = isert_conn->cm_id->device; 166962306a36Sopenharmony_ci struct iscsit_cmd *cmd = isert_cmd->iscsit_cmd; 167062306a36Sopenharmony_ci 167162306a36Sopenharmony_ci isert_dbg("Cmd %p i_state %d\n", isert_cmd, cmd->i_state); 167262306a36Sopenharmony_ci 167362306a36Sopenharmony_ci switch (cmd->i_state) { 167462306a36Sopenharmony_ci case ISTATE_SEND_TASKMGTRSP: 167562306a36Sopenharmony_ci iscsit_tmr_post_handler(cmd, cmd->conn); 167662306a36Sopenharmony_ci fallthrough; 167762306a36Sopenharmony_ci case ISTATE_SEND_REJECT: 167862306a36Sopenharmony_ci case ISTATE_SEND_TEXTRSP: 167962306a36Sopenharmony_ci cmd->i_state = ISTATE_SENT_STATUS; 168062306a36Sopenharmony_ci isert_completion_put(&isert_cmd->tx_desc, isert_cmd, 168162306a36Sopenharmony_ci ib_dev, false); 168262306a36Sopenharmony_ci break; 168362306a36Sopenharmony_ci case ISTATE_SEND_LOGOUTRSP: 168462306a36Sopenharmony_ci iscsit_logout_post_handler(cmd, cmd->conn); 168562306a36Sopenharmony_ci break; 168662306a36Sopenharmony_ci default: 168762306a36Sopenharmony_ci isert_err("Unknown i_state %d\n", cmd->i_state); 168862306a36Sopenharmony_ci dump_stack(); 168962306a36Sopenharmony_ci break; 169062306a36Sopenharmony_ci } 169162306a36Sopenharmony_ci} 169262306a36Sopenharmony_ci 169362306a36Sopenharmony_cistatic void 169462306a36Sopenharmony_ciisert_login_send_done(struct ib_cq *cq, struct ib_wc *wc) 169562306a36Sopenharmony_ci{ 169662306a36Sopenharmony_ci struct isert_conn *isert_conn = wc->qp->qp_context; 169762306a36Sopenharmony_ci struct ib_device *ib_dev = isert_conn->cm_id->device; 169862306a36Sopenharmony_ci struct iser_tx_desc *tx_desc = cqe_to_tx_desc(wc->wr_cqe); 169962306a36Sopenharmony_ci 170062306a36Sopenharmony_ci if (unlikely(wc->status != IB_WC_SUCCESS)) { 170162306a36Sopenharmony_ci isert_print_wc(wc, "login send"); 170262306a36Sopenharmony_ci if (wc->status != IB_WC_WR_FLUSH_ERR) 170362306a36Sopenharmony_ci iscsit_cause_connection_reinstatement(isert_conn->conn, 0); 170462306a36Sopenharmony_ci } 170562306a36Sopenharmony_ci 170662306a36Sopenharmony_ci isert_unmap_tx_desc(tx_desc, ib_dev); 170762306a36Sopenharmony_ci} 170862306a36Sopenharmony_ci 170962306a36Sopenharmony_cistatic void 171062306a36Sopenharmony_ciisert_send_done(struct ib_cq *cq, struct ib_wc *wc) 171162306a36Sopenharmony_ci{ 171262306a36Sopenharmony_ci struct isert_conn *isert_conn = wc->qp->qp_context; 171362306a36Sopenharmony_ci struct ib_device *ib_dev = isert_conn->cm_id->device; 171462306a36Sopenharmony_ci struct iser_tx_desc *tx_desc = cqe_to_tx_desc(wc->wr_cqe); 171562306a36Sopenharmony_ci struct isert_cmd *isert_cmd = tx_desc_to_cmd(tx_desc); 171662306a36Sopenharmony_ci 171762306a36Sopenharmony_ci if (unlikely(wc->status != IB_WC_SUCCESS)) { 171862306a36Sopenharmony_ci isert_print_wc(wc, "send"); 171962306a36Sopenharmony_ci if (wc->status != IB_WC_WR_FLUSH_ERR) 172062306a36Sopenharmony_ci iscsit_cause_connection_reinstatement(isert_conn->conn, 0); 172162306a36Sopenharmony_ci isert_completion_put(tx_desc, isert_cmd, ib_dev, true); 172262306a36Sopenharmony_ci return; 172362306a36Sopenharmony_ci } 172462306a36Sopenharmony_ci 172562306a36Sopenharmony_ci isert_dbg("Cmd %p\n", isert_cmd); 172662306a36Sopenharmony_ci 172762306a36Sopenharmony_ci switch (isert_cmd->iscsit_cmd->i_state) { 172862306a36Sopenharmony_ci case ISTATE_SEND_TASKMGTRSP: 172962306a36Sopenharmony_ci case ISTATE_SEND_LOGOUTRSP: 173062306a36Sopenharmony_ci case ISTATE_SEND_REJECT: 173162306a36Sopenharmony_ci case ISTATE_SEND_TEXTRSP: 173262306a36Sopenharmony_ci isert_unmap_tx_desc(tx_desc, ib_dev); 173362306a36Sopenharmony_ci 173462306a36Sopenharmony_ci INIT_WORK(&isert_cmd->comp_work, isert_do_control_comp); 173562306a36Sopenharmony_ci queue_work(isert_comp_wq, &isert_cmd->comp_work); 173662306a36Sopenharmony_ci return; 173762306a36Sopenharmony_ci default: 173862306a36Sopenharmony_ci isert_cmd->iscsit_cmd->i_state = ISTATE_SENT_STATUS; 173962306a36Sopenharmony_ci isert_completion_put(tx_desc, isert_cmd, ib_dev, false); 174062306a36Sopenharmony_ci break; 174162306a36Sopenharmony_ci } 174262306a36Sopenharmony_ci} 174362306a36Sopenharmony_ci 174462306a36Sopenharmony_cistatic int 174562306a36Sopenharmony_ciisert_post_response(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd) 174662306a36Sopenharmony_ci{ 174762306a36Sopenharmony_ci int ret; 174862306a36Sopenharmony_ci 174962306a36Sopenharmony_ci ret = isert_post_recv(isert_conn, isert_cmd->rx_desc); 175062306a36Sopenharmony_ci if (ret) 175162306a36Sopenharmony_ci return ret; 175262306a36Sopenharmony_ci 175362306a36Sopenharmony_ci ret = ib_post_send(isert_conn->qp, &isert_cmd->tx_desc.send_wr, NULL); 175462306a36Sopenharmony_ci if (ret) { 175562306a36Sopenharmony_ci isert_err("ib_post_send failed with %d\n", ret); 175662306a36Sopenharmony_ci return ret; 175762306a36Sopenharmony_ci } 175862306a36Sopenharmony_ci return ret; 175962306a36Sopenharmony_ci} 176062306a36Sopenharmony_ci 176162306a36Sopenharmony_cistatic int 176262306a36Sopenharmony_ciisert_put_response(struct iscsit_conn *conn, struct iscsit_cmd *cmd) 176362306a36Sopenharmony_ci{ 176462306a36Sopenharmony_ci struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); 176562306a36Sopenharmony_ci struct isert_conn *isert_conn = conn->context; 176662306a36Sopenharmony_ci struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr; 176762306a36Sopenharmony_ci struct iscsi_scsi_rsp *hdr = (struct iscsi_scsi_rsp *) 176862306a36Sopenharmony_ci &isert_cmd->tx_desc.iscsi_header; 176962306a36Sopenharmony_ci 177062306a36Sopenharmony_ci isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc); 177162306a36Sopenharmony_ci iscsit_build_rsp_pdu(cmd, conn, true, hdr); 177262306a36Sopenharmony_ci isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc); 177362306a36Sopenharmony_ci /* 177462306a36Sopenharmony_ci * Attach SENSE DATA payload to iSCSI Response PDU 177562306a36Sopenharmony_ci */ 177662306a36Sopenharmony_ci if (cmd->se_cmd.sense_buffer && 177762306a36Sopenharmony_ci ((cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) || 177862306a36Sopenharmony_ci (cmd->se_cmd.se_cmd_flags & SCF_EMULATED_TASK_SENSE))) { 177962306a36Sopenharmony_ci struct isert_device *device = isert_conn->device; 178062306a36Sopenharmony_ci struct ib_device *ib_dev = device->ib_device; 178162306a36Sopenharmony_ci struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1]; 178262306a36Sopenharmony_ci u32 padding, pdu_len; 178362306a36Sopenharmony_ci 178462306a36Sopenharmony_ci put_unaligned_be16(cmd->se_cmd.scsi_sense_length, 178562306a36Sopenharmony_ci cmd->sense_buffer); 178662306a36Sopenharmony_ci cmd->se_cmd.scsi_sense_length += sizeof(__be16); 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci padding = -(cmd->se_cmd.scsi_sense_length) & 3; 178962306a36Sopenharmony_ci hton24(hdr->dlength, (u32)cmd->se_cmd.scsi_sense_length); 179062306a36Sopenharmony_ci pdu_len = cmd->se_cmd.scsi_sense_length + padding; 179162306a36Sopenharmony_ci 179262306a36Sopenharmony_ci isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev, 179362306a36Sopenharmony_ci (void *)cmd->sense_buffer, pdu_len, 179462306a36Sopenharmony_ci DMA_TO_DEVICE); 179562306a36Sopenharmony_ci if (ib_dma_mapping_error(ib_dev, isert_cmd->pdu_buf_dma)) 179662306a36Sopenharmony_ci return -ENOMEM; 179762306a36Sopenharmony_ci 179862306a36Sopenharmony_ci isert_cmd->pdu_buf_len = pdu_len; 179962306a36Sopenharmony_ci tx_dsg->addr = isert_cmd->pdu_buf_dma; 180062306a36Sopenharmony_ci tx_dsg->length = pdu_len; 180162306a36Sopenharmony_ci tx_dsg->lkey = device->pd->local_dma_lkey; 180262306a36Sopenharmony_ci isert_cmd->tx_desc.num_sge = 2; 180362306a36Sopenharmony_ci } 180462306a36Sopenharmony_ci 180562306a36Sopenharmony_ci isert_init_send_wr(isert_conn, isert_cmd, send_wr); 180662306a36Sopenharmony_ci 180762306a36Sopenharmony_ci isert_dbg("Posting SCSI Response\n"); 180862306a36Sopenharmony_ci 180962306a36Sopenharmony_ci return isert_post_response(isert_conn, isert_cmd); 181062306a36Sopenharmony_ci} 181162306a36Sopenharmony_ci 181262306a36Sopenharmony_cistatic void 181362306a36Sopenharmony_ciisert_aborted_task(struct iscsit_conn *conn, struct iscsit_cmd *cmd) 181462306a36Sopenharmony_ci{ 181562306a36Sopenharmony_ci struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); 181662306a36Sopenharmony_ci struct isert_conn *isert_conn = conn->context; 181762306a36Sopenharmony_ci 181862306a36Sopenharmony_ci spin_lock_bh(&conn->cmd_lock); 181962306a36Sopenharmony_ci if (!list_empty(&cmd->i_conn_node)) 182062306a36Sopenharmony_ci list_del_init(&cmd->i_conn_node); 182162306a36Sopenharmony_ci spin_unlock_bh(&conn->cmd_lock); 182262306a36Sopenharmony_ci 182362306a36Sopenharmony_ci if (cmd->data_direction == DMA_TO_DEVICE) 182462306a36Sopenharmony_ci iscsit_stop_dataout_timer(cmd); 182562306a36Sopenharmony_ci isert_rdma_rw_ctx_destroy(isert_cmd, isert_conn); 182662306a36Sopenharmony_ci} 182762306a36Sopenharmony_ci 182862306a36Sopenharmony_cistatic enum target_prot_op 182962306a36Sopenharmony_ciisert_get_sup_prot_ops(struct iscsit_conn *conn) 183062306a36Sopenharmony_ci{ 183162306a36Sopenharmony_ci struct isert_conn *isert_conn = conn->context; 183262306a36Sopenharmony_ci struct isert_device *device = isert_conn->device; 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci if (conn->tpg->tpg_attrib.t10_pi) { 183562306a36Sopenharmony_ci if (device->pi_capable) { 183662306a36Sopenharmony_ci isert_info("conn %p PI offload enabled\n", isert_conn); 183762306a36Sopenharmony_ci isert_conn->pi_support = true; 183862306a36Sopenharmony_ci return TARGET_PROT_ALL; 183962306a36Sopenharmony_ci } 184062306a36Sopenharmony_ci } 184162306a36Sopenharmony_ci 184262306a36Sopenharmony_ci isert_info("conn %p PI offload disabled\n", isert_conn); 184362306a36Sopenharmony_ci isert_conn->pi_support = false; 184462306a36Sopenharmony_ci 184562306a36Sopenharmony_ci return TARGET_PROT_NORMAL; 184662306a36Sopenharmony_ci} 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_cistatic int 184962306a36Sopenharmony_ciisert_put_nopin(struct iscsit_cmd *cmd, struct iscsit_conn *conn, 185062306a36Sopenharmony_ci bool nopout_response) 185162306a36Sopenharmony_ci{ 185262306a36Sopenharmony_ci struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); 185362306a36Sopenharmony_ci struct isert_conn *isert_conn = conn->context; 185462306a36Sopenharmony_ci struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr; 185562306a36Sopenharmony_ci 185662306a36Sopenharmony_ci isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc); 185762306a36Sopenharmony_ci iscsit_build_nopin_rsp(cmd, conn, (struct iscsi_nopin *) 185862306a36Sopenharmony_ci &isert_cmd->tx_desc.iscsi_header, 185962306a36Sopenharmony_ci nopout_response); 186062306a36Sopenharmony_ci isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc); 186162306a36Sopenharmony_ci isert_init_send_wr(isert_conn, isert_cmd, send_wr); 186262306a36Sopenharmony_ci 186362306a36Sopenharmony_ci isert_dbg("conn %p Posting NOPIN Response\n", isert_conn); 186462306a36Sopenharmony_ci 186562306a36Sopenharmony_ci return isert_post_response(isert_conn, isert_cmd); 186662306a36Sopenharmony_ci} 186762306a36Sopenharmony_ci 186862306a36Sopenharmony_cistatic int 186962306a36Sopenharmony_ciisert_put_logout_rsp(struct iscsit_cmd *cmd, struct iscsit_conn *conn) 187062306a36Sopenharmony_ci{ 187162306a36Sopenharmony_ci struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); 187262306a36Sopenharmony_ci struct isert_conn *isert_conn = conn->context; 187362306a36Sopenharmony_ci struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr; 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_ci isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc); 187662306a36Sopenharmony_ci iscsit_build_logout_rsp(cmd, conn, (struct iscsi_logout_rsp *) 187762306a36Sopenharmony_ci &isert_cmd->tx_desc.iscsi_header); 187862306a36Sopenharmony_ci isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc); 187962306a36Sopenharmony_ci isert_init_send_wr(isert_conn, isert_cmd, send_wr); 188062306a36Sopenharmony_ci 188162306a36Sopenharmony_ci isert_dbg("conn %p Posting Logout Response\n", isert_conn); 188262306a36Sopenharmony_ci 188362306a36Sopenharmony_ci return isert_post_response(isert_conn, isert_cmd); 188462306a36Sopenharmony_ci} 188562306a36Sopenharmony_ci 188662306a36Sopenharmony_cistatic int 188762306a36Sopenharmony_ciisert_put_tm_rsp(struct iscsit_cmd *cmd, struct iscsit_conn *conn) 188862306a36Sopenharmony_ci{ 188962306a36Sopenharmony_ci struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); 189062306a36Sopenharmony_ci struct isert_conn *isert_conn = conn->context; 189162306a36Sopenharmony_ci struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr; 189262306a36Sopenharmony_ci 189362306a36Sopenharmony_ci isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc); 189462306a36Sopenharmony_ci iscsit_build_task_mgt_rsp(cmd, conn, (struct iscsi_tm_rsp *) 189562306a36Sopenharmony_ci &isert_cmd->tx_desc.iscsi_header); 189662306a36Sopenharmony_ci isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc); 189762306a36Sopenharmony_ci isert_init_send_wr(isert_conn, isert_cmd, send_wr); 189862306a36Sopenharmony_ci 189962306a36Sopenharmony_ci isert_dbg("conn %p Posting Task Management Response\n", isert_conn); 190062306a36Sopenharmony_ci 190162306a36Sopenharmony_ci return isert_post_response(isert_conn, isert_cmd); 190262306a36Sopenharmony_ci} 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_cistatic int 190562306a36Sopenharmony_ciisert_put_reject(struct iscsit_cmd *cmd, struct iscsit_conn *conn) 190662306a36Sopenharmony_ci{ 190762306a36Sopenharmony_ci struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); 190862306a36Sopenharmony_ci struct isert_conn *isert_conn = conn->context; 190962306a36Sopenharmony_ci struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr; 191062306a36Sopenharmony_ci struct isert_device *device = isert_conn->device; 191162306a36Sopenharmony_ci struct ib_device *ib_dev = device->ib_device; 191262306a36Sopenharmony_ci struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1]; 191362306a36Sopenharmony_ci struct iscsi_reject *hdr = 191462306a36Sopenharmony_ci (struct iscsi_reject *)&isert_cmd->tx_desc.iscsi_header; 191562306a36Sopenharmony_ci 191662306a36Sopenharmony_ci isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc); 191762306a36Sopenharmony_ci iscsit_build_reject(cmd, conn, hdr); 191862306a36Sopenharmony_ci isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc); 191962306a36Sopenharmony_ci 192062306a36Sopenharmony_ci hton24(hdr->dlength, ISCSI_HDR_LEN); 192162306a36Sopenharmony_ci isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev, 192262306a36Sopenharmony_ci (void *)cmd->buf_ptr, ISCSI_HDR_LEN, 192362306a36Sopenharmony_ci DMA_TO_DEVICE); 192462306a36Sopenharmony_ci if (ib_dma_mapping_error(ib_dev, isert_cmd->pdu_buf_dma)) 192562306a36Sopenharmony_ci return -ENOMEM; 192662306a36Sopenharmony_ci isert_cmd->pdu_buf_len = ISCSI_HDR_LEN; 192762306a36Sopenharmony_ci tx_dsg->addr = isert_cmd->pdu_buf_dma; 192862306a36Sopenharmony_ci tx_dsg->length = ISCSI_HDR_LEN; 192962306a36Sopenharmony_ci tx_dsg->lkey = device->pd->local_dma_lkey; 193062306a36Sopenharmony_ci isert_cmd->tx_desc.num_sge = 2; 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci isert_init_send_wr(isert_conn, isert_cmd, send_wr); 193362306a36Sopenharmony_ci 193462306a36Sopenharmony_ci isert_dbg("conn %p Posting Reject\n", isert_conn); 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci return isert_post_response(isert_conn, isert_cmd); 193762306a36Sopenharmony_ci} 193862306a36Sopenharmony_ci 193962306a36Sopenharmony_cistatic int 194062306a36Sopenharmony_ciisert_put_text_rsp(struct iscsit_cmd *cmd, struct iscsit_conn *conn) 194162306a36Sopenharmony_ci{ 194262306a36Sopenharmony_ci struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); 194362306a36Sopenharmony_ci struct isert_conn *isert_conn = conn->context; 194462306a36Sopenharmony_ci struct ib_send_wr *send_wr = &isert_cmd->tx_desc.send_wr; 194562306a36Sopenharmony_ci struct iscsi_text_rsp *hdr = 194662306a36Sopenharmony_ci (struct iscsi_text_rsp *)&isert_cmd->tx_desc.iscsi_header; 194762306a36Sopenharmony_ci u32 txt_rsp_len; 194862306a36Sopenharmony_ci int rc; 194962306a36Sopenharmony_ci 195062306a36Sopenharmony_ci isert_create_send_desc(isert_conn, isert_cmd, &isert_cmd->tx_desc); 195162306a36Sopenharmony_ci rc = iscsit_build_text_rsp(cmd, conn, hdr, ISCSI_INFINIBAND); 195262306a36Sopenharmony_ci if (rc < 0) 195362306a36Sopenharmony_ci return rc; 195462306a36Sopenharmony_ci 195562306a36Sopenharmony_ci txt_rsp_len = rc; 195662306a36Sopenharmony_ci isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc); 195762306a36Sopenharmony_ci 195862306a36Sopenharmony_ci if (txt_rsp_len) { 195962306a36Sopenharmony_ci struct isert_device *device = isert_conn->device; 196062306a36Sopenharmony_ci struct ib_device *ib_dev = device->ib_device; 196162306a36Sopenharmony_ci struct ib_sge *tx_dsg = &isert_cmd->tx_desc.tx_sg[1]; 196262306a36Sopenharmony_ci void *txt_rsp_buf = cmd->buf_ptr; 196362306a36Sopenharmony_ci 196462306a36Sopenharmony_ci isert_cmd->pdu_buf_dma = ib_dma_map_single(ib_dev, 196562306a36Sopenharmony_ci txt_rsp_buf, txt_rsp_len, DMA_TO_DEVICE); 196662306a36Sopenharmony_ci if (ib_dma_mapping_error(ib_dev, isert_cmd->pdu_buf_dma)) 196762306a36Sopenharmony_ci return -ENOMEM; 196862306a36Sopenharmony_ci 196962306a36Sopenharmony_ci isert_cmd->pdu_buf_len = txt_rsp_len; 197062306a36Sopenharmony_ci tx_dsg->addr = isert_cmd->pdu_buf_dma; 197162306a36Sopenharmony_ci tx_dsg->length = txt_rsp_len; 197262306a36Sopenharmony_ci tx_dsg->lkey = device->pd->local_dma_lkey; 197362306a36Sopenharmony_ci isert_cmd->tx_desc.num_sge = 2; 197462306a36Sopenharmony_ci } 197562306a36Sopenharmony_ci isert_init_send_wr(isert_conn, isert_cmd, send_wr); 197662306a36Sopenharmony_ci 197762306a36Sopenharmony_ci isert_dbg("conn %p Text Response\n", isert_conn); 197862306a36Sopenharmony_ci 197962306a36Sopenharmony_ci return isert_post_response(isert_conn, isert_cmd); 198062306a36Sopenharmony_ci} 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_cistatic inline void 198362306a36Sopenharmony_ciisert_set_dif_domain(struct se_cmd *se_cmd, struct ib_sig_domain *domain) 198462306a36Sopenharmony_ci{ 198562306a36Sopenharmony_ci domain->sig_type = IB_SIG_TYPE_T10_DIF; 198662306a36Sopenharmony_ci domain->sig.dif.bg_type = IB_T10DIF_CRC; 198762306a36Sopenharmony_ci domain->sig.dif.pi_interval = se_cmd->se_dev->dev_attrib.block_size; 198862306a36Sopenharmony_ci domain->sig.dif.ref_tag = se_cmd->reftag_seed; 198962306a36Sopenharmony_ci /* 199062306a36Sopenharmony_ci * At the moment we hard code those, but if in the future 199162306a36Sopenharmony_ci * the target core would like to use it, we will take it 199262306a36Sopenharmony_ci * from se_cmd. 199362306a36Sopenharmony_ci */ 199462306a36Sopenharmony_ci domain->sig.dif.apptag_check_mask = 0xffff; 199562306a36Sopenharmony_ci domain->sig.dif.app_escape = true; 199662306a36Sopenharmony_ci domain->sig.dif.ref_escape = true; 199762306a36Sopenharmony_ci if (se_cmd->prot_type == TARGET_DIF_TYPE1_PROT || 199862306a36Sopenharmony_ci se_cmd->prot_type == TARGET_DIF_TYPE2_PROT) 199962306a36Sopenharmony_ci domain->sig.dif.ref_remap = true; 200062306a36Sopenharmony_ci} 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_cistatic int 200362306a36Sopenharmony_ciisert_set_sig_attrs(struct se_cmd *se_cmd, struct ib_sig_attrs *sig_attrs) 200462306a36Sopenharmony_ci{ 200562306a36Sopenharmony_ci memset(sig_attrs, 0, sizeof(*sig_attrs)); 200662306a36Sopenharmony_ci 200762306a36Sopenharmony_ci switch (se_cmd->prot_op) { 200862306a36Sopenharmony_ci case TARGET_PROT_DIN_INSERT: 200962306a36Sopenharmony_ci case TARGET_PROT_DOUT_STRIP: 201062306a36Sopenharmony_ci sig_attrs->mem.sig_type = IB_SIG_TYPE_NONE; 201162306a36Sopenharmony_ci isert_set_dif_domain(se_cmd, &sig_attrs->wire); 201262306a36Sopenharmony_ci break; 201362306a36Sopenharmony_ci case TARGET_PROT_DOUT_INSERT: 201462306a36Sopenharmony_ci case TARGET_PROT_DIN_STRIP: 201562306a36Sopenharmony_ci sig_attrs->wire.sig_type = IB_SIG_TYPE_NONE; 201662306a36Sopenharmony_ci isert_set_dif_domain(se_cmd, &sig_attrs->mem); 201762306a36Sopenharmony_ci break; 201862306a36Sopenharmony_ci case TARGET_PROT_DIN_PASS: 201962306a36Sopenharmony_ci case TARGET_PROT_DOUT_PASS: 202062306a36Sopenharmony_ci isert_set_dif_domain(se_cmd, &sig_attrs->wire); 202162306a36Sopenharmony_ci isert_set_dif_domain(se_cmd, &sig_attrs->mem); 202262306a36Sopenharmony_ci break; 202362306a36Sopenharmony_ci default: 202462306a36Sopenharmony_ci isert_err("Unsupported PI operation %d\n", se_cmd->prot_op); 202562306a36Sopenharmony_ci return -EINVAL; 202662306a36Sopenharmony_ci } 202762306a36Sopenharmony_ci 202862306a36Sopenharmony_ci if (se_cmd->prot_checks & TARGET_DIF_CHECK_GUARD) 202962306a36Sopenharmony_ci sig_attrs->check_mask |= IB_SIG_CHECK_GUARD; 203062306a36Sopenharmony_ci if (se_cmd->prot_checks & TARGET_DIF_CHECK_APPTAG) 203162306a36Sopenharmony_ci sig_attrs->check_mask |= IB_SIG_CHECK_APPTAG; 203262306a36Sopenharmony_ci if (se_cmd->prot_checks & TARGET_DIF_CHECK_REFTAG) 203362306a36Sopenharmony_ci sig_attrs->check_mask |= IB_SIG_CHECK_REFTAG; 203462306a36Sopenharmony_ci 203562306a36Sopenharmony_ci return 0; 203662306a36Sopenharmony_ci} 203762306a36Sopenharmony_ci 203862306a36Sopenharmony_cistatic int 203962306a36Sopenharmony_ciisert_rdma_rw_ctx_post(struct isert_cmd *cmd, struct isert_conn *conn, 204062306a36Sopenharmony_ci struct ib_cqe *cqe, struct ib_send_wr *chain_wr) 204162306a36Sopenharmony_ci{ 204262306a36Sopenharmony_ci struct se_cmd *se_cmd = &cmd->iscsit_cmd->se_cmd; 204362306a36Sopenharmony_ci enum dma_data_direction dir = target_reverse_dma_direction(se_cmd); 204462306a36Sopenharmony_ci u8 port_num = conn->cm_id->port_num; 204562306a36Sopenharmony_ci u64 addr; 204662306a36Sopenharmony_ci u32 rkey, offset; 204762306a36Sopenharmony_ci int ret; 204862306a36Sopenharmony_ci 204962306a36Sopenharmony_ci if (cmd->ctx_init_done) 205062306a36Sopenharmony_ci goto rdma_ctx_post; 205162306a36Sopenharmony_ci 205262306a36Sopenharmony_ci if (dir == DMA_FROM_DEVICE) { 205362306a36Sopenharmony_ci addr = cmd->write_va; 205462306a36Sopenharmony_ci rkey = cmd->write_stag; 205562306a36Sopenharmony_ci offset = cmd->iscsit_cmd->write_data_done; 205662306a36Sopenharmony_ci } else { 205762306a36Sopenharmony_ci addr = cmd->read_va; 205862306a36Sopenharmony_ci rkey = cmd->read_stag; 205962306a36Sopenharmony_ci offset = 0; 206062306a36Sopenharmony_ci } 206162306a36Sopenharmony_ci 206262306a36Sopenharmony_ci if (isert_prot_cmd(conn, se_cmd)) { 206362306a36Sopenharmony_ci struct ib_sig_attrs sig_attrs; 206462306a36Sopenharmony_ci 206562306a36Sopenharmony_ci ret = isert_set_sig_attrs(se_cmd, &sig_attrs); 206662306a36Sopenharmony_ci if (ret) 206762306a36Sopenharmony_ci return ret; 206862306a36Sopenharmony_ci 206962306a36Sopenharmony_ci WARN_ON_ONCE(offset); 207062306a36Sopenharmony_ci ret = rdma_rw_ctx_signature_init(&cmd->rw, conn->qp, port_num, 207162306a36Sopenharmony_ci se_cmd->t_data_sg, se_cmd->t_data_nents, 207262306a36Sopenharmony_ci se_cmd->t_prot_sg, se_cmd->t_prot_nents, 207362306a36Sopenharmony_ci &sig_attrs, addr, rkey, dir); 207462306a36Sopenharmony_ci } else { 207562306a36Sopenharmony_ci ret = rdma_rw_ctx_init(&cmd->rw, conn->qp, port_num, 207662306a36Sopenharmony_ci se_cmd->t_data_sg, se_cmd->t_data_nents, 207762306a36Sopenharmony_ci offset, addr, rkey, dir); 207862306a36Sopenharmony_ci } 207962306a36Sopenharmony_ci 208062306a36Sopenharmony_ci if (ret < 0) { 208162306a36Sopenharmony_ci isert_err("Cmd: %p failed to prepare RDMA res\n", cmd); 208262306a36Sopenharmony_ci return ret; 208362306a36Sopenharmony_ci } 208462306a36Sopenharmony_ci 208562306a36Sopenharmony_ci cmd->ctx_init_done = true; 208662306a36Sopenharmony_ci 208762306a36Sopenharmony_cirdma_ctx_post: 208862306a36Sopenharmony_ci ret = rdma_rw_ctx_post(&cmd->rw, conn->qp, port_num, cqe, chain_wr); 208962306a36Sopenharmony_ci if (ret < 0) 209062306a36Sopenharmony_ci isert_err("Cmd: %p failed to post RDMA res\n", cmd); 209162306a36Sopenharmony_ci return ret; 209262306a36Sopenharmony_ci} 209362306a36Sopenharmony_ci 209462306a36Sopenharmony_cistatic int 209562306a36Sopenharmony_ciisert_put_datain(struct iscsit_conn *conn, struct iscsit_cmd *cmd) 209662306a36Sopenharmony_ci{ 209762306a36Sopenharmony_ci struct se_cmd *se_cmd = &cmd->se_cmd; 209862306a36Sopenharmony_ci struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); 209962306a36Sopenharmony_ci struct isert_conn *isert_conn = conn->context; 210062306a36Sopenharmony_ci struct ib_cqe *cqe = NULL; 210162306a36Sopenharmony_ci struct ib_send_wr *chain_wr = NULL; 210262306a36Sopenharmony_ci int rc; 210362306a36Sopenharmony_ci 210462306a36Sopenharmony_ci isert_dbg("Cmd: %p RDMA_WRITE data_length: %u\n", 210562306a36Sopenharmony_ci isert_cmd, se_cmd->data_length); 210662306a36Sopenharmony_ci 210762306a36Sopenharmony_ci if (isert_prot_cmd(isert_conn, se_cmd)) { 210862306a36Sopenharmony_ci isert_cmd->tx_desc.tx_cqe.done = isert_rdma_write_done; 210962306a36Sopenharmony_ci cqe = &isert_cmd->tx_desc.tx_cqe; 211062306a36Sopenharmony_ci } else { 211162306a36Sopenharmony_ci /* 211262306a36Sopenharmony_ci * Build isert_conn->tx_desc for iSCSI response PDU and attach 211362306a36Sopenharmony_ci */ 211462306a36Sopenharmony_ci isert_create_send_desc(isert_conn, isert_cmd, 211562306a36Sopenharmony_ci &isert_cmd->tx_desc); 211662306a36Sopenharmony_ci iscsit_build_rsp_pdu(cmd, conn, true, (struct iscsi_scsi_rsp *) 211762306a36Sopenharmony_ci &isert_cmd->tx_desc.iscsi_header); 211862306a36Sopenharmony_ci isert_init_tx_hdrs(isert_conn, &isert_cmd->tx_desc); 211962306a36Sopenharmony_ci isert_init_send_wr(isert_conn, isert_cmd, 212062306a36Sopenharmony_ci &isert_cmd->tx_desc.send_wr); 212162306a36Sopenharmony_ci 212262306a36Sopenharmony_ci rc = isert_post_recv(isert_conn, isert_cmd->rx_desc); 212362306a36Sopenharmony_ci if (rc) 212462306a36Sopenharmony_ci return rc; 212562306a36Sopenharmony_ci 212662306a36Sopenharmony_ci chain_wr = &isert_cmd->tx_desc.send_wr; 212762306a36Sopenharmony_ci } 212862306a36Sopenharmony_ci 212962306a36Sopenharmony_ci rc = isert_rdma_rw_ctx_post(isert_cmd, isert_conn, cqe, chain_wr); 213062306a36Sopenharmony_ci isert_dbg("Cmd: %p posted RDMA_WRITE for iSER Data READ rc: %d\n", 213162306a36Sopenharmony_ci isert_cmd, rc); 213262306a36Sopenharmony_ci return rc; 213362306a36Sopenharmony_ci} 213462306a36Sopenharmony_ci 213562306a36Sopenharmony_cistatic int 213662306a36Sopenharmony_ciisert_get_dataout(struct iscsit_conn *conn, struct iscsit_cmd *cmd, bool recovery) 213762306a36Sopenharmony_ci{ 213862306a36Sopenharmony_ci struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); 213962306a36Sopenharmony_ci int ret; 214062306a36Sopenharmony_ci 214162306a36Sopenharmony_ci isert_dbg("Cmd: %p RDMA_READ data_length: %u write_data_done: %u\n", 214262306a36Sopenharmony_ci isert_cmd, cmd->se_cmd.data_length, cmd->write_data_done); 214362306a36Sopenharmony_ci 214462306a36Sopenharmony_ci isert_cmd->tx_desc.tx_cqe.done = isert_rdma_read_done; 214562306a36Sopenharmony_ci ret = isert_rdma_rw_ctx_post(isert_cmd, conn->context, 214662306a36Sopenharmony_ci &isert_cmd->tx_desc.tx_cqe, NULL); 214762306a36Sopenharmony_ci 214862306a36Sopenharmony_ci isert_dbg("Cmd: %p posted RDMA_READ memory for ISER Data WRITE rc: %d\n", 214962306a36Sopenharmony_ci isert_cmd, ret); 215062306a36Sopenharmony_ci return ret; 215162306a36Sopenharmony_ci} 215262306a36Sopenharmony_ci 215362306a36Sopenharmony_cistatic int 215462306a36Sopenharmony_ciisert_immediate_queue(struct iscsit_conn *conn, struct iscsit_cmd *cmd, int state) 215562306a36Sopenharmony_ci{ 215662306a36Sopenharmony_ci struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); 215762306a36Sopenharmony_ci int ret = 0; 215862306a36Sopenharmony_ci 215962306a36Sopenharmony_ci switch (state) { 216062306a36Sopenharmony_ci case ISTATE_REMOVE: 216162306a36Sopenharmony_ci spin_lock_bh(&conn->cmd_lock); 216262306a36Sopenharmony_ci list_del_init(&cmd->i_conn_node); 216362306a36Sopenharmony_ci spin_unlock_bh(&conn->cmd_lock); 216462306a36Sopenharmony_ci isert_put_cmd(isert_cmd, true); 216562306a36Sopenharmony_ci break; 216662306a36Sopenharmony_ci case ISTATE_SEND_NOPIN_WANT_RESPONSE: 216762306a36Sopenharmony_ci ret = isert_put_nopin(cmd, conn, false); 216862306a36Sopenharmony_ci break; 216962306a36Sopenharmony_ci default: 217062306a36Sopenharmony_ci isert_err("Unknown immediate state: 0x%02x\n", state); 217162306a36Sopenharmony_ci ret = -EINVAL; 217262306a36Sopenharmony_ci break; 217362306a36Sopenharmony_ci } 217462306a36Sopenharmony_ci 217562306a36Sopenharmony_ci return ret; 217662306a36Sopenharmony_ci} 217762306a36Sopenharmony_ci 217862306a36Sopenharmony_cistatic int 217962306a36Sopenharmony_ciisert_response_queue(struct iscsit_conn *conn, struct iscsit_cmd *cmd, int state) 218062306a36Sopenharmony_ci{ 218162306a36Sopenharmony_ci struct isert_conn *isert_conn = conn->context; 218262306a36Sopenharmony_ci int ret; 218362306a36Sopenharmony_ci 218462306a36Sopenharmony_ci switch (state) { 218562306a36Sopenharmony_ci case ISTATE_SEND_LOGOUTRSP: 218662306a36Sopenharmony_ci ret = isert_put_logout_rsp(cmd, conn); 218762306a36Sopenharmony_ci if (!ret) 218862306a36Sopenharmony_ci isert_conn->logout_posted = true; 218962306a36Sopenharmony_ci break; 219062306a36Sopenharmony_ci case ISTATE_SEND_NOPIN: 219162306a36Sopenharmony_ci ret = isert_put_nopin(cmd, conn, true); 219262306a36Sopenharmony_ci break; 219362306a36Sopenharmony_ci case ISTATE_SEND_TASKMGTRSP: 219462306a36Sopenharmony_ci ret = isert_put_tm_rsp(cmd, conn); 219562306a36Sopenharmony_ci break; 219662306a36Sopenharmony_ci case ISTATE_SEND_REJECT: 219762306a36Sopenharmony_ci ret = isert_put_reject(cmd, conn); 219862306a36Sopenharmony_ci break; 219962306a36Sopenharmony_ci case ISTATE_SEND_TEXTRSP: 220062306a36Sopenharmony_ci ret = isert_put_text_rsp(cmd, conn); 220162306a36Sopenharmony_ci break; 220262306a36Sopenharmony_ci case ISTATE_SEND_STATUS: 220362306a36Sopenharmony_ci /* 220462306a36Sopenharmony_ci * Special case for sending non GOOD SCSI status from TX thread 220562306a36Sopenharmony_ci * context during pre se_cmd excecution failure. 220662306a36Sopenharmony_ci */ 220762306a36Sopenharmony_ci ret = isert_put_response(conn, cmd); 220862306a36Sopenharmony_ci break; 220962306a36Sopenharmony_ci default: 221062306a36Sopenharmony_ci isert_err("Unknown response state: 0x%02x\n", state); 221162306a36Sopenharmony_ci ret = -EINVAL; 221262306a36Sopenharmony_ci break; 221362306a36Sopenharmony_ci } 221462306a36Sopenharmony_ci 221562306a36Sopenharmony_ci return ret; 221662306a36Sopenharmony_ci} 221762306a36Sopenharmony_ci 221862306a36Sopenharmony_cistruct rdma_cm_id * 221962306a36Sopenharmony_ciisert_setup_id(struct isert_np *isert_np) 222062306a36Sopenharmony_ci{ 222162306a36Sopenharmony_ci struct iscsi_np *np = isert_np->np; 222262306a36Sopenharmony_ci struct rdma_cm_id *id; 222362306a36Sopenharmony_ci struct sockaddr *sa; 222462306a36Sopenharmony_ci int ret; 222562306a36Sopenharmony_ci 222662306a36Sopenharmony_ci sa = (struct sockaddr *)&np->np_sockaddr; 222762306a36Sopenharmony_ci isert_dbg("ksockaddr: %p, sa: %p\n", &np->np_sockaddr, sa); 222862306a36Sopenharmony_ci 222962306a36Sopenharmony_ci id = rdma_create_id(&init_net, isert_cma_handler, isert_np, 223062306a36Sopenharmony_ci RDMA_PS_TCP, IB_QPT_RC); 223162306a36Sopenharmony_ci if (IS_ERR(id)) { 223262306a36Sopenharmony_ci isert_err("rdma_create_id() failed: %ld\n", PTR_ERR(id)); 223362306a36Sopenharmony_ci ret = PTR_ERR(id); 223462306a36Sopenharmony_ci goto out; 223562306a36Sopenharmony_ci } 223662306a36Sopenharmony_ci isert_dbg("id %p context %p\n", id, id->context); 223762306a36Sopenharmony_ci 223862306a36Sopenharmony_ci /* 223962306a36Sopenharmony_ci * Allow both IPv4 and IPv6 sockets to bind a single port 224062306a36Sopenharmony_ci * at the same time. 224162306a36Sopenharmony_ci */ 224262306a36Sopenharmony_ci ret = rdma_set_afonly(id, 1); 224362306a36Sopenharmony_ci if (ret) { 224462306a36Sopenharmony_ci isert_err("rdma_set_afonly() failed: %d\n", ret); 224562306a36Sopenharmony_ci goto out_id; 224662306a36Sopenharmony_ci } 224762306a36Sopenharmony_ci 224862306a36Sopenharmony_ci ret = rdma_bind_addr(id, sa); 224962306a36Sopenharmony_ci if (ret) { 225062306a36Sopenharmony_ci isert_err("rdma_bind_addr() failed: %d\n", ret); 225162306a36Sopenharmony_ci goto out_id; 225262306a36Sopenharmony_ci } 225362306a36Sopenharmony_ci 225462306a36Sopenharmony_ci ret = rdma_listen(id, 0); 225562306a36Sopenharmony_ci if (ret) { 225662306a36Sopenharmony_ci isert_err("rdma_listen() failed: %d\n", ret); 225762306a36Sopenharmony_ci goto out_id; 225862306a36Sopenharmony_ci } 225962306a36Sopenharmony_ci 226062306a36Sopenharmony_ci return id; 226162306a36Sopenharmony_ciout_id: 226262306a36Sopenharmony_ci rdma_destroy_id(id); 226362306a36Sopenharmony_ciout: 226462306a36Sopenharmony_ci return ERR_PTR(ret); 226562306a36Sopenharmony_ci} 226662306a36Sopenharmony_ci 226762306a36Sopenharmony_cistatic int 226862306a36Sopenharmony_ciisert_setup_np(struct iscsi_np *np, 226962306a36Sopenharmony_ci struct sockaddr_storage *ksockaddr) 227062306a36Sopenharmony_ci{ 227162306a36Sopenharmony_ci struct isert_np *isert_np; 227262306a36Sopenharmony_ci struct rdma_cm_id *isert_lid; 227362306a36Sopenharmony_ci int ret; 227462306a36Sopenharmony_ci 227562306a36Sopenharmony_ci isert_np = kzalloc(sizeof(struct isert_np), GFP_KERNEL); 227662306a36Sopenharmony_ci if (!isert_np) 227762306a36Sopenharmony_ci return -ENOMEM; 227862306a36Sopenharmony_ci 227962306a36Sopenharmony_ci sema_init(&isert_np->sem, 0); 228062306a36Sopenharmony_ci mutex_init(&isert_np->mutex); 228162306a36Sopenharmony_ci INIT_LIST_HEAD(&isert_np->accepted); 228262306a36Sopenharmony_ci INIT_LIST_HEAD(&isert_np->pending); 228362306a36Sopenharmony_ci isert_np->np = np; 228462306a36Sopenharmony_ci 228562306a36Sopenharmony_ci /* 228662306a36Sopenharmony_ci * Setup the np->np_sockaddr from the passed sockaddr setup 228762306a36Sopenharmony_ci * in iscsi_target_configfs.c code.. 228862306a36Sopenharmony_ci */ 228962306a36Sopenharmony_ci memcpy(&np->np_sockaddr, ksockaddr, 229062306a36Sopenharmony_ci sizeof(struct sockaddr_storage)); 229162306a36Sopenharmony_ci 229262306a36Sopenharmony_ci isert_lid = isert_setup_id(isert_np); 229362306a36Sopenharmony_ci if (IS_ERR(isert_lid)) { 229462306a36Sopenharmony_ci ret = PTR_ERR(isert_lid); 229562306a36Sopenharmony_ci goto out; 229662306a36Sopenharmony_ci } 229762306a36Sopenharmony_ci 229862306a36Sopenharmony_ci isert_np->cm_id = isert_lid; 229962306a36Sopenharmony_ci np->np_context = isert_np; 230062306a36Sopenharmony_ci 230162306a36Sopenharmony_ci return 0; 230262306a36Sopenharmony_ci 230362306a36Sopenharmony_ciout: 230462306a36Sopenharmony_ci kfree(isert_np); 230562306a36Sopenharmony_ci 230662306a36Sopenharmony_ci return ret; 230762306a36Sopenharmony_ci} 230862306a36Sopenharmony_ci 230962306a36Sopenharmony_cistatic int 231062306a36Sopenharmony_ciisert_rdma_accept(struct isert_conn *isert_conn) 231162306a36Sopenharmony_ci{ 231262306a36Sopenharmony_ci struct rdma_cm_id *cm_id = isert_conn->cm_id; 231362306a36Sopenharmony_ci struct rdma_conn_param cp; 231462306a36Sopenharmony_ci int ret; 231562306a36Sopenharmony_ci struct iser_cm_hdr rsp_hdr; 231662306a36Sopenharmony_ci 231762306a36Sopenharmony_ci memset(&cp, 0, sizeof(struct rdma_conn_param)); 231862306a36Sopenharmony_ci cp.initiator_depth = isert_conn->initiator_depth; 231962306a36Sopenharmony_ci cp.retry_count = 7; 232062306a36Sopenharmony_ci cp.rnr_retry_count = 7; 232162306a36Sopenharmony_ci 232262306a36Sopenharmony_ci memset(&rsp_hdr, 0, sizeof(rsp_hdr)); 232362306a36Sopenharmony_ci rsp_hdr.flags = ISERT_ZBVA_NOT_USED; 232462306a36Sopenharmony_ci if (!isert_conn->snd_w_inv) 232562306a36Sopenharmony_ci rsp_hdr.flags = rsp_hdr.flags | ISERT_SEND_W_INV_NOT_USED; 232662306a36Sopenharmony_ci cp.private_data = (void *)&rsp_hdr; 232762306a36Sopenharmony_ci cp.private_data_len = sizeof(rsp_hdr); 232862306a36Sopenharmony_ci 232962306a36Sopenharmony_ci ret = rdma_accept(cm_id, &cp); 233062306a36Sopenharmony_ci if (ret) { 233162306a36Sopenharmony_ci isert_err("rdma_accept() failed with: %d\n", ret); 233262306a36Sopenharmony_ci return ret; 233362306a36Sopenharmony_ci } 233462306a36Sopenharmony_ci 233562306a36Sopenharmony_ci return 0; 233662306a36Sopenharmony_ci} 233762306a36Sopenharmony_ci 233862306a36Sopenharmony_cistatic int 233962306a36Sopenharmony_ciisert_get_login_rx(struct iscsit_conn *conn, struct iscsi_login *login) 234062306a36Sopenharmony_ci{ 234162306a36Sopenharmony_ci struct isert_conn *isert_conn = conn->context; 234262306a36Sopenharmony_ci int ret; 234362306a36Sopenharmony_ci 234462306a36Sopenharmony_ci isert_info("before login_req comp conn: %p\n", isert_conn); 234562306a36Sopenharmony_ci ret = wait_for_completion_interruptible(&isert_conn->login_req_comp); 234662306a36Sopenharmony_ci if (ret) { 234762306a36Sopenharmony_ci isert_err("isert_conn %p interrupted before got login req\n", 234862306a36Sopenharmony_ci isert_conn); 234962306a36Sopenharmony_ci return ret; 235062306a36Sopenharmony_ci } 235162306a36Sopenharmony_ci reinit_completion(&isert_conn->login_req_comp); 235262306a36Sopenharmony_ci 235362306a36Sopenharmony_ci /* 235462306a36Sopenharmony_ci * For login requests after the first PDU, isert_rx_login_req() will 235562306a36Sopenharmony_ci * kick queue_delayed_work(isert_login_wq, &conn->login_work) as 235662306a36Sopenharmony_ci * the packet is received, which turns this callback from 235762306a36Sopenharmony_ci * iscsi_target_do_login_rx() into a NOP. 235862306a36Sopenharmony_ci */ 235962306a36Sopenharmony_ci if (!login->first_request) 236062306a36Sopenharmony_ci return 0; 236162306a36Sopenharmony_ci 236262306a36Sopenharmony_ci isert_rx_login_req(isert_conn); 236362306a36Sopenharmony_ci 236462306a36Sopenharmony_ci isert_info("before login_comp conn: %p\n", conn); 236562306a36Sopenharmony_ci ret = wait_for_completion_interruptible(&isert_conn->login_comp); 236662306a36Sopenharmony_ci if (ret) 236762306a36Sopenharmony_ci return ret; 236862306a36Sopenharmony_ci 236962306a36Sopenharmony_ci isert_info("processing login->req: %p\n", login->req); 237062306a36Sopenharmony_ci 237162306a36Sopenharmony_ci return 0; 237262306a36Sopenharmony_ci} 237362306a36Sopenharmony_ci 237462306a36Sopenharmony_cistatic void 237562306a36Sopenharmony_ciisert_set_conn_info(struct iscsi_np *np, struct iscsit_conn *conn, 237662306a36Sopenharmony_ci struct isert_conn *isert_conn) 237762306a36Sopenharmony_ci{ 237862306a36Sopenharmony_ci struct rdma_cm_id *cm_id = isert_conn->cm_id; 237962306a36Sopenharmony_ci struct rdma_route *cm_route = &cm_id->route; 238062306a36Sopenharmony_ci 238162306a36Sopenharmony_ci conn->login_family = np->np_sockaddr.ss_family; 238262306a36Sopenharmony_ci 238362306a36Sopenharmony_ci conn->login_sockaddr = cm_route->addr.dst_addr; 238462306a36Sopenharmony_ci conn->local_sockaddr = cm_route->addr.src_addr; 238562306a36Sopenharmony_ci} 238662306a36Sopenharmony_ci 238762306a36Sopenharmony_cistatic int 238862306a36Sopenharmony_ciisert_accept_np(struct iscsi_np *np, struct iscsit_conn *conn) 238962306a36Sopenharmony_ci{ 239062306a36Sopenharmony_ci struct isert_np *isert_np = np->np_context; 239162306a36Sopenharmony_ci struct isert_conn *isert_conn; 239262306a36Sopenharmony_ci int ret; 239362306a36Sopenharmony_ci 239462306a36Sopenharmony_ciaccept_wait: 239562306a36Sopenharmony_ci ret = down_interruptible(&isert_np->sem); 239662306a36Sopenharmony_ci if (ret) 239762306a36Sopenharmony_ci return -ENODEV; 239862306a36Sopenharmony_ci 239962306a36Sopenharmony_ci spin_lock_bh(&np->np_thread_lock); 240062306a36Sopenharmony_ci if (np->np_thread_state >= ISCSI_NP_THREAD_RESET) { 240162306a36Sopenharmony_ci spin_unlock_bh(&np->np_thread_lock); 240262306a36Sopenharmony_ci isert_dbg("np_thread_state %d\n", 240362306a36Sopenharmony_ci np->np_thread_state); 240462306a36Sopenharmony_ci /* 240562306a36Sopenharmony_ci * No point in stalling here when np_thread 240662306a36Sopenharmony_ci * is in state RESET/SHUTDOWN/EXIT - bail 240762306a36Sopenharmony_ci */ 240862306a36Sopenharmony_ci return -ENODEV; 240962306a36Sopenharmony_ci } 241062306a36Sopenharmony_ci spin_unlock_bh(&np->np_thread_lock); 241162306a36Sopenharmony_ci 241262306a36Sopenharmony_ci mutex_lock(&isert_np->mutex); 241362306a36Sopenharmony_ci if (list_empty(&isert_np->pending)) { 241462306a36Sopenharmony_ci mutex_unlock(&isert_np->mutex); 241562306a36Sopenharmony_ci goto accept_wait; 241662306a36Sopenharmony_ci } 241762306a36Sopenharmony_ci isert_conn = list_first_entry(&isert_np->pending, 241862306a36Sopenharmony_ci struct isert_conn, node); 241962306a36Sopenharmony_ci list_del_init(&isert_conn->node); 242062306a36Sopenharmony_ci mutex_unlock(&isert_np->mutex); 242162306a36Sopenharmony_ci 242262306a36Sopenharmony_ci conn->context = isert_conn; 242362306a36Sopenharmony_ci isert_conn->conn = conn; 242462306a36Sopenharmony_ci isert_conn->state = ISER_CONN_BOUND; 242562306a36Sopenharmony_ci 242662306a36Sopenharmony_ci isert_set_conn_info(np, conn, isert_conn); 242762306a36Sopenharmony_ci 242862306a36Sopenharmony_ci isert_dbg("Processing isert_conn: %p\n", isert_conn); 242962306a36Sopenharmony_ci 243062306a36Sopenharmony_ci return 0; 243162306a36Sopenharmony_ci} 243262306a36Sopenharmony_ci 243362306a36Sopenharmony_cistatic void 243462306a36Sopenharmony_ciisert_free_np(struct iscsi_np *np) 243562306a36Sopenharmony_ci{ 243662306a36Sopenharmony_ci struct isert_np *isert_np = np->np_context; 243762306a36Sopenharmony_ci struct isert_conn *isert_conn, *n; 243862306a36Sopenharmony_ci LIST_HEAD(drop_conn_list); 243962306a36Sopenharmony_ci 244062306a36Sopenharmony_ci if (isert_np->cm_id) 244162306a36Sopenharmony_ci rdma_destroy_id(isert_np->cm_id); 244262306a36Sopenharmony_ci 244362306a36Sopenharmony_ci /* 244462306a36Sopenharmony_ci * FIXME: At this point we don't have a good way to insure 244562306a36Sopenharmony_ci * that at this point we don't have hanging connections that 244662306a36Sopenharmony_ci * completed RDMA establishment but didn't start iscsi login 244762306a36Sopenharmony_ci * process. So work-around this by cleaning up what ever piled 244862306a36Sopenharmony_ci * up in accepted and pending lists. 244962306a36Sopenharmony_ci */ 245062306a36Sopenharmony_ci mutex_lock(&isert_np->mutex); 245162306a36Sopenharmony_ci if (!list_empty(&isert_np->pending)) { 245262306a36Sopenharmony_ci isert_info("Still have isert pending connections\n"); 245362306a36Sopenharmony_ci list_for_each_entry_safe(isert_conn, n, 245462306a36Sopenharmony_ci &isert_np->pending, 245562306a36Sopenharmony_ci node) { 245662306a36Sopenharmony_ci isert_info("cleaning isert_conn %p state (%d)\n", 245762306a36Sopenharmony_ci isert_conn, isert_conn->state); 245862306a36Sopenharmony_ci list_move_tail(&isert_conn->node, &drop_conn_list); 245962306a36Sopenharmony_ci } 246062306a36Sopenharmony_ci } 246162306a36Sopenharmony_ci 246262306a36Sopenharmony_ci if (!list_empty(&isert_np->accepted)) { 246362306a36Sopenharmony_ci isert_info("Still have isert accepted connections\n"); 246462306a36Sopenharmony_ci list_for_each_entry_safe(isert_conn, n, 246562306a36Sopenharmony_ci &isert_np->accepted, 246662306a36Sopenharmony_ci node) { 246762306a36Sopenharmony_ci isert_info("cleaning isert_conn %p state (%d)\n", 246862306a36Sopenharmony_ci isert_conn, isert_conn->state); 246962306a36Sopenharmony_ci list_move_tail(&isert_conn->node, &drop_conn_list); 247062306a36Sopenharmony_ci } 247162306a36Sopenharmony_ci } 247262306a36Sopenharmony_ci mutex_unlock(&isert_np->mutex); 247362306a36Sopenharmony_ci 247462306a36Sopenharmony_ci list_for_each_entry_safe(isert_conn, n, &drop_conn_list, node) { 247562306a36Sopenharmony_ci list_del_init(&isert_conn->node); 247662306a36Sopenharmony_ci isert_connect_release(isert_conn); 247762306a36Sopenharmony_ci } 247862306a36Sopenharmony_ci 247962306a36Sopenharmony_ci np->np_context = NULL; 248062306a36Sopenharmony_ci kfree(isert_np); 248162306a36Sopenharmony_ci} 248262306a36Sopenharmony_ci 248362306a36Sopenharmony_cistatic void isert_release_work(struct work_struct *work) 248462306a36Sopenharmony_ci{ 248562306a36Sopenharmony_ci struct isert_conn *isert_conn = container_of(work, 248662306a36Sopenharmony_ci struct isert_conn, 248762306a36Sopenharmony_ci release_work); 248862306a36Sopenharmony_ci 248962306a36Sopenharmony_ci isert_info("Starting release conn %p\n", isert_conn); 249062306a36Sopenharmony_ci 249162306a36Sopenharmony_ci mutex_lock(&isert_conn->mutex); 249262306a36Sopenharmony_ci isert_conn->state = ISER_CONN_DOWN; 249362306a36Sopenharmony_ci mutex_unlock(&isert_conn->mutex); 249462306a36Sopenharmony_ci 249562306a36Sopenharmony_ci isert_info("Destroying conn %p\n", isert_conn); 249662306a36Sopenharmony_ci isert_put_conn(isert_conn); 249762306a36Sopenharmony_ci} 249862306a36Sopenharmony_ci 249962306a36Sopenharmony_cistatic void 250062306a36Sopenharmony_ciisert_wait4logout(struct isert_conn *isert_conn) 250162306a36Sopenharmony_ci{ 250262306a36Sopenharmony_ci struct iscsit_conn *conn = isert_conn->conn; 250362306a36Sopenharmony_ci 250462306a36Sopenharmony_ci isert_info("conn %p\n", isert_conn); 250562306a36Sopenharmony_ci 250662306a36Sopenharmony_ci if (isert_conn->logout_posted) { 250762306a36Sopenharmony_ci isert_info("conn %p wait for conn_logout_comp\n", isert_conn); 250862306a36Sopenharmony_ci wait_for_completion_timeout(&conn->conn_logout_comp, 250962306a36Sopenharmony_ci SECONDS_FOR_LOGOUT_COMP * HZ); 251062306a36Sopenharmony_ci } 251162306a36Sopenharmony_ci} 251262306a36Sopenharmony_ci 251362306a36Sopenharmony_cistatic void 251462306a36Sopenharmony_ciisert_wait4cmds(struct iscsit_conn *conn) 251562306a36Sopenharmony_ci{ 251662306a36Sopenharmony_ci isert_info("iscsit_conn %p\n", conn); 251762306a36Sopenharmony_ci 251862306a36Sopenharmony_ci if (conn->sess) { 251962306a36Sopenharmony_ci target_stop_cmd_counter(conn->cmd_cnt); 252062306a36Sopenharmony_ci target_wait_for_cmds(conn->cmd_cnt); 252162306a36Sopenharmony_ci } 252262306a36Sopenharmony_ci} 252362306a36Sopenharmony_ci 252462306a36Sopenharmony_ci/** 252562306a36Sopenharmony_ci * isert_put_unsol_pending_cmds() - Drop commands waiting for 252662306a36Sopenharmony_ci * unsolicitate dataout 252762306a36Sopenharmony_ci * @conn: iscsi connection 252862306a36Sopenharmony_ci * 252962306a36Sopenharmony_ci * We might still have commands that are waiting for unsolicited 253062306a36Sopenharmony_ci * dataouts messages. We must put the extra reference on those 253162306a36Sopenharmony_ci * before blocking on the target_wait_for_session_cmds 253262306a36Sopenharmony_ci */ 253362306a36Sopenharmony_cistatic void 253462306a36Sopenharmony_ciisert_put_unsol_pending_cmds(struct iscsit_conn *conn) 253562306a36Sopenharmony_ci{ 253662306a36Sopenharmony_ci struct iscsit_cmd *cmd, *tmp; 253762306a36Sopenharmony_ci static LIST_HEAD(drop_cmd_list); 253862306a36Sopenharmony_ci 253962306a36Sopenharmony_ci spin_lock_bh(&conn->cmd_lock); 254062306a36Sopenharmony_ci list_for_each_entry_safe(cmd, tmp, &conn->conn_cmd_list, i_conn_node) { 254162306a36Sopenharmony_ci if ((cmd->cmd_flags & ICF_NON_IMMEDIATE_UNSOLICITED_DATA) && 254262306a36Sopenharmony_ci (cmd->write_data_done < conn->sess->sess_ops->FirstBurstLength) && 254362306a36Sopenharmony_ci (cmd->write_data_done < cmd->se_cmd.data_length)) 254462306a36Sopenharmony_ci list_move_tail(&cmd->i_conn_node, &drop_cmd_list); 254562306a36Sopenharmony_ci } 254662306a36Sopenharmony_ci spin_unlock_bh(&conn->cmd_lock); 254762306a36Sopenharmony_ci 254862306a36Sopenharmony_ci list_for_each_entry_safe(cmd, tmp, &drop_cmd_list, i_conn_node) { 254962306a36Sopenharmony_ci list_del_init(&cmd->i_conn_node); 255062306a36Sopenharmony_ci if (cmd->i_state != ISTATE_REMOVE) { 255162306a36Sopenharmony_ci struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd); 255262306a36Sopenharmony_ci 255362306a36Sopenharmony_ci isert_info("conn %p dropping cmd %p\n", conn, cmd); 255462306a36Sopenharmony_ci isert_put_cmd(isert_cmd, true); 255562306a36Sopenharmony_ci } 255662306a36Sopenharmony_ci } 255762306a36Sopenharmony_ci} 255862306a36Sopenharmony_ci 255962306a36Sopenharmony_cistatic void isert_wait_conn(struct iscsit_conn *conn) 256062306a36Sopenharmony_ci{ 256162306a36Sopenharmony_ci struct isert_conn *isert_conn = conn->context; 256262306a36Sopenharmony_ci 256362306a36Sopenharmony_ci isert_info("Starting conn %p\n", isert_conn); 256462306a36Sopenharmony_ci 256562306a36Sopenharmony_ci mutex_lock(&isert_conn->mutex); 256662306a36Sopenharmony_ci isert_conn_terminate(isert_conn); 256762306a36Sopenharmony_ci mutex_unlock(&isert_conn->mutex); 256862306a36Sopenharmony_ci 256962306a36Sopenharmony_ci ib_drain_qp(isert_conn->qp); 257062306a36Sopenharmony_ci isert_put_unsol_pending_cmds(conn); 257162306a36Sopenharmony_ci isert_wait4cmds(conn); 257262306a36Sopenharmony_ci isert_wait4logout(isert_conn); 257362306a36Sopenharmony_ci 257462306a36Sopenharmony_ci queue_work(isert_release_wq, &isert_conn->release_work); 257562306a36Sopenharmony_ci} 257662306a36Sopenharmony_ci 257762306a36Sopenharmony_cistatic void isert_free_conn(struct iscsit_conn *conn) 257862306a36Sopenharmony_ci{ 257962306a36Sopenharmony_ci struct isert_conn *isert_conn = conn->context; 258062306a36Sopenharmony_ci 258162306a36Sopenharmony_ci ib_drain_qp(isert_conn->qp); 258262306a36Sopenharmony_ci isert_put_conn(isert_conn); 258362306a36Sopenharmony_ci} 258462306a36Sopenharmony_ci 258562306a36Sopenharmony_cistatic void isert_get_rx_pdu(struct iscsit_conn *conn) 258662306a36Sopenharmony_ci{ 258762306a36Sopenharmony_ci struct completion comp; 258862306a36Sopenharmony_ci 258962306a36Sopenharmony_ci init_completion(&comp); 259062306a36Sopenharmony_ci 259162306a36Sopenharmony_ci wait_for_completion_interruptible(&comp); 259262306a36Sopenharmony_ci} 259362306a36Sopenharmony_ci 259462306a36Sopenharmony_cistatic struct iscsit_transport iser_target_transport = { 259562306a36Sopenharmony_ci .name = "IB/iSER", 259662306a36Sopenharmony_ci .transport_type = ISCSI_INFINIBAND, 259762306a36Sopenharmony_ci .rdma_shutdown = true, 259862306a36Sopenharmony_ci .priv_size = sizeof(struct isert_cmd), 259962306a36Sopenharmony_ci .owner = THIS_MODULE, 260062306a36Sopenharmony_ci .iscsit_setup_np = isert_setup_np, 260162306a36Sopenharmony_ci .iscsit_accept_np = isert_accept_np, 260262306a36Sopenharmony_ci .iscsit_free_np = isert_free_np, 260362306a36Sopenharmony_ci .iscsit_wait_conn = isert_wait_conn, 260462306a36Sopenharmony_ci .iscsit_free_conn = isert_free_conn, 260562306a36Sopenharmony_ci .iscsit_get_login_rx = isert_get_login_rx, 260662306a36Sopenharmony_ci .iscsit_put_login_tx = isert_put_login_tx, 260762306a36Sopenharmony_ci .iscsit_immediate_queue = isert_immediate_queue, 260862306a36Sopenharmony_ci .iscsit_response_queue = isert_response_queue, 260962306a36Sopenharmony_ci .iscsit_get_dataout = isert_get_dataout, 261062306a36Sopenharmony_ci .iscsit_queue_data_in = isert_put_datain, 261162306a36Sopenharmony_ci .iscsit_queue_status = isert_put_response, 261262306a36Sopenharmony_ci .iscsit_aborted_task = isert_aborted_task, 261362306a36Sopenharmony_ci .iscsit_get_rx_pdu = isert_get_rx_pdu, 261462306a36Sopenharmony_ci .iscsit_get_sup_prot_ops = isert_get_sup_prot_ops, 261562306a36Sopenharmony_ci}; 261662306a36Sopenharmony_ci 261762306a36Sopenharmony_cistatic int __init isert_init(void) 261862306a36Sopenharmony_ci{ 261962306a36Sopenharmony_ci isert_login_wq = alloc_workqueue("isert_login_wq", 0, 0); 262062306a36Sopenharmony_ci if (!isert_login_wq) { 262162306a36Sopenharmony_ci isert_err("Unable to allocate isert_login_wq\n"); 262262306a36Sopenharmony_ci return -ENOMEM; 262362306a36Sopenharmony_ci } 262462306a36Sopenharmony_ci 262562306a36Sopenharmony_ci isert_comp_wq = alloc_workqueue("isert_comp_wq", 262662306a36Sopenharmony_ci WQ_UNBOUND | WQ_HIGHPRI, 0); 262762306a36Sopenharmony_ci if (!isert_comp_wq) { 262862306a36Sopenharmony_ci isert_err("Unable to allocate isert_comp_wq\n"); 262962306a36Sopenharmony_ci goto destroy_login_wq; 263062306a36Sopenharmony_ci } 263162306a36Sopenharmony_ci 263262306a36Sopenharmony_ci isert_release_wq = alloc_workqueue("isert_release_wq", WQ_UNBOUND, 263362306a36Sopenharmony_ci WQ_UNBOUND_MAX_ACTIVE); 263462306a36Sopenharmony_ci if (!isert_release_wq) { 263562306a36Sopenharmony_ci isert_err("Unable to allocate isert_release_wq\n"); 263662306a36Sopenharmony_ci goto destroy_comp_wq; 263762306a36Sopenharmony_ci } 263862306a36Sopenharmony_ci 263962306a36Sopenharmony_ci iscsit_register_transport(&iser_target_transport); 264062306a36Sopenharmony_ci isert_info("iSER_TARGET[0] - Loaded iser_target_transport\n"); 264162306a36Sopenharmony_ci 264262306a36Sopenharmony_ci return 0; 264362306a36Sopenharmony_ci 264462306a36Sopenharmony_cidestroy_comp_wq: 264562306a36Sopenharmony_ci destroy_workqueue(isert_comp_wq); 264662306a36Sopenharmony_cidestroy_login_wq: 264762306a36Sopenharmony_ci destroy_workqueue(isert_login_wq); 264862306a36Sopenharmony_ci 264962306a36Sopenharmony_ci return -ENOMEM; 265062306a36Sopenharmony_ci} 265162306a36Sopenharmony_ci 265262306a36Sopenharmony_cistatic void __exit isert_exit(void) 265362306a36Sopenharmony_ci{ 265462306a36Sopenharmony_ci flush_workqueue(isert_login_wq); 265562306a36Sopenharmony_ci destroy_workqueue(isert_release_wq); 265662306a36Sopenharmony_ci destroy_workqueue(isert_comp_wq); 265762306a36Sopenharmony_ci iscsit_unregister_transport(&iser_target_transport); 265862306a36Sopenharmony_ci isert_info("iSER_TARGET[0] - Released iser_target_transport\n"); 265962306a36Sopenharmony_ci destroy_workqueue(isert_login_wq); 266062306a36Sopenharmony_ci} 266162306a36Sopenharmony_ci 266262306a36Sopenharmony_ciMODULE_DESCRIPTION("iSER-Target for mainline target infrastructure"); 266362306a36Sopenharmony_ciMODULE_AUTHOR("nab@Linux-iSCSI.org"); 266462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 266562306a36Sopenharmony_ci 266662306a36Sopenharmony_cimodule_init(isert_init); 266762306a36Sopenharmony_cimodule_exit(isert_exit); 2668