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