18c2ecf20Sopenharmony_ci/*
28c2ecf20Sopenharmony_ci * Copyright (c) 2005 Cisco Systems.  All rights reserved.
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci * This software is available to you under a choice of one of two
58c2ecf20Sopenharmony_ci * licenses.  You may choose to be licensed under the terms of the GNU
68c2ecf20Sopenharmony_ci * General Public License (GPL) Version 2, available from the file
78c2ecf20Sopenharmony_ci * COPYING in the main directory of this source tree, or the
88c2ecf20Sopenharmony_ci * OpenIB.org BSD license below:
98c2ecf20Sopenharmony_ci *
108c2ecf20Sopenharmony_ci *     Redistribution and use in source and binary forms, with or
118c2ecf20Sopenharmony_ci *     without modification, are permitted provided that the following
128c2ecf20Sopenharmony_ci *     conditions are met:
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci *      - Redistributions of source code must retain the above
158c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
168c2ecf20Sopenharmony_ci *        disclaimer.
178c2ecf20Sopenharmony_ci *
188c2ecf20Sopenharmony_ci *      - Redistributions in binary form must reproduce the above
198c2ecf20Sopenharmony_ci *        copyright notice, this list of conditions and the following
208c2ecf20Sopenharmony_ci *        disclaimer in the documentation and/or other materials
218c2ecf20Sopenharmony_ci *        provided with the distribution.
228c2ecf20Sopenharmony_ci *
238c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
248c2ecf20Sopenharmony_ci * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
258c2ecf20Sopenharmony_ci * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
268c2ecf20Sopenharmony_ci * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
278c2ecf20Sopenharmony_ci * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
288c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
298c2ecf20Sopenharmony_ci * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
308c2ecf20Sopenharmony_ci * SOFTWARE.
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#include <linux/module.h>
368c2ecf20Sopenharmony_ci#include <linux/init.h>
378c2ecf20Sopenharmony_ci#include <linux/slab.h>
388c2ecf20Sopenharmony_ci#include <linux/err.h>
398c2ecf20Sopenharmony_ci#include <linux/string.h>
408c2ecf20Sopenharmony_ci#include <linux/parser.h>
418c2ecf20Sopenharmony_ci#include <linux/random.h>
428c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
438c2ecf20Sopenharmony_ci#include <linux/lockdep.h>
448c2ecf20Sopenharmony_ci#include <linux/inet.h>
458c2ecf20Sopenharmony_ci#include <rdma/ib_cache.h>
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_ci#include <linux/atomic.h>
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#include <scsi/scsi.h>
508c2ecf20Sopenharmony_ci#include <scsi/scsi_device.h>
518c2ecf20Sopenharmony_ci#include <scsi/scsi_dbg.h>
528c2ecf20Sopenharmony_ci#include <scsi/scsi_tcq.h>
538c2ecf20Sopenharmony_ci#include <scsi/srp.h>
548c2ecf20Sopenharmony_ci#include <scsi/scsi_transport_srp.h>
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci#include "ib_srp.h"
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci#define DRV_NAME	"ib_srp"
598c2ecf20Sopenharmony_ci#define PFX		DRV_NAME ": "
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ciMODULE_AUTHOR("Roland Dreier");
628c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("InfiniBand SCSI RDMA Protocol initiator");
638c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci#if !defined(CONFIG_DYNAMIC_DEBUG)
668c2ecf20Sopenharmony_ci#define DEFINE_DYNAMIC_DEBUG_METADATA(name, fmt)
678c2ecf20Sopenharmony_ci#define DYNAMIC_DEBUG_BRANCH(descriptor) false
688c2ecf20Sopenharmony_ci#endif
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic unsigned int srp_sg_tablesize;
718c2ecf20Sopenharmony_cistatic unsigned int cmd_sg_entries;
728c2ecf20Sopenharmony_cistatic unsigned int indirect_sg_entries;
738c2ecf20Sopenharmony_cistatic bool allow_ext_sg;
748c2ecf20Sopenharmony_cistatic bool register_always = true;
758c2ecf20Sopenharmony_cistatic bool never_register;
768c2ecf20Sopenharmony_cistatic int topspin_workarounds = 1;
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_cimodule_param(srp_sg_tablesize, uint, 0444);
798c2ecf20Sopenharmony_ciMODULE_PARM_DESC(srp_sg_tablesize, "Deprecated name for cmd_sg_entries");
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cimodule_param(cmd_sg_entries, uint, 0444);
828c2ecf20Sopenharmony_ciMODULE_PARM_DESC(cmd_sg_entries,
838c2ecf20Sopenharmony_ci		 "Default number of gather/scatter entries in the SRP command (default is 12, max 255)");
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cimodule_param(indirect_sg_entries, uint, 0444);
868c2ecf20Sopenharmony_ciMODULE_PARM_DESC(indirect_sg_entries,
878c2ecf20Sopenharmony_ci		 "Default max number of gather/scatter entries (default is 12, max is " __stringify(SG_MAX_SEGMENTS) ")");
888c2ecf20Sopenharmony_ci
898c2ecf20Sopenharmony_cimodule_param(allow_ext_sg, bool, 0444);
908c2ecf20Sopenharmony_ciMODULE_PARM_DESC(allow_ext_sg,
918c2ecf20Sopenharmony_ci		  "Default behavior when there are more than cmd_sg_entries S/G entries after mapping; fails the request when false (default false)");
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cimodule_param(topspin_workarounds, int, 0444);
948c2ecf20Sopenharmony_ciMODULE_PARM_DESC(topspin_workarounds,
958c2ecf20Sopenharmony_ci		 "Enable workarounds for Topspin/Cisco SRP target bugs if != 0");
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_cimodule_param(register_always, bool, 0444);
988c2ecf20Sopenharmony_ciMODULE_PARM_DESC(register_always,
998c2ecf20Sopenharmony_ci		 "Use memory registration even for contiguous memory regions");
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_cimodule_param(never_register, bool, 0444);
1028c2ecf20Sopenharmony_ciMODULE_PARM_DESC(never_register, "Never register memory");
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_cistatic const struct kernel_param_ops srp_tmo_ops;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistatic int srp_reconnect_delay = 10;
1078c2ecf20Sopenharmony_cimodule_param_cb(reconnect_delay, &srp_tmo_ops, &srp_reconnect_delay,
1088c2ecf20Sopenharmony_ci		S_IRUGO | S_IWUSR);
1098c2ecf20Sopenharmony_ciMODULE_PARM_DESC(reconnect_delay, "Time between successive reconnect attempts");
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic int srp_fast_io_fail_tmo = 15;
1128c2ecf20Sopenharmony_cimodule_param_cb(fast_io_fail_tmo, &srp_tmo_ops, &srp_fast_io_fail_tmo,
1138c2ecf20Sopenharmony_ci		S_IRUGO | S_IWUSR);
1148c2ecf20Sopenharmony_ciMODULE_PARM_DESC(fast_io_fail_tmo,
1158c2ecf20Sopenharmony_ci		 "Number of seconds between the observation of a transport"
1168c2ecf20Sopenharmony_ci		 " layer error and failing all I/O. \"off\" means that this"
1178c2ecf20Sopenharmony_ci		 " functionality is disabled.");
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_cistatic int srp_dev_loss_tmo = 600;
1208c2ecf20Sopenharmony_cimodule_param_cb(dev_loss_tmo, &srp_tmo_ops, &srp_dev_loss_tmo,
1218c2ecf20Sopenharmony_ci		S_IRUGO | S_IWUSR);
1228c2ecf20Sopenharmony_ciMODULE_PARM_DESC(dev_loss_tmo,
1238c2ecf20Sopenharmony_ci		 "Maximum number of seconds that the SRP transport should"
1248c2ecf20Sopenharmony_ci		 " insulate transport layer errors. After this time has been"
1258c2ecf20Sopenharmony_ci		 " exceeded the SCSI host is removed. Should be"
1268c2ecf20Sopenharmony_ci		 " between 1 and " __stringify(SCSI_DEVICE_BLOCK_MAX_TIMEOUT)
1278c2ecf20Sopenharmony_ci		 " if fast_io_fail_tmo has not been set. \"off\" means that"
1288c2ecf20Sopenharmony_ci		 " this functionality is disabled.");
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic bool srp_use_imm_data = true;
1318c2ecf20Sopenharmony_cimodule_param_named(use_imm_data, srp_use_imm_data, bool, 0644);
1328c2ecf20Sopenharmony_ciMODULE_PARM_DESC(use_imm_data,
1338c2ecf20Sopenharmony_ci		 "Whether or not to request permission to use immediate data during SRP login.");
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_cistatic unsigned int srp_max_imm_data = 8 * 1024;
1368c2ecf20Sopenharmony_cimodule_param_named(max_imm_data, srp_max_imm_data, uint, 0644);
1378c2ecf20Sopenharmony_ciMODULE_PARM_DESC(max_imm_data, "Maximum immediate data size.");
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_cistatic unsigned ch_count;
1408c2ecf20Sopenharmony_cimodule_param(ch_count, uint, 0444);
1418c2ecf20Sopenharmony_ciMODULE_PARM_DESC(ch_count,
1428c2ecf20Sopenharmony_ci		 "Number of RDMA channels to use for communication with an SRP target. Using more than one channel improves performance if the HCA supports multiple completion vectors. The default value is the minimum of four times the number of online CPU sockets and the number of completion vectors supported by the HCA.");
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_cistatic int srp_add_one(struct ib_device *device);
1458c2ecf20Sopenharmony_cistatic void srp_remove_one(struct ib_device *device, void *client_data);
1468c2ecf20Sopenharmony_cistatic void srp_rename_dev(struct ib_device *device, void *client_data);
1478c2ecf20Sopenharmony_cistatic void srp_recv_done(struct ib_cq *cq, struct ib_wc *wc);
1488c2ecf20Sopenharmony_cistatic void srp_handle_qp_err(struct ib_cq *cq, struct ib_wc *wc,
1498c2ecf20Sopenharmony_ci		const char *opname);
1508c2ecf20Sopenharmony_cistatic int srp_ib_cm_handler(struct ib_cm_id *cm_id,
1518c2ecf20Sopenharmony_ci			     const struct ib_cm_event *event);
1528c2ecf20Sopenharmony_cistatic int srp_rdma_cm_handler(struct rdma_cm_id *cm_id,
1538c2ecf20Sopenharmony_ci			       struct rdma_cm_event *event);
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_cistatic struct scsi_transport_template *ib_srp_transport_template;
1568c2ecf20Sopenharmony_cistatic struct workqueue_struct *srp_remove_wq;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_cistatic struct ib_client srp_client = {
1598c2ecf20Sopenharmony_ci	.name   = "srp",
1608c2ecf20Sopenharmony_ci	.add    = srp_add_one,
1618c2ecf20Sopenharmony_ci	.remove = srp_remove_one,
1628c2ecf20Sopenharmony_ci	.rename = srp_rename_dev
1638c2ecf20Sopenharmony_ci};
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic struct ib_sa_client srp_sa_client;
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic int srp_tmo_get(char *buffer, const struct kernel_param *kp)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	int tmo = *(int *)kp->arg;
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (tmo >= 0)
1728c2ecf20Sopenharmony_ci		return sprintf(buffer, "%d\n", tmo);
1738c2ecf20Sopenharmony_ci	else
1748c2ecf20Sopenharmony_ci		return sprintf(buffer, "off\n");
1758c2ecf20Sopenharmony_ci}
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic int srp_tmo_set(const char *val, const struct kernel_param *kp)
1788c2ecf20Sopenharmony_ci{
1798c2ecf20Sopenharmony_ci	int tmo, res;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	res = srp_parse_tmo(&tmo, val);
1828c2ecf20Sopenharmony_ci	if (res)
1838c2ecf20Sopenharmony_ci		goto out;
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_ci	if (kp->arg == &srp_reconnect_delay)
1868c2ecf20Sopenharmony_ci		res = srp_tmo_valid(tmo, srp_fast_io_fail_tmo,
1878c2ecf20Sopenharmony_ci				    srp_dev_loss_tmo);
1888c2ecf20Sopenharmony_ci	else if (kp->arg == &srp_fast_io_fail_tmo)
1898c2ecf20Sopenharmony_ci		res = srp_tmo_valid(srp_reconnect_delay, tmo, srp_dev_loss_tmo);
1908c2ecf20Sopenharmony_ci	else
1918c2ecf20Sopenharmony_ci		res = srp_tmo_valid(srp_reconnect_delay, srp_fast_io_fail_tmo,
1928c2ecf20Sopenharmony_ci				    tmo);
1938c2ecf20Sopenharmony_ci	if (res)
1948c2ecf20Sopenharmony_ci		goto out;
1958c2ecf20Sopenharmony_ci	*(int *)kp->arg = tmo;
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ciout:
1988c2ecf20Sopenharmony_ci	return res;
1998c2ecf20Sopenharmony_ci}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistatic const struct kernel_param_ops srp_tmo_ops = {
2028c2ecf20Sopenharmony_ci	.get = srp_tmo_get,
2038c2ecf20Sopenharmony_ci	.set = srp_tmo_set,
2048c2ecf20Sopenharmony_ci};
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic inline struct srp_target_port *host_to_target(struct Scsi_Host *host)
2078c2ecf20Sopenharmony_ci{
2088c2ecf20Sopenharmony_ci	return (struct srp_target_port *) host->hostdata;
2098c2ecf20Sopenharmony_ci}
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_cistatic const char *srp_target_info(struct Scsi_Host *host)
2128c2ecf20Sopenharmony_ci{
2138c2ecf20Sopenharmony_ci	return host_to_target(host)->target_name;
2148c2ecf20Sopenharmony_ci}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic int srp_target_is_topspin(struct srp_target_port *target)
2178c2ecf20Sopenharmony_ci{
2188c2ecf20Sopenharmony_ci	static const u8 topspin_oui[3] = { 0x00, 0x05, 0xad };
2198c2ecf20Sopenharmony_ci	static const u8 cisco_oui[3]   = { 0x00, 0x1b, 0x0d };
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	return topspin_workarounds &&
2228c2ecf20Sopenharmony_ci		(!memcmp(&target->ioc_guid, topspin_oui, sizeof topspin_oui) ||
2238c2ecf20Sopenharmony_ci		 !memcmp(&target->ioc_guid, cisco_oui, sizeof cisco_oui));
2248c2ecf20Sopenharmony_ci}
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_cistatic struct srp_iu *srp_alloc_iu(struct srp_host *host, size_t size,
2278c2ecf20Sopenharmony_ci				   gfp_t gfp_mask,
2288c2ecf20Sopenharmony_ci				   enum dma_data_direction direction)
2298c2ecf20Sopenharmony_ci{
2308c2ecf20Sopenharmony_ci	struct srp_iu *iu;
2318c2ecf20Sopenharmony_ci
2328c2ecf20Sopenharmony_ci	iu = kmalloc(sizeof *iu, gfp_mask);
2338c2ecf20Sopenharmony_ci	if (!iu)
2348c2ecf20Sopenharmony_ci		goto out;
2358c2ecf20Sopenharmony_ci
2368c2ecf20Sopenharmony_ci	iu->buf = kzalloc(size, gfp_mask);
2378c2ecf20Sopenharmony_ci	if (!iu->buf)
2388c2ecf20Sopenharmony_ci		goto out_free_iu;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	iu->dma = ib_dma_map_single(host->srp_dev->dev, iu->buf, size,
2418c2ecf20Sopenharmony_ci				    direction);
2428c2ecf20Sopenharmony_ci	if (ib_dma_mapping_error(host->srp_dev->dev, iu->dma))
2438c2ecf20Sopenharmony_ci		goto out_free_buf;
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_ci	iu->size      = size;
2468c2ecf20Sopenharmony_ci	iu->direction = direction;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	return iu;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ciout_free_buf:
2518c2ecf20Sopenharmony_ci	kfree(iu->buf);
2528c2ecf20Sopenharmony_ciout_free_iu:
2538c2ecf20Sopenharmony_ci	kfree(iu);
2548c2ecf20Sopenharmony_ciout:
2558c2ecf20Sopenharmony_ci	return NULL;
2568c2ecf20Sopenharmony_ci}
2578c2ecf20Sopenharmony_ci
2588c2ecf20Sopenharmony_cistatic void srp_free_iu(struct srp_host *host, struct srp_iu *iu)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	if (!iu)
2618c2ecf20Sopenharmony_ci		return;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	ib_dma_unmap_single(host->srp_dev->dev, iu->dma, iu->size,
2648c2ecf20Sopenharmony_ci			    iu->direction);
2658c2ecf20Sopenharmony_ci	kfree(iu->buf);
2668c2ecf20Sopenharmony_ci	kfree(iu);
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_cistatic void srp_qp_event(struct ib_event *event, void *context)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	pr_debug("QP event %s (%d)\n",
2728c2ecf20Sopenharmony_ci		 ib_event_msg(event->event), event->event);
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_cistatic int srp_init_ib_qp(struct srp_target_port *target,
2768c2ecf20Sopenharmony_ci			  struct ib_qp *qp)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	struct ib_qp_attr *attr;
2798c2ecf20Sopenharmony_ci	int ret;
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	attr = kmalloc(sizeof *attr, GFP_KERNEL);
2828c2ecf20Sopenharmony_ci	if (!attr)
2838c2ecf20Sopenharmony_ci		return -ENOMEM;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ci	ret = ib_find_cached_pkey(target->srp_host->srp_dev->dev,
2868c2ecf20Sopenharmony_ci				  target->srp_host->port,
2878c2ecf20Sopenharmony_ci				  be16_to_cpu(target->ib_cm.pkey),
2888c2ecf20Sopenharmony_ci				  &attr->pkey_index);
2898c2ecf20Sopenharmony_ci	if (ret)
2908c2ecf20Sopenharmony_ci		goto out;
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci	attr->qp_state        = IB_QPS_INIT;
2938c2ecf20Sopenharmony_ci	attr->qp_access_flags = (IB_ACCESS_REMOTE_READ |
2948c2ecf20Sopenharmony_ci				    IB_ACCESS_REMOTE_WRITE);
2958c2ecf20Sopenharmony_ci	attr->port_num        = target->srp_host->port;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	ret = ib_modify_qp(qp, attr,
2988c2ecf20Sopenharmony_ci			   IB_QP_STATE		|
2998c2ecf20Sopenharmony_ci			   IB_QP_PKEY_INDEX	|
3008c2ecf20Sopenharmony_ci			   IB_QP_ACCESS_FLAGS	|
3018c2ecf20Sopenharmony_ci			   IB_QP_PORT);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ciout:
3048c2ecf20Sopenharmony_ci	kfree(attr);
3058c2ecf20Sopenharmony_ci	return ret;
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_cistatic int srp_new_ib_cm_id(struct srp_rdma_ch *ch)
3098c2ecf20Sopenharmony_ci{
3108c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
3118c2ecf20Sopenharmony_ci	struct ib_cm_id *new_cm_id;
3128c2ecf20Sopenharmony_ci
3138c2ecf20Sopenharmony_ci	new_cm_id = ib_create_cm_id(target->srp_host->srp_dev->dev,
3148c2ecf20Sopenharmony_ci				    srp_ib_cm_handler, ch);
3158c2ecf20Sopenharmony_ci	if (IS_ERR(new_cm_id))
3168c2ecf20Sopenharmony_ci		return PTR_ERR(new_cm_id);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	if (ch->ib_cm.cm_id)
3198c2ecf20Sopenharmony_ci		ib_destroy_cm_id(ch->ib_cm.cm_id);
3208c2ecf20Sopenharmony_ci	ch->ib_cm.cm_id = new_cm_id;
3218c2ecf20Sopenharmony_ci	if (rdma_cap_opa_ah(target->srp_host->srp_dev->dev,
3228c2ecf20Sopenharmony_ci			    target->srp_host->port))
3238c2ecf20Sopenharmony_ci		ch->ib_cm.path.rec_type = SA_PATH_REC_TYPE_OPA;
3248c2ecf20Sopenharmony_ci	else
3258c2ecf20Sopenharmony_ci		ch->ib_cm.path.rec_type = SA_PATH_REC_TYPE_IB;
3268c2ecf20Sopenharmony_ci	ch->ib_cm.path.sgid = target->sgid;
3278c2ecf20Sopenharmony_ci	ch->ib_cm.path.dgid = target->ib_cm.orig_dgid;
3288c2ecf20Sopenharmony_ci	ch->ib_cm.path.pkey = target->ib_cm.pkey;
3298c2ecf20Sopenharmony_ci	ch->ib_cm.path.service_id = target->ib_cm.service_id;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	return 0;
3328c2ecf20Sopenharmony_ci}
3338c2ecf20Sopenharmony_ci
3348c2ecf20Sopenharmony_cistatic int srp_new_rdma_cm_id(struct srp_rdma_ch *ch)
3358c2ecf20Sopenharmony_ci{
3368c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
3378c2ecf20Sopenharmony_ci	struct rdma_cm_id *new_cm_id;
3388c2ecf20Sopenharmony_ci	int ret;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	new_cm_id = rdma_create_id(target->net, srp_rdma_cm_handler, ch,
3418c2ecf20Sopenharmony_ci				   RDMA_PS_TCP, IB_QPT_RC);
3428c2ecf20Sopenharmony_ci	if (IS_ERR(new_cm_id)) {
3438c2ecf20Sopenharmony_ci		ret = PTR_ERR(new_cm_id);
3448c2ecf20Sopenharmony_ci		new_cm_id = NULL;
3458c2ecf20Sopenharmony_ci		goto out;
3468c2ecf20Sopenharmony_ci	}
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	init_completion(&ch->done);
3498c2ecf20Sopenharmony_ci	ret = rdma_resolve_addr(new_cm_id, target->rdma_cm.src_specified ?
3508c2ecf20Sopenharmony_ci				&target->rdma_cm.src.sa : NULL,
3518c2ecf20Sopenharmony_ci				&target->rdma_cm.dst.sa,
3528c2ecf20Sopenharmony_ci				SRP_PATH_REC_TIMEOUT_MS);
3538c2ecf20Sopenharmony_ci	if (ret) {
3548c2ecf20Sopenharmony_ci		pr_err("No route available from %pISpsc to %pISpsc (%d)\n",
3558c2ecf20Sopenharmony_ci		       &target->rdma_cm.src, &target->rdma_cm.dst, ret);
3568c2ecf20Sopenharmony_ci		goto out;
3578c2ecf20Sopenharmony_ci	}
3588c2ecf20Sopenharmony_ci	ret = wait_for_completion_interruptible(&ch->done);
3598c2ecf20Sopenharmony_ci	if (ret < 0)
3608c2ecf20Sopenharmony_ci		goto out;
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	ret = ch->status;
3638c2ecf20Sopenharmony_ci	if (ret) {
3648c2ecf20Sopenharmony_ci		pr_err("Resolving address %pISpsc failed (%d)\n",
3658c2ecf20Sopenharmony_ci		       &target->rdma_cm.dst, ret);
3668c2ecf20Sopenharmony_ci		goto out;
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	swap(ch->rdma_cm.cm_id, new_cm_id);
3708c2ecf20Sopenharmony_ci
3718c2ecf20Sopenharmony_ciout:
3728c2ecf20Sopenharmony_ci	if (new_cm_id)
3738c2ecf20Sopenharmony_ci		rdma_destroy_id(new_cm_id);
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ci	return ret;
3768c2ecf20Sopenharmony_ci}
3778c2ecf20Sopenharmony_ci
3788c2ecf20Sopenharmony_cistatic int srp_new_cm_id(struct srp_rdma_ch *ch)
3798c2ecf20Sopenharmony_ci{
3808c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
3818c2ecf20Sopenharmony_ci
3828c2ecf20Sopenharmony_ci	return target->using_rdma_cm ? srp_new_rdma_cm_id(ch) :
3838c2ecf20Sopenharmony_ci		srp_new_ib_cm_id(ch);
3848c2ecf20Sopenharmony_ci}
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci/**
3878c2ecf20Sopenharmony_ci * srp_destroy_fr_pool() - free the resources owned by a pool
3888c2ecf20Sopenharmony_ci * @pool: Fast registration pool to be destroyed.
3898c2ecf20Sopenharmony_ci */
3908c2ecf20Sopenharmony_cistatic void srp_destroy_fr_pool(struct srp_fr_pool *pool)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	int i;
3938c2ecf20Sopenharmony_ci	struct srp_fr_desc *d;
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci	if (!pool)
3968c2ecf20Sopenharmony_ci		return;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	for (i = 0, d = &pool->desc[0]; i < pool->size; i++, d++) {
3998c2ecf20Sopenharmony_ci		if (d->mr)
4008c2ecf20Sopenharmony_ci			ib_dereg_mr(d->mr);
4018c2ecf20Sopenharmony_ci	}
4028c2ecf20Sopenharmony_ci	kfree(pool);
4038c2ecf20Sopenharmony_ci}
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci/**
4068c2ecf20Sopenharmony_ci * srp_create_fr_pool() - allocate and initialize a pool for fast registration
4078c2ecf20Sopenharmony_ci * @device:            IB device to allocate fast registration descriptors for.
4088c2ecf20Sopenharmony_ci * @pd:                Protection domain associated with the FR descriptors.
4098c2ecf20Sopenharmony_ci * @pool_size:         Number of descriptors to allocate.
4108c2ecf20Sopenharmony_ci * @max_page_list_len: Maximum fast registration work request page list length.
4118c2ecf20Sopenharmony_ci */
4128c2ecf20Sopenharmony_cistatic struct srp_fr_pool *srp_create_fr_pool(struct ib_device *device,
4138c2ecf20Sopenharmony_ci					      struct ib_pd *pd, int pool_size,
4148c2ecf20Sopenharmony_ci					      int max_page_list_len)
4158c2ecf20Sopenharmony_ci{
4168c2ecf20Sopenharmony_ci	struct srp_fr_pool *pool;
4178c2ecf20Sopenharmony_ci	struct srp_fr_desc *d;
4188c2ecf20Sopenharmony_ci	struct ib_mr *mr;
4198c2ecf20Sopenharmony_ci	int i, ret = -EINVAL;
4208c2ecf20Sopenharmony_ci	enum ib_mr_type mr_type;
4218c2ecf20Sopenharmony_ci
4228c2ecf20Sopenharmony_ci	if (pool_size <= 0)
4238c2ecf20Sopenharmony_ci		goto err;
4248c2ecf20Sopenharmony_ci	ret = -ENOMEM;
4258c2ecf20Sopenharmony_ci	pool = kzalloc(struct_size(pool, desc, pool_size), GFP_KERNEL);
4268c2ecf20Sopenharmony_ci	if (!pool)
4278c2ecf20Sopenharmony_ci		goto err;
4288c2ecf20Sopenharmony_ci	pool->size = pool_size;
4298c2ecf20Sopenharmony_ci	pool->max_page_list_len = max_page_list_len;
4308c2ecf20Sopenharmony_ci	spin_lock_init(&pool->lock);
4318c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&pool->free_list);
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci	if (device->attrs.device_cap_flags & IB_DEVICE_SG_GAPS_REG)
4348c2ecf20Sopenharmony_ci		mr_type = IB_MR_TYPE_SG_GAPS;
4358c2ecf20Sopenharmony_ci	else
4368c2ecf20Sopenharmony_ci		mr_type = IB_MR_TYPE_MEM_REG;
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	for (i = 0, d = &pool->desc[0]; i < pool->size; i++, d++) {
4398c2ecf20Sopenharmony_ci		mr = ib_alloc_mr(pd, mr_type, max_page_list_len);
4408c2ecf20Sopenharmony_ci		if (IS_ERR(mr)) {
4418c2ecf20Sopenharmony_ci			ret = PTR_ERR(mr);
4428c2ecf20Sopenharmony_ci			if (ret == -ENOMEM)
4438c2ecf20Sopenharmony_ci				pr_info("%s: ib_alloc_mr() failed. Try to reduce max_cmd_per_lun, max_sect or ch_count\n",
4448c2ecf20Sopenharmony_ci					dev_name(&device->dev));
4458c2ecf20Sopenharmony_ci			goto destroy_pool;
4468c2ecf20Sopenharmony_ci		}
4478c2ecf20Sopenharmony_ci		d->mr = mr;
4488c2ecf20Sopenharmony_ci		list_add_tail(&d->entry, &pool->free_list);
4498c2ecf20Sopenharmony_ci	}
4508c2ecf20Sopenharmony_ci
4518c2ecf20Sopenharmony_ciout:
4528c2ecf20Sopenharmony_ci	return pool;
4538c2ecf20Sopenharmony_ci
4548c2ecf20Sopenharmony_cidestroy_pool:
4558c2ecf20Sopenharmony_ci	srp_destroy_fr_pool(pool);
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_cierr:
4588c2ecf20Sopenharmony_ci	pool = ERR_PTR(ret);
4598c2ecf20Sopenharmony_ci	goto out;
4608c2ecf20Sopenharmony_ci}
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci/**
4638c2ecf20Sopenharmony_ci * srp_fr_pool_get() - obtain a descriptor suitable for fast registration
4648c2ecf20Sopenharmony_ci * @pool: Pool to obtain descriptor from.
4658c2ecf20Sopenharmony_ci */
4668c2ecf20Sopenharmony_cistatic struct srp_fr_desc *srp_fr_pool_get(struct srp_fr_pool *pool)
4678c2ecf20Sopenharmony_ci{
4688c2ecf20Sopenharmony_ci	struct srp_fr_desc *d = NULL;
4698c2ecf20Sopenharmony_ci	unsigned long flags;
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	spin_lock_irqsave(&pool->lock, flags);
4728c2ecf20Sopenharmony_ci	if (!list_empty(&pool->free_list)) {
4738c2ecf20Sopenharmony_ci		d = list_first_entry(&pool->free_list, typeof(*d), entry);
4748c2ecf20Sopenharmony_ci		list_del(&d->entry);
4758c2ecf20Sopenharmony_ci	}
4768c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&pool->lock, flags);
4778c2ecf20Sopenharmony_ci
4788c2ecf20Sopenharmony_ci	return d;
4798c2ecf20Sopenharmony_ci}
4808c2ecf20Sopenharmony_ci
4818c2ecf20Sopenharmony_ci/**
4828c2ecf20Sopenharmony_ci * srp_fr_pool_put() - put an FR descriptor back in the free list
4838c2ecf20Sopenharmony_ci * @pool: Pool the descriptor was allocated from.
4848c2ecf20Sopenharmony_ci * @desc: Pointer to an array of fast registration descriptor pointers.
4858c2ecf20Sopenharmony_ci * @n:    Number of descriptors to put back.
4868c2ecf20Sopenharmony_ci *
4878c2ecf20Sopenharmony_ci * Note: The caller must already have queued an invalidation request for
4888c2ecf20Sopenharmony_ci * desc->mr->rkey before calling this function.
4898c2ecf20Sopenharmony_ci */
4908c2ecf20Sopenharmony_cistatic void srp_fr_pool_put(struct srp_fr_pool *pool, struct srp_fr_desc **desc,
4918c2ecf20Sopenharmony_ci			    int n)
4928c2ecf20Sopenharmony_ci{
4938c2ecf20Sopenharmony_ci	unsigned long flags;
4948c2ecf20Sopenharmony_ci	int i;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	spin_lock_irqsave(&pool->lock, flags);
4978c2ecf20Sopenharmony_ci	for (i = 0; i < n; i++)
4988c2ecf20Sopenharmony_ci		list_add(&desc[i]->entry, &pool->free_list);
4998c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&pool->lock, flags);
5008c2ecf20Sopenharmony_ci}
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_cistatic struct srp_fr_pool *srp_alloc_fr_pool(struct srp_target_port *target)
5038c2ecf20Sopenharmony_ci{
5048c2ecf20Sopenharmony_ci	struct srp_device *dev = target->srp_host->srp_dev;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	return srp_create_fr_pool(dev->dev, dev->pd, target->mr_pool_size,
5078c2ecf20Sopenharmony_ci				  dev->max_pages_per_mr);
5088c2ecf20Sopenharmony_ci}
5098c2ecf20Sopenharmony_ci
5108c2ecf20Sopenharmony_ci/**
5118c2ecf20Sopenharmony_ci * srp_destroy_qp() - destroy an RDMA queue pair
5128c2ecf20Sopenharmony_ci * @ch: SRP RDMA channel.
5138c2ecf20Sopenharmony_ci *
5148c2ecf20Sopenharmony_ci * Drain the qp before destroying it.  This avoids that the receive
5158c2ecf20Sopenharmony_ci * completion handler can access the queue pair while it is
5168c2ecf20Sopenharmony_ci * being destroyed.
5178c2ecf20Sopenharmony_ci */
5188c2ecf20Sopenharmony_cistatic void srp_destroy_qp(struct srp_rdma_ch *ch)
5198c2ecf20Sopenharmony_ci{
5208c2ecf20Sopenharmony_ci	spin_lock_irq(&ch->lock);
5218c2ecf20Sopenharmony_ci	ib_process_cq_direct(ch->send_cq, -1);
5228c2ecf20Sopenharmony_ci	spin_unlock_irq(&ch->lock);
5238c2ecf20Sopenharmony_ci
5248c2ecf20Sopenharmony_ci	ib_drain_qp(ch->qp);
5258c2ecf20Sopenharmony_ci	ib_destroy_qp(ch->qp);
5268c2ecf20Sopenharmony_ci}
5278c2ecf20Sopenharmony_ci
5288c2ecf20Sopenharmony_cistatic int srp_create_ch_ib(struct srp_rdma_ch *ch)
5298c2ecf20Sopenharmony_ci{
5308c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
5318c2ecf20Sopenharmony_ci	struct srp_device *dev = target->srp_host->srp_dev;
5328c2ecf20Sopenharmony_ci	const struct ib_device_attr *attr = &dev->dev->attrs;
5338c2ecf20Sopenharmony_ci	struct ib_qp_init_attr *init_attr;
5348c2ecf20Sopenharmony_ci	struct ib_cq *recv_cq, *send_cq;
5358c2ecf20Sopenharmony_ci	struct ib_qp *qp;
5368c2ecf20Sopenharmony_ci	struct srp_fr_pool *fr_pool = NULL;
5378c2ecf20Sopenharmony_ci	const int m = 1 + dev->use_fast_reg * target->mr_per_cmd * 2;
5388c2ecf20Sopenharmony_ci	int ret;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	init_attr = kzalloc(sizeof *init_attr, GFP_KERNEL);
5418c2ecf20Sopenharmony_ci	if (!init_attr)
5428c2ecf20Sopenharmony_ci		return -ENOMEM;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	/* queue_size + 1 for ib_drain_rq() */
5458c2ecf20Sopenharmony_ci	recv_cq = ib_alloc_cq(dev->dev, ch, target->queue_size + 1,
5468c2ecf20Sopenharmony_ci				ch->comp_vector, IB_POLL_SOFTIRQ);
5478c2ecf20Sopenharmony_ci	if (IS_ERR(recv_cq)) {
5488c2ecf20Sopenharmony_ci		ret = PTR_ERR(recv_cq);
5498c2ecf20Sopenharmony_ci		goto err;
5508c2ecf20Sopenharmony_ci	}
5518c2ecf20Sopenharmony_ci
5528c2ecf20Sopenharmony_ci	send_cq = ib_alloc_cq(dev->dev, ch, m * target->queue_size,
5538c2ecf20Sopenharmony_ci				ch->comp_vector, IB_POLL_DIRECT);
5548c2ecf20Sopenharmony_ci	if (IS_ERR(send_cq)) {
5558c2ecf20Sopenharmony_ci		ret = PTR_ERR(send_cq);
5568c2ecf20Sopenharmony_ci		goto err_recv_cq;
5578c2ecf20Sopenharmony_ci	}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_ci	init_attr->event_handler       = srp_qp_event;
5608c2ecf20Sopenharmony_ci	init_attr->cap.max_send_wr     = m * target->queue_size;
5618c2ecf20Sopenharmony_ci	init_attr->cap.max_recv_wr     = target->queue_size + 1;
5628c2ecf20Sopenharmony_ci	init_attr->cap.max_recv_sge    = 1;
5638c2ecf20Sopenharmony_ci	init_attr->cap.max_send_sge    = min(SRP_MAX_SGE, attr->max_send_sge);
5648c2ecf20Sopenharmony_ci	init_attr->sq_sig_type         = IB_SIGNAL_REQ_WR;
5658c2ecf20Sopenharmony_ci	init_attr->qp_type             = IB_QPT_RC;
5668c2ecf20Sopenharmony_ci	init_attr->send_cq             = send_cq;
5678c2ecf20Sopenharmony_ci	init_attr->recv_cq             = recv_cq;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ci	ch->max_imm_sge = min(init_attr->cap.max_send_sge - 1U, 255U);
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_ci	if (target->using_rdma_cm) {
5728c2ecf20Sopenharmony_ci		ret = rdma_create_qp(ch->rdma_cm.cm_id, dev->pd, init_attr);
5738c2ecf20Sopenharmony_ci		qp = ch->rdma_cm.cm_id->qp;
5748c2ecf20Sopenharmony_ci	} else {
5758c2ecf20Sopenharmony_ci		qp = ib_create_qp(dev->pd, init_attr);
5768c2ecf20Sopenharmony_ci		if (!IS_ERR(qp)) {
5778c2ecf20Sopenharmony_ci			ret = srp_init_ib_qp(target, qp);
5788c2ecf20Sopenharmony_ci			if (ret)
5798c2ecf20Sopenharmony_ci				ib_destroy_qp(qp);
5808c2ecf20Sopenharmony_ci		} else {
5818c2ecf20Sopenharmony_ci			ret = PTR_ERR(qp);
5828c2ecf20Sopenharmony_ci		}
5838c2ecf20Sopenharmony_ci	}
5848c2ecf20Sopenharmony_ci	if (ret) {
5858c2ecf20Sopenharmony_ci		pr_err("QP creation failed for dev %s: %d\n",
5868c2ecf20Sopenharmony_ci		       dev_name(&dev->dev->dev), ret);
5878c2ecf20Sopenharmony_ci		goto err_send_cq;
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	if (dev->use_fast_reg) {
5918c2ecf20Sopenharmony_ci		fr_pool = srp_alloc_fr_pool(target);
5928c2ecf20Sopenharmony_ci		if (IS_ERR(fr_pool)) {
5938c2ecf20Sopenharmony_ci			ret = PTR_ERR(fr_pool);
5948c2ecf20Sopenharmony_ci			shost_printk(KERN_WARNING, target->scsi_host, PFX
5958c2ecf20Sopenharmony_ci				     "FR pool allocation failed (%d)\n", ret);
5968c2ecf20Sopenharmony_ci			goto err_qp;
5978c2ecf20Sopenharmony_ci		}
5988c2ecf20Sopenharmony_ci	}
5998c2ecf20Sopenharmony_ci
6008c2ecf20Sopenharmony_ci	if (ch->qp)
6018c2ecf20Sopenharmony_ci		srp_destroy_qp(ch);
6028c2ecf20Sopenharmony_ci	if (ch->recv_cq)
6038c2ecf20Sopenharmony_ci		ib_free_cq(ch->recv_cq);
6048c2ecf20Sopenharmony_ci	if (ch->send_cq)
6058c2ecf20Sopenharmony_ci		ib_free_cq(ch->send_cq);
6068c2ecf20Sopenharmony_ci
6078c2ecf20Sopenharmony_ci	ch->qp = qp;
6088c2ecf20Sopenharmony_ci	ch->recv_cq = recv_cq;
6098c2ecf20Sopenharmony_ci	ch->send_cq = send_cq;
6108c2ecf20Sopenharmony_ci
6118c2ecf20Sopenharmony_ci	if (dev->use_fast_reg) {
6128c2ecf20Sopenharmony_ci		if (ch->fr_pool)
6138c2ecf20Sopenharmony_ci			srp_destroy_fr_pool(ch->fr_pool);
6148c2ecf20Sopenharmony_ci		ch->fr_pool = fr_pool;
6158c2ecf20Sopenharmony_ci	}
6168c2ecf20Sopenharmony_ci
6178c2ecf20Sopenharmony_ci	kfree(init_attr);
6188c2ecf20Sopenharmony_ci	return 0;
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_cierr_qp:
6218c2ecf20Sopenharmony_ci	if (target->using_rdma_cm)
6228c2ecf20Sopenharmony_ci		rdma_destroy_qp(ch->rdma_cm.cm_id);
6238c2ecf20Sopenharmony_ci	else
6248c2ecf20Sopenharmony_ci		ib_destroy_qp(qp);
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_cierr_send_cq:
6278c2ecf20Sopenharmony_ci	ib_free_cq(send_cq);
6288c2ecf20Sopenharmony_ci
6298c2ecf20Sopenharmony_cierr_recv_cq:
6308c2ecf20Sopenharmony_ci	ib_free_cq(recv_cq);
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_cierr:
6338c2ecf20Sopenharmony_ci	kfree(init_attr);
6348c2ecf20Sopenharmony_ci	return ret;
6358c2ecf20Sopenharmony_ci}
6368c2ecf20Sopenharmony_ci
6378c2ecf20Sopenharmony_ci/*
6388c2ecf20Sopenharmony_ci * Note: this function may be called without srp_alloc_iu_bufs() having been
6398c2ecf20Sopenharmony_ci * invoked. Hence the ch->[rt]x_ring checks.
6408c2ecf20Sopenharmony_ci */
6418c2ecf20Sopenharmony_cistatic void srp_free_ch_ib(struct srp_target_port *target,
6428c2ecf20Sopenharmony_ci			   struct srp_rdma_ch *ch)
6438c2ecf20Sopenharmony_ci{
6448c2ecf20Sopenharmony_ci	struct srp_device *dev = target->srp_host->srp_dev;
6458c2ecf20Sopenharmony_ci	int i;
6468c2ecf20Sopenharmony_ci
6478c2ecf20Sopenharmony_ci	if (!ch->target)
6488c2ecf20Sopenharmony_ci		return;
6498c2ecf20Sopenharmony_ci
6508c2ecf20Sopenharmony_ci	if (target->using_rdma_cm) {
6518c2ecf20Sopenharmony_ci		if (ch->rdma_cm.cm_id) {
6528c2ecf20Sopenharmony_ci			rdma_destroy_id(ch->rdma_cm.cm_id);
6538c2ecf20Sopenharmony_ci			ch->rdma_cm.cm_id = NULL;
6548c2ecf20Sopenharmony_ci		}
6558c2ecf20Sopenharmony_ci	} else {
6568c2ecf20Sopenharmony_ci		if (ch->ib_cm.cm_id) {
6578c2ecf20Sopenharmony_ci			ib_destroy_cm_id(ch->ib_cm.cm_id);
6588c2ecf20Sopenharmony_ci			ch->ib_cm.cm_id = NULL;
6598c2ecf20Sopenharmony_ci		}
6608c2ecf20Sopenharmony_ci	}
6618c2ecf20Sopenharmony_ci
6628c2ecf20Sopenharmony_ci	/* If srp_new_cm_id() succeeded but srp_create_ch_ib() not, return. */
6638c2ecf20Sopenharmony_ci	if (!ch->qp)
6648c2ecf20Sopenharmony_ci		return;
6658c2ecf20Sopenharmony_ci
6668c2ecf20Sopenharmony_ci	if (dev->use_fast_reg) {
6678c2ecf20Sopenharmony_ci		if (ch->fr_pool)
6688c2ecf20Sopenharmony_ci			srp_destroy_fr_pool(ch->fr_pool);
6698c2ecf20Sopenharmony_ci	}
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_ci	srp_destroy_qp(ch);
6728c2ecf20Sopenharmony_ci	ib_free_cq(ch->send_cq);
6738c2ecf20Sopenharmony_ci	ib_free_cq(ch->recv_cq);
6748c2ecf20Sopenharmony_ci
6758c2ecf20Sopenharmony_ci	/*
6768c2ecf20Sopenharmony_ci	 * Avoid that the SCSI error handler tries to use this channel after
6778c2ecf20Sopenharmony_ci	 * it has been freed. The SCSI error handler can namely continue
6788c2ecf20Sopenharmony_ci	 * trying to perform recovery actions after scsi_remove_host()
6798c2ecf20Sopenharmony_ci	 * returned.
6808c2ecf20Sopenharmony_ci	 */
6818c2ecf20Sopenharmony_ci	ch->target = NULL;
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci	ch->qp = NULL;
6848c2ecf20Sopenharmony_ci	ch->send_cq = ch->recv_cq = NULL;
6858c2ecf20Sopenharmony_ci
6868c2ecf20Sopenharmony_ci	if (ch->rx_ring) {
6878c2ecf20Sopenharmony_ci		for (i = 0; i < target->queue_size; ++i)
6888c2ecf20Sopenharmony_ci			srp_free_iu(target->srp_host, ch->rx_ring[i]);
6898c2ecf20Sopenharmony_ci		kfree(ch->rx_ring);
6908c2ecf20Sopenharmony_ci		ch->rx_ring = NULL;
6918c2ecf20Sopenharmony_ci	}
6928c2ecf20Sopenharmony_ci	if (ch->tx_ring) {
6938c2ecf20Sopenharmony_ci		for (i = 0; i < target->queue_size; ++i)
6948c2ecf20Sopenharmony_ci			srp_free_iu(target->srp_host, ch->tx_ring[i]);
6958c2ecf20Sopenharmony_ci		kfree(ch->tx_ring);
6968c2ecf20Sopenharmony_ci		ch->tx_ring = NULL;
6978c2ecf20Sopenharmony_ci	}
6988c2ecf20Sopenharmony_ci}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_cistatic void srp_path_rec_completion(int status,
7018c2ecf20Sopenharmony_ci				    struct sa_path_rec *pathrec,
7028c2ecf20Sopenharmony_ci				    void *ch_ptr)
7038c2ecf20Sopenharmony_ci{
7048c2ecf20Sopenharmony_ci	struct srp_rdma_ch *ch = ch_ptr;
7058c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
7068c2ecf20Sopenharmony_ci
7078c2ecf20Sopenharmony_ci	ch->status = status;
7088c2ecf20Sopenharmony_ci	if (status)
7098c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, target->scsi_host,
7108c2ecf20Sopenharmony_ci			     PFX "Got failed path rec status %d\n", status);
7118c2ecf20Sopenharmony_ci	else
7128c2ecf20Sopenharmony_ci		ch->ib_cm.path = *pathrec;
7138c2ecf20Sopenharmony_ci	complete(&ch->done);
7148c2ecf20Sopenharmony_ci}
7158c2ecf20Sopenharmony_ci
7168c2ecf20Sopenharmony_cistatic int srp_ib_lookup_path(struct srp_rdma_ch *ch)
7178c2ecf20Sopenharmony_ci{
7188c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
7198c2ecf20Sopenharmony_ci	int ret;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	ch->ib_cm.path.numb_path = 1;
7228c2ecf20Sopenharmony_ci
7238c2ecf20Sopenharmony_ci	init_completion(&ch->done);
7248c2ecf20Sopenharmony_ci
7258c2ecf20Sopenharmony_ci	ch->ib_cm.path_query_id = ib_sa_path_rec_get(&srp_sa_client,
7268c2ecf20Sopenharmony_ci					       target->srp_host->srp_dev->dev,
7278c2ecf20Sopenharmony_ci					       target->srp_host->port,
7288c2ecf20Sopenharmony_ci					       &ch->ib_cm.path,
7298c2ecf20Sopenharmony_ci					       IB_SA_PATH_REC_SERVICE_ID |
7308c2ecf20Sopenharmony_ci					       IB_SA_PATH_REC_DGID	 |
7318c2ecf20Sopenharmony_ci					       IB_SA_PATH_REC_SGID	 |
7328c2ecf20Sopenharmony_ci					       IB_SA_PATH_REC_NUMB_PATH	 |
7338c2ecf20Sopenharmony_ci					       IB_SA_PATH_REC_PKEY,
7348c2ecf20Sopenharmony_ci					       SRP_PATH_REC_TIMEOUT_MS,
7358c2ecf20Sopenharmony_ci					       GFP_KERNEL,
7368c2ecf20Sopenharmony_ci					       srp_path_rec_completion,
7378c2ecf20Sopenharmony_ci					       ch, &ch->ib_cm.path_query);
7388c2ecf20Sopenharmony_ci	if (ch->ib_cm.path_query_id < 0)
7398c2ecf20Sopenharmony_ci		return ch->ib_cm.path_query_id;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci	ret = wait_for_completion_interruptible(&ch->done);
7428c2ecf20Sopenharmony_ci	if (ret < 0)
7438c2ecf20Sopenharmony_ci		return ret;
7448c2ecf20Sopenharmony_ci
7458c2ecf20Sopenharmony_ci	if (ch->status < 0)
7468c2ecf20Sopenharmony_ci		shost_printk(KERN_WARNING, target->scsi_host,
7478c2ecf20Sopenharmony_ci			     PFX "Path record query failed: sgid %pI6, dgid %pI6, pkey %#04x, service_id %#16llx\n",
7488c2ecf20Sopenharmony_ci			     ch->ib_cm.path.sgid.raw, ch->ib_cm.path.dgid.raw,
7498c2ecf20Sopenharmony_ci			     be16_to_cpu(target->ib_cm.pkey),
7508c2ecf20Sopenharmony_ci			     be64_to_cpu(target->ib_cm.service_id));
7518c2ecf20Sopenharmony_ci
7528c2ecf20Sopenharmony_ci	return ch->status;
7538c2ecf20Sopenharmony_ci}
7548c2ecf20Sopenharmony_ci
7558c2ecf20Sopenharmony_cistatic int srp_rdma_lookup_path(struct srp_rdma_ch *ch)
7568c2ecf20Sopenharmony_ci{
7578c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
7588c2ecf20Sopenharmony_ci	int ret;
7598c2ecf20Sopenharmony_ci
7608c2ecf20Sopenharmony_ci	init_completion(&ch->done);
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	ret = rdma_resolve_route(ch->rdma_cm.cm_id, SRP_PATH_REC_TIMEOUT_MS);
7638c2ecf20Sopenharmony_ci	if (ret)
7648c2ecf20Sopenharmony_ci		return ret;
7658c2ecf20Sopenharmony_ci
7668c2ecf20Sopenharmony_ci	wait_for_completion_interruptible(&ch->done);
7678c2ecf20Sopenharmony_ci
7688c2ecf20Sopenharmony_ci	if (ch->status != 0)
7698c2ecf20Sopenharmony_ci		shost_printk(KERN_WARNING, target->scsi_host,
7708c2ecf20Sopenharmony_ci			     PFX "Path resolution failed\n");
7718c2ecf20Sopenharmony_ci
7728c2ecf20Sopenharmony_ci	return ch->status;
7738c2ecf20Sopenharmony_ci}
7748c2ecf20Sopenharmony_ci
7758c2ecf20Sopenharmony_cistatic int srp_lookup_path(struct srp_rdma_ch *ch)
7768c2ecf20Sopenharmony_ci{
7778c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
7788c2ecf20Sopenharmony_ci
7798c2ecf20Sopenharmony_ci	return target->using_rdma_cm ? srp_rdma_lookup_path(ch) :
7808c2ecf20Sopenharmony_ci		srp_ib_lookup_path(ch);
7818c2ecf20Sopenharmony_ci}
7828c2ecf20Sopenharmony_ci
7838c2ecf20Sopenharmony_cistatic u8 srp_get_subnet_timeout(struct srp_host *host)
7848c2ecf20Sopenharmony_ci{
7858c2ecf20Sopenharmony_ci	struct ib_port_attr attr;
7868c2ecf20Sopenharmony_ci	int ret;
7878c2ecf20Sopenharmony_ci	u8 subnet_timeout = 18;
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_ci	ret = ib_query_port(host->srp_dev->dev, host->port, &attr);
7908c2ecf20Sopenharmony_ci	if (ret == 0)
7918c2ecf20Sopenharmony_ci		subnet_timeout = attr.subnet_timeout;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	if (unlikely(subnet_timeout < 15))
7948c2ecf20Sopenharmony_ci		pr_warn("%s: subnet timeout %d may cause SRP login to fail.\n",
7958c2ecf20Sopenharmony_ci			dev_name(&host->srp_dev->dev->dev), subnet_timeout);
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	return subnet_timeout;
7988c2ecf20Sopenharmony_ci}
7998c2ecf20Sopenharmony_ci
8008c2ecf20Sopenharmony_cistatic int srp_send_req(struct srp_rdma_ch *ch, uint32_t max_iu_len,
8018c2ecf20Sopenharmony_ci			bool multich)
8028c2ecf20Sopenharmony_ci{
8038c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
8048c2ecf20Sopenharmony_ci	struct {
8058c2ecf20Sopenharmony_ci		struct rdma_conn_param	  rdma_param;
8068c2ecf20Sopenharmony_ci		struct srp_login_req_rdma rdma_req;
8078c2ecf20Sopenharmony_ci		struct ib_cm_req_param	  ib_param;
8088c2ecf20Sopenharmony_ci		struct srp_login_req	  ib_req;
8098c2ecf20Sopenharmony_ci	} *req = NULL;
8108c2ecf20Sopenharmony_ci	char *ipi, *tpi;
8118c2ecf20Sopenharmony_ci	int status;
8128c2ecf20Sopenharmony_ci
8138c2ecf20Sopenharmony_ci	req = kzalloc(sizeof *req, GFP_KERNEL);
8148c2ecf20Sopenharmony_ci	if (!req)
8158c2ecf20Sopenharmony_ci		return -ENOMEM;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci	req->ib_param.flow_control = 1;
8188c2ecf20Sopenharmony_ci	req->ib_param.retry_count = target->tl_retry_count;
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_ci	/*
8218c2ecf20Sopenharmony_ci	 * Pick some arbitrary defaults here; we could make these
8228c2ecf20Sopenharmony_ci	 * module parameters if anyone cared about setting them.
8238c2ecf20Sopenharmony_ci	 */
8248c2ecf20Sopenharmony_ci	req->ib_param.responder_resources = 4;
8258c2ecf20Sopenharmony_ci	req->ib_param.rnr_retry_count = 7;
8268c2ecf20Sopenharmony_ci	req->ib_param.max_cm_retries = 15;
8278c2ecf20Sopenharmony_ci
8288c2ecf20Sopenharmony_ci	req->ib_req.opcode = SRP_LOGIN_REQ;
8298c2ecf20Sopenharmony_ci	req->ib_req.tag = 0;
8308c2ecf20Sopenharmony_ci	req->ib_req.req_it_iu_len = cpu_to_be32(max_iu_len);
8318c2ecf20Sopenharmony_ci	req->ib_req.req_buf_fmt	= cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
8328c2ecf20Sopenharmony_ci					      SRP_BUF_FORMAT_INDIRECT);
8338c2ecf20Sopenharmony_ci	req->ib_req.req_flags = (multich ? SRP_MULTICHAN_MULTI :
8348c2ecf20Sopenharmony_ci				 SRP_MULTICHAN_SINGLE);
8358c2ecf20Sopenharmony_ci	if (srp_use_imm_data) {
8368c2ecf20Sopenharmony_ci		req->ib_req.req_flags |= SRP_IMMED_REQUESTED;
8378c2ecf20Sopenharmony_ci		req->ib_req.imm_data_offset = cpu_to_be16(SRP_IMM_DATA_OFFSET);
8388c2ecf20Sopenharmony_ci	}
8398c2ecf20Sopenharmony_ci
8408c2ecf20Sopenharmony_ci	if (target->using_rdma_cm) {
8418c2ecf20Sopenharmony_ci		req->rdma_param.flow_control = req->ib_param.flow_control;
8428c2ecf20Sopenharmony_ci		req->rdma_param.responder_resources =
8438c2ecf20Sopenharmony_ci			req->ib_param.responder_resources;
8448c2ecf20Sopenharmony_ci		req->rdma_param.initiator_depth = req->ib_param.initiator_depth;
8458c2ecf20Sopenharmony_ci		req->rdma_param.retry_count = req->ib_param.retry_count;
8468c2ecf20Sopenharmony_ci		req->rdma_param.rnr_retry_count = req->ib_param.rnr_retry_count;
8478c2ecf20Sopenharmony_ci		req->rdma_param.private_data = &req->rdma_req;
8488c2ecf20Sopenharmony_ci		req->rdma_param.private_data_len = sizeof(req->rdma_req);
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci		req->rdma_req.opcode = req->ib_req.opcode;
8518c2ecf20Sopenharmony_ci		req->rdma_req.tag = req->ib_req.tag;
8528c2ecf20Sopenharmony_ci		req->rdma_req.req_it_iu_len = req->ib_req.req_it_iu_len;
8538c2ecf20Sopenharmony_ci		req->rdma_req.req_buf_fmt = req->ib_req.req_buf_fmt;
8548c2ecf20Sopenharmony_ci		req->rdma_req.req_flags	= req->ib_req.req_flags;
8558c2ecf20Sopenharmony_ci		req->rdma_req.imm_data_offset = req->ib_req.imm_data_offset;
8568c2ecf20Sopenharmony_ci
8578c2ecf20Sopenharmony_ci		ipi = req->rdma_req.initiator_port_id;
8588c2ecf20Sopenharmony_ci		tpi = req->rdma_req.target_port_id;
8598c2ecf20Sopenharmony_ci	} else {
8608c2ecf20Sopenharmony_ci		u8 subnet_timeout;
8618c2ecf20Sopenharmony_ci
8628c2ecf20Sopenharmony_ci		subnet_timeout = srp_get_subnet_timeout(target->srp_host);
8638c2ecf20Sopenharmony_ci
8648c2ecf20Sopenharmony_ci		req->ib_param.primary_path = &ch->ib_cm.path;
8658c2ecf20Sopenharmony_ci		req->ib_param.alternate_path = NULL;
8668c2ecf20Sopenharmony_ci		req->ib_param.service_id = target->ib_cm.service_id;
8678c2ecf20Sopenharmony_ci		get_random_bytes(&req->ib_param.starting_psn, 4);
8688c2ecf20Sopenharmony_ci		req->ib_param.starting_psn &= 0xffffff;
8698c2ecf20Sopenharmony_ci		req->ib_param.qp_num = ch->qp->qp_num;
8708c2ecf20Sopenharmony_ci		req->ib_param.qp_type = ch->qp->qp_type;
8718c2ecf20Sopenharmony_ci		req->ib_param.local_cm_response_timeout = subnet_timeout + 2;
8728c2ecf20Sopenharmony_ci		req->ib_param.remote_cm_response_timeout = subnet_timeout + 2;
8738c2ecf20Sopenharmony_ci		req->ib_param.private_data = &req->ib_req;
8748c2ecf20Sopenharmony_ci		req->ib_param.private_data_len = sizeof(req->ib_req);
8758c2ecf20Sopenharmony_ci
8768c2ecf20Sopenharmony_ci		ipi = req->ib_req.initiator_port_id;
8778c2ecf20Sopenharmony_ci		tpi = req->ib_req.target_port_id;
8788c2ecf20Sopenharmony_ci	}
8798c2ecf20Sopenharmony_ci
8808c2ecf20Sopenharmony_ci	/*
8818c2ecf20Sopenharmony_ci	 * In the published SRP specification (draft rev. 16a), the
8828c2ecf20Sopenharmony_ci	 * port identifier format is 8 bytes of ID extension followed
8838c2ecf20Sopenharmony_ci	 * by 8 bytes of GUID.  Older drafts put the two halves in the
8848c2ecf20Sopenharmony_ci	 * opposite order, so that the GUID comes first.
8858c2ecf20Sopenharmony_ci	 *
8868c2ecf20Sopenharmony_ci	 * Targets conforming to these obsolete drafts can be
8878c2ecf20Sopenharmony_ci	 * recognized by the I/O Class they report.
8888c2ecf20Sopenharmony_ci	 */
8898c2ecf20Sopenharmony_ci	if (target->io_class == SRP_REV10_IB_IO_CLASS) {
8908c2ecf20Sopenharmony_ci		memcpy(ipi,     &target->sgid.global.interface_id, 8);
8918c2ecf20Sopenharmony_ci		memcpy(ipi + 8, &target->initiator_ext, 8);
8928c2ecf20Sopenharmony_ci		memcpy(tpi,     &target->ioc_guid, 8);
8938c2ecf20Sopenharmony_ci		memcpy(tpi + 8, &target->id_ext, 8);
8948c2ecf20Sopenharmony_ci	} else {
8958c2ecf20Sopenharmony_ci		memcpy(ipi,     &target->initiator_ext, 8);
8968c2ecf20Sopenharmony_ci		memcpy(ipi + 8, &target->sgid.global.interface_id, 8);
8978c2ecf20Sopenharmony_ci		memcpy(tpi,     &target->id_ext, 8);
8988c2ecf20Sopenharmony_ci		memcpy(tpi + 8, &target->ioc_guid, 8);
8998c2ecf20Sopenharmony_ci	}
9008c2ecf20Sopenharmony_ci
9018c2ecf20Sopenharmony_ci	/*
9028c2ecf20Sopenharmony_ci	 * Topspin/Cisco SRP targets will reject our login unless we
9038c2ecf20Sopenharmony_ci	 * zero out the first 8 bytes of our initiator port ID and set
9048c2ecf20Sopenharmony_ci	 * the second 8 bytes to the local node GUID.
9058c2ecf20Sopenharmony_ci	 */
9068c2ecf20Sopenharmony_ci	if (srp_target_is_topspin(target)) {
9078c2ecf20Sopenharmony_ci		shost_printk(KERN_DEBUG, target->scsi_host,
9088c2ecf20Sopenharmony_ci			     PFX "Topspin/Cisco initiator port ID workaround "
9098c2ecf20Sopenharmony_ci			     "activated for target GUID %016llx\n",
9108c2ecf20Sopenharmony_ci			     be64_to_cpu(target->ioc_guid));
9118c2ecf20Sopenharmony_ci		memset(ipi, 0, 8);
9128c2ecf20Sopenharmony_ci		memcpy(ipi + 8, &target->srp_host->srp_dev->dev->node_guid, 8);
9138c2ecf20Sopenharmony_ci	}
9148c2ecf20Sopenharmony_ci
9158c2ecf20Sopenharmony_ci	if (target->using_rdma_cm)
9168c2ecf20Sopenharmony_ci		status = rdma_connect(ch->rdma_cm.cm_id, &req->rdma_param);
9178c2ecf20Sopenharmony_ci	else
9188c2ecf20Sopenharmony_ci		status = ib_send_cm_req(ch->ib_cm.cm_id, &req->ib_param);
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	kfree(req);
9218c2ecf20Sopenharmony_ci
9228c2ecf20Sopenharmony_ci	return status;
9238c2ecf20Sopenharmony_ci}
9248c2ecf20Sopenharmony_ci
9258c2ecf20Sopenharmony_cistatic bool srp_queue_remove_work(struct srp_target_port *target)
9268c2ecf20Sopenharmony_ci{
9278c2ecf20Sopenharmony_ci	bool changed = false;
9288c2ecf20Sopenharmony_ci
9298c2ecf20Sopenharmony_ci	spin_lock_irq(&target->lock);
9308c2ecf20Sopenharmony_ci	if (target->state != SRP_TARGET_REMOVED) {
9318c2ecf20Sopenharmony_ci		target->state = SRP_TARGET_REMOVED;
9328c2ecf20Sopenharmony_ci		changed = true;
9338c2ecf20Sopenharmony_ci	}
9348c2ecf20Sopenharmony_ci	spin_unlock_irq(&target->lock);
9358c2ecf20Sopenharmony_ci
9368c2ecf20Sopenharmony_ci	if (changed)
9378c2ecf20Sopenharmony_ci		queue_work(srp_remove_wq, &target->remove_work);
9388c2ecf20Sopenharmony_ci
9398c2ecf20Sopenharmony_ci	return changed;
9408c2ecf20Sopenharmony_ci}
9418c2ecf20Sopenharmony_ci
9428c2ecf20Sopenharmony_cistatic void srp_disconnect_target(struct srp_target_port *target)
9438c2ecf20Sopenharmony_ci{
9448c2ecf20Sopenharmony_ci	struct srp_rdma_ch *ch;
9458c2ecf20Sopenharmony_ci	int i, ret;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	/* XXX should send SRP_I_LOGOUT request */
9488c2ecf20Sopenharmony_ci
9498c2ecf20Sopenharmony_ci	for (i = 0; i < target->ch_count; i++) {
9508c2ecf20Sopenharmony_ci		ch = &target->ch[i];
9518c2ecf20Sopenharmony_ci		ch->connected = false;
9528c2ecf20Sopenharmony_ci		ret = 0;
9538c2ecf20Sopenharmony_ci		if (target->using_rdma_cm) {
9548c2ecf20Sopenharmony_ci			if (ch->rdma_cm.cm_id)
9558c2ecf20Sopenharmony_ci				rdma_disconnect(ch->rdma_cm.cm_id);
9568c2ecf20Sopenharmony_ci		} else {
9578c2ecf20Sopenharmony_ci			if (ch->ib_cm.cm_id)
9588c2ecf20Sopenharmony_ci				ret = ib_send_cm_dreq(ch->ib_cm.cm_id,
9598c2ecf20Sopenharmony_ci						      NULL, 0);
9608c2ecf20Sopenharmony_ci		}
9618c2ecf20Sopenharmony_ci		if (ret < 0) {
9628c2ecf20Sopenharmony_ci			shost_printk(KERN_DEBUG, target->scsi_host,
9638c2ecf20Sopenharmony_ci				     PFX "Sending CM DREQ failed\n");
9648c2ecf20Sopenharmony_ci		}
9658c2ecf20Sopenharmony_ci	}
9668c2ecf20Sopenharmony_ci}
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_cistatic int srp_exit_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
9698c2ecf20Sopenharmony_ci{
9708c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(shost);
9718c2ecf20Sopenharmony_ci	struct srp_device *dev = target->srp_host->srp_dev;
9728c2ecf20Sopenharmony_ci	struct ib_device *ibdev = dev->dev;
9738c2ecf20Sopenharmony_ci	struct srp_request *req = scsi_cmd_priv(cmd);
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_ci	kfree(req->fr_list);
9768c2ecf20Sopenharmony_ci	if (req->indirect_dma_addr) {
9778c2ecf20Sopenharmony_ci		ib_dma_unmap_single(ibdev, req->indirect_dma_addr,
9788c2ecf20Sopenharmony_ci				    target->indirect_size,
9798c2ecf20Sopenharmony_ci				    DMA_TO_DEVICE);
9808c2ecf20Sopenharmony_ci	}
9818c2ecf20Sopenharmony_ci	kfree(req->indirect_desc);
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci	return 0;
9848c2ecf20Sopenharmony_ci}
9858c2ecf20Sopenharmony_ci
9868c2ecf20Sopenharmony_cistatic int srp_init_cmd_priv(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
9878c2ecf20Sopenharmony_ci{
9888c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(shost);
9898c2ecf20Sopenharmony_ci	struct srp_device *srp_dev = target->srp_host->srp_dev;
9908c2ecf20Sopenharmony_ci	struct ib_device *ibdev = srp_dev->dev;
9918c2ecf20Sopenharmony_ci	struct srp_request *req = scsi_cmd_priv(cmd);
9928c2ecf20Sopenharmony_ci	dma_addr_t dma_addr;
9938c2ecf20Sopenharmony_ci	int ret = -ENOMEM;
9948c2ecf20Sopenharmony_ci
9958c2ecf20Sopenharmony_ci	if (srp_dev->use_fast_reg) {
9968c2ecf20Sopenharmony_ci		req->fr_list = kmalloc_array(target->mr_per_cmd, sizeof(void *),
9978c2ecf20Sopenharmony_ci					GFP_KERNEL);
9988c2ecf20Sopenharmony_ci		if (!req->fr_list)
9998c2ecf20Sopenharmony_ci			goto out;
10008c2ecf20Sopenharmony_ci	}
10018c2ecf20Sopenharmony_ci	req->indirect_desc = kmalloc(target->indirect_size, GFP_KERNEL);
10028c2ecf20Sopenharmony_ci	if (!req->indirect_desc)
10038c2ecf20Sopenharmony_ci		goto out;
10048c2ecf20Sopenharmony_ci
10058c2ecf20Sopenharmony_ci	dma_addr = ib_dma_map_single(ibdev, req->indirect_desc,
10068c2ecf20Sopenharmony_ci				     target->indirect_size,
10078c2ecf20Sopenharmony_ci				     DMA_TO_DEVICE);
10088c2ecf20Sopenharmony_ci	if (ib_dma_mapping_error(ibdev, dma_addr)) {
10098c2ecf20Sopenharmony_ci		srp_exit_cmd_priv(shost, cmd);
10108c2ecf20Sopenharmony_ci		goto out;
10118c2ecf20Sopenharmony_ci	}
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	req->indirect_dma_addr = dma_addr;
10148c2ecf20Sopenharmony_ci	ret = 0;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ciout:
10178c2ecf20Sopenharmony_ci	return ret;
10188c2ecf20Sopenharmony_ci}
10198c2ecf20Sopenharmony_ci
10208c2ecf20Sopenharmony_ci/**
10218c2ecf20Sopenharmony_ci * srp_del_scsi_host_attr() - Remove attributes defined in the host template.
10228c2ecf20Sopenharmony_ci * @shost: SCSI host whose attributes to remove from sysfs.
10238c2ecf20Sopenharmony_ci *
10248c2ecf20Sopenharmony_ci * Note: Any attributes defined in the host template and that did not exist
10258c2ecf20Sopenharmony_ci * before invocation of this function will be ignored.
10268c2ecf20Sopenharmony_ci */
10278c2ecf20Sopenharmony_cistatic void srp_del_scsi_host_attr(struct Scsi_Host *shost)
10288c2ecf20Sopenharmony_ci{
10298c2ecf20Sopenharmony_ci	struct device_attribute **attr;
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	for (attr = shost->hostt->shost_attrs; attr && *attr; ++attr)
10328c2ecf20Sopenharmony_ci		device_remove_file(&shost->shost_dev, *attr);
10338c2ecf20Sopenharmony_ci}
10348c2ecf20Sopenharmony_ci
10358c2ecf20Sopenharmony_cistatic void srp_remove_target(struct srp_target_port *target)
10368c2ecf20Sopenharmony_ci{
10378c2ecf20Sopenharmony_ci	struct srp_rdma_ch *ch;
10388c2ecf20Sopenharmony_ci	int i;
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci	WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED);
10418c2ecf20Sopenharmony_ci
10428c2ecf20Sopenharmony_ci	srp_del_scsi_host_attr(target->scsi_host);
10438c2ecf20Sopenharmony_ci	srp_rport_get(target->rport);
10448c2ecf20Sopenharmony_ci	srp_remove_host(target->scsi_host);
10458c2ecf20Sopenharmony_ci	scsi_remove_host(target->scsi_host);
10468c2ecf20Sopenharmony_ci	srp_stop_rport_timers(target->rport);
10478c2ecf20Sopenharmony_ci	srp_disconnect_target(target);
10488c2ecf20Sopenharmony_ci	kobj_ns_drop(KOBJ_NS_TYPE_NET, target->net);
10498c2ecf20Sopenharmony_ci	for (i = 0; i < target->ch_count; i++) {
10508c2ecf20Sopenharmony_ci		ch = &target->ch[i];
10518c2ecf20Sopenharmony_ci		srp_free_ch_ib(target, ch);
10528c2ecf20Sopenharmony_ci	}
10538c2ecf20Sopenharmony_ci	cancel_work_sync(&target->tl_err_work);
10548c2ecf20Sopenharmony_ci	srp_rport_put(target->rport);
10558c2ecf20Sopenharmony_ci	kfree(target->ch);
10568c2ecf20Sopenharmony_ci	target->ch = NULL;
10578c2ecf20Sopenharmony_ci
10588c2ecf20Sopenharmony_ci	spin_lock(&target->srp_host->target_lock);
10598c2ecf20Sopenharmony_ci	list_del(&target->list);
10608c2ecf20Sopenharmony_ci	spin_unlock(&target->srp_host->target_lock);
10618c2ecf20Sopenharmony_ci
10628c2ecf20Sopenharmony_ci	scsi_host_put(target->scsi_host);
10638c2ecf20Sopenharmony_ci}
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_cistatic void srp_remove_work(struct work_struct *work)
10668c2ecf20Sopenharmony_ci{
10678c2ecf20Sopenharmony_ci	struct srp_target_port *target =
10688c2ecf20Sopenharmony_ci		container_of(work, struct srp_target_port, remove_work);
10698c2ecf20Sopenharmony_ci
10708c2ecf20Sopenharmony_ci	WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED);
10718c2ecf20Sopenharmony_ci
10728c2ecf20Sopenharmony_ci	srp_remove_target(target);
10738c2ecf20Sopenharmony_ci}
10748c2ecf20Sopenharmony_ci
10758c2ecf20Sopenharmony_cistatic void srp_rport_delete(struct srp_rport *rport)
10768c2ecf20Sopenharmony_ci{
10778c2ecf20Sopenharmony_ci	struct srp_target_port *target = rport->lld_data;
10788c2ecf20Sopenharmony_ci
10798c2ecf20Sopenharmony_ci	srp_queue_remove_work(target);
10808c2ecf20Sopenharmony_ci}
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci/**
10838c2ecf20Sopenharmony_ci * srp_connected_ch() - number of connected channels
10848c2ecf20Sopenharmony_ci * @target: SRP target port.
10858c2ecf20Sopenharmony_ci */
10868c2ecf20Sopenharmony_cistatic int srp_connected_ch(struct srp_target_port *target)
10878c2ecf20Sopenharmony_ci{
10888c2ecf20Sopenharmony_ci	int i, c = 0;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	for (i = 0; i < target->ch_count; i++)
10918c2ecf20Sopenharmony_ci		c += target->ch[i].connected;
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_ci	return c;
10948c2ecf20Sopenharmony_ci}
10958c2ecf20Sopenharmony_ci
10968c2ecf20Sopenharmony_cistatic int srp_connect_ch(struct srp_rdma_ch *ch, uint32_t max_iu_len,
10978c2ecf20Sopenharmony_ci			  bool multich)
10988c2ecf20Sopenharmony_ci{
10998c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
11008c2ecf20Sopenharmony_ci	int ret;
11018c2ecf20Sopenharmony_ci
11028c2ecf20Sopenharmony_ci	WARN_ON_ONCE(!multich && srp_connected_ch(target) > 0);
11038c2ecf20Sopenharmony_ci
11048c2ecf20Sopenharmony_ci	ret = srp_lookup_path(ch);
11058c2ecf20Sopenharmony_ci	if (ret)
11068c2ecf20Sopenharmony_ci		goto out;
11078c2ecf20Sopenharmony_ci
11088c2ecf20Sopenharmony_ci	while (1) {
11098c2ecf20Sopenharmony_ci		init_completion(&ch->done);
11108c2ecf20Sopenharmony_ci		ret = srp_send_req(ch, max_iu_len, multich);
11118c2ecf20Sopenharmony_ci		if (ret)
11128c2ecf20Sopenharmony_ci			goto out;
11138c2ecf20Sopenharmony_ci		ret = wait_for_completion_interruptible(&ch->done);
11148c2ecf20Sopenharmony_ci		if (ret < 0)
11158c2ecf20Sopenharmony_ci			goto out;
11168c2ecf20Sopenharmony_ci
11178c2ecf20Sopenharmony_ci		/*
11188c2ecf20Sopenharmony_ci		 * The CM event handling code will set status to
11198c2ecf20Sopenharmony_ci		 * SRP_PORT_REDIRECT if we get a port redirect REJ
11208c2ecf20Sopenharmony_ci		 * back, or SRP_DLID_REDIRECT if we get a lid/qp
11218c2ecf20Sopenharmony_ci		 * redirect REJ back.
11228c2ecf20Sopenharmony_ci		 */
11238c2ecf20Sopenharmony_ci		ret = ch->status;
11248c2ecf20Sopenharmony_ci		switch (ret) {
11258c2ecf20Sopenharmony_ci		case 0:
11268c2ecf20Sopenharmony_ci			ch->connected = true;
11278c2ecf20Sopenharmony_ci			goto out;
11288c2ecf20Sopenharmony_ci
11298c2ecf20Sopenharmony_ci		case SRP_PORT_REDIRECT:
11308c2ecf20Sopenharmony_ci			ret = srp_lookup_path(ch);
11318c2ecf20Sopenharmony_ci			if (ret)
11328c2ecf20Sopenharmony_ci				goto out;
11338c2ecf20Sopenharmony_ci			break;
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci		case SRP_DLID_REDIRECT:
11368c2ecf20Sopenharmony_ci			break;
11378c2ecf20Sopenharmony_ci
11388c2ecf20Sopenharmony_ci		case SRP_STALE_CONN:
11398c2ecf20Sopenharmony_ci			shost_printk(KERN_ERR, target->scsi_host, PFX
11408c2ecf20Sopenharmony_ci				     "giving up on stale connection\n");
11418c2ecf20Sopenharmony_ci			ret = -ECONNRESET;
11428c2ecf20Sopenharmony_ci			goto out;
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci		default:
11458c2ecf20Sopenharmony_ci			goto out;
11468c2ecf20Sopenharmony_ci		}
11478c2ecf20Sopenharmony_ci	}
11488c2ecf20Sopenharmony_ci
11498c2ecf20Sopenharmony_ciout:
11508c2ecf20Sopenharmony_ci	return ret <= 0 ? ret : -ENODEV;
11518c2ecf20Sopenharmony_ci}
11528c2ecf20Sopenharmony_ci
11538c2ecf20Sopenharmony_cistatic void srp_inv_rkey_err_done(struct ib_cq *cq, struct ib_wc *wc)
11548c2ecf20Sopenharmony_ci{
11558c2ecf20Sopenharmony_ci	srp_handle_qp_err(cq, wc, "INV RKEY");
11568c2ecf20Sopenharmony_ci}
11578c2ecf20Sopenharmony_ci
11588c2ecf20Sopenharmony_cistatic int srp_inv_rkey(struct srp_request *req, struct srp_rdma_ch *ch,
11598c2ecf20Sopenharmony_ci		u32 rkey)
11608c2ecf20Sopenharmony_ci{
11618c2ecf20Sopenharmony_ci	struct ib_send_wr wr = {
11628c2ecf20Sopenharmony_ci		.opcode		    = IB_WR_LOCAL_INV,
11638c2ecf20Sopenharmony_ci		.next		    = NULL,
11648c2ecf20Sopenharmony_ci		.num_sge	    = 0,
11658c2ecf20Sopenharmony_ci		.send_flags	    = 0,
11668c2ecf20Sopenharmony_ci		.ex.invalidate_rkey = rkey,
11678c2ecf20Sopenharmony_ci	};
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	wr.wr_cqe = &req->reg_cqe;
11708c2ecf20Sopenharmony_ci	req->reg_cqe.done = srp_inv_rkey_err_done;
11718c2ecf20Sopenharmony_ci	return ib_post_send(ch->qp, &wr, NULL);
11728c2ecf20Sopenharmony_ci}
11738c2ecf20Sopenharmony_ci
11748c2ecf20Sopenharmony_cistatic void srp_unmap_data(struct scsi_cmnd *scmnd,
11758c2ecf20Sopenharmony_ci			   struct srp_rdma_ch *ch,
11768c2ecf20Sopenharmony_ci			   struct srp_request *req)
11778c2ecf20Sopenharmony_ci{
11788c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
11798c2ecf20Sopenharmony_ci	struct srp_device *dev = target->srp_host->srp_dev;
11808c2ecf20Sopenharmony_ci	struct ib_device *ibdev = dev->dev;
11818c2ecf20Sopenharmony_ci	int i, res;
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	if (!scsi_sglist(scmnd) ||
11848c2ecf20Sopenharmony_ci	    (scmnd->sc_data_direction != DMA_TO_DEVICE &&
11858c2ecf20Sopenharmony_ci	     scmnd->sc_data_direction != DMA_FROM_DEVICE))
11868c2ecf20Sopenharmony_ci		return;
11878c2ecf20Sopenharmony_ci
11888c2ecf20Sopenharmony_ci	if (dev->use_fast_reg) {
11898c2ecf20Sopenharmony_ci		struct srp_fr_desc **pfr;
11908c2ecf20Sopenharmony_ci
11918c2ecf20Sopenharmony_ci		for (i = req->nmdesc, pfr = req->fr_list; i > 0; i--, pfr++) {
11928c2ecf20Sopenharmony_ci			res = srp_inv_rkey(req, ch, (*pfr)->mr->rkey);
11938c2ecf20Sopenharmony_ci			if (res < 0) {
11948c2ecf20Sopenharmony_ci				shost_printk(KERN_ERR, target->scsi_host, PFX
11958c2ecf20Sopenharmony_ci				  "Queueing INV WR for rkey %#x failed (%d)\n",
11968c2ecf20Sopenharmony_ci				  (*pfr)->mr->rkey, res);
11978c2ecf20Sopenharmony_ci				queue_work(system_long_wq,
11988c2ecf20Sopenharmony_ci					   &target->tl_err_work);
11998c2ecf20Sopenharmony_ci			}
12008c2ecf20Sopenharmony_ci		}
12018c2ecf20Sopenharmony_ci		if (req->nmdesc)
12028c2ecf20Sopenharmony_ci			srp_fr_pool_put(ch->fr_pool, req->fr_list,
12038c2ecf20Sopenharmony_ci					req->nmdesc);
12048c2ecf20Sopenharmony_ci	}
12058c2ecf20Sopenharmony_ci
12068c2ecf20Sopenharmony_ci	ib_dma_unmap_sg(ibdev, scsi_sglist(scmnd), scsi_sg_count(scmnd),
12078c2ecf20Sopenharmony_ci			scmnd->sc_data_direction);
12088c2ecf20Sopenharmony_ci}
12098c2ecf20Sopenharmony_ci
12108c2ecf20Sopenharmony_ci/**
12118c2ecf20Sopenharmony_ci * srp_claim_req - Take ownership of the scmnd associated with a request.
12128c2ecf20Sopenharmony_ci * @ch: SRP RDMA channel.
12138c2ecf20Sopenharmony_ci * @req: SRP request.
12148c2ecf20Sopenharmony_ci * @sdev: If not NULL, only take ownership for this SCSI device.
12158c2ecf20Sopenharmony_ci * @scmnd: If NULL, take ownership of @req->scmnd. If not NULL, only take
12168c2ecf20Sopenharmony_ci *         ownership of @req->scmnd if it equals @scmnd.
12178c2ecf20Sopenharmony_ci *
12188c2ecf20Sopenharmony_ci * Return value:
12198c2ecf20Sopenharmony_ci * Either NULL or a pointer to the SCSI command the caller became owner of.
12208c2ecf20Sopenharmony_ci */
12218c2ecf20Sopenharmony_cistatic struct scsi_cmnd *srp_claim_req(struct srp_rdma_ch *ch,
12228c2ecf20Sopenharmony_ci				       struct srp_request *req,
12238c2ecf20Sopenharmony_ci				       struct scsi_device *sdev,
12248c2ecf20Sopenharmony_ci				       struct scsi_cmnd *scmnd)
12258c2ecf20Sopenharmony_ci{
12268c2ecf20Sopenharmony_ci	unsigned long flags;
12278c2ecf20Sopenharmony_ci
12288c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ch->lock, flags);
12298c2ecf20Sopenharmony_ci	if (req->scmnd &&
12308c2ecf20Sopenharmony_ci	    (!sdev || req->scmnd->device == sdev) &&
12318c2ecf20Sopenharmony_ci	    (!scmnd || req->scmnd == scmnd)) {
12328c2ecf20Sopenharmony_ci		scmnd = req->scmnd;
12338c2ecf20Sopenharmony_ci		req->scmnd = NULL;
12348c2ecf20Sopenharmony_ci	} else {
12358c2ecf20Sopenharmony_ci		scmnd = NULL;
12368c2ecf20Sopenharmony_ci	}
12378c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ch->lock, flags);
12388c2ecf20Sopenharmony_ci
12398c2ecf20Sopenharmony_ci	return scmnd;
12408c2ecf20Sopenharmony_ci}
12418c2ecf20Sopenharmony_ci
12428c2ecf20Sopenharmony_ci/**
12438c2ecf20Sopenharmony_ci * srp_free_req() - Unmap data and adjust ch->req_lim.
12448c2ecf20Sopenharmony_ci * @ch:     SRP RDMA channel.
12458c2ecf20Sopenharmony_ci * @req:    Request to be freed.
12468c2ecf20Sopenharmony_ci * @scmnd:  SCSI command associated with @req.
12478c2ecf20Sopenharmony_ci * @req_lim_delta: Amount to be added to @target->req_lim.
12488c2ecf20Sopenharmony_ci */
12498c2ecf20Sopenharmony_cistatic void srp_free_req(struct srp_rdma_ch *ch, struct srp_request *req,
12508c2ecf20Sopenharmony_ci			 struct scsi_cmnd *scmnd, s32 req_lim_delta)
12518c2ecf20Sopenharmony_ci{
12528c2ecf20Sopenharmony_ci	unsigned long flags;
12538c2ecf20Sopenharmony_ci
12548c2ecf20Sopenharmony_ci	srp_unmap_data(scmnd, ch, req);
12558c2ecf20Sopenharmony_ci
12568c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ch->lock, flags);
12578c2ecf20Sopenharmony_ci	ch->req_lim += req_lim_delta;
12588c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ch->lock, flags);
12598c2ecf20Sopenharmony_ci}
12608c2ecf20Sopenharmony_ci
12618c2ecf20Sopenharmony_cistatic void srp_finish_req(struct srp_rdma_ch *ch, struct srp_request *req,
12628c2ecf20Sopenharmony_ci			   struct scsi_device *sdev, int result)
12638c2ecf20Sopenharmony_ci{
12648c2ecf20Sopenharmony_ci	struct scsi_cmnd *scmnd = srp_claim_req(ch, req, sdev, NULL);
12658c2ecf20Sopenharmony_ci
12668c2ecf20Sopenharmony_ci	if (scmnd) {
12678c2ecf20Sopenharmony_ci		srp_free_req(ch, req, scmnd, 0);
12688c2ecf20Sopenharmony_ci		scmnd->result = result;
12698c2ecf20Sopenharmony_ci		scmnd->scsi_done(scmnd);
12708c2ecf20Sopenharmony_ci	}
12718c2ecf20Sopenharmony_ci}
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_cistruct srp_terminate_context {
12748c2ecf20Sopenharmony_ci	struct srp_target_port *srp_target;
12758c2ecf20Sopenharmony_ci	int scsi_result;
12768c2ecf20Sopenharmony_ci};
12778c2ecf20Sopenharmony_ci
12788c2ecf20Sopenharmony_cistatic bool srp_terminate_cmd(struct scsi_cmnd *scmnd, void *context_ptr,
12798c2ecf20Sopenharmony_ci			      bool reserved)
12808c2ecf20Sopenharmony_ci{
12818c2ecf20Sopenharmony_ci	struct srp_terminate_context *context = context_ptr;
12828c2ecf20Sopenharmony_ci	struct srp_target_port *target = context->srp_target;
12838c2ecf20Sopenharmony_ci	u32 tag = blk_mq_unique_tag(scmnd->request);
12848c2ecf20Sopenharmony_ci	struct srp_rdma_ch *ch = &target->ch[blk_mq_unique_tag_to_hwq(tag)];
12858c2ecf20Sopenharmony_ci	struct srp_request *req = scsi_cmd_priv(scmnd);
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	srp_finish_req(ch, req, NULL, context->scsi_result);
12888c2ecf20Sopenharmony_ci
12898c2ecf20Sopenharmony_ci	return true;
12908c2ecf20Sopenharmony_ci}
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_cistatic void srp_terminate_io(struct srp_rport *rport)
12938c2ecf20Sopenharmony_ci{
12948c2ecf20Sopenharmony_ci	struct srp_target_port *target = rport->lld_data;
12958c2ecf20Sopenharmony_ci	struct srp_terminate_context context = { .srp_target = target,
12968c2ecf20Sopenharmony_ci		.scsi_result = DID_TRANSPORT_FAILFAST << 16 };
12978c2ecf20Sopenharmony_ci
12988c2ecf20Sopenharmony_ci	scsi_host_busy_iter(target->scsi_host, srp_terminate_cmd, &context);
12998c2ecf20Sopenharmony_ci}
13008c2ecf20Sopenharmony_ci
13018c2ecf20Sopenharmony_ci/* Calculate maximum initiator to target information unit length. */
13028c2ecf20Sopenharmony_cistatic uint32_t srp_max_it_iu_len(int cmd_sg_cnt, bool use_imm_data,
13038c2ecf20Sopenharmony_ci				  uint32_t max_it_iu_size)
13048c2ecf20Sopenharmony_ci{
13058c2ecf20Sopenharmony_ci	uint32_t max_iu_len = sizeof(struct srp_cmd) + SRP_MAX_ADD_CDB_LEN +
13068c2ecf20Sopenharmony_ci		sizeof(struct srp_indirect_buf) +
13078c2ecf20Sopenharmony_ci		cmd_sg_cnt * sizeof(struct srp_direct_buf);
13088c2ecf20Sopenharmony_ci
13098c2ecf20Sopenharmony_ci	if (use_imm_data)
13108c2ecf20Sopenharmony_ci		max_iu_len = max(max_iu_len, SRP_IMM_DATA_OFFSET +
13118c2ecf20Sopenharmony_ci				 srp_max_imm_data);
13128c2ecf20Sopenharmony_ci
13138c2ecf20Sopenharmony_ci	if (max_it_iu_size)
13148c2ecf20Sopenharmony_ci		max_iu_len = min(max_iu_len, max_it_iu_size);
13158c2ecf20Sopenharmony_ci
13168c2ecf20Sopenharmony_ci	pr_debug("max_iu_len = %d\n", max_iu_len);
13178c2ecf20Sopenharmony_ci
13188c2ecf20Sopenharmony_ci	return max_iu_len;
13198c2ecf20Sopenharmony_ci}
13208c2ecf20Sopenharmony_ci
13218c2ecf20Sopenharmony_ci/*
13228c2ecf20Sopenharmony_ci * It is up to the caller to ensure that srp_rport_reconnect() calls are
13238c2ecf20Sopenharmony_ci * serialized and that no concurrent srp_queuecommand(), srp_abort(),
13248c2ecf20Sopenharmony_ci * srp_reset_device() or srp_reset_host() calls will occur while this function
13258c2ecf20Sopenharmony_ci * is in progress. One way to realize that is not to call this function
13268c2ecf20Sopenharmony_ci * directly but to call srp_reconnect_rport() instead since that last function
13278c2ecf20Sopenharmony_ci * serializes calls of this function via rport->mutex and also blocks
13288c2ecf20Sopenharmony_ci * srp_queuecommand() calls before invoking this function.
13298c2ecf20Sopenharmony_ci */
13308c2ecf20Sopenharmony_cistatic int srp_rport_reconnect(struct srp_rport *rport)
13318c2ecf20Sopenharmony_ci{
13328c2ecf20Sopenharmony_ci	struct srp_target_port *target = rport->lld_data;
13338c2ecf20Sopenharmony_ci	struct srp_rdma_ch *ch;
13348c2ecf20Sopenharmony_ci	uint32_t max_iu_len = srp_max_it_iu_len(target->cmd_sg_cnt,
13358c2ecf20Sopenharmony_ci						srp_use_imm_data,
13368c2ecf20Sopenharmony_ci						target->max_it_iu_size);
13378c2ecf20Sopenharmony_ci	int i, j, ret = 0;
13388c2ecf20Sopenharmony_ci	bool multich = false;
13398c2ecf20Sopenharmony_ci
13408c2ecf20Sopenharmony_ci	srp_disconnect_target(target);
13418c2ecf20Sopenharmony_ci
13428c2ecf20Sopenharmony_ci	if (target->state == SRP_TARGET_SCANNING)
13438c2ecf20Sopenharmony_ci		return -ENODEV;
13448c2ecf20Sopenharmony_ci
13458c2ecf20Sopenharmony_ci	/*
13468c2ecf20Sopenharmony_ci	 * Now get a new local CM ID so that we avoid confusing the target in
13478c2ecf20Sopenharmony_ci	 * case things are really fouled up. Doing so also ensures that all CM
13488c2ecf20Sopenharmony_ci	 * callbacks will have finished before a new QP is allocated.
13498c2ecf20Sopenharmony_ci	 */
13508c2ecf20Sopenharmony_ci	for (i = 0; i < target->ch_count; i++) {
13518c2ecf20Sopenharmony_ci		ch = &target->ch[i];
13528c2ecf20Sopenharmony_ci		ret += srp_new_cm_id(ch);
13538c2ecf20Sopenharmony_ci	}
13548c2ecf20Sopenharmony_ci	{
13558c2ecf20Sopenharmony_ci		struct srp_terminate_context context = {
13568c2ecf20Sopenharmony_ci			.srp_target = target, .scsi_result = DID_RESET << 16};
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci		scsi_host_busy_iter(target->scsi_host, srp_terminate_cmd,
13598c2ecf20Sopenharmony_ci				    &context);
13608c2ecf20Sopenharmony_ci	}
13618c2ecf20Sopenharmony_ci	for (i = 0; i < target->ch_count; i++) {
13628c2ecf20Sopenharmony_ci		ch = &target->ch[i];
13638c2ecf20Sopenharmony_ci		/*
13648c2ecf20Sopenharmony_ci		 * Whether or not creating a new CM ID succeeded, create a new
13658c2ecf20Sopenharmony_ci		 * QP. This guarantees that all completion callback function
13668c2ecf20Sopenharmony_ci		 * invocations have finished before request resetting starts.
13678c2ecf20Sopenharmony_ci		 */
13688c2ecf20Sopenharmony_ci		ret += srp_create_ch_ib(ch);
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&ch->free_tx);
13718c2ecf20Sopenharmony_ci		for (j = 0; j < target->queue_size; ++j)
13728c2ecf20Sopenharmony_ci			list_add(&ch->tx_ring[j]->list, &ch->free_tx);
13738c2ecf20Sopenharmony_ci	}
13748c2ecf20Sopenharmony_ci
13758c2ecf20Sopenharmony_ci	target->qp_in_error = false;
13768c2ecf20Sopenharmony_ci
13778c2ecf20Sopenharmony_ci	for (i = 0; i < target->ch_count; i++) {
13788c2ecf20Sopenharmony_ci		ch = &target->ch[i];
13798c2ecf20Sopenharmony_ci		if (ret)
13808c2ecf20Sopenharmony_ci			break;
13818c2ecf20Sopenharmony_ci		ret = srp_connect_ch(ch, max_iu_len, multich);
13828c2ecf20Sopenharmony_ci		multich = true;
13838c2ecf20Sopenharmony_ci	}
13848c2ecf20Sopenharmony_ci
13858c2ecf20Sopenharmony_ci	if (ret == 0)
13868c2ecf20Sopenharmony_ci		shost_printk(KERN_INFO, target->scsi_host,
13878c2ecf20Sopenharmony_ci			     PFX "reconnect succeeded\n");
13888c2ecf20Sopenharmony_ci
13898c2ecf20Sopenharmony_ci	return ret;
13908c2ecf20Sopenharmony_ci}
13918c2ecf20Sopenharmony_ci
13928c2ecf20Sopenharmony_cistatic void srp_map_desc(struct srp_map_state *state, dma_addr_t dma_addr,
13938c2ecf20Sopenharmony_ci			 unsigned int dma_len, u32 rkey)
13948c2ecf20Sopenharmony_ci{
13958c2ecf20Sopenharmony_ci	struct srp_direct_buf *desc = state->desc;
13968c2ecf20Sopenharmony_ci
13978c2ecf20Sopenharmony_ci	WARN_ON_ONCE(!dma_len);
13988c2ecf20Sopenharmony_ci
13998c2ecf20Sopenharmony_ci	desc->va = cpu_to_be64(dma_addr);
14008c2ecf20Sopenharmony_ci	desc->key = cpu_to_be32(rkey);
14018c2ecf20Sopenharmony_ci	desc->len = cpu_to_be32(dma_len);
14028c2ecf20Sopenharmony_ci
14038c2ecf20Sopenharmony_ci	state->total_len += dma_len;
14048c2ecf20Sopenharmony_ci	state->desc++;
14058c2ecf20Sopenharmony_ci	state->ndesc++;
14068c2ecf20Sopenharmony_ci}
14078c2ecf20Sopenharmony_ci
14088c2ecf20Sopenharmony_cistatic void srp_reg_mr_err_done(struct ib_cq *cq, struct ib_wc *wc)
14098c2ecf20Sopenharmony_ci{
14108c2ecf20Sopenharmony_ci	srp_handle_qp_err(cq, wc, "FAST REG");
14118c2ecf20Sopenharmony_ci}
14128c2ecf20Sopenharmony_ci
14138c2ecf20Sopenharmony_ci/*
14148c2ecf20Sopenharmony_ci * Map up to sg_nents elements of state->sg where *sg_offset_p is the offset
14158c2ecf20Sopenharmony_ci * where to start in the first element. If sg_offset_p != NULL then
14168c2ecf20Sopenharmony_ci * *sg_offset_p is updated to the offset in state->sg[retval] of the first
14178c2ecf20Sopenharmony_ci * byte that has not yet been mapped.
14188c2ecf20Sopenharmony_ci */
14198c2ecf20Sopenharmony_cistatic int srp_map_finish_fr(struct srp_map_state *state,
14208c2ecf20Sopenharmony_ci			     struct srp_request *req,
14218c2ecf20Sopenharmony_ci			     struct srp_rdma_ch *ch, int sg_nents,
14228c2ecf20Sopenharmony_ci			     unsigned int *sg_offset_p)
14238c2ecf20Sopenharmony_ci{
14248c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
14258c2ecf20Sopenharmony_ci	struct srp_device *dev = target->srp_host->srp_dev;
14268c2ecf20Sopenharmony_ci	struct ib_reg_wr wr;
14278c2ecf20Sopenharmony_ci	struct srp_fr_desc *desc;
14288c2ecf20Sopenharmony_ci	u32 rkey;
14298c2ecf20Sopenharmony_ci	int n, err;
14308c2ecf20Sopenharmony_ci
14318c2ecf20Sopenharmony_ci	if (state->fr.next >= state->fr.end) {
14328c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, ch->target->scsi_host,
14338c2ecf20Sopenharmony_ci			     PFX "Out of MRs (mr_per_cmd = %d)\n",
14348c2ecf20Sopenharmony_ci			     ch->target->mr_per_cmd);
14358c2ecf20Sopenharmony_ci		return -ENOMEM;
14368c2ecf20Sopenharmony_ci	}
14378c2ecf20Sopenharmony_ci
14388c2ecf20Sopenharmony_ci	WARN_ON_ONCE(!dev->use_fast_reg);
14398c2ecf20Sopenharmony_ci
14408c2ecf20Sopenharmony_ci	if (sg_nents == 1 && target->global_rkey) {
14418c2ecf20Sopenharmony_ci		unsigned int sg_offset = sg_offset_p ? *sg_offset_p : 0;
14428c2ecf20Sopenharmony_ci
14438c2ecf20Sopenharmony_ci		srp_map_desc(state, sg_dma_address(state->sg) + sg_offset,
14448c2ecf20Sopenharmony_ci			     sg_dma_len(state->sg) - sg_offset,
14458c2ecf20Sopenharmony_ci			     target->global_rkey);
14468c2ecf20Sopenharmony_ci		if (sg_offset_p)
14478c2ecf20Sopenharmony_ci			*sg_offset_p = 0;
14488c2ecf20Sopenharmony_ci		return 1;
14498c2ecf20Sopenharmony_ci	}
14508c2ecf20Sopenharmony_ci
14518c2ecf20Sopenharmony_ci	desc = srp_fr_pool_get(ch->fr_pool);
14528c2ecf20Sopenharmony_ci	if (!desc)
14538c2ecf20Sopenharmony_ci		return -ENOMEM;
14548c2ecf20Sopenharmony_ci
14558c2ecf20Sopenharmony_ci	rkey = ib_inc_rkey(desc->mr->rkey);
14568c2ecf20Sopenharmony_ci	ib_update_fast_reg_key(desc->mr, rkey);
14578c2ecf20Sopenharmony_ci
14588c2ecf20Sopenharmony_ci	n = ib_map_mr_sg(desc->mr, state->sg, sg_nents, sg_offset_p,
14598c2ecf20Sopenharmony_ci			 dev->mr_page_size);
14608c2ecf20Sopenharmony_ci	if (unlikely(n < 0)) {
14618c2ecf20Sopenharmony_ci		srp_fr_pool_put(ch->fr_pool, &desc, 1);
14628c2ecf20Sopenharmony_ci		pr_debug("%s: ib_map_mr_sg(%d, %d) returned %d.\n",
14638c2ecf20Sopenharmony_ci			 dev_name(&req->scmnd->device->sdev_gendev), sg_nents,
14648c2ecf20Sopenharmony_ci			 sg_offset_p ? *sg_offset_p : -1, n);
14658c2ecf20Sopenharmony_ci		return n;
14668c2ecf20Sopenharmony_ci	}
14678c2ecf20Sopenharmony_ci
14688c2ecf20Sopenharmony_ci	WARN_ON_ONCE(desc->mr->length == 0);
14698c2ecf20Sopenharmony_ci
14708c2ecf20Sopenharmony_ci	req->reg_cqe.done = srp_reg_mr_err_done;
14718c2ecf20Sopenharmony_ci
14728c2ecf20Sopenharmony_ci	wr.wr.next = NULL;
14738c2ecf20Sopenharmony_ci	wr.wr.opcode = IB_WR_REG_MR;
14748c2ecf20Sopenharmony_ci	wr.wr.wr_cqe = &req->reg_cqe;
14758c2ecf20Sopenharmony_ci	wr.wr.num_sge = 0;
14768c2ecf20Sopenharmony_ci	wr.wr.send_flags = 0;
14778c2ecf20Sopenharmony_ci	wr.mr = desc->mr;
14788c2ecf20Sopenharmony_ci	wr.key = desc->mr->rkey;
14798c2ecf20Sopenharmony_ci	wr.access = (IB_ACCESS_LOCAL_WRITE |
14808c2ecf20Sopenharmony_ci		     IB_ACCESS_REMOTE_READ |
14818c2ecf20Sopenharmony_ci		     IB_ACCESS_REMOTE_WRITE);
14828c2ecf20Sopenharmony_ci
14838c2ecf20Sopenharmony_ci	*state->fr.next++ = desc;
14848c2ecf20Sopenharmony_ci	state->nmdesc++;
14858c2ecf20Sopenharmony_ci
14868c2ecf20Sopenharmony_ci	srp_map_desc(state, desc->mr->iova,
14878c2ecf20Sopenharmony_ci		     desc->mr->length, desc->mr->rkey);
14888c2ecf20Sopenharmony_ci
14898c2ecf20Sopenharmony_ci	err = ib_post_send(ch->qp, &wr.wr, NULL);
14908c2ecf20Sopenharmony_ci	if (unlikely(err)) {
14918c2ecf20Sopenharmony_ci		WARN_ON_ONCE(err == -ENOMEM);
14928c2ecf20Sopenharmony_ci		return err;
14938c2ecf20Sopenharmony_ci	}
14948c2ecf20Sopenharmony_ci
14958c2ecf20Sopenharmony_ci	return n;
14968c2ecf20Sopenharmony_ci}
14978c2ecf20Sopenharmony_ci
14988c2ecf20Sopenharmony_cistatic int srp_map_sg_fr(struct srp_map_state *state, struct srp_rdma_ch *ch,
14998c2ecf20Sopenharmony_ci			 struct srp_request *req, struct scatterlist *scat,
15008c2ecf20Sopenharmony_ci			 int count)
15018c2ecf20Sopenharmony_ci{
15028c2ecf20Sopenharmony_ci	unsigned int sg_offset = 0;
15038c2ecf20Sopenharmony_ci
15048c2ecf20Sopenharmony_ci	state->fr.next = req->fr_list;
15058c2ecf20Sopenharmony_ci	state->fr.end = req->fr_list + ch->target->mr_per_cmd;
15068c2ecf20Sopenharmony_ci	state->sg = scat;
15078c2ecf20Sopenharmony_ci
15088c2ecf20Sopenharmony_ci	if (count == 0)
15098c2ecf20Sopenharmony_ci		return 0;
15108c2ecf20Sopenharmony_ci
15118c2ecf20Sopenharmony_ci	while (count) {
15128c2ecf20Sopenharmony_ci		int i, n;
15138c2ecf20Sopenharmony_ci
15148c2ecf20Sopenharmony_ci		n = srp_map_finish_fr(state, req, ch, count, &sg_offset);
15158c2ecf20Sopenharmony_ci		if (unlikely(n < 0))
15168c2ecf20Sopenharmony_ci			return n;
15178c2ecf20Sopenharmony_ci
15188c2ecf20Sopenharmony_ci		count -= n;
15198c2ecf20Sopenharmony_ci		for (i = 0; i < n; i++)
15208c2ecf20Sopenharmony_ci			state->sg = sg_next(state->sg);
15218c2ecf20Sopenharmony_ci	}
15228c2ecf20Sopenharmony_ci
15238c2ecf20Sopenharmony_ci	return 0;
15248c2ecf20Sopenharmony_ci}
15258c2ecf20Sopenharmony_ci
15268c2ecf20Sopenharmony_cistatic int srp_map_sg_dma(struct srp_map_state *state, struct srp_rdma_ch *ch,
15278c2ecf20Sopenharmony_ci			  struct srp_request *req, struct scatterlist *scat,
15288c2ecf20Sopenharmony_ci			  int count)
15298c2ecf20Sopenharmony_ci{
15308c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
15318c2ecf20Sopenharmony_ci	struct scatterlist *sg;
15328c2ecf20Sopenharmony_ci	int i;
15338c2ecf20Sopenharmony_ci
15348c2ecf20Sopenharmony_ci	for_each_sg(scat, sg, count, i) {
15358c2ecf20Sopenharmony_ci		srp_map_desc(state, sg_dma_address(sg), sg_dma_len(sg),
15368c2ecf20Sopenharmony_ci			     target->global_rkey);
15378c2ecf20Sopenharmony_ci	}
15388c2ecf20Sopenharmony_ci
15398c2ecf20Sopenharmony_ci	return 0;
15408c2ecf20Sopenharmony_ci}
15418c2ecf20Sopenharmony_ci
15428c2ecf20Sopenharmony_ci/*
15438c2ecf20Sopenharmony_ci * Register the indirect data buffer descriptor with the HCA.
15448c2ecf20Sopenharmony_ci *
15458c2ecf20Sopenharmony_ci * Note: since the indirect data buffer descriptor has been allocated with
15468c2ecf20Sopenharmony_ci * kmalloc() it is guaranteed that this buffer is a physically contiguous
15478c2ecf20Sopenharmony_ci * memory buffer.
15488c2ecf20Sopenharmony_ci */
15498c2ecf20Sopenharmony_cistatic int srp_map_idb(struct srp_rdma_ch *ch, struct srp_request *req,
15508c2ecf20Sopenharmony_ci		       void **next_mr, void **end_mr, u32 idb_len,
15518c2ecf20Sopenharmony_ci		       __be32 *idb_rkey)
15528c2ecf20Sopenharmony_ci{
15538c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
15548c2ecf20Sopenharmony_ci	struct srp_device *dev = target->srp_host->srp_dev;
15558c2ecf20Sopenharmony_ci	struct srp_map_state state;
15568c2ecf20Sopenharmony_ci	struct srp_direct_buf idb_desc;
15578c2ecf20Sopenharmony_ci	struct scatterlist idb_sg[1];
15588c2ecf20Sopenharmony_ci	int ret;
15598c2ecf20Sopenharmony_ci
15608c2ecf20Sopenharmony_ci	memset(&state, 0, sizeof(state));
15618c2ecf20Sopenharmony_ci	memset(&idb_desc, 0, sizeof(idb_desc));
15628c2ecf20Sopenharmony_ci	state.gen.next = next_mr;
15638c2ecf20Sopenharmony_ci	state.gen.end = end_mr;
15648c2ecf20Sopenharmony_ci	state.desc = &idb_desc;
15658c2ecf20Sopenharmony_ci	state.base_dma_addr = req->indirect_dma_addr;
15668c2ecf20Sopenharmony_ci	state.dma_len = idb_len;
15678c2ecf20Sopenharmony_ci
15688c2ecf20Sopenharmony_ci	if (dev->use_fast_reg) {
15698c2ecf20Sopenharmony_ci		state.sg = idb_sg;
15708c2ecf20Sopenharmony_ci		sg_init_one(idb_sg, req->indirect_desc, idb_len);
15718c2ecf20Sopenharmony_ci		idb_sg->dma_address = req->indirect_dma_addr; /* hack! */
15728c2ecf20Sopenharmony_ci#ifdef CONFIG_NEED_SG_DMA_LENGTH
15738c2ecf20Sopenharmony_ci		idb_sg->dma_length = idb_sg->length;	      /* hack^2 */
15748c2ecf20Sopenharmony_ci#endif
15758c2ecf20Sopenharmony_ci		ret = srp_map_finish_fr(&state, req, ch, 1, NULL);
15768c2ecf20Sopenharmony_ci		if (ret < 0)
15778c2ecf20Sopenharmony_ci			return ret;
15788c2ecf20Sopenharmony_ci		WARN_ON_ONCE(ret < 1);
15798c2ecf20Sopenharmony_ci	} else {
15808c2ecf20Sopenharmony_ci		return -EINVAL;
15818c2ecf20Sopenharmony_ci	}
15828c2ecf20Sopenharmony_ci
15838c2ecf20Sopenharmony_ci	*idb_rkey = idb_desc.key;
15848c2ecf20Sopenharmony_ci
15858c2ecf20Sopenharmony_ci	return 0;
15868c2ecf20Sopenharmony_ci}
15878c2ecf20Sopenharmony_ci
15888c2ecf20Sopenharmony_cistatic void srp_check_mapping(struct srp_map_state *state,
15898c2ecf20Sopenharmony_ci			      struct srp_rdma_ch *ch, struct srp_request *req,
15908c2ecf20Sopenharmony_ci			      struct scatterlist *scat, int count)
15918c2ecf20Sopenharmony_ci{
15928c2ecf20Sopenharmony_ci	struct srp_device *dev = ch->target->srp_host->srp_dev;
15938c2ecf20Sopenharmony_ci	struct srp_fr_desc **pfr;
15948c2ecf20Sopenharmony_ci	u64 desc_len = 0, mr_len = 0;
15958c2ecf20Sopenharmony_ci	int i;
15968c2ecf20Sopenharmony_ci
15978c2ecf20Sopenharmony_ci	for (i = 0; i < state->ndesc; i++)
15988c2ecf20Sopenharmony_ci		desc_len += be32_to_cpu(req->indirect_desc[i].len);
15998c2ecf20Sopenharmony_ci	if (dev->use_fast_reg)
16008c2ecf20Sopenharmony_ci		for (i = 0, pfr = req->fr_list; i < state->nmdesc; i++, pfr++)
16018c2ecf20Sopenharmony_ci			mr_len += (*pfr)->mr->length;
16028c2ecf20Sopenharmony_ci	if (desc_len != scsi_bufflen(req->scmnd) ||
16038c2ecf20Sopenharmony_ci	    mr_len > scsi_bufflen(req->scmnd))
16048c2ecf20Sopenharmony_ci		pr_err("Inconsistent: scsi len %d <> desc len %lld <> mr len %lld; ndesc %d; nmdesc = %d\n",
16058c2ecf20Sopenharmony_ci		       scsi_bufflen(req->scmnd), desc_len, mr_len,
16068c2ecf20Sopenharmony_ci		       state->ndesc, state->nmdesc);
16078c2ecf20Sopenharmony_ci}
16088c2ecf20Sopenharmony_ci
16098c2ecf20Sopenharmony_ci/**
16108c2ecf20Sopenharmony_ci * srp_map_data() - map SCSI data buffer onto an SRP request
16118c2ecf20Sopenharmony_ci * @scmnd: SCSI command to map
16128c2ecf20Sopenharmony_ci * @ch: SRP RDMA channel
16138c2ecf20Sopenharmony_ci * @req: SRP request
16148c2ecf20Sopenharmony_ci *
16158c2ecf20Sopenharmony_ci * Returns the length in bytes of the SRP_CMD IU or a negative value if
16168c2ecf20Sopenharmony_ci * mapping failed. The size of any immediate data is not included in the
16178c2ecf20Sopenharmony_ci * return value.
16188c2ecf20Sopenharmony_ci */
16198c2ecf20Sopenharmony_cistatic int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch,
16208c2ecf20Sopenharmony_ci			struct srp_request *req)
16218c2ecf20Sopenharmony_ci{
16228c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
16238c2ecf20Sopenharmony_ci	struct scatterlist *scat, *sg;
16248c2ecf20Sopenharmony_ci	struct srp_cmd *cmd = req->cmd->buf;
16258c2ecf20Sopenharmony_ci	int i, len, nents, count, ret;
16268c2ecf20Sopenharmony_ci	struct srp_device *dev;
16278c2ecf20Sopenharmony_ci	struct ib_device *ibdev;
16288c2ecf20Sopenharmony_ci	struct srp_map_state state;
16298c2ecf20Sopenharmony_ci	struct srp_indirect_buf *indirect_hdr;
16308c2ecf20Sopenharmony_ci	u64 data_len;
16318c2ecf20Sopenharmony_ci	u32 idb_len, table_len;
16328c2ecf20Sopenharmony_ci	__be32 idb_rkey;
16338c2ecf20Sopenharmony_ci	u8 fmt;
16348c2ecf20Sopenharmony_ci
16358c2ecf20Sopenharmony_ci	req->cmd->num_sge = 1;
16368c2ecf20Sopenharmony_ci
16378c2ecf20Sopenharmony_ci	if (!scsi_sglist(scmnd) || scmnd->sc_data_direction == DMA_NONE)
16388c2ecf20Sopenharmony_ci		return sizeof(struct srp_cmd) + cmd->add_cdb_len;
16398c2ecf20Sopenharmony_ci
16408c2ecf20Sopenharmony_ci	if (scmnd->sc_data_direction != DMA_FROM_DEVICE &&
16418c2ecf20Sopenharmony_ci	    scmnd->sc_data_direction != DMA_TO_DEVICE) {
16428c2ecf20Sopenharmony_ci		shost_printk(KERN_WARNING, target->scsi_host,
16438c2ecf20Sopenharmony_ci			     PFX "Unhandled data direction %d\n",
16448c2ecf20Sopenharmony_ci			     scmnd->sc_data_direction);
16458c2ecf20Sopenharmony_ci		return -EINVAL;
16468c2ecf20Sopenharmony_ci	}
16478c2ecf20Sopenharmony_ci
16488c2ecf20Sopenharmony_ci	nents = scsi_sg_count(scmnd);
16498c2ecf20Sopenharmony_ci	scat  = scsi_sglist(scmnd);
16508c2ecf20Sopenharmony_ci	data_len = scsi_bufflen(scmnd);
16518c2ecf20Sopenharmony_ci
16528c2ecf20Sopenharmony_ci	dev = target->srp_host->srp_dev;
16538c2ecf20Sopenharmony_ci	ibdev = dev->dev;
16548c2ecf20Sopenharmony_ci
16558c2ecf20Sopenharmony_ci	count = ib_dma_map_sg(ibdev, scat, nents, scmnd->sc_data_direction);
16568c2ecf20Sopenharmony_ci	if (unlikely(count == 0))
16578c2ecf20Sopenharmony_ci		return -EIO;
16588c2ecf20Sopenharmony_ci
16598c2ecf20Sopenharmony_ci	if (ch->use_imm_data &&
16608c2ecf20Sopenharmony_ci	    count <= ch->max_imm_sge &&
16618c2ecf20Sopenharmony_ci	    SRP_IMM_DATA_OFFSET + data_len <= ch->max_it_iu_len &&
16628c2ecf20Sopenharmony_ci	    scmnd->sc_data_direction == DMA_TO_DEVICE) {
16638c2ecf20Sopenharmony_ci		struct srp_imm_buf *buf;
16648c2ecf20Sopenharmony_ci		struct ib_sge *sge = &req->cmd->sge[1];
16658c2ecf20Sopenharmony_ci
16668c2ecf20Sopenharmony_ci		fmt = SRP_DATA_DESC_IMM;
16678c2ecf20Sopenharmony_ci		len = SRP_IMM_DATA_OFFSET;
16688c2ecf20Sopenharmony_ci		req->nmdesc = 0;
16698c2ecf20Sopenharmony_ci		buf = (void *)cmd->add_data + cmd->add_cdb_len;
16708c2ecf20Sopenharmony_ci		buf->len = cpu_to_be32(data_len);
16718c2ecf20Sopenharmony_ci		WARN_ON_ONCE((void *)(buf + 1) > (void *)cmd + len);
16728c2ecf20Sopenharmony_ci		for_each_sg(scat, sg, count, i) {
16738c2ecf20Sopenharmony_ci			sge[i].addr   = sg_dma_address(sg);
16748c2ecf20Sopenharmony_ci			sge[i].length = sg_dma_len(sg);
16758c2ecf20Sopenharmony_ci			sge[i].lkey   = target->lkey;
16768c2ecf20Sopenharmony_ci		}
16778c2ecf20Sopenharmony_ci		req->cmd->num_sge += count;
16788c2ecf20Sopenharmony_ci		goto map_complete;
16798c2ecf20Sopenharmony_ci	}
16808c2ecf20Sopenharmony_ci
16818c2ecf20Sopenharmony_ci	fmt = SRP_DATA_DESC_DIRECT;
16828c2ecf20Sopenharmony_ci	len = sizeof(struct srp_cmd) + cmd->add_cdb_len +
16838c2ecf20Sopenharmony_ci		sizeof(struct srp_direct_buf);
16848c2ecf20Sopenharmony_ci
16858c2ecf20Sopenharmony_ci	if (count == 1 && target->global_rkey) {
16868c2ecf20Sopenharmony_ci		/*
16878c2ecf20Sopenharmony_ci		 * The midlayer only generated a single gather/scatter
16888c2ecf20Sopenharmony_ci		 * entry, or DMA mapping coalesced everything to a
16898c2ecf20Sopenharmony_ci		 * single entry.  So a direct descriptor along with
16908c2ecf20Sopenharmony_ci		 * the DMA MR suffices.
16918c2ecf20Sopenharmony_ci		 */
16928c2ecf20Sopenharmony_ci		struct srp_direct_buf *buf;
16938c2ecf20Sopenharmony_ci
16948c2ecf20Sopenharmony_ci		buf = (void *)cmd->add_data + cmd->add_cdb_len;
16958c2ecf20Sopenharmony_ci		buf->va  = cpu_to_be64(sg_dma_address(scat));
16968c2ecf20Sopenharmony_ci		buf->key = cpu_to_be32(target->global_rkey);
16978c2ecf20Sopenharmony_ci		buf->len = cpu_to_be32(sg_dma_len(scat));
16988c2ecf20Sopenharmony_ci
16998c2ecf20Sopenharmony_ci		req->nmdesc = 0;
17008c2ecf20Sopenharmony_ci		goto map_complete;
17018c2ecf20Sopenharmony_ci	}
17028c2ecf20Sopenharmony_ci
17038c2ecf20Sopenharmony_ci	/*
17048c2ecf20Sopenharmony_ci	 * We have more than one scatter/gather entry, so build our indirect
17058c2ecf20Sopenharmony_ci	 * descriptor table, trying to merge as many entries as we can.
17068c2ecf20Sopenharmony_ci	 */
17078c2ecf20Sopenharmony_ci	indirect_hdr = (void *)cmd->add_data + cmd->add_cdb_len;
17088c2ecf20Sopenharmony_ci
17098c2ecf20Sopenharmony_ci	ib_dma_sync_single_for_cpu(ibdev, req->indirect_dma_addr,
17108c2ecf20Sopenharmony_ci				   target->indirect_size, DMA_TO_DEVICE);
17118c2ecf20Sopenharmony_ci
17128c2ecf20Sopenharmony_ci	memset(&state, 0, sizeof(state));
17138c2ecf20Sopenharmony_ci	state.desc = req->indirect_desc;
17148c2ecf20Sopenharmony_ci	if (dev->use_fast_reg)
17158c2ecf20Sopenharmony_ci		ret = srp_map_sg_fr(&state, ch, req, scat, count);
17168c2ecf20Sopenharmony_ci	else
17178c2ecf20Sopenharmony_ci		ret = srp_map_sg_dma(&state, ch, req, scat, count);
17188c2ecf20Sopenharmony_ci	req->nmdesc = state.nmdesc;
17198c2ecf20Sopenharmony_ci	if (ret < 0)
17208c2ecf20Sopenharmony_ci		goto unmap;
17218c2ecf20Sopenharmony_ci
17228c2ecf20Sopenharmony_ci	{
17238c2ecf20Sopenharmony_ci		DEFINE_DYNAMIC_DEBUG_METADATA(ddm,
17248c2ecf20Sopenharmony_ci			"Memory mapping consistency check");
17258c2ecf20Sopenharmony_ci		if (DYNAMIC_DEBUG_BRANCH(ddm))
17268c2ecf20Sopenharmony_ci			srp_check_mapping(&state, ch, req, scat, count);
17278c2ecf20Sopenharmony_ci	}
17288c2ecf20Sopenharmony_ci
17298c2ecf20Sopenharmony_ci	/* We've mapped the request, now pull as much of the indirect
17308c2ecf20Sopenharmony_ci	 * descriptor table as we can into the command buffer. If this
17318c2ecf20Sopenharmony_ci	 * target is not using an external indirect table, we are
17328c2ecf20Sopenharmony_ci	 * guaranteed to fit into the command, as the SCSI layer won't
17338c2ecf20Sopenharmony_ci	 * give us more S/G entries than we allow.
17348c2ecf20Sopenharmony_ci	 */
17358c2ecf20Sopenharmony_ci	if (state.ndesc == 1) {
17368c2ecf20Sopenharmony_ci		/*
17378c2ecf20Sopenharmony_ci		 * Memory registration collapsed the sg-list into one entry,
17388c2ecf20Sopenharmony_ci		 * so use a direct descriptor.
17398c2ecf20Sopenharmony_ci		 */
17408c2ecf20Sopenharmony_ci		struct srp_direct_buf *buf;
17418c2ecf20Sopenharmony_ci
17428c2ecf20Sopenharmony_ci		buf = (void *)cmd->add_data + cmd->add_cdb_len;
17438c2ecf20Sopenharmony_ci		*buf = req->indirect_desc[0];
17448c2ecf20Sopenharmony_ci		goto map_complete;
17458c2ecf20Sopenharmony_ci	}
17468c2ecf20Sopenharmony_ci
17478c2ecf20Sopenharmony_ci	if (unlikely(target->cmd_sg_cnt < state.ndesc &&
17488c2ecf20Sopenharmony_ci						!target->allow_ext_sg)) {
17498c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, target->scsi_host,
17508c2ecf20Sopenharmony_ci			     "Could not fit S/G list into SRP_CMD\n");
17518c2ecf20Sopenharmony_ci		ret = -EIO;
17528c2ecf20Sopenharmony_ci		goto unmap;
17538c2ecf20Sopenharmony_ci	}
17548c2ecf20Sopenharmony_ci
17558c2ecf20Sopenharmony_ci	count = min(state.ndesc, target->cmd_sg_cnt);
17568c2ecf20Sopenharmony_ci	table_len = state.ndesc * sizeof (struct srp_direct_buf);
17578c2ecf20Sopenharmony_ci	idb_len = sizeof(struct srp_indirect_buf) + table_len;
17588c2ecf20Sopenharmony_ci
17598c2ecf20Sopenharmony_ci	fmt = SRP_DATA_DESC_INDIRECT;
17608c2ecf20Sopenharmony_ci	len = sizeof(struct srp_cmd) + cmd->add_cdb_len +
17618c2ecf20Sopenharmony_ci		sizeof(struct srp_indirect_buf);
17628c2ecf20Sopenharmony_ci	len += count * sizeof (struct srp_direct_buf);
17638c2ecf20Sopenharmony_ci
17648c2ecf20Sopenharmony_ci	memcpy(indirect_hdr->desc_list, req->indirect_desc,
17658c2ecf20Sopenharmony_ci	       count * sizeof (struct srp_direct_buf));
17668c2ecf20Sopenharmony_ci
17678c2ecf20Sopenharmony_ci	if (!target->global_rkey) {
17688c2ecf20Sopenharmony_ci		ret = srp_map_idb(ch, req, state.gen.next, state.gen.end,
17698c2ecf20Sopenharmony_ci				  idb_len, &idb_rkey);
17708c2ecf20Sopenharmony_ci		if (ret < 0)
17718c2ecf20Sopenharmony_ci			goto unmap;
17728c2ecf20Sopenharmony_ci		req->nmdesc++;
17738c2ecf20Sopenharmony_ci	} else {
17748c2ecf20Sopenharmony_ci		idb_rkey = cpu_to_be32(target->global_rkey);
17758c2ecf20Sopenharmony_ci	}
17768c2ecf20Sopenharmony_ci
17778c2ecf20Sopenharmony_ci	indirect_hdr->table_desc.va = cpu_to_be64(req->indirect_dma_addr);
17788c2ecf20Sopenharmony_ci	indirect_hdr->table_desc.key = idb_rkey;
17798c2ecf20Sopenharmony_ci	indirect_hdr->table_desc.len = cpu_to_be32(table_len);
17808c2ecf20Sopenharmony_ci	indirect_hdr->len = cpu_to_be32(state.total_len);
17818c2ecf20Sopenharmony_ci
17828c2ecf20Sopenharmony_ci	if (scmnd->sc_data_direction == DMA_TO_DEVICE)
17838c2ecf20Sopenharmony_ci		cmd->data_out_desc_cnt = count;
17848c2ecf20Sopenharmony_ci	else
17858c2ecf20Sopenharmony_ci		cmd->data_in_desc_cnt = count;
17868c2ecf20Sopenharmony_ci
17878c2ecf20Sopenharmony_ci	ib_dma_sync_single_for_device(ibdev, req->indirect_dma_addr, table_len,
17888c2ecf20Sopenharmony_ci				      DMA_TO_DEVICE);
17898c2ecf20Sopenharmony_ci
17908c2ecf20Sopenharmony_cimap_complete:
17918c2ecf20Sopenharmony_ci	if (scmnd->sc_data_direction == DMA_TO_DEVICE)
17928c2ecf20Sopenharmony_ci		cmd->buf_fmt = fmt << 4;
17938c2ecf20Sopenharmony_ci	else
17948c2ecf20Sopenharmony_ci		cmd->buf_fmt = fmt;
17958c2ecf20Sopenharmony_ci
17968c2ecf20Sopenharmony_ci	return len;
17978c2ecf20Sopenharmony_ci
17988c2ecf20Sopenharmony_ciunmap:
17998c2ecf20Sopenharmony_ci	srp_unmap_data(scmnd, ch, req);
18008c2ecf20Sopenharmony_ci	if (ret == -ENOMEM && req->nmdesc >= target->mr_pool_size)
18018c2ecf20Sopenharmony_ci		ret = -E2BIG;
18028c2ecf20Sopenharmony_ci	return ret;
18038c2ecf20Sopenharmony_ci}
18048c2ecf20Sopenharmony_ci
18058c2ecf20Sopenharmony_ci/*
18068c2ecf20Sopenharmony_ci * Return an IU and possible credit to the free pool
18078c2ecf20Sopenharmony_ci */
18088c2ecf20Sopenharmony_cistatic void srp_put_tx_iu(struct srp_rdma_ch *ch, struct srp_iu *iu,
18098c2ecf20Sopenharmony_ci			  enum srp_iu_type iu_type)
18108c2ecf20Sopenharmony_ci{
18118c2ecf20Sopenharmony_ci	unsigned long flags;
18128c2ecf20Sopenharmony_ci
18138c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ch->lock, flags);
18148c2ecf20Sopenharmony_ci	list_add(&iu->list, &ch->free_tx);
18158c2ecf20Sopenharmony_ci	if (iu_type != SRP_IU_RSP)
18168c2ecf20Sopenharmony_ci		++ch->req_lim;
18178c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ch->lock, flags);
18188c2ecf20Sopenharmony_ci}
18198c2ecf20Sopenharmony_ci
18208c2ecf20Sopenharmony_ci/*
18218c2ecf20Sopenharmony_ci * Must be called with ch->lock held to protect req_lim and free_tx.
18228c2ecf20Sopenharmony_ci * If IU is not sent, it must be returned using srp_put_tx_iu().
18238c2ecf20Sopenharmony_ci *
18248c2ecf20Sopenharmony_ci * Note:
18258c2ecf20Sopenharmony_ci * An upper limit for the number of allocated information units for each
18268c2ecf20Sopenharmony_ci * request type is:
18278c2ecf20Sopenharmony_ci * - SRP_IU_CMD: SRP_CMD_SQ_SIZE, since the SCSI mid-layer never queues
18288c2ecf20Sopenharmony_ci *   more than Scsi_Host.can_queue requests.
18298c2ecf20Sopenharmony_ci * - SRP_IU_TSK_MGMT: SRP_TSK_MGMT_SQ_SIZE.
18308c2ecf20Sopenharmony_ci * - SRP_IU_RSP: 1, since a conforming SRP target never sends more than
18318c2ecf20Sopenharmony_ci *   one unanswered SRP request to an initiator.
18328c2ecf20Sopenharmony_ci */
18338c2ecf20Sopenharmony_cistatic struct srp_iu *__srp_get_tx_iu(struct srp_rdma_ch *ch,
18348c2ecf20Sopenharmony_ci				      enum srp_iu_type iu_type)
18358c2ecf20Sopenharmony_ci{
18368c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
18378c2ecf20Sopenharmony_ci	s32 rsv = (iu_type == SRP_IU_TSK_MGMT) ? 0 : SRP_TSK_MGMT_SQ_SIZE;
18388c2ecf20Sopenharmony_ci	struct srp_iu *iu;
18398c2ecf20Sopenharmony_ci
18408c2ecf20Sopenharmony_ci	lockdep_assert_held(&ch->lock);
18418c2ecf20Sopenharmony_ci
18428c2ecf20Sopenharmony_ci	ib_process_cq_direct(ch->send_cq, -1);
18438c2ecf20Sopenharmony_ci
18448c2ecf20Sopenharmony_ci	if (list_empty(&ch->free_tx))
18458c2ecf20Sopenharmony_ci		return NULL;
18468c2ecf20Sopenharmony_ci
18478c2ecf20Sopenharmony_ci	/* Initiator responses to target requests do not consume credits */
18488c2ecf20Sopenharmony_ci	if (iu_type != SRP_IU_RSP) {
18498c2ecf20Sopenharmony_ci		if (ch->req_lim <= rsv) {
18508c2ecf20Sopenharmony_ci			++target->zero_req_lim;
18518c2ecf20Sopenharmony_ci			return NULL;
18528c2ecf20Sopenharmony_ci		}
18538c2ecf20Sopenharmony_ci
18548c2ecf20Sopenharmony_ci		--ch->req_lim;
18558c2ecf20Sopenharmony_ci	}
18568c2ecf20Sopenharmony_ci
18578c2ecf20Sopenharmony_ci	iu = list_first_entry(&ch->free_tx, struct srp_iu, list);
18588c2ecf20Sopenharmony_ci	list_del(&iu->list);
18598c2ecf20Sopenharmony_ci	return iu;
18608c2ecf20Sopenharmony_ci}
18618c2ecf20Sopenharmony_ci
18628c2ecf20Sopenharmony_ci/*
18638c2ecf20Sopenharmony_ci * Note: if this function is called from inside ib_drain_sq() then it will
18648c2ecf20Sopenharmony_ci * be called without ch->lock being held. If ib_drain_sq() dequeues a WQE
18658c2ecf20Sopenharmony_ci * with status IB_WC_SUCCESS then that's a bug.
18668c2ecf20Sopenharmony_ci */
18678c2ecf20Sopenharmony_cistatic void srp_send_done(struct ib_cq *cq, struct ib_wc *wc)
18688c2ecf20Sopenharmony_ci{
18698c2ecf20Sopenharmony_ci	struct srp_iu *iu = container_of(wc->wr_cqe, struct srp_iu, cqe);
18708c2ecf20Sopenharmony_ci	struct srp_rdma_ch *ch = cq->cq_context;
18718c2ecf20Sopenharmony_ci
18728c2ecf20Sopenharmony_ci	if (unlikely(wc->status != IB_WC_SUCCESS)) {
18738c2ecf20Sopenharmony_ci		srp_handle_qp_err(cq, wc, "SEND");
18748c2ecf20Sopenharmony_ci		return;
18758c2ecf20Sopenharmony_ci	}
18768c2ecf20Sopenharmony_ci
18778c2ecf20Sopenharmony_ci	lockdep_assert_held(&ch->lock);
18788c2ecf20Sopenharmony_ci
18798c2ecf20Sopenharmony_ci	list_add(&iu->list, &ch->free_tx);
18808c2ecf20Sopenharmony_ci}
18818c2ecf20Sopenharmony_ci
18828c2ecf20Sopenharmony_ci/**
18838c2ecf20Sopenharmony_ci * srp_post_send() - send an SRP information unit
18848c2ecf20Sopenharmony_ci * @ch: RDMA channel over which to send the information unit.
18858c2ecf20Sopenharmony_ci * @iu: Information unit to send.
18868c2ecf20Sopenharmony_ci * @len: Length of the information unit excluding immediate data.
18878c2ecf20Sopenharmony_ci */
18888c2ecf20Sopenharmony_cistatic int srp_post_send(struct srp_rdma_ch *ch, struct srp_iu *iu, int len)
18898c2ecf20Sopenharmony_ci{
18908c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
18918c2ecf20Sopenharmony_ci	struct ib_send_wr wr;
18928c2ecf20Sopenharmony_ci
18938c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(iu->num_sge > SRP_MAX_SGE))
18948c2ecf20Sopenharmony_ci		return -EINVAL;
18958c2ecf20Sopenharmony_ci
18968c2ecf20Sopenharmony_ci	iu->sge[0].addr   = iu->dma;
18978c2ecf20Sopenharmony_ci	iu->sge[0].length = len;
18988c2ecf20Sopenharmony_ci	iu->sge[0].lkey   = target->lkey;
18998c2ecf20Sopenharmony_ci
19008c2ecf20Sopenharmony_ci	iu->cqe.done = srp_send_done;
19018c2ecf20Sopenharmony_ci
19028c2ecf20Sopenharmony_ci	wr.next       = NULL;
19038c2ecf20Sopenharmony_ci	wr.wr_cqe     = &iu->cqe;
19048c2ecf20Sopenharmony_ci	wr.sg_list    = &iu->sge[0];
19058c2ecf20Sopenharmony_ci	wr.num_sge    = iu->num_sge;
19068c2ecf20Sopenharmony_ci	wr.opcode     = IB_WR_SEND;
19078c2ecf20Sopenharmony_ci	wr.send_flags = IB_SEND_SIGNALED;
19088c2ecf20Sopenharmony_ci
19098c2ecf20Sopenharmony_ci	return ib_post_send(ch->qp, &wr, NULL);
19108c2ecf20Sopenharmony_ci}
19118c2ecf20Sopenharmony_ci
19128c2ecf20Sopenharmony_cistatic int srp_post_recv(struct srp_rdma_ch *ch, struct srp_iu *iu)
19138c2ecf20Sopenharmony_ci{
19148c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
19158c2ecf20Sopenharmony_ci	struct ib_recv_wr wr;
19168c2ecf20Sopenharmony_ci	struct ib_sge list;
19178c2ecf20Sopenharmony_ci
19188c2ecf20Sopenharmony_ci	list.addr   = iu->dma;
19198c2ecf20Sopenharmony_ci	list.length = iu->size;
19208c2ecf20Sopenharmony_ci	list.lkey   = target->lkey;
19218c2ecf20Sopenharmony_ci
19228c2ecf20Sopenharmony_ci	iu->cqe.done = srp_recv_done;
19238c2ecf20Sopenharmony_ci
19248c2ecf20Sopenharmony_ci	wr.next     = NULL;
19258c2ecf20Sopenharmony_ci	wr.wr_cqe   = &iu->cqe;
19268c2ecf20Sopenharmony_ci	wr.sg_list  = &list;
19278c2ecf20Sopenharmony_ci	wr.num_sge  = 1;
19288c2ecf20Sopenharmony_ci
19298c2ecf20Sopenharmony_ci	return ib_post_recv(ch->qp, &wr, NULL);
19308c2ecf20Sopenharmony_ci}
19318c2ecf20Sopenharmony_ci
19328c2ecf20Sopenharmony_cistatic void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp)
19338c2ecf20Sopenharmony_ci{
19348c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
19358c2ecf20Sopenharmony_ci	struct srp_request *req;
19368c2ecf20Sopenharmony_ci	struct scsi_cmnd *scmnd;
19378c2ecf20Sopenharmony_ci	unsigned long flags;
19388c2ecf20Sopenharmony_ci
19398c2ecf20Sopenharmony_ci	if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) {
19408c2ecf20Sopenharmony_ci		spin_lock_irqsave(&ch->lock, flags);
19418c2ecf20Sopenharmony_ci		ch->req_lim += be32_to_cpu(rsp->req_lim_delta);
19428c2ecf20Sopenharmony_ci		if (rsp->tag == ch->tsk_mgmt_tag) {
19438c2ecf20Sopenharmony_ci			ch->tsk_mgmt_status = -1;
19448c2ecf20Sopenharmony_ci			if (be32_to_cpu(rsp->resp_data_len) >= 4)
19458c2ecf20Sopenharmony_ci				ch->tsk_mgmt_status = rsp->data[3];
19468c2ecf20Sopenharmony_ci			complete(&ch->tsk_mgmt_done);
19478c2ecf20Sopenharmony_ci		} else {
19488c2ecf20Sopenharmony_ci			shost_printk(KERN_ERR, target->scsi_host,
19498c2ecf20Sopenharmony_ci				     "Received tsk mgmt response too late for tag %#llx\n",
19508c2ecf20Sopenharmony_ci				     rsp->tag);
19518c2ecf20Sopenharmony_ci		}
19528c2ecf20Sopenharmony_ci		spin_unlock_irqrestore(&ch->lock, flags);
19538c2ecf20Sopenharmony_ci	} else {
19548c2ecf20Sopenharmony_ci		scmnd = scsi_host_find_tag(target->scsi_host, rsp->tag);
19558c2ecf20Sopenharmony_ci		if (scmnd) {
19568c2ecf20Sopenharmony_ci			req = scsi_cmd_priv(scmnd);
19578c2ecf20Sopenharmony_ci			scmnd = srp_claim_req(ch, req, NULL, scmnd);
19588c2ecf20Sopenharmony_ci		}
19598c2ecf20Sopenharmony_ci		if (!scmnd) {
19608c2ecf20Sopenharmony_ci			shost_printk(KERN_ERR, target->scsi_host,
19618c2ecf20Sopenharmony_ci				     "Null scmnd for RSP w/tag %#016llx received on ch %td / QP %#x\n",
19628c2ecf20Sopenharmony_ci				     rsp->tag, ch - target->ch, ch->qp->qp_num);
19638c2ecf20Sopenharmony_ci
19648c2ecf20Sopenharmony_ci			spin_lock_irqsave(&ch->lock, flags);
19658c2ecf20Sopenharmony_ci			ch->req_lim += be32_to_cpu(rsp->req_lim_delta);
19668c2ecf20Sopenharmony_ci			spin_unlock_irqrestore(&ch->lock, flags);
19678c2ecf20Sopenharmony_ci
19688c2ecf20Sopenharmony_ci			return;
19698c2ecf20Sopenharmony_ci		}
19708c2ecf20Sopenharmony_ci		scmnd->result = rsp->status;
19718c2ecf20Sopenharmony_ci
19728c2ecf20Sopenharmony_ci		if (rsp->flags & SRP_RSP_FLAG_SNSVALID) {
19738c2ecf20Sopenharmony_ci			memcpy(scmnd->sense_buffer, rsp->data +
19748c2ecf20Sopenharmony_ci			       be32_to_cpu(rsp->resp_data_len),
19758c2ecf20Sopenharmony_ci			       min_t(int, be32_to_cpu(rsp->sense_data_len),
19768c2ecf20Sopenharmony_ci				     SCSI_SENSE_BUFFERSIZE));
19778c2ecf20Sopenharmony_ci		}
19788c2ecf20Sopenharmony_ci
19798c2ecf20Sopenharmony_ci		if (unlikely(rsp->flags & SRP_RSP_FLAG_DIUNDER))
19808c2ecf20Sopenharmony_ci			scsi_set_resid(scmnd, be32_to_cpu(rsp->data_in_res_cnt));
19818c2ecf20Sopenharmony_ci		else if (unlikely(rsp->flags & SRP_RSP_FLAG_DOUNDER))
19828c2ecf20Sopenharmony_ci			scsi_set_resid(scmnd, be32_to_cpu(rsp->data_out_res_cnt));
19838c2ecf20Sopenharmony_ci
19848c2ecf20Sopenharmony_ci		srp_free_req(ch, req, scmnd,
19858c2ecf20Sopenharmony_ci			     be32_to_cpu(rsp->req_lim_delta));
19868c2ecf20Sopenharmony_ci
19878c2ecf20Sopenharmony_ci		scmnd->scsi_done(scmnd);
19888c2ecf20Sopenharmony_ci	}
19898c2ecf20Sopenharmony_ci}
19908c2ecf20Sopenharmony_ci
19918c2ecf20Sopenharmony_cistatic int srp_response_common(struct srp_rdma_ch *ch, s32 req_delta,
19928c2ecf20Sopenharmony_ci			       void *rsp, int len)
19938c2ecf20Sopenharmony_ci{
19948c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
19958c2ecf20Sopenharmony_ci	struct ib_device *dev = target->srp_host->srp_dev->dev;
19968c2ecf20Sopenharmony_ci	unsigned long flags;
19978c2ecf20Sopenharmony_ci	struct srp_iu *iu;
19988c2ecf20Sopenharmony_ci	int err;
19998c2ecf20Sopenharmony_ci
20008c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ch->lock, flags);
20018c2ecf20Sopenharmony_ci	ch->req_lim += req_delta;
20028c2ecf20Sopenharmony_ci	iu = __srp_get_tx_iu(ch, SRP_IU_RSP);
20038c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ch->lock, flags);
20048c2ecf20Sopenharmony_ci
20058c2ecf20Sopenharmony_ci	if (!iu) {
20068c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, target->scsi_host, PFX
20078c2ecf20Sopenharmony_ci			     "no IU available to send response\n");
20088c2ecf20Sopenharmony_ci		return 1;
20098c2ecf20Sopenharmony_ci	}
20108c2ecf20Sopenharmony_ci
20118c2ecf20Sopenharmony_ci	iu->num_sge = 1;
20128c2ecf20Sopenharmony_ci	ib_dma_sync_single_for_cpu(dev, iu->dma, len, DMA_TO_DEVICE);
20138c2ecf20Sopenharmony_ci	memcpy(iu->buf, rsp, len);
20148c2ecf20Sopenharmony_ci	ib_dma_sync_single_for_device(dev, iu->dma, len, DMA_TO_DEVICE);
20158c2ecf20Sopenharmony_ci
20168c2ecf20Sopenharmony_ci	err = srp_post_send(ch, iu, len);
20178c2ecf20Sopenharmony_ci	if (err) {
20188c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, target->scsi_host, PFX
20198c2ecf20Sopenharmony_ci			     "unable to post response: %d\n", err);
20208c2ecf20Sopenharmony_ci		srp_put_tx_iu(ch, iu, SRP_IU_RSP);
20218c2ecf20Sopenharmony_ci	}
20228c2ecf20Sopenharmony_ci
20238c2ecf20Sopenharmony_ci	return err;
20248c2ecf20Sopenharmony_ci}
20258c2ecf20Sopenharmony_ci
20268c2ecf20Sopenharmony_cistatic void srp_process_cred_req(struct srp_rdma_ch *ch,
20278c2ecf20Sopenharmony_ci				 struct srp_cred_req *req)
20288c2ecf20Sopenharmony_ci{
20298c2ecf20Sopenharmony_ci	struct srp_cred_rsp rsp = {
20308c2ecf20Sopenharmony_ci		.opcode = SRP_CRED_RSP,
20318c2ecf20Sopenharmony_ci		.tag = req->tag,
20328c2ecf20Sopenharmony_ci	};
20338c2ecf20Sopenharmony_ci	s32 delta = be32_to_cpu(req->req_lim_delta);
20348c2ecf20Sopenharmony_ci
20358c2ecf20Sopenharmony_ci	if (srp_response_common(ch, delta, &rsp, sizeof(rsp)))
20368c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, ch->target->scsi_host, PFX
20378c2ecf20Sopenharmony_ci			     "problems processing SRP_CRED_REQ\n");
20388c2ecf20Sopenharmony_ci}
20398c2ecf20Sopenharmony_ci
20408c2ecf20Sopenharmony_cistatic void srp_process_aer_req(struct srp_rdma_ch *ch,
20418c2ecf20Sopenharmony_ci				struct srp_aer_req *req)
20428c2ecf20Sopenharmony_ci{
20438c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
20448c2ecf20Sopenharmony_ci	struct srp_aer_rsp rsp = {
20458c2ecf20Sopenharmony_ci		.opcode = SRP_AER_RSP,
20468c2ecf20Sopenharmony_ci		.tag = req->tag,
20478c2ecf20Sopenharmony_ci	};
20488c2ecf20Sopenharmony_ci	s32 delta = be32_to_cpu(req->req_lim_delta);
20498c2ecf20Sopenharmony_ci
20508c2ecf20Sopenharmony_ci	shost_printk(KERN_ERR, target->scsi_host, PFX
20518c2ecf20Sopenharmony_ci		     "ignoring AER for LUN %llu\n", scsilun_to_int(&req->lun));
20528c2ecf20Sopenharmony_ci
20538c2ecf20Sopenharmony_ci	if (srp_response_common(ch, delta, &rsp, sizeof(rsp)))
20548c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, target->scsi_host, PFX
20558c2ecf20Sopenharmony_ci			     "problems processing SRP_AER_REQ\n");
20568c2ecf20Sopenharmony_ci}
20578c2ecf20Sopenharmony_ci
20588c2ecf20Sopenharmony_cistatic void srp_recv_done(struct ib_cq *cq, struct ib_wc *wc)
20598c2ecf20Sopenharmony_ci{
20608c2ecf20Sopenharmony_ci	struct srp_iu *iu = container_of(wc->wr_cqe, struct srp_iu, cqe);
20618c2ecf20Sopenharmony_ci	struct srp_rdma_ch *ch = cq->cq_context;
20628c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
20638c2ecf20Sopenharmony_ci	struct ib_device *dev = target->srp_host->srp_dev->dev;
20648c2ecf20Sopenharmony_ci	int res;
20658c2ecf20Sopenharmony_ci	u8 opcode;
20668c2ecf20Sopenharmony_ci
20678c2ecf20Sopenharmony_ci	if (unlikely(wc->status != IB_WC_SUCCESS)) {
20688c2ecf20Sopenharmony_ci		srp_handle_qp_err(cq, wc, "RECV");
20698c2ecf20Sopenharmony_ci		return;
20708c2ecf20Sopenharmony_ci	}
20718c2ecf20Sopenharmony_ci
20728c2ecf20Sopenharmony_ci	ib_dma_sync_single_for_cpu(dev, iu->dma, ch->max_ti_iu_len,
20738c2ecf20Sopenharmony_ci				   DMA_FROM_DEVICE);
20748c2ecf20Sopenharmony_ci
20758c2ecf20Sopenharmony_ci	opcode = *(u8 *) iu->buf;
20768c2ecf20Sopenharmony_ci
20778c2ecf20Sopenharmony_ci	if (0) {
20788c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, target->scsi_host,
20798c2ecf20Sopenharmony_ci			     PFX "recv completion, opcode 0x%02x\n", opcode);
20808c2ecf20Sopenharmony_ci		print_hex_dump(KERN_ERR, "", DUMP_PREFIX_OFFSET, 8, 1,
20818c2ecf20Sopenharmony_ci			       iu->buf, wc->byte_len, true);
20828c2ecf20Sopenharmony_ci	}
20838c2ecf20Sopenharmony_ci
20848c2ecf20Sopenharmony_ci	switch (opcode) {
20858c2ecf20Sopenharmony_ci	case SRP_RSP:
20868c2ecf20Sopenharmony_ci		srp_process_rsp(ch, iu->buf);
20878c2ecf20Sopenharmony_ci		break;
20888c2ecf20Sopenharmony_ci
20898c2ecf20Sopenharmony_ci	case SRP_CRED_REQ:
20908c2ecf20Sopenharmony_ci		srp_process_cred_req(ch, iu->buf);
20918c2ecf20Sopenharmony_ci		break;
20928c2ecf20Sopenharmony_ci
20938c2ecf20Sopenharmony_ci	case SRP_AER_REQ:
20948c2ecf20Sopenharmony_ci		srp_process_aer_req(ch, iu->buf);
20958c2ecf20Sopenharmony_ci		break;
20968c2ecf20Sopenharmony_ci
20978c2ecf20Sopenharmony_ci	case SRP_T_LOGOUT:
20988c2ecf20Sopenharmony_ci		/* XXX Handle target logout */
20998c2ecf20Sopenharmony_ci		shost_printk(KERN_WARNING, target->scsi_host,
21008c2ecf20Sopenharmony_ci			     PFX "Got target logout request\n");
21018c2ecf20Sopenharmony_ci		break;
21028c2ecf20Sopenharmony_ci
21038c2ecf20Sopenharmony_ci	default:
21048c2ecf20Sopenharmony_ci		shost_printk(KERN_WARNING, target->scsi_host,
21058c2ecf20Sopenharmony_ci			     PFX "Unhandled SRP opcode 0x%02x\n", opcode);
21068c2ecf20Sopenharmony_ci		break;
21078c2ecf20Sopenharmony_ci	}
21088c2ecf20Sopenharmony_ci
21098c2ecf20Sopenharmony_ci	ib_dma_sync_single_for_device(dev, iu->dma, ch->max_ti_iu_len,
21108c2ecf20Sopenharmony_ci				      DMA_FROM_DEVICE);
21118c2ecf20Sopenharmony_ci
21128c2ecf20Sopenharmony_ci	res = srp_post_recv(ch, iu);
21138c2ecf20Sopenharmony_ci	if (res != 0)
21148c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, target->scsi_host,
21158c2ecf20Sopenharmony_ci			     PFX "Recv failed with error code %d\n", res);
21168c2ecf20Sopenharmony_ci}
21178c2ecf20Sopenharmony_ci
21188c2ecf20Sopenharmony_ci/**
21198c2ecf20Sopenharmony_ci * srp_tl_err_work() - handle a transport layer error
21208c2ecf20Sopenharmony_ci * @work: Work structure embedded in an SRP target port.
21218c2ecf20Sopenharmony_ci *
21228c2ecf20Sopenharmony_ci * Note: This function may get invoked before the rport has been created,
21238c2ecf20Sopenharmony_ci * hence the target->rport test.
21248c2ecf20Sopenharmony_ci */
21258c2ecf20Sopenharmony_cistatic void srp_tl_err_work(struct work_struct *work)
21268c2ecf20Sopenharmony_ci{
21278c2ecf20Sopenharmony_ci	struct srp_target_port *target;
21288c2ecf20Sopenharmony_ci
21298c2ecf20Sopenharmony_ci	target = container_of(work, struct srp_target_port, tl_err_work);
21308c2ecf20Sopenharmony_ci	if (target->rport)
21318c2ecf20Sopenharmony_ci		srp_start_tl_fail_timers(target->rport);
21328c2ecf20Sopenharmony_ci}
21338c2ecf20Sopenharmony_ci
21348c2ecf20Sopenharmony_cistatic void srp_handle_qp_err(struct ib_cq *cq, struct ib_wc *wc,
21358c2ecf20Sopenharmony_ci		const char *opname)
21368c2ecf20Sopenharmony_ci{
21378c2ecf20Sopenharmony_ci	struct srp_rdma_ch *ch = cq->cq_context;
21388c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
21398c2ecf20Sopenharmony_ci
21408c2ecf20Sopenharmony_ci	if (ch->connected && !target->qp_in_error) {
21418c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, target->scsi_host,
21428c2ecf20Sopenharmony_ci			     PFX "failed %s status %s (%d) for CQE %p\n",
21438c2ecf20Sopenharmony_ci			     opname, ib_wc_status_msg(wc->status), wc->status,
21448c2ecf20Sopenharmony_ci			     wc->wr_cqe);
21458c2ecf20Sopenharmony_ci		queue_work(system_long_wq, &target->tl_err_work);
21468c2ecf20Sopenharmony_ci	}
21478c2ecf20Sopenharmony_ci	target->qp_in_error = true;
21488c2ecf20Sopenharmony_ci}
21498c2ecf20Sopenharmony_ci
21508c2ecf20Sopenharmony_cistatic int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
21518c2ecf20Sopenharmony_ci{
21528c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(shost);
21538c2ecf20Sopenharmony_ci	struct srp_rdma_ch *ch;
21548c2ecf20Sopenharmony_ci	struct srp_request *req = scsi_cmd_priv(scmnd);
21558c2ecf20Sopenharmony_ci	struct srp_iu *iu;
21568c2ecf20Sopenharmony_ci	struct srp_cmd *cmd;
21578c2ecf20Sopenharmony_ci	struct ib_device *dev;
21588c2ecf20Sopenharmony_ci	unsigned long flags;
21598c2ecf20Sopenharmony_ci	u32 tag;
21608c2ecf20Sopenharmony_ci	int len, ret;
21618c2ecf20Sopenharmony_ci
21628c2ecf20Sopenharmony_ci	scmnd->result = srp_chkready(target->rport);
21638c2ecf20Sopenharmony_ci	if (unlikely(scmnd->result))
21648c2ecf20Sopenharmony_ci		goto err;
21658c2ecf20Sopenharmony_ci
21668c2ecf20Sopenharmony_ci	WARN_ON_ONCE(scmnd->request->tag < 0);
21678c2ecf20Sopenharmony_ci	tag = blk_mq_unique_tag(scmnd->request);
21688c2ecf20Sopenharmony_ci	ch = &target->ch[blk_mq_unique_tag_to_hwq(tag)];
21698c2ecf20Sopenharmony_ci
21708c2ecf20Sopenharmony_ci	spin_lock_irqsave(&ch->lock, flags);
21718c2ecf20Sopenharmony_ci	iu = __srp_get_tx_iu(ch, SRP_IU_CMD);
21728c2ecf20Sopenharmony_ci	spin_unlock_irqrestore(&ch->lock, flags);
21738c2ecf20Sopenharmony_ci
21748c2ecf20Sopenharmony_ci	if (!iu)
21758c2ecf20Sopenharmony_ci		goto err;
21768c2ecf20Sopenharmony_ci
21778c2ecf20Sopenharmony_ci	dev = target->srp_host->srp_dev->dev;
21788c2ecf20Sopenharmony_ci	ib_dma_sync_single_for_cpu(dev, iu->dma, ch->max_it_iu_len,
21798c2ecf20Sopenharmony_ci				   DMA_TO_DEVICE);
21808c2ecf20Sopenharmony_ci
21818c2ecf20Sopenharmony_ci	cmd = iu->buf;
21828c2ecf20Sopenharmony_ci	memset(cmd, 0, sizeof *cmd);
21838c2ecf20Sopenharmony_ci
21848c2ecf20Sopenharmony_ci	cmd->opcode = SRP_CMD;
21858c2ecf20Sopenharmony_ci	int_to_scsilun(scmnd->device->lun, &cmd->lun);
21868c2ecf20Sopenharmony_ci	cmd->tag    = tag;
21878c2ecf20Sopenharmony_ci	memcpy(cmd->cdb, scmnd->cmnd, scmnd->cmd_len);
21888c2ecf20Sopenharmony_ci	if (unlikely(scmnd->cmd_len > sizeof(cmd->cdb))) {
21898c2ecf20Sopenharmony_ci		cmd->add_cdb_len = round_up(scmnd->cmd_len - sizeof(cmd->cdb),
21908c2ecf20Sopenharmony_ci					    4);
21918c2ecf20Sopenharmony_ci		if (WARN_ON_ONCE(cmd->add_cdb_len > SRP_MAX_ADD_CDB_LEN))
21928c2ecf20Sopenharmony_ci			goto err_iu;
21938c2ecf20Sopenharmony_ci	}
21948c2ecf20Sopenharmony_ci
21958c2ecf20Sopenharmony_ci	req->scmnd    = scmnd;
21968c2ecf20Sopenharmony_ci	req->cmd      = iu;
21978c2ecf20Sopenharmony_ci
21988c2ecf20Sopenharmony_ci	len = srp_map_data(scmnd, ch, req);
21998c2ecf20Sopenharmony_ci	if (len < 0) {
22008c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, target->scsi_host,
22018c2ecf20Sopenharmony_ci			     PFX "Failed to map data (%d)\n", len);
22028c2ecf20Sopenharmony_ci		/*
22038c2ecf20Sopenharmony_ci		 * If we ran out of memory descriptors (-ENOMEM) because an
22048c2ecf20Sopenharmony_ci		 * application is queuing many requests with more than
22058c2ecf20Sopenharmony_ci		 * max_pages_per_mr sg-list elements, tell the SCSI mid-layer
22068c2ecf20Sopenharmony_ci		 * to reduce queue depth temporarily.
22078c2ecf20Sopenharmony_ci		 */
22088c2ecf20Sopenharmony_ci		scmnd->result = len == -ENOMEM ?
22098c2ecf20Sopenharmony_ci			DID_OK << 16 | QUEUE_FULL << 1 : DID_ERROR << 16;
22108c2ecf20Sopenharmony_ci		goto err_iu;
22118c2ecf20Sopenharmony_ci	}
22128c2ecf20Sopenharmony_ci
22138c2ecf20Sopenharmony_ci	ib_dma_sync_single_for_device(dev, iu->dma, ch->max_it_iu_len,
22148c2ecf20Sopenharmony_ci				      DMA_TO_DEVICE);
22158c2ecf20Sopenharmony_ci
22168c2ecf20Sopenharmony_ci	if (srp_post_send(ch, iu, len)) {
22178c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n");
22188c2ecf20Sopenharmony_ci		scmnd->result = DID_ERROR << 16;
22198c2ecf20Sopenharmony_ci		goto err_unmap;
22208c2ecf20Sopenharmony_ci	}
22218c2ecf20Sopenharmony_ci
22228c2ecf20Sopenharmony_ci	return 0;
22238c2ecf20Sopenharmony_ci
22248c2ecf20Sopenharmony_cierr_unmap:
22258c2ecf20Sopenharmony_ci	srp_unmap_data(scmnd, ch, req);
22268c2ecf20Sopenharmony_ci
22278c2ecf20Sopenharmony_cierr_iu:
22288c2ecf20Sopenharmony_ci	srp_put_tx_iu(ch, iu, SRP_IU_CMD);
22298c2ecf20Sopenharmony_ci
22308c2ecf20Sopenharmony_ci	/*
22318c2ecf20Sopenharmony_ci	 * Avoid that the loops that iterate over the request ring can
22328c2ecf20Sopenharmony_ci	 * encounter a dangling SCSI command pointer.
22338c2ecf20Sopenharmony_ci	 */
22348c2ecf20Sopenharmony_ci	req->scmnd = NULL;
22358c2ecf20Sopenharmony_ci
22368c2ecf20Sopenharmony_cierr:
22378c2ecf20Sopenharmony_ci	if (scmnd->result) {
22388c2ecf20Sopenharmony_ci		scmnd->scsi_done(scmnd);
22398c2ecf20Sopenharmony_ci		ret = 0;
22408c2ecf20Sopenharmony_ci	} else {
22418c2ecf20Sopenharmony_ci		ret = SCSI_MLQUEUE_HOST_BUSY;
22428c2ecf20Sopenharmony_ci	}
22438c2ecf20Sopenharmony_ci
22448c2ecf20Sopenharmony_ci	return ret;
22458c2ecf20Sopenharmony_ci}
22468c2ecf20Sopenharmony_ci
22478c2ecf20Sopenharmony_ci/*
22488c2ecf20Sopenharmony_ci * Note: the resources allocated in this function are freed in
22498c2ecf20Sopenharmony_ci * srp_free_ch_ib().
22508c2ecf20Sopenharmony_ci */
22518c2ecf20Sopenharmony_cistatic int srp_alloc_iu_bufs(struct srp_rdma_ch *ch)
22528c2ecf20Sopenharmony_ci{
22538c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
22548c2ecf20Sopenharmony_ci	int i;
22558c2ecf20Sopenharmony_ci
22568c2ecf20Sopenharmony_ci	ch->rx_ring = kcalloc(target->queue_size, sizeof(*ch->rx_ring),
22578c2ecf20Sopenharmony_ci			      GFP_KERNEL);
22588c2ecf20Sopenharmony_ci	if (!ch->rx_ring)
22598c2ecf20Sopenharmony_ci		goto err_no_ring;
22608c2ecf20Sopenharmony_ci	ch->tx_ring = kcalloc(target->queue_size, sizeof(*ch->tx_ring),
22618c2ecf20Sopenharmony_ci			      GFP_KERNEL);
22628c2ecf20Sopenharmony_ci	if (!ch->tx_ring)
22638c2ecf20Sopenharmony_ci		goto err_no_ring;
22648c2ecf20Sopenharmony_ci
22658c2ecf20Sopenharmony_ci	for (i = 0; i < target->queue_size; ++i) {
22668c2ecf20Sopenharmony_ci		ch->rx_ring[i] = srp_alloc_iu(target->srp_host,
22678c2ecf20Sopenharmony_ci					      ch->max_ti_iu_len,
22688c2ecf20Sopenharmony_ci					      GFP_KERNEL, DMA_FROM_DEVICE);
22698c2ecf20Sopenharmony_ci		if (!ch->rx_ring[i])
22708c2ecf20Sopenharmony_ci			goto err;
22718c2ecf20Sopenharmony_ci	}
22728c2ecf20Sopenharmony_ci
22738c2ecf20Sopenharmony_ci	for (i = 0; i < target->queue_size; ++i) {
22748c2ecf20Sopenharmony_ci		ch->tx_ring[i] = srp_alloc_iu(target->srp_host,
22758c2ecf20Sopenharmony_ci					      ch->max_it_iu_len,
22768c2ecf20Sopenharmony_ci					      GFP_KERNEL, DMA_TO_DEVICE);
22778c2ecf20Sopenharmony_ci		if (!ch->tx_ring[i])
22788c2ecf20Sopenharmony_ci			goto err;
22798c2ecf20Sopenharmony_ci
22808c2ecf20Sopenharmony_ci		list_add(&ch->tx_ring[i]->list, &ch->free_tx);
22818c2ecf20Sopenharmony_ci	}
22828c2ecf20Sopenharmony_ci
22838c2ecf20Sopenharmony_ci	return 0;
22848c2ecf20Sopenharmony_ci
22858c2ecf20Sopenharmony_cierr:
22868c2ecf20Sopenharmony_ci	for (i = 0; i < target->queue_size; ++i) {
22878c2ecf20Sopenharmony_ci		srp_free_iu(target->srp_host, ch->rx_ring[i]);
22888c2ecf20Sopenharmony_ci		srp_free_iu(target->srp_host, ch->tx_ring[i]);
22898c2ecf20Sopenharmony_ci	}
22908c2ecf20Sopenharmony_ci
22918c2ecf20Sopenharmony_ci
22928c2ecf20Sopenharmony_cierr_no_ring:
22938c2ecf20Sopenharmony_ci	kfree(ch->tx_ring);
22948c2ecf20Sopenharmony_ci	ch->tx_ring = NULL;
22958c2ecf20Sopenharmony_ci	kfree(ch->rx_ring);
22968c2ecf20Sopenharmony_ci	ch->rx_ring = NULL;
22978c2ecf20Sopenharmony_ci
22988c2ecf20Sopenharmony_ci	return -ENOMEM;
22998c2ecf20Sopenharmony_ci}
23008c2ecf20Sopenharmony_ci
23018c2ecf20Sopenharmony_cistatic uint32_t srp_compute_rq_tmo(struct ib_qp_attr *qp_attr, int attr_mask)
23028c2ecf20Sopenharmony_ci{
23038c2ecf20Sopenharmony_ci	uint64_t T_tr_ns, max_compl_time_ms;
23048c2ecf20Sopenharmony_ci	uint32_t rq_tmo_jiffies;
23058c2ecf20Sopenharmony_ci
23068c2ecf20Sopenharmony_ci	/*
23078c2ecf20Sopenharmony_ci	 * According to section 11.2.4.2 in the IBTA spec (Modify Queue Pair,
23088c2ecf20Sopenharmony_ci	 * table 91), both the QP timeout and the retry count have to be set
23098c2ecf20Sopenharmony_ci	 * for RC QP's during the RTR to RTS transition.
23108c2ecf20Sopenharmony_ci	 */
23118c2ecf20Sopenharmony_ci	WARN_ON_ONCE((attr_mask & (IB_QP_TIMEOUT | IB_QP_RETRY_CNT)) !=
23128c2ecf20Sopenharmony_ci		     (IB_QP_TIMEOUT | IB_QP_RETRY_CNT));
23138c2ecf20Sopenharmony_ci
23148c2ecf20Sopenharmony_ci	/*
23158c2ecf20Sopenharmony_ci	 * Set target->rq_tmo_jiffies to one second more than the largest time
23168c2ecf20Sopenharmony_ci	 * it can take before an error completion is generated. See also
23178c2ecf20Sopenharmony_ci	 * C9-140..142 in the IBTA spec for more information about how to
23188c2ecf20Sopenharmony_ci	 * convert the QP Local ACK Timeout value to nanoseconds.
23198c2ecf20Sopenharmony_ci	 */
23208c2ecf20Sopenharmony_ci	T_tr_ns = 4096 * (1ULL << qp_attr->timeout);
23218c2ecf20Sopenharmony_ci	max_compl_time_ms = qp_attr->retry_cnt * 4 * T_tr_ns;
23228c2ecf20Sopenharmony_ci	do_div(max_compl_time_ms, NSEC_PER_MSEC);
23238c2ecf20Sopenharmony_ci	rq_tmo_jiffies = msecs_to_jiffies(max_compl_time_ms + 1000);
23248c2ecf20Sopenharmony_ci
23258c2ecf20Sopenharmony_ci	return rq_tmo_jiffies;
23268c2ecf20Sopenharmony_ci}
23278c2ecf20Sopenharmony_ci
23288c2ecf20Sopenharmony_cistatic void srp_cm_rep_handler(struct ib_cm_id *cm_id,
23298c2ecf20Sopenharmony_ci			       const struct srp_login_rsp *lrsp,
23308c2ecf20Sopenharmony_ci			       struct srp_rdma_ch *ch)
23318c2ecf20Sopenharmony_ci{
23328c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
23338c2ecf20Sopenharmony_ci	struct ib_qp_attr *qp_attr = NULL;
23348c2ecf20Sopenharmony_ci	int attr_mask = 0;
23358c2ecf20Sopenharmony_ci	int ret = 0;
23368c2ecf20Sopenharmony_ci	int i;
23378c2ecf20Sopenharmony_ci
23388c2ecf20Sopenharmony_ci	if (lrsp->opcode == SRP_LOGIN_RSP) {
23398c2ecf20Sopenharmony_ci		ch->max_ti_iu_len = be32_to_cpu(lrsp->max_ti_iu_len);
23408c2ecf20Sopenharmony_ci		ch->req_lim       = be32_to_cpu(lrsp->req_lim_delta);
23418c2ecf20Sopenharmony_ci		ch->use_imm_data  = srp_use_imm_data &&
23428c2ecf20Sopenharmony_ci			(lrsp->rsp_flags & SRP_LOGIN_RSP_IMMED_SUPP);
23438c2ecf20Sopenharmony_ci		ch->max_it_iu_len = srp_max_it_iu_len(target->cmd_sg_cnt,
23448c2ecf20Sopenharmony_ci						      ch->use_imm_data,
23458c2ecf20Sopenharmony_ci						      target->max_it_iu_size);
23468c2ecf20Sopenharmony_ci		WARN_ON_ONCE(ch->max_it_iu_len >
23478c2ecf20Sopenharmony_ci			     be32_to_cpu(lrsp->max_it_iu_len));
23488c2ecf20Sopenharmony_ci
23498c2ecf20Sopenharmony_ci		if (ch->use_imm_data)
23508c2ecf20Sopenharmony_ci			shost_printk(KERN_DEBUG, target->scsi_host,
23518c2ecf20Sopenharmony_ci				     PFX "using immediate data\n");
23528c2ecf20Sopenharmony_ci
23538c2ecf20Sopenharmony_ci		/*
23548c2ecf20Sopenharmony_ci		 * Reserve credits for task management so we don't
23558c2ecf20Sopenharmony_ci		 * bounce requests back to the SCSI mid-layer.
23568c2ecf20Sopenharmony_ci		 */
23578c2ecf20Sopenharmony_ci		target->scsi_host->can_queue
23588c2ecf20Sopenharmony_ci			= min(ch->req_lim - SRP_TSK_MGMT_SQ_SIZE,
23598c2ecf20Sopenharmony_ci			      target->scsi_host->can_queue);
23608c2ecf20Sopenharmony_ci		target->scsi_host->cmd_per_lun
23618c2ecf20Sopenharmony_ci			= min_t(int, target->scsi_host->can_queue,
23628c2ecf20Sopenharmony_ci				target->scsi_host->cmd_per_lun);
23638c2ecf20Sopenharmony_ci	} else {
23648c2ecf20Sopenharmony_ci		shost_printk(KERN_WARNING, target->scsi_host,
23658c2ecf20Sopenharmony_ci			     PFX "Unhandled RSP opcode %#x\n", lrsp->opcode);
23668c2ecf20Sopenharmony_ci		ret = -ECONNRESET;
23678c2ecf20Sopenharmony_ci		goto error;
23688c2ecf20Sopenharmony_ci	}
23698c2ecf20Sopenharmony_ci
23708c2ecf20Sopenharmony_ci	if (!ch->rx_ring) {
23718c2ecf20Sopenharmony_ci		ret = srp_alloc_iu_bufs(ch);
23728c2ecf20Sopenharmony_ci		if (ret)
23738c2ecf20Sopenharmony_ci			goto error;
23748c2ecf20Sopenharmony_ci	}
23758c2ecf20Sopenharmony_ci
23768c2ecf20Sopenharmony_ci	for (i = 0; i < target->queue_size; i++) {
23778c2ecf20Sopenharmony_ci		struct srp_iu *iu = ch->rx_ring[i];
23788c2ecf20Sopenharmony_ci
23798c2ecf20Sopenharmony_ci		ret = srp_post_recv(ch, iu);
23808c2ecf20Sopenharmony_ci		if (ret)
23818c2ecf20Sopenharmony_ci			goto error;
23828c2ecf20Sopenharmony_ci	}
23838c2ecf20Sopenharmony_ci
23848c2ecf20Sopenharmony_ci	if (!target->using_rdma_cm) {
23858c2ecf20Sopenharmony_ci		ret = -ENOMEM;
23868c2ecf20Sopenharmony_ci		qp_attr = kmalloc(sizeof(*qp_attr), GFP_KERNEL);
23878c2ecf20Sopenharmony_ci		if (!qp_attr)
23888c2ecf20Sopenharmony_ci			goto error;
23898c2ecf20Sopenharmony_ci
23908c2ecf20Sopenharmony_ci		qp_attr->qp_state = IB_QPS_RTR;
23918c2ecf20Sopenharmony_ci		ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask);
23928c2ecf20Sopenharmony_ci		if (ret)
23938c2ecf20Sopenharmony_ci			goto error_free;
23948c2ecf20Sopenharmony_ci
23958c2ecf20Sopenharmony_ci		ret = ib_modify_qp(ch->qp, qp_attr, attr_mask);
23968c2ecf20Sopenharmony_ci		if (ret)
23978c2ecf20Sopenharmony_ci			goto error_free;
23988c2ecf20Sopenharmony_ci
23998c2ecf20Sopenharmony_ci		qp_attr->qp_state = IB_QPS_RTS;
24008c2ecf20Sopenharmony_ci		ret = ib_cm_init_qp_attr(cm_id, qp_attr, &attr_mask);
24018c2ecf20Sopenharmony_ci		if (ret)
24028c2ecf20Sopenharmony_ci			goto error_free;
24038c2ecf20Sopenharmony_ci
24048c2ecf20Sopenharmony_ci		target->rq_tmo_jiffies = srp_compute_rq_tmo(qp_attr, attr_mask);
24058c2ecf20Sopenharmony_ci
24068c2ecf20Sopenharmony_ci		ret = ib_modify_qp(ch->qp, qp_attr, attr_mask);
24078c2ecf20Sopenharmony_ci		if (ret)
24088c2ecf20Sopenharmony_ci			goto error_free;
24098c2ecf20Sopenharmony_ci
24108c2ecf20Sopenharmony_ci		ret = ib_send_cm_rtu(cm_id, NULL, 0);
24118c2ecf20Sopenharmony_ci	}
24128c2ecf20Sopenharmony_ci
24138c2ecf20Sopenharmony_cierror_free:
24148c2ecf20Sopenharmony_ci	kfree(qp_attr);
24158c2ecf20Sopenharmony_ci
24168c2ecf20Sopenharmony_cierror:
24178c2ecf20Sopenharmony_ci	ch->status = ret;
24188c2ecf20Sopenharmony_ci}
24198c2ecf20Sopenharmony_ci
24208c2ecf20Sopenharmony_cistatic void srp_ib_cm_rej_handler(struct ib_cm_id *cm_id,
24218c2ecf20Sopenharmony_ci				  const struct ib_cm_event *event,
24228c2ecf20Sopenharmony_ci				  struct srp_rdma_ch *ch)
24238c2ecf20Sopenharmony_ci{
24248c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
24258c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = target->scsi_host;
24268c2ecf20Sopenharmony_ci	struct ib_class_port_info *cpi;
24278c2ecf20Sopenharmony_ci	int opcode;
24288c2ecf20Sopenharmony_ci	u16 dlid;
24298c2ecf20Sopenharmony_ci
24308c2ecf20Sopenharmony_ci	switch (event->param.rej_rcvd.reason) {
24318c2ecf20Sopenharmony_ci	case IB_CM_REJ_PORT_CM_REDIRECT:
24328c2ecf20Sopenharmony_ci		cpi = event->param.rej_rcvd.ari;
24338c2ecf20Sopenharmony_ci		dlid = be16_to_cpu(cpi->redirect_lid);
24348c2ecf20Sopenharmony_ci		sa_path_set_dlid(&ch->ib_cm.path, dlid);
24358c2ecf20Sopenharmony_ci		ch->ib_cm.path.pkey = cpi->redirect_pkey;
24368c2ecf20Sopenharmony_ci		cm_id->remote_cm_qpn = be32_to_cpu(cpi->redirect_qp) & 0x00ffffff;
24378c2ecf20Sopenharmony_ci		memcpy(ch->ib_cm.path.dgid.raw, cpi->redirect_gid, 16);
24388c2ecf20Sopenharmony_ci
24398c2ecf20Sopenharmony_ci		ch->status = dlid ? SRP_DLID_REDIRECT : SRP_PORT_REDIRECT;
24408c2ecf20Sopenharmony_ci		break;
24418c2ecf20Sopenharmony_ci
24428c2ecf20Sopenharmony_ci	case IB_CM_REJ_PORT_REDIRECT:
24438c2ecf20Sopenharmony_ci		if (srp_target_is_topspin(target)) {
24448c2ecf20Sopenharmony_ci			union ib_gid *dgid = &ch->ib_cm.path.dgid;
24458c2ecf20Sopenharmony_ci
24468c2ecf20Sopenharmony_ci			/*
24478c2ecf20Sopenharmony_ci			 * Topspin/Cisco SRP gateways incorrectly send
24488c2ecf20Sopenharmony_ci			 * reject reason code 25 when they mean 24
24498c2ecf20Sopenharmony_ci			 * (port redirect).
24508c2ecf20Sopenharmony_ci			 */
24518c2ecf20Sopenharmony_ci			memcpy(dgid->raw, event->param.rej_rcvd.ari, 16);
24528c2ecf20Sopenharmony_ci
24538c2ecf20Sopenharmony_ci			shost_printk(KERN_DEBUG, shost,
24548c2ecf20Sopenharmony_ci				     PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n",
24558c2ecf20Sopenharmony_ci				     be64_to_cpu(dgid->global.subnet_prefix),
24568c2ecf20Sopenharmony_ci				     be64_to_cpu(dgid->global.interface_id));
24578c2ecf20Sopenharmony_ci
24588c2ecf20Sopenharmony_ci			ch->status = SRP_PORT_REDIRECT;
24598c2ecf20Sopenharmony_ci		} else {
24608c2ecf20Sopenharmony_ci			shost_printk(KERN_WARNING, shost,
24618c2ecf20Sopenharmony_ci				     "  REJ reason: IB_CM_REJ_PORT_REDIRECT\n");
24628c2ecf20Sopenharmony_ci			ch->status = -ECONNRESET;
24638c2ecf20Sopenharmony_ci		}
24648c2ecf20Sopenharmony_ci		break;
24658c2ecf20Sopenharmony_ci
24668c2ecf20Sopenharmony_ci	case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID:
24678c2ecf20Sopenharmony_ci		shost_printk(KERN_WARNING, shost,
24688c2ecf20Sopenharmony_ci			    "  REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n");
24698c2ecf20Sopenharmony_ci		ch->status = -ECONNRESET;
24708c2ecf20Sopenharmony_ci		break;
24718c2ecf20Sopenharmony_ci
24728c2ecf20Sopenharmony_ci	case IB_CM_REJ_CONSUMER_DEFINED:
24738c2ecf20Sopenharmony_ci		opcode = *(u8 *) event->private_data;
24748c2ecf20Sopenharmony_ci		if (opcode == SRP_LOGIN_REJ) {
24758c2ecf20Sopenharmony_ci			struct srp_login_rej *rej = event->private_data;
24768c2ecf20Sopenharmony_ci			u32 reason = be32_to_cpu(rej->reason);
24778c2ecf20Sopenharmony_ci
24788c2ecf20Sopenharmony_ci			if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE)
24798c2ecf20Sopenharmony_ci				shost_printk(KERN_WARNING, shost,
24808c2ecf20Sopenharmony_ci					     PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n");
24818c2ecf20Sopenharmony_ci			else
24828c2ecf20Sopenharmony_ci				shost_printk(KERN_WARNING, shost, PFX
24838c2ecf20Sopenharmony_ci					     "SRP LOGIN from %pI6 to %pI6 REJECTED, reason 0x%08x\n",
24848c2ecf20Sopenharmony_ci					     target->sgid.raw,
24858c2ecf20Sopenharmony_ci					     target->ib_cm.orig_dgid.raw,
24868c2ecf20Sopenharmony_ci					     reason);
24878c2ecf20Sopenharmony_ci		} else
24888c2ecf20Sopenharmony_ci			shost_printk(KERN_WARNING, shost,
24898c2ecf20Sopenharmony_ci				     "  REJ reason: IB_CM_REJ_CONSUMER_DEFINED,"
24908c2ecf20Sopenharmony_ci				     " opcode 0x%02x\n", opcode);
24918c2ecf20Sopenharmony_ci		ch->status = -ECONNRESET;
24928c2ecf20Sopenharmony_ci		break;
24938c2ecf20Sopenharmony_ci
24948c2ecf20Sopenharmony_ci	case IB_CM_REJ_STALE_CONN:
24958c2ecf20Sopenharmony_ci		shost_printk(KERN_WARNING, shost, "  REJ reason: stale connection\n");
24968c2ecf20Sopenharmony_ci		ch->status = SRP_STALE_CONN;
24978c2ecf20Sopenharmony_ci		break;
24988c2ecf20Sopenharmony_ci
24998c2ecf20Sopenharmony_ci	default:
25008c2ecf20Sopenharmony_ci		shost_printk(KERN_WARNING, shost, "  REJ reason 0x%x\n",
25018c2ecf20Sopenharmony_ci			     event->param.rej_rcvd.reason);
25028c2ecf20Sopenharmony_ci		ch->status = -ECONNRESET;
25038c2ecf20Sopenharmony_ci	}
25048c2ecf20Sopenharmony_ci}
25058c2ecf20Sopenharmony_ci
25068c2ecf20Sopenharmony_cistatic int srp_ib_cm_handler(struct ib_cm_id *cm_id,
25078c2ecf20Sopenharmony_ci			     const struct ib_cm_event *event)
25088c2ecf20Sopenharmony_ci{
25098c2ecf20Sopenharmony_ci	struct srp_rdma_ch *ch = cm_id->context;
25108c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
25118c2ecf20Sopenharmony_ci	int comp = 0;
25128c2ecf20Sopenharmony_ci
25138c2ecf20Sopenharmony_ci	switch (event->event) {
25148c2ecf20Sopenharmony_ci	case IB_CM_REQ_ERROR:
25158c2ecf20Sopenharmony_ci		shost_printk(KERN_DEBUG, target->scsi_host,
25168c2ecf20Sopenharmony_ci			     PFX "Sending CM REQ failed\n");
25178c2ecf20Sopenharmony_ci		comp = 1;
25188c2ecf20Sopenharmony_ci		ch->status = -ECONNRESET;
25198c2ecf20Sopenharmony_ci		break;
25208c2ecf20Sopenharmony_ci
25218c2ecf20Sopenharmony_ci	case IB_CM_REP_RECEIVED:
25228c2ecf20Sopenharmony_ci		comp = 1;
25238c2ecf20Sopenharmony_ci		srp_cm_rep_handler(cm_id, event->private_data, ch);
25248c2ecf20Sopenharmony_ci		break;
25258c2ecf20Sopenharmony_ci
25268c2ecf20Sopenharmony_ci	case IB_CM_REJ_RECEIVED:
25278c2ecf20Sopenharmony_ci		shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n");
25288c2ecf20Sopenharmony_ci		comp = 1;
25298c2ecf20Sopenharmony_ci
25308c2ecf20Sopenharmony_ci		srp_ib_cm_rej_handler(cm_id, event, ch);
25318c2ecf20Sopenharmony_ci		break;
25328c2ecf20Sopenharmony_ci
25338c2ecf20Sopenharmony_ci	case IB_CM_DREQ_RECEIVED:
25348c2ecf20Sopenharmony_ci		shost_printk(KERN_WARNING, target->scsi_host,
25358c2ecf20Sopenharmony_ci			     PFX "DREQ received - connection closed\n");
25368c2ecf20Sopenharmony_ci		ch->connected = false;
25378c2ecf20Sopenharmony_ci		if (ib_send_cm_drep(cm_id, NULL, 0))
25388c2ecf20Sopenharmony_ci			shost_printk(KERN_ERR, target->scsi_host,
25398c2ecf20Sopenharmony_ci				     PFX "Sending CM DREP failed\n");
25408c2ecf20Sopenharmony_ci		queue_work(system_long_wq, &target->tl_err_work);
25418c2ecf20Sopenharmony_ci		break;
25428c2ecf20Sopenharmony_ci
25438c2ecf20Sopenharmony_ci	case IB_CM_TIMEWAIT_EXIT:
25448c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, target->scsi_host,
25458c2ecf20Sopenharmony_ci			     PFX "connection closed\n");
25468c2ecf20Sopenharmony_ci		comp = 1;
25478c2ecf20Sopenharmony_ci
25488c2ecf20Sopenharmony_ci		ch->status = 0;
25498c2ecf20Sopenharmony_ci		break;
25508c2ecf20Sopenharmony_ci
25518c2ecf20Sopenharmony_ci	case IB_CM_MRA_RECEIVED:
25528c2ecf20Sopenharmony_ci	case IB_CM_DREQ_ERROR:
25538c2ecf20Sopenharmony_ci	case IB_CM_DREP_RECEIVED:
25548c2ecf20Sopenharmony_ci		break;
25558c2ecf20Sopenharmony_ci
25568c2ecf20Sopenharmony_ci	default:
25578c2ecf20Sopenharmony_ci		shost_printk(KERN_WARNING, target->scsi_host,
25588c2ecf20Sopenharmony_ci			     PFX "Unhandled CM event %d\n", event->event);
25598c2ecf20Sopenharmony_ci		break;
25608c2ecf20Sopenharmony_ci	}
25618c2ecf20Sopenharmony_ci
25628c2ecf20Sopenharmony_ci	if (comp)
25638c2ecf20Sopenharmony_ci		complete(&ch->done);
25648c2ecf20Sopenharmony_ci
25658c2ecf20Sopenharmony_ci	return 0;
25668c2ecf20Sopenharmony_ci}
25678c2ecf20Sopenharmony_ci
25688c2ecf20Sopenharmony_cistatic void srp_rdma_cm_rej_handler(struct srp_rdma_ch *ch,
25698c2ecf20Sopenharmony_ci				    struct rdma_cm_event *event)
25708c2ecf20Sopenharmony_ci{
25718c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
25728c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = target->scsi_host;
25738c2ecf20Sopenharmony_ci	int opcode;
25748c2ecf20Sopenharmony_ci
25758c2ecf20Sopenharmony_ci	switch (event->status) {
25768c2ecf20Sopenharmony_ci	case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID:
25778c2ecf20Sopenharmony_ci		shost_printk(KERN_WARNING, shost,
25788c2ecf20Sopenharmony_ci			    "  REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n");
25798c2ecf20Sopenharmony_ci		ch->status = -ECONNRESET;
25808c2ecf20Sopenharmony_ci		break;
25818c2ecf20Sopenharmony_ci
25828c2ecf20Sopenharmony_ci	case IB_CM_REJ_CONSUMER_DEFINED:
25838c2ecf20Sopenharmony_ci		opcode = *(u8 *) event->param.conn.private_data;
25848c2ecf20Sopenharmony_ci		if (opcode == SRP_LOGIN_REJ) {
25858c2ecf20Sopenharmony_ci			struct srp_login_rej *rej =
25868c2ecf20Sopenharmony_ci				(struct srp_login_rej *)
25878c2ecf20Sopenharmony_ci				event->param.conn.private_data;
25888c2ecf20Sopenharmony_ci			u32 reason = be32_to_cpu(rej->reason);
25898c2ecf20Sopenharmony_ci
25908c2ecf20Sopenharmony_ci			if (reason == SRP_LOGIN_REJ_REQ_IT_IU_LENGTH_TOO_LARGE)
25918c2ecf20Sopenharmony_ci				shost_printk(KERN_WARNING, shost,
25928c2ecf20Sopenharmony_ci					     PFX "SRP_LOGIN_REJ: requested max_it_iu_len too large\n");
25938c2ecf20Sopenharmony_ci			else
25948c2ecf20Sopenharmony_ci				shost_printk(KERN_WARNING, shost,
25958c2ecf20Sopenharmony_ci					    PFX "SRP LOGIN REJECTED, reason 0x%08x\n", reason);
25968c2ecf20Sopenharmony_ci		} else {
25978c2ecf20Sopenharmony_ci			shost_printk(KERN_WARNING, shost,
25988c2ecf20Sopenharmony_ci				     "  REJ reason: IB_CM_REJ_CONSUMER_DEFINED, opcode 0x%02x\n",
25998c2ecf20Sopenharmony_ci				     opcode);
26008c2ecf20Sopenharmony_ci		}
26018c2ecf20Sopenharmony_ci		ch->status = -ECONNRESET;
26028c2ecf20Sopenharmony_ci		break;
26038c2ecf20Sopenharmony_ci
26048c2ecf20Sopenharmony_ci	case IB_CM_REJ_STALE_CONN:
26058c2ecf20Sopenharmony_ci		shost_printk(KERN_WARNING, shost,
26068c2ecf20Sopenharmony_ci			     "  REJ reason: stale connection\n");
26078c2ecf20Sopenharmony_ci		ch->status = SRP_STALE_CONN;
26088c2ecf20Sopenharmony_ci		break;
26098c2ecf20Sopenharmony_ci
26108c2ecf20Sopenharmony_ci	default:
26118c2ecf20Sopenharmony_ci		shost_printk(KERN_WARNING, shost, "  REJ reason 0x%x\n",
26128c2ecf20Sopenharmony_ci			     event->status);
26138c2ecf20Sopenharmony_ci		ch->status = -ECONNRESET;
26148c2ecf20Sopenharmony_ci		break;
26158c2ecf20Sopenharmony_ci	}
26168c2ecf20Sopenharmony_ci}
26178c2ecf20Sopenharmony_ci
26188c2ecf20Sopenharmony_cistatic int srp_rdma_cm_handler(struct rdma_cm_id *cm_id,
26198c2ecf20Sopenharmony_ci			       struct rdma_cm_event *event)
26208c2ecf20Sopenharmony_ci{
26218c2ecf20Sopenharmony_ci	struct srp_rdma_ch *ch = cm_id->context;
26228c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
26238c2ecf20Sopenharmony_ci	int comp = 0;
26248c2ecf20Sopenharmony_ci
26258c2ecf20Sopenharmony_ci	switch (event->event) {
26268c2ecf20Sopenharmony_ci	case RDMA_CM_EVENT_ADDR_RESOLVED:
26278c2ecf20Sopenharmony_ci		ch->status = 0;
26288c2ecf20Sopenharmony_ci		comp = 1;
26298c2ecf20Sopenharmony_ci		break;
26308c2ecf20Sopenharmony_ci
26318c2ecf20Sopenharmony_ci	case RDMA_CM_EVENT_ADDR_ERROR:
26328c2ecf20Sopenharmony_ci		ch->status = -ENXIO;
26338c2ecf20Sopenharmony_ci		comp = 1;
26348c2ecf20Sopenharmony_ci		break;
26358c2ecf20Sopenharmony_ci
26368c2ecf20Sopenharmony_ci	case RDMA_CM_EVENT_ROUTE_RESOLVED:
26378c2ecf20Sopenharmony_ci		ch->status = 0;
26388c2ecf20Sopenharmony_ci		comp = 1;
26398c2ecf20Sopenharmony_ci		break;
26408c2ecf20Sopenharmony_ci
26418c2ecf20Sopenharmony_ci	case RDMA_CM_EVENT_ROUTE_ERROR:
26428c2ecf20Sopenharmony_ci	case RDMA_CM_EVENT_UNREACHABLE:
26438c2ecf20Sopenharmony_ci		ch->status = -EHOSTUNREACH;
26448c2ecf20Sopenharmony_ci		comp = 1;
26458c2ecf20Sopenharmony_ci		break;
26468c2ecf20Sopenharmony_ci
26478c2ecf20Sopenharmony_ci	case RDMA_CM_EVENT_CONNECT_ERROR:
26488c2ecf20Sopenharmony_ci		shost_printk(KERN_DEBUG, target->scsi_host,
26498c2ecf20Sopenharmony_ci			     PFX "Sending CM REQ failed\n");
26508c2ecf20Sopenharmony_ci		comp = 1;
26518c2ecf20Sopenharmony_ci		ch->status = -ECONNRESET;
26528c2ecf20Sopenharmony_ci		break;
26538c2ecf20Sopenharmony_ci
26548c2ecf20Sopenharmony_ci	case RDMA_CM_EVENT_ESTABLISHED:
26558c2ecf20Sopenharmony_ci		comp = 1;
26568c2ecf20Sopenharmony_ci		srp_cm_rep_handler(NULL, event->param.conn.private_data, ch);
26578c2ecf20Sopenharmony_ci		break;
26588c2ecf20Sopenharmony_ci
26598c2ecf20Sopenharmony_ci	case RDMA_CM_EVENT_REJECTED:
26608c2ecf20Sopenharmony_ci		shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n");
26618c2ecf20Sopenharmony_ci		comp = 1;
26628c2ecf20Sopenharmony_ci
26638c2ecf20Sopenharmony_ci		srp_rdma_cm_rej_handler(ch, event);
26648c2ecf20Sopenharmony_ci		break;
26658c2ecf20Sopenharmony_ci
26668c2ecf20Sopenharmony_ci	case RDMA_CM_EVENT_DISCONNECTED:
26678c2ecf20Sopenharmony_ci		if (ch->connected) {
26688c2ecf20Sopenharmony_ci			shost_printk(KERN_WARNING, target->scsi_host,
26698c2ecf20Sopenharmony_ci				     PFX "received DREQ\n");
26708c2ecf20Sopenharmony_ci			rdma_disconnect(ch->rdma_cm.cm_id);
26718c2ecf20Sopenharmony_ci			comp = 1;
26728c2ecf20Sopenharmony_ci			ch->status = 0;
26738c2ecf20Sopenharmony_ci			queue_work(system_long_wq, &target->tl_err_work);
26748c2ecf20Sopenharmony_ci		}
26758c2ecf20Sopenharmony_ci		break;
26768c2ecf20Sopenharmony_ci
26778c2ecf20Sopenharmony_ci	case RDMA_CM_EVENT_TIMEWAIT_EXIT:
26788c2ecf20Sopenharmony_ci		shost_printk(KERN_ERR, target->scsi_host,
26798c2ecf20Sopenharmony_ci			     PFX "connection closed\n");
26808c2ecf20Sopenharmony_ci
26818c2ecf20Sopenharmony_ci		comp = 1;
26828c2ecf20Sopenharmony_ci		ch->status = 0;
26838c2ecf20Sopenharmony_ci		break;
26848c2ecf20Sopenharmony_ci
26858c2ecf20Sopenharmony_ci	default:
26868c2ecf20Sopenharmony_ci		shost_printk(KERN_WARNING, target->scsi_host,
26878c2ecf20Sopenharmony_ci			     PFX "Unhandled CM event %d\n", event->event);
26888c2ecf20Sopenharmony_ci		break;
26898c2ecf20Sopenharmony_ci	}
26908c2ecf20Sopenharmony_ci
26918c2ecf20Sopenharmony_ci	if (comp)
26928c2ecf20Sopenharmony_ci		complete(&ch->done);
26938c2ecf20Sopenharmony_ci
26948c2ecf20Sopenharmony_ci	return 0;
26958c2ecf20Sopenharmony_ci}
26968c2ecf20Sopenharmony_ci
26978c2ecf20Sopenharmony_ci/**
26988c2ecf20Sopenharmony_ci * srp_change_queue_depth - setting device queue depth
26998c2ecf20Sopenharmony_ci * @sdev: scsi device struct
27008c2ecf20Sopenharmony_ci * @qdepth: requested queue depth
27018c2ecf20Sopenharmony_ci *
27028c2ecf20Sopenharmony_ci * Returns queue depth.
27038c2ecf20Sopenharmony_ci */
27048c2ecf20Sopenharmony_cistatic int
27058c2ecf20Sopenharmony_cisrp_change_queue_depth(struct scsi_device *sdev, int qdepth)
27068c2ecf20Sopenharmony_ci{
27078c2ecf20Sopenharmony_ci	if (!sdev->tagged_supported)
27088c2ecf20Sopenharmony_ci		qdepth = 1;
27098c2ecf20Sopenharmony_ci	return scsi_change_queue_depth(sdev, qdepth);
27108c2ecf20Sopenharmony_ci}
27118c2ecf20Sopenharmony_ci
27128c2ecf20Sopenharmony_cistatic int srp_send_tsk_mgmt(struct srp_rdma_ch *ch, u64 req_tag, u64 lun,
27138c2ecf20Sopenharmony_ci			     u8 func, u8 *status)
27148c2ecf20Sopenharmony_ci{
27158c2ecf20Sopenharmony_ci	struct srp_target_port *target = ch->target;
27168c2ecf20Sopenharmony_ci	struct srp_rport *rport = target->rport;
27178c2ecf20Sopenharmony_ci	struct ib_device *dev = target->srp_host->srp_dev->dev;
27188c2ecf20Sopenharmony_ci	struct srp_iu *iu;
27198c2ecf20Sopenharmony_ci	struct srp_tsk_mgmt *tsk_mgmt;
27208c2ecf20Sopenharmony_ci	int res;
27218c2ecf20Sopenharmony_ci
27228c2ecf20Sopenharmony_ci	if (!ch->connected || target->qp_in_error)
27238c2ecf20Sopenharmony_ci		return -1;
27248c2ecf20Sopenharmony_ci
27258c2ecf20Sopenharmony_ci	/*
27268c2ecf20Sopenharmony_ci	 * Lock the rport mutex to avoid that srp_create_ch_ib() is
27278c2ecf20Sopenharmony_ci	 * invoked while a task management function is being sent.
27288c2ecf20Sopenharmony_ci	 */
27298c2ecf20Sopenharmony_ci	mutex_lock(&rport->mutex);
27308c2ecf20Sopenharmony_ci	spin_lock_irq(&ch->lock);
27318c2ecf20Sopenharmony_ci	iu = __srp_get_tx_iu(ch, SRP_IU_TSK_MGMT);
27328c2ecf20Sopenharmony_ci	spin_unlock_irq(&ch->lock);
27338c2ecf20Sopenharmony_ci
27348c2ecf20Sopenharmony_ci	if (!iu) {
27358c2ecf20Sopenharmony_ci		mutex_unlock(&rport->mutex);
27368c2ecf20Sopenharmony_ci
27378c2ecf20Sopenharmony_ci		return -1;
27388c2ecf20Sopenharmony_ci	}
27398c2ecf20Sopenharmony_ci
27408c2ecf20Sopenharmony_ci	iu->num_sge = 1;
27418c2ecf20Sopenharmony_ci
27428c2ecf20Sopenharmony_ci	ib_dma_sync_single_for_cpu(dev, iu->dma, sizeof *tsk_mgmt,
27438c2ecf20Sopenharmony_ci				   DMA_TO_DEVICE);
27448c2ecf20Sopenharmony_ci	tsk_mgmt = iu->buf;
27458c2ecf20Sopenharmony_ci	memset(tsk_mgmt, 0, sizeof *tsk_mgmt);
27468c2ecf20Sopenharmony_ci
27478c2ecf20Sopenharmony_ci	tsk_mgmt->opcode 	= SRP_TSK_MGMT;
27488c2ecf20Sopenharmony_ci	int_to_scsilun(lun, &tsk_mgmt->lun);
27498c2ecf20Sopenharmony_ci	tsk_mgmt->tsk_mgmt_func = func;
27508c2ecf20Sopenharmony_ci	tsk_mgmt->task_tag	= req_tag;
27518c2ecf20Sopenharmony_ci
27528c2ecf20Sopenharmony_ci	spin_lock_irq(&ch->lock);
27538c2ecf20Sopenharmony_ci	ch->tsk_mgmt_tag = (ch->tsk_mgmt_tag + 1) | SRP_TAG_TSK_MGMT;
27548c2ecf20Sopenharmony_ci	tsk_mgmt->tag = ch->tsk_mgmt_tag;
27558c2ecf20Sopenharmony_ci	spin_unlock_irq(&ch->lock);
27568c2ecf20Sopenharmony_ci
27578c2ecf20Sopenharmony_ci	init_completion(&ch->tsk_mgmt_done);
27588c2ecf20Sopenharmony_ci
27598c2ecf20Sopenharmony_ci	ib_dma_sync_single_for_device(dev, iu->dma, sizeof *tsk_mgmt,
27608c2ecf20Sopenharmony_ci				      DMA_TO_DEVICE);
27618c2ecf20Sopenharmony_ci	if (srp_post_send(ch, iu, sizeof(*tsk_mgmt))) {
27628c2ecf20Sopenharmony_ci		srp_put_tx_iu(ch, iu, SRP_IU_TSK_MGMT);
27638c2ecf20Sopenharmony_ci		mutex_unlock(&rport->mutex);
27648c2ecf20Sopenharmony_ci
27658c2ecf20Sopenharmony_ci		return -1;
27668c2ecf20Sopenharmony_ci	}
27678c2ecf20Sopenharmony_ci	res = wait_for_completion_timeout(&ch->tsk_mgmt_done,
27688c2ecf20Sopenharmony_ci					msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS));
27698c2ecf20Sopenharmony_ci	if (res > 0 && status)
27708c2ecf20Sopenharmony_ci		*status = ch->tsk_mgmt_status;
27718c2ecf20Sopenharmony_ci	mutex_unlock(&rport->mutex);
27728c2ecf20Sopenharmony_ci
27738c2ecf20Sopenharmony_ci	WARN_ON_ONCE(res < 0);
27748c2ecf20Sopenharmony_ci
27758c2ecf20Sopenharmony_ci	return res > 0 ? 0 : -1;
27768c2ecf20Sopenharmony_ci}
27778c2ecf20Sopenharmony_ci
27788c2ecf20Sopenharmony_cistatic int srp_abort(struct scsi_cmnd *scmnd)
27798c2ecf20Sopenharmony_ci{
27808c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(scmnd->device->host);
27818c2ecf20Sopenharmony_ci	struct srp_request *req = scsi_cmd_priv(scmnd);
27828c2ecf20Sopenharmony_ci	u32 tag;
27838c2ecf20Sopenharmony_ci	u16 ch_idx;
27848c2ecf20Sopenharmony_ci	struct srp_rdma_ch *ch;
27858c2ecf20Sopenharmony_ci
27868c2ecf20Sopenharmony_ci	shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n");
27878c2ecf20Sopenharmony_ci
27888c2ecf20Sopenharmony_ci	tag = blk_mq_unique_tag(scmnd->request);
27898c2ecf20Sopenharmony_ci	ch_idx = blk_mq_unique_tag_to_hwq(tag);
27908c2ecf20Sopenharmony_ci	if (WARN_ON_ONCE(ch_idx >= target->ch_count))
27918c2ecf20Sopenharmony_ci		return SUCCESS;
27928c2ecf20Sopenharmony_ci	ch = &target->ch[ch_idx];
27938c2ecf20Sopenharmony_ci	if (!srp_claim_req(ch, req, NULL, scmnd))
27948c2ecf20Sopenharmony_ci		return SUCCESS;
27958c2ecf20Sopenharmony_ci	shost_printk(KERN_ERR, target->scsi_host,
27968c2ecf20Sopenharmony_ci		     "Sending SRP abort for tag %#x\n", tag);
27978c2ecf20Sopenharmony_ci	if (srp_send_tsk_mgmt(ch, tag, scmnd->device->lun,
27988c2ecf20Sopenharmony_ci			      SRP_TSK_ABORT_TASK, NULL) == 0) {
27998c2ecf20Sopenharmony_ci		srp_free_req(ch, req, scmnd, 0);
28008c2ecf20Sopenharmony_ci		return SUCCESS;
28018c2ecf20Sopenharmony_ci	}
28028c2ecf20Sopenharmony_ci	if (target->rport->state == SRP_RPORT_LOST)
28038c2ecf20Sopenharmony_ci		return FAST_IO_FAIL;
28048c2ecf20Sopenharmony_ci
28058c2ecf20Sopenharmony_ci	return FAILED;
28068c2ecf20Sopenharmony_ci}
28078c2ecf20Sopenharmony_ci
28088c2ecf20Sopenharmony_cistatic int srp_reset_device(struct scsi_cmnd *scmnd)
28098c2ecf20Sopenharmony_ci{
28108c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(scmnd->device->host);
28118c2ecf20Sopenharmony_ci	struct srp_rdma_ch *ch;
28128c2ecf20Sopenharmony_ci	u8 status;
28138c2ecf20Sopenharmony_ci
28148c2ecf20Sopenharmony_ci	shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n");
28158c2ecf20Sopenharmony_ci
28168c2ecf20Sopenharmony_ci	ch = &target->ch[0];
28178c2ecf20Sopenharmony_ci	if (srp_send_tsk_mgmt(ch, SRP_TAG_NO_REQ, scmnd->device->lun,
28188c2ecf20Sopenharmony_ci			      SRP_TSK_LUN_RESET, &status))
28198c2ecf20Sopenharmony_ci		return FAILED;
28208c2ecf20Sopenharmony_ci	if (status)
28218c2ecf20Sopenharmony_ci		return FAILED;
28228c2ecf20Sopenharmony_ci
28238c2ecf20Sopenharmony_ci	return SUCCESS;
28248c2ecf20Sopenharmony_ci}
28258c2ecf20Sopenharmony_ci
28268c2ecf20Sopenharmony_cistatic int srp_reset_host(struct scsi_cmnd *scmnd)
28278c2ecf20Sopenharmony_ci{
28288c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(scmnd->device->host);
28298c2ecf20Sopenharmony_ci
28308c2ecf20Sopenharmony_ci	shost_printk(KERN_ERR, target->scsi_host, PFX "SRP reset_host called\n");
28318c2ecf20Sopenharmony_ci
28328c2ecf20Sopenharmony_ci	return srp_reconnect_rport(target->rport) == 0 ? SUCCESS : FAILED;
28338c2ecf20Sopenharmony_ci}
28348c2ecf20Sopenharmony_ci
28358c2ecf20Sopenharmony_cistatic int srp_target_alloc(struct scsi_target *starget)
28368c2ecf20Sopenharmony_ci{
28378c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = dev_to_shost(starget->dev.parent);
28388c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(shost);
28398c2ecf20Sopenharmony_ci
28408c2ecf20Sopenharmony_ci	if (target->target_can_queue)
28418c2ecf20Sopenharmony_ci		starget->can_queue = target->target_can_queue;
28428c2ecf20Sopenharmony_ci	return 0;
28438c2ecf20Sopenharmony_ci}
28448c2ecf20Sopenharmony_ci
28458c2ecf20Sopenharmony_cistatic int srp_slave_configure(struct scsi_device *sdev)
28468c2ecf20Sopenharmony_ci{
28478c2ecf20Sopenharmony_ci	struct Scsi_Host *shost = sdev->host;
28488c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(shost);
28498c2ecf20Sopenharmony_ci	struct request_queue *q = sdev->request_queue;
28508c2ecf20Sopenharmony_ci	unsigned long timeout;
28518c2ecf20Sopenharmony_ci
28528c2ecf20Sopenharmony_ci	if (sdev->type == TYPE_DISK) {
28538c2ecf20Sopenharmony_ci		timeout = max_t(unsigned, 30 * HZ, target->rq_tmo_jiffies);
28548c2ecf20Sopenharmony_ci		blk_queue_rq_timeout(q, timeout);
28558c2ecf20Sopenharmony_ci	}
28568c2ecf20Sopenharmony_ci
28578c2ecf20Sopenharmony_ci	return 0;
28588c2ecf20Sopenharmony_ci}
28598c2ecf20Sopenharmony_ci
28608c2ecf20Sopenharmony_cistatic ssize_t show_id_ext(struct device *dev, struct device_attribute *attr,
28618c2ecf20Sopenharmony_ci			   char *buf)
28628c2ecf20Sopenharmony_ci{
28638c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(class_to_shost(dev));
28648c2ecf20Sopenharmony_ci
28658c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%016llx\n", be64_to_cpu(target->id_ext));
28668c2ecf20Sopenharmony_ci}
28678c2ecf20Sopenharmony_ci
28688c2ecf20Sopenharmony_cistatic ssize_t show_ioc_guid(struct device *dev, struct device_attribute *attr,
28698c2ecf20Sopenharmony_ci			     char *buf)
28708c2ecf20Sopenharmony_ci{
28718c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(class_to_shost(dev));
28728c2ecf20Sopenharmony_ci
28738c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%016llx\n", be64_to_cpu(target->ioc_guid));
28748c2ecf20Sopenharmony_ci}
28758c2ecf20Sopenharmony_ci
28768c2ecf20Sopenharmony_cistatic ssize_t show_service_id(struct device *dev,
28778c2ecf20Sopenharmony_ci			       struct device_attribute *attr, char *buf)
28788c2ecf20Sopenharmony_ci{
28798c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(class_to_shost(dev));
28808c2ecf20Sopenharmony_ci
28818c2ecf20Sopenharmony_ci	if (target->using_rdma_cm)
28828c2ecf20Sopenharmony_ci		return -ENOENT;
28838c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%016llx\n",
28848c2ecf20Sopenharmony_ci		       be64_to_cpu(target->ib_cm.service_id));
28858c2ecf20Sopenharmony_ci}
28868c2ecf20Sopenharmony_ci
28878c2ecf20Sopenharmony_cistatic ssize_t show_pkey(struct device *dev, struct device_attribute *attr,
28888c2ecf20Sopenharmony_ci			 char *buf)
28898c2ecf20Sopenharmony_ci{
28908c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(class_to_shost(dev));
28918c2ecf20Sopenharmony_ci
28928c2ecf20Sopenharmony_ci	if (target->using_rdma_cm)
28938c2ecf20Sopenharmony_ci		return -ENOENT;
28948c2ecf20Sopenharmony_ci	return sprintf(buf, "0x%04x\n", be16_to_cpu(target->ib_cm.pkey));
28958c2ecf20Sopenharmony_ci}
28968c2ecf20Sopenharmony_ci
28978c2ecf20Sopenharmony_cistatic ssize_t show_sgid(struct device *dev, struct device_attribute *attr,
28988c2ecf20Sopenharmony_ci			 char *buf)
28998c2ecf20Sopenharmony_ci{
29008c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(class_to_shost(dev));
29018c2ecf20Sopenharmony_ci
29028c2ecf20Sopenharmony_ci	return sprintf(buf, "%pI6\n", target->sgid.raw);
29038c2ecf20Sopenharmony_ci}
29048c2ecf20Sopenharmony_ci
29058c2ecf20Sopenharmony_cistatic ssize_t show_dgid(struct device *dev, struct device_attribute *attr,
29068c2ecf20Sopenharmony_ci			 char *buf)
29078c2ecf20Sopenharmony_ci{
29088c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(class_to_shost(dev));
29098c2ecf20Sopenharmony_ci	struct srp_rdma_ch *ch = &target->ch[0];
29108c2ecf20Sopenharmony_ci
29118c2ecf20Sopenharmony_ci	if (target->using_rdma_cm)
29128c2ecf20Sopenharmony_ci		return -ENOENT;
29138c2ecf20Sopenharmony_ci	return sprintf(buf, "%pI6\n", ch->ib_cm.path.dgid.raw);
29148c2ecf20Sopenharmony_ci}
29158c2ecf20Sopenharmony_ci
29168c2ecf20Sopenharmony_cistatic ssize_t show_orig_dgid(struct device *dev,
29178c2ecf20Sopenharmony_ci			      struct device_attribute *attr, char *buf)
29188c2ecf20Sopenharmony_ci{
29198c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(class_to_shost(dev));
29208c2ecf20Sopenharmony_ci
29218c2ecf20Sopenharmony_ci	if (target->using_rdma_cm)
29228c2ecf20Sopenharmony_ci		return -ENOENT;
29238c2ecf20Sopenharmony_ci	return sprintf(buf, "%pI6\n", target->ib_cm.orig_dgid.raw);
29248c2ecf20Sopenharmony_ci}
29258c2ecf20Sopenharmony_ci
29268c2ecf20Sopenharmony_cistatic ssize_t show_req_lim(struct device *dev,
29278c2ecf20Sopenharmony_ci			    struct device_attribute *attr, char *buf)
29288c2ecf20Sopenharmony_ci{
29298c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(class_to_shost(dev));
29308c2ecf20Sopenharmony_ci	struct srp_rdma_ch *ch;
29318c2ecf20Sopenharmony_ci	int i, req_lim = INT_MAX;
29328c2ecf20Sopenharmony_ci
29338c2ecf20Sopenharmony_ci	for (i = 0; i < target->ch_count; i++) {
29348c2ecf20Sopenharmony_ci		ch = &target->ch[i];
29358c2ecf20Sopenharmony_ci		req_lim = min(req_lim, ch->req_lim);
29368c2ecf20Sopenharmony_ci	}
29378c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", req_lim);
29388c2ecf20Sopenharmony_ci}
29398c2ecf20Sopenharmony_ci
29408c2ecf20Sopenharmony_cistatic ssize_t show_zero_req_lim(struct device *dev,
29418c2ecf20Sopenharmony_ci				 struct device_attribute *attr, char *buf)
29428c2ecf20Sopenharmony_ci{
29438c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(class_to_shost(dev));
29448c2ecf20Sopenharmony_ci
29458c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", target->zero_req_lim);
29468c2ecf20Sopenharmony_ci}
29478c2ecf20Sopenharmony_ci
29488c2ecf20Sopenharmony_cistatic ssize_t show_local_ib_port(struct device *dev,
29498c2ecf20Sopenharmony_ci				  struct device_attribute *attr, char *buf)
29508c2ecf20Sopenharmony_ci{
29518c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(class_to_shost(dev));
29528c2ecf20Sopenharmony_ci
29538c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", target->srp_host->port);
29548c2ecf20Sopenharmony_ci}
29558c2ecf20Sopenharmony_ci
29568c2ecf20Sopenharmony_cistatic ssize_t show_local_ib_device(struct device *dev,
29578c2ecf20Sopenharmony_ci				    struct device_attribute *attr, char *buf)
29588c2ecf20Sopenharmony_ci{
29598c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(class_to_shost(dev));
29608c2ecf20Sopenharmony_ci
29618c2ecf20Sopenharmony_ci	return sprintf(buf, "%s\n",
29628c2ecf20Sopenharmony_ci		       dev_name(&target->srp_host->srp_dev->dev->dev));
29638c2ecf20Sopenharmony_ci}
29648c2ecf20Sopenharmony_ci
29658c2ecf20Sopenharmony_cistatic ssize_t show_ch_count(struct device *dev, struct device_attribute *attr,
29668c2ecf20Sopenharmony_ci			     char *buf)
29678c2ecf20Sopenharmony_ci{
29688c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(class_to_shost(dev));
29698c2ecf20Sopenharmony_ci
29708c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", target->ch_count);
29718c2ecf20Sopenharmony_ci}
29728c2ecf20Sopenharmony_ci
29738c2ecf20Sopenharmony_cistatic ssize_t show_comp_vector(struct device *dev,
29748c2ecf20Sopenharmony_ci				struct device_attribute *attr, char *buf)
29758c2ecf20Sopenharmony_ci{
29768c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(class_to_shost(dev));
29778c2ecf20Sopenharmony_ci
29788c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", target->comp_vector);
29798c2ecf20Sopenharmony_ci}
29808c2ecf20Sopenharmony_ci
29818c2ecf20Sopenharmony_cistatic ssize_t show_tl_retry_count(struct device *dev,
29828c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
29838c2ecf20Sopenharmony_ci{
29848c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(class_to_shost(dev));
29858c2ecf20Sopenharmony_ci
29868c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", target->tl_retry_count);
29878c2ecf20Sopenharmony_ci}
29888c2ecf20Sopenharmony_ci
29898c2ecf20Sopenharmony_cistatic ssize_t show_cmd_sg_entries(struct device *dev,
29908c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
29918c2ecf20Sopenharmony_ci{
29928c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(class_to_shost(dev));
29938c2ecf20Sopenharmony_ci
29948c2ecf20Sopenharmony_ci	return sprintf(buf, "%u\n", target->cmd_sg_cnt);
29958c2ecf20Sopenharmony_ci}
29968c2ecf20Sopenharmony_ci
29978c2ecf20Sopenharmony_cistatic ssize_t show_allow_ext_sg(struct device *dev,
29988c2ecf20Sopenharmony_ci				 struct device_attribute *attr, char *buf)
29998c2ecf20Sopenharmony_ci{
30008c2ecf20Sopenharmony_ci	struct srp_target_port *target = host_to_target(class_to_shost(dev));
30018c2ecf20Sopenharmony_ci
30028c2ecf20Sopenharmony_ci	return sprintf(buf, "%s\n", target->allow_ext_sg ? "true" : "false");
30038c2ecf20Sopenharmony_ci}
30048c2ecf20Sopenharmony_ci
30058c2ecf20Sopenharmony_cistatic DEVICE_ATTR(id_ext,	    S_IRUGO, show_id_ext,	   NULL);
30068c2ecf20Sopenharmony_cistatic DEVICE_ATTR(ioc_guid,	    S_IRUGO, show_ioc_guid,	   NULL);
30078c2ecf20Sopenharmony_cistatic DEVICE_ATTR(service_id,	    S_IRUGO, show_service_id,	   NULL);
30088c2ecf20Sopenharmony_cistatic DEVICE_ATTR(pkey,	    S_IRUGO, show_pkey,		   NULL);
30098c2ecf20Sopenharmony_cistatic DEVICE_ATTR(sgid,	    S_IRUGO, show_sgid,		   NULL);
30108c2ecf20Sopenharmony_cistatic DEVICE_ATTR(dgid,	    S_IRUGO, show_dgid,		   NULL);
30118c2ecf20Sopenharmony_cistatic DEVICE_ATTR(orig_dgid,	    S_IRUGO, show_orig_dgid,	   NULL);
30128c2ecf20Sopenharmony_cistatic DEVICE_ATTR(req_lim,         S_IRUGO, show_req_lim,         NULL);
30138c2ecf20Sopenharmony_cistatic DEVICE_ATTR(zero_req_lim,    S_IRUGO, show_zero_req_lim,	   NULL);
30148c2ecf20Sopenharmony_cistatic DEVICE_ATTR(local_ib_port,   S_IRUGO, show_local_ib_port,   NULL);
30158c2ecf20Sopenharmony_cistatic DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL);
30168c2ecf20Sopenharmony_cistatic DEVICE_ATTR(ch_count,        S_IRUGO, show_ch_count,        NULL);
30178c2ecf20Sopenharmony_cistatic DEVICE_ATTR(comp_vector,     S_IRUGO, show_comp_vector,     NULL);
30188c2ecf20Sopenharmony_cistatic DEVICE_ATTR(tl_retry_count,  S_IRUGO, show_tl_retry_count,  NULL);
30198c2ecf20Sopenharmony_cistatic DEVICE_ATTR(cmd_sg_entries,  S_IRUGO, show_cmd_sg_entries,  NULL);
30208c2ecf20Sopenharmony_cistatic DEVICE_ATTR(allow_ext_sg,    S_IRUGO, show_allow_ext_sg,    NULL);
30218c2ecf20Sopenharmony_ci
30228c2ecf20Sopenharmony_cistatic struct device_attribute *srp_host_attrs[] = {
30238c2ecf20Sopenharmony_ci	&dev_attr_id_ext,
30248c2ecf20Sopenharmony_ci	&dev_attr_ioc_guid,
30258c2ecf20Sopenharmony_ci	&dev_attr_service_id,
30268c2ecf20Sopenharmony_ci	&dev_attr_pkey,
30278c2ecf20Sopenharmony_ci	&dev_attr_sgid,
30288c2ecf20Sopenharmony_ci	&dev_attr_dgid,
30298c2ecf20Sopenharmony_ci	&dev_attr_orig_dgid,
30308c2ecf20Sopenharmony_ci	&dev_attr_req_lim,
30318c2ecf20Sopenharmony_ci	&dev_attr_zero_req_lim,
30328c2ecf20Sopenharmony_ci	&dev_attr_local_ib_port,
30338c2ecf20Sopenharmony_ci	&dev_attr_local_ib_device,
30348c2ecf20Sopenharmony_ci	&dev_attr_ch_count,
30358c2ecf20Sopenharmony_ci	&dev_attr_comp_vector,
30368c2ecf20Sopenharmony_ci	&dev_attr_tl_retry_count,
30378c2ecf20Sopenharmony_ci	&dev_attr_cmd_sg_entries,
30388c2ecf20Sopenharmony_ci	&dev_attr_allow_ext_sg,
30398c2ecf20Sopenharmony_ci	NULL
30408c2ecf20Sopenharmony_ci};
30418c2ecf20Sopenharmony_ci
30428c2ecf20Sopenharmony_cistatic struct scsi_host_template srp_template = {
30438c2ecf20Sopenharmony_ci	.module				= THIS_MODULE,
30448c2ecf20Sopenharmony_ci	.name				= "InfiniBand SRP initiator",
30458c2ecf20Sopenharmony_ci	.proc_name			= DRV_NAME,
30468c2ecf20Sopenharmony_ci	.target_alloc			= srp_target_alloc,
30478c2ecf20Sopenharmony_ci	.slave_configure		= srp_slave_configure,
30488c2ecf20Sopenharmony_ci	.info				= srp_target_info,
30498c2ecf20Sopenharmony_ci	.init_cmd_priv			= srp_init_cmd_priv,
30508c2ecf20Sopenharmony_ci	.exit_cmd_priv			= srp_exit_cmd_priv,
30518c2ecf20Sopenharmony_ci	.queuecommand			= srp_queuecommand,
30528c2ecf20Sopenharmony_ci	.change_queue_depth             = srp_change_queue_depth,
30538c2ecf20Sopenharmony_ci	.eh_timed_out			= srp_timed_out,
30548c2ecf20Sopenharmony_ci	.eh_abort_handler		= srp_abort,
30558c2ecf20Sopenharmony_ci	.eh_device_reset_handler	= srp_reset_device,
30568c2ecf20Sopenharmony_ci	.eh_host_reset_handler		= srp_reset_host,
30578c2ecf20Sopenharmony_ci	.skip_settle_delay		= true,
30588c2ecf20Sopenharmony_ci	.sg_tablesize			= SRP_DEF_SG_TABLESIZE,
30598c2ecf20Sopenharmony_ci	.can_queue			= SRP_DEFAULT_CMD_SQ_SIZE,
30608c2ecf20Sopenharmony_ci	.this_id			= -1,
30618c2ecf20Sopenharmony_ci	.cmd_per_lun			= SRP_DEFAULT_CMD_SQ_SIZE,
30628c2ecf20Sopenharmony_ci	.shost_attrs			= srp_host_attrs,
30638c2ecf20Sopenharmony_ci	.track_queue_depth		= 1,
30648c2ecf20Sopenharmony_ci	.cmd_size			= sizeof(struct srp_request),
30658c2ecf20Sopenharmony_ci};
30668c2ecf20Sopenharmony_ci
30678c2ecf20Sopenharmony_cistatic int srp_sdev_count(struct Scsi_Host *host)
30688c2ecf20Sopenharmony_ci{
30698c2ecf20Sopenharmony_ci	struct scsi_device *sdev;
30708c2ecf20Sopenharmony_ci	int c = 0;
30718c2ecf20Sopenharmony_ci
30728c2ecf20Sopenharmony_ci	shost_for_each_device(sdev, host)
30738c2ecf20Sopenharmony_ci		c++;
30748c2ecf20Sopenharmony_ci
30758c2ecf20Sopenharmony_ci	return c;
30768c2ecf20Sopenharmony_ci}
30778c2ecf20Sopenharmony_ci
30788c2ecf20Sopenharmony_ci/*
30798c2ecf20Sopenharmony_ci * Return values:
30808c2ecf20Sopenharmony_ci * < 0 upon failure. Caller is responsible for SRP target port cleanup.
30818c2ecf20Sopenharmony_ci * 0 and target->state == SRP_TARGET_REMOVED if asynchronous target port
30828c2ecf20Sopenharmony_ci *    removal has been scheduled.
30838c2ecf20Sopenharmony_ci * 0 and target->state != SRP_TARGET_REMOVED upon success.
30848c2ecf20Sopenharmony_ci */
30858c2ecf20Sopenharmony_cistatic int srp_add_target(struct srp_host *host, struct srp_target_port *target)
30868c2ecf20Sopenharmony_ci{
30878c2ecf20Sopenharmony_ci	struct srp_rport_identifiers ids;
30888c2ecf20Sopenharmony_ci	struct srp_rport *rport;
30898c2ecf20Sopenharmony_ci
30908c2ecf20Sopenharmony_ci	target->state = SRP_TARGET_SCANNING;
30918c2ecf20Sopenharmony_ci	sprintf(target->target_name, "SRP.T10:%016llX",
30928c2ecf20Sopenharmony_ci		be64_to_cpu(target->id_ext));
30938c2ecf20Sopenharmony_ci
30948c2ecf20Sopenharmony_ci	if (scsi_add_host(target->scsi_host, host->srp_dev->dev->dev.parent))
30958c2ecf20Sopenharmony_ci		return -ENODEV;
30968c2ecf20Sopenharmony_ci
30978c2ecf20Sopenharmony_ci	memcpy(ids.port_id, &target->id_ext, 8);
30988c2ecf20Sopenharmony_ci	memcpy(ids.port_id + 8, &target->ioc_guid, 8);
30998c2ecf20Sopenharmony_ci	ids.roles = SRP_RPORT_ROLE_TARGET;
31008c2ecf20Sopenharmony_ci	rport = srp_rport_add(target->scsi_host, &ids);
31018c2ecf20Sopenharmony_ci	if (IS_ERR(rport)) {
31028c2ecf20Sopenharmony_ci		scsi_remove_host(target->scsi_host);
31038c2ecf20Sopenharmony_ci		return PTR_ERR(rport);
31048c2ecf20Sopenharmony_ci	}
31058c2ecf20Sopenharmony_ci
31068c2ecf20Sopenharmony_ci	rport->lld_data = target;
31078c2ecf20Sopenharmony_ci	target->rport = rport;
31088c2ecf20Sopenharmony_ci
31098c2ecf20Sopenharmony_ci	spin_lock(&host->target_lock);
31108c2ecf20Sopenharmony_ci	list_add_tail(&target->list, &host->target_list);
31118c2ecf20Sopenharmony_ci	spin_unlock(&host->target_lock);
31128c2ecf20Sopenharmony_ci
31138c2ecf20Sopenharmony_ci	scsi_scan_target(&target->scsi_host->shost_gendev,
31148c2ecf20Sopenharmony_ci			 0, target->scsi_id, SCAN_WILD_CARD, SCSI_SCAN_INITIAL);
31158c2ecf20Sopenharmony_ci
31168c2ecf20Sopenharmony_ci	if (srp_connected_ch(target) < target->ch_count ||
31178c2ecf20Sopenharmony_ci	    target->qp_in_error) {
31188c2ecf20Sopenharmony_ci		shost_printk(KERN_INFO, target->scsi_host,
31198c2ecf20Sopenharmony_ci			     PFX "SCSI scan failed - removing SCSI host\n");
31208c2ecf20Sopenharmony_ci		srp_queue_remove_work(target);
31218c2ecf20Sopenharmony_ci		goto out;
31228c2ecf20Sopenharmony_ci	}
31238c2ecf20Sopenharmony_ci
31248c2ecf20Sopenharmony_ci	pr_debug("%s: SCSI scan succeeded - detected %d LUNs\n",
31258c2ecf20Sopenharmony_ci		 dev_name(&target->scsi_host->shost_gendev),
31268c2ecf20Sopenharmony_ci		 srp_sdev_count(target->scsi_host));
31278c2ecf20Sopenharmony_ci
31288c2ecf20Sopenharmony_ci	spin_lock_irq(&target->lock);
31298c2ecf20Sopenharmony_ci	if (target->state == SRP_TARGET_SCANNING)
31308c2ecf20Sopenharmony_ci		target->state = SRP_TARGET_LIVE;
31318c2ecf20Sopenharmony_ci	spin_unlock_irq(&target->lock);
31328c2ecf20Sopenharmony_ci
31338c2ecf20Sopenharmony_ciout:
31348c2ecf20Sopenharmony_ci	return 0;
31358c2ecf20Sopenharmony_ci}
31368c2ecf20Sopenharmony_ci
31378c2ecf20Sopenharmony_cistatic void srp_release_dev(struct device *dev)
31388c2ecf20Sopenharmony_ci{
31398c2ecf20Sopenharmony_ci	struct srp_host *host =
31408c2ecf20Sopenharmony_ci		container_of(dev, struct srp_host, dev);
31418c2ecf20Sopenharmony_ci
31428c2ecf20Sopenharmony_ci	complete(&host->released);
31438c2ecf20Sopenharmony_ci}
31448c2ecf20Sopenharmony_ci
31458c2ecf20Sopenharmony_cistatic struct class srp_class = {
31468c2ecf20Sopenharmony_ci	.name    = "infiniband_srp",
31478c2ecf20Sopenharmony_ci	.dev_release = srp_release_dev
31488c2ecf20Sopenharmony_ci};
31498c2ecf20Sopenharmony_ci
31508c2ecf20Sopenharmony_ci/**
31518c2ecf20Sopenharmony_ci * srp_conn_unique() - check whether the connection to a target is unique
31528c2ecf20Sopenharmony_ci * @host:   SRP host.
31538c2ecf20Sopenharmony_ci * @target: SRP target port.
31548c2ecf20Sopenharmony_ci */
31558c2ecf20Sopenharmony_cistatic bool srp_conn_unique(struct srp_host *host,
31568c2ecf20Sopenharmony_ci			    struct srp_target_port *target)
31578c2ecf20Sopenharmony_ci{
31588c2ecf20Sopenharmony_ci	struct srp_target_port *t;
31598c2ecf20Sopenharmony_ci	bool ret = false;
31608c2ecf20Sopenharmony_ci
31618c2ecf20Sopenharmony_ci	if (target->state == SRP_TARGET_REMOVED)
31628c2ecf20Sopenharmony_ci		goto out;
31638c2ecf20Sopenharmony_ci
31648c2ecf20Sopenharmony_ci	ret = true;
31658c2ecf20Sopenharmony_ci
31668c2ecf20Sopenharmony_ci	spin_lock(&host->target_lock);
31678c2ecf20Sopenharmony_ci	list_for_each_entry(t, &host->target_list, list) {
31688c2ecf20Sopenharmony_ci		if (t != target &&
31698c2ecf20Sopenharmony_ci		    target->id_ext == t->id_ext &&
31708c2ecf20Sopenharmony_ci		    target->ioc_guid == t->ioc_guid &&
31718c2ecf20Sopenharmony_ci		    target->initiator_ext == t->initiator_ext) {
31728c2ecf20Sopenharmony_ci			ret = false;
31738c2ecf20Sopenharmony_ci			break;
31748c2ecf20Sopenharmony_ci		}
31758c2ecf20Sopenharmony_ci	}
31768c2ecf20Sopenharmony_ci	spin_unlock(&host->target_lock);
31778c2ecf20Sopenharmony_ci
31788c2ecf20Sopenharmony_ciout:
31798c2ecf20Sopenharmony_ci	return ret;
31808c2ecf20Sopenharmony_ci}
31818c2ecf20Sopenharmony_ci
31828c2ecf20Sopenharmony_ci/*
31838c2ecf20Sopenharmony_ci * Target ports are added by writing
31848c2ecf20Sopenharmony_ci *
31858c2ecf20Sopenharmony_ci *     id_ext=<SRP ID ext>,ioc_guid=<SRP IOC GUID>,dgid=<dest GID>,
31868c2ecf20Sopenharmony_ci *     pkey=<P_Key>,service_id=<service ID>
31878c2ecf20Sopenharmony_ci * or
31888c2ecf20Sopenharmony_ci *     id_ext=<SRP ID ext>,ioc_guid=<SRP IOC GUID>,
31898c2ecf20Sopenharmony_ci *     [src=<IPv4 address>,]dest=<IPv4 address>:<port number>
31908c2ecf20Sopenharmony_ci *
31918c2ecf20Sopenharmony_ci * to the add_target sysfs attribute.
31928c2ecf20Sopenharmony_ci */
31938c2ecf20Sopenharmony_cienum {
31948c2ecf20Sopenharmony_ci	SRP_OPT_ERR		= 0,
31958c2ecf20Sopenharmony_ci	SRP_OPT_ID_EXT		= 1 << 0,
31968c2ecf20Sopenharmony_ci	SRP_OPT_IOC_GUID	= 1 << 1,
31978c2ecf20Sopenharmony_ci	SRP_OPT_DGID		= 1 << 2,
31988c2ecf20Sopenharmony_ci	SRP_OPT_PKEY		= 1 << 3,
31998c2ecf20Sopenharmony_ci	SRP_OPT_SERVICE_ID	= 1 << 4,
32008c2ecf20Sopenharmony_ci	SRP_OPT_MAX_SECT	= 1 << 5,
32018c2ecf20Sopenharmony_ci	SRP_OPT_MAX_CMD_PER_LUN	= 1 << 6,
32028c2ecf20Sopenharmony_ci	SRP_OPT_IO_CLASS	= 1 << 7,
32038c2ecf20Sopenharmony_ci	SRP_OPT_INITIATOR_EXT	= 1 << 8,
32048c2ecf20Sopenharmony_ci	SRP_OPT_CMD_SG_ENTRIES	= 1 << 9,
32058c2ecf20Sopenharmony_ci	SRP_OPT_ALLOW_EXT_SG	= 1 << 10,
32068c2ecf20Sopenharmony_ci	SRP_OPT_SG_TABLESIZE	= 1 << 11,
32078c2ecf20Sopenharmony_ci	SRP_OPT_COMP_VECTOR	= 1 << 12,
32088c2ecf20Sopenharmony_ci	SRP_OPT_TL_RETRY_COUNT	= 1 << 13,
32098c2ecf20Sopenharmony_ci	SRP_OPT_QUEUE_SIZE	= 1 << 14,
32108c2ecf20Sopenharmony_ci	SRP_OPT_IP_SRC		= 1 << 15,
32118c2ecf20Sopenharmony_ci	SRP_OPT_IP_DEST		= 1 << 16,
32128c2ecf20Sopenharmony_ci	SRP_OPT_TARGET_CAN_QUEUE= 1 << 17,
32138c2ecf20Sopenharmony_ci	SRP_OPT_MAX_IT_IU_SIZE  = 1 << 18,
32148c2ecf20Sopenharmony_ci	SRP_OPT_CH_COUNT	= 1 << 19,
32158c2ecf20Sopenharmony_ci};
32168c2ecf20Sopenharmony_ci
32178c2ecf20Sopenharmony_cistatic unsigned int srp_opt_mandatory[] = {
32188c2ecf20Sopenharmony_ci	SRP_OPT_ID_EXT		|
32198c2ecf20Sopenharmony_ci	SRP_OPT_IOC_GUID	|
32208c2ecf20Sopenharmony_ci	SRP_OPT_DGID		|
32218c2ecf20Sopenharmony_ci	SRP_OPT_PKEY		|
32228c2ecf20Sopenharmony_ci	SRP_OPT_SERVICE_ID,
32238c2ecf20Sopenharmony_ci	SRP_OPT_ID_EXT		|
32248c2ecf20Sopenharmony_ci	SRP_OPT_IOC_GUID	|
32258c2ecf20Sopenharmony_ci	SRP_OPT_IP_DEST,
32268c2ecf20Sopenharmony_ci};
32278c2ecf20Sopenharmony_ci
32288c2ecf20Sopenharmony_cistatic const match_table_t srp_opt_tokens = {
32298c2ecf20Sopenharmony_ci	{ SRP_OPT_ID_EXT,		"id_ext=%s" 		},
32308c2ecf20Sopenharmony_ci	{ SRP_OPT_IOC_GUID,		"ioc_guid=%s" 		},
32318c2ecf20Sopenharmony_ci	{ SRP_OPT_DGID,			"dgid=%s" 		},
32328c2ecf20Sopenharmony_ci	{ SRP_OPT_PKEY,			"pkey=%x" 		},
32338c2ecf20Sopenharmony_ci	{ SRP_OPT_SERVICE_ID,		"service_id=%s"		},
32348c2ecf20Sopenharmony_ci	{ SRP_OPT_MAX_SECT,		"max_sect=%d" 		},
32358c2ecf20Sopenharmony_ci	{ SRP_OPT_MAX_CMD_PER_LUN,	"max_cmd_per_lun=%d" 	},
32368c2ecf20Sopenharmony_ci	{ SRP_OPT_TARGET_CAN_QUEUE,	"target_can_queue=%d"	},
32378c2ecf20Sopenharmony_ci	{ SRP_OPT_IO_CLASS,		"io_class=%x"		},
32388c2ecf20Sopenharmony_ci	{ SRP_OPT_INITIATOR_EXT,	"initiator_ext=%s"	},
32398c2ecf20Sopenharmony_ci	{ SRP_OPT_CMD_SG_ENTRIES,	"cmd_sg_entries=%u"	},
32408c2ecf20Sopenharmony_ci	{ SRP_OPT_ALLOW_EXT_SG,		"allow_ext_sg=%u"	},
32418c2ecf20Sopenharmony_ci	{ SRP_OPT_SG_TABLESIZE,		"sg_tablesize=%u"	},
32428c2ecf20Sopenharmony_ci	{ SRP_OPT_COMP_VECTOR,		"comp_vector=%u"	},
32438c2ecf20Sopenharmony_ci	{ SRP_OPT_TL_RETRY_COUNT,	"tl_retry_count=%u"	},
32448c2ecf20Sopenharmony_ci	{ SRP_OPT_QUEUE_SIZE,		"queue_size=%d"		},
32458c2ecf20Sopenharmony_ci	{ SRP_OPT_IP_SRC,		"src=%s"		},
32468c2ecf20Sopenharmony_ci	{ SRP_OPT_IP_DEST,		"dest=%s"		},
32478c2ecf20Sopenharmony_ci	{ SRP_OPT_MAX_IT_IU_SIZE,	"max_it_iu_size=%d"	},
32488c2ecf20Sopenharmony_ci	{ SRP_OPT_CH_COUNT,		"ch_count=%u",		},
32498c2ecf20Sopenharmony_ci	{ SRP_OPT_ERR,			NULL 			}
32508c2ecf20Sopenharmony_ci};
32518c2ecf20Sopenharmony_ci
32528c2ecf20Sopenharmony_ci/**
32538c2ecf20Sopenharmony_ci * srp_parse_in - parse an IP address and port number combination
32548c2ecf20Sopenharmony_ci * @net:	   [in]  Network namespace.
32558c2ecf20Sopenharmony_ci * @sa:		   [out] Address family, IP address and port number.
32568c2ecf20Sopenharmony_ci * @addr_port_str: [in]  IP address and port number.
32578c2ecf20Sopenharmony_ci * @has_port:	   [out] Whether or not @addr_port_str includes a port number.
32588c2ecf20Sopenharmony_ci *
32598c2ecf20Sopenharmony_ci * Parse the following address formats:
32608c2ecf20Sopenharmony_ci * - IPv4: <ip_address>:<port>, e.g. 1.2.3.4:5.
32618c2ecf20Sopenharmony_ci * - IPv6: \[<ipv6_address>\]:<port>, e.g. [1::2:3%4]:5.
32628c2ecf20Sopenharmony_ci */
32638c2ecf20Sopenharmony_cistatic int srp_parse_in(struct net *net, struct sockaddr_storage *sa,
32648c2ecf20Sopenharmony_ci			const char *addr_port_str, bool *has_port)
32658c2ecf20Sopenharmony_ci{
32668c2ecf20Sopenharmony_ci	char *addr_end, *addr = kstrdup(addr_port_str, GFP_KERNEL);
32678c2ecf20Sopenharmony_ci	char *port_str;
32688c2ecf20Sopenharmony_ci	int ret;
32698c2ecf20Sopenharmony_ci
32708c2ecf20Sopenharmony_ci	if (!addr)
32718c2ecf20Sopenharmony_ci		return -ENOMEM;
32728c2ecf20Sopenharmony_ci	port_str = strrchr(addr, ':');
32738c2ecf20Sopenharmony_ci	if (port_str && strchr(port_str, ']'))
32748c2ecf20Sopenharmony_ci		port_str = NULL;
32758c2ecf20Sopenharmony_ci	if (port_str)
32768c2ecf20Sopenharmony_ci		*port_str++ = '\0';
32778c2ecf20Sopenharmony_ci	if (has_port)
32788c2ecf20Sopenharmony_ci		*has_port = port_str != NULL;
32798c2ecf20Sopenharmony_ci	ret = inet_pton_with_scope(net, AF_INET, addr, port_str, sa);
32808c2ecf20Sopenharmony_ci	if (ret && addr[0]) {
32818c2ecf20Sopenharmony_ci		addr_end = addr + strlen(addr) - 1;
32828c2ecf20Sopenharmony_ci		if (addr[0] == '[' && *addr_end == ']') {
32838c2ecf20Sopenharmony_ci			*addr_end = '\0';
32848c2ecf20Sopenharmony_ci			ret = inet_pton_with_scope(net, AF_INET6, addr + 1,
32858c2ecf20Sopenharmony_ci						   port_str, sa);
32868c2ecf20Sopenharmony_ci		}
32878c2ecf20Sopenharmony_ci	}
32888c2ecf20Sopenharmony_ci	kfree(addr);
32898c2ecf20Sopenharmony_ci	pr_debug("%s -> %pISpfsc\n", addr_port_str, sa);
32908c2ecf20Sopenharmony_ci	return ret;
32918c2ecf20Sopenharmony_ci}
32928c2ecf20Sopenharmony_ci
32938c2ecf20Sopenharmony_cistatic int srp_parse_options(struct net *net, const char *buf,
32948c2ecf20Sopenharmony_ci			     struct srp_target_port *target)
32958c2ecf20Sopenharmony_ci{
32968c2ecf20Sopenharmony_ci	char *options, *sep_opt;
32978c2ecf20Sopenharmony_ci	char *p;
32988c2ecf20Sopenharmony_ci	substring_t args[MAX_OPT_ARGS];
32998c2ecf20Sopenharmony_ci	unsigned long long ull;
33008c2ecf20Sopenharmony_ci	bool has_port;
33018c2ecf20Sopenharmony_ci	int opt_mask = 0;
33028c2ecf20Sopenharmony_ci	int token;
33038c2ecf20Sopenharmony_ci	int ret = -EINVAL;
33048c2ecf20Sopenharmony_ci	int i;
33058c2ecf20Sopenharmony_ci
33068c2ecf20Sopenharmony_ci	options = kstrdup(buf, GFP_KERNEL);
33078c2ecf20Sopenharmony_ci	if (!options)
33088c2ecf20Sopenharmony_ci		return -ENOMEM;
33098c2ecf20Sopenharmony_ci
33108c2ecf20Sopenharmony_ci	sep_opt = options;
33118c2ecf20Sopenharmony_ci	while ((p = strsep(&sep_opt, ",\n")) != NULL) {
33128c2ecf20Sopenharmony_ci		if (!*p)
33138c2ecf20Sopenharmony_ci			continue;
33148c2ecf20Sopenharmony_ci
33158c2ecf20Sopenharmony_ci		token = match_token(p, srp_opt_tokens, args);
33168c2ecf20Sopenharmony_ci		opt_mask |= token;
33178c2ecf20Sopenharmony_ci
33188c2ecf20Sopenharmony_ci		switch (token) {
33198c2ecf20Sopenharmony_ci		case SRP_OPT_ID_EXT:
33208c2ecf20Sopenharmony_ci			p = match_strdup(args);
33218c2ecf20Sopenharmony_ci			if (!p) {
33228c2ecf20Sopenharmony_ci				ret = -ENOMEM;
33238c2ecf20Sopenharmony_ci				goto out;
33248c2ecf20Sopenharmony_ci			}
33258c2ecf20Sopenharmony_ci			ret = kstrtoull(p, 16, &ull);
33268c2ecf20Sopenharmony_ci			if (ret) {
33278c2ecf20Sopenharmony_ci				pr_warn("invalid id_ext parameter '%s'\n", p);
33288c2ecf20Sopenharmony_ci				kfree(p);
33298c2ecf20Sopenharmony_ci				goto out;
33308c2ecf20Sopenharmony_ci			}
33318c2ecf20Sopenharmony_ci			target->id_ext = cpu_to_be64(ull);
33328c2ecf20Sopenharmony_ci			kfree(p);
33338c2ecf20Sopenharmony_ci			break;
33348c2ecf20Sopenharmony_ci
33358c2ecf20Sopenharmony_ci		case SRP_OPT_IOC_GUID:
33368c2ecf20Sopenharmony_ci			p = match_strdup(args);
33378c2ecf20Sopenharmony_ci			if (!p) {
33388c2ecf20Sopenharmony_ci				ret = -ENOMEM;
33398c2ecf20Sopenharmony_ci				goto out;
33408c2ecf20Sopenharmony_ci			}
33418c2ecf20Sopenharmony_ci			ret = kstrtoull(p, 16, &ull);
33428c2ecf20Sopenharmony_ci			if (ret) {
33438c2ecf20Sopenharmony_ci				pr_warn("invalid ioc_guid parameter '%s'\n", p);
33448c2ecf20Sopenharmony_ci				kfree(p);
33458c2ecf20Sopenharmony_ci				goto out;
33468c2ecf20Sopenharmony_ci			}
33478c2ecf20Sopenharmony_ci			target->ioc_guid = cpu_to_be64(ull);
33488c2ecf20Sopenharmony_ci			kfree(p);
33498c2ecf20Sopenharmony_ci			break;
33508c2ecf20Sopenharmony_ci
33518c2ecf20Sopenharmony_ci		case SRP_OPT_DGID:
33528c2ecf20Sopenharmony_ci			p = match_strdup(args);
33538c2ecf20Sopenharmony_ci			if (!p) {
33548c2ecf20Sopenharmony_ci				ret = -ENOMEM;
33558c2ecf20Sopenharmony_ci				goto out;
33568c2ecf20Sopenharmony_ci			}
33578c2ecf20Sopenharmony_ci			if (strlen(p) != 32) {
33588c2ecf20Sopenharmony_ci				pr_warn("bad dest GID parameter '%s'\n", p);
33598c2ecf20Sopenharmony_ci				kfree(p);
33608c2ecf20Sopenharmony_ci				goto out;
33618c2ecf20Sopenharmony_ci			}
33628c2ecf20Sopenharmony_ci
33638c2ecf20Sopenharmony_ci			ret = hex2bin(target->ib_cm.orig_dgid.raw, p, 16);
33648c2ecf20Sopenharmony_ci			kfree(p);
33658c2ecf20Sopenharmony_ci			if (ret < 0)
33668c2ecf20Sopenharmony_ci				goto out;
33678c2ecf20Sopenharmony_ci			break;
33688c2ecf20Sopenharmony_ci
33698c2ecf20Sopenharmony_ci		case SRP_OPT_PKEY:
33708c2ecf20Sopenharmony_ci			ret = match_hex(args, &token);
33718c2ecf20Sopenharmony_ci			if (ret) {
33728c2ecf20Sopenharmony_ci				pr_warn("bad P_Key parameter '%s'\n", p);
33738c2ecf20Sopenharmony_ci				goto out;
33748c2ecf20Sopenharmony_ci			}
33758c2ecf20Sopenharmony_ci			target->ib_cm.pkey = cpu_to_be16(token);
33768c2ecf20Sopenharmony_ci			break;
33778c2ecf20Sopenharmony_ci
33788c2ecf20Sopenharmony_ci		case SRP_OPT_SERVICE_ID:
33798c2ecf20Sopenharmony_ci			p = match_strdup(args);
33808c2ecf20Sopenharmony_ci			if (!p) {
33818c2ecf20Sopenharmony_ci				ret = -ENOMEM;
33828c2ecf20Sopenharmony_ci				goto out;
33838c2ecf20Sopenharmony_ci			}
33848c2ecf20Sopenharmony_ci			ret = kstrtoull(p, 16, &ull);
33858c2ecf20Sopenharmony_ci			if (ret) {
33868c2ecf20Sopenharmony_ci				pr_warn("bad service_id parameter '%s'\n", p);
33878c2ecf20Sopenharmony_ci				kfree(p);
33888c2ecf20Sopenharmony_ci				goto out;
33898c2ecf20Sopenharmony_ci			}
33908c2ecf20Sopenharmony_ci			target->ib_cm.service_id = cpu_to_be64(ull);
33918c2ecf20Sopenharmony_ci			kfree(p);
33928c2ecf20Sopenharmony_ci			break;
33938c2ecf20Sopenharmony_ci
33948c2ecf20Sopenharmony_ci		case SRP_OPT_IP_SRC:
33958c2ecf20Sopenharmony_ci			p = match_strdup(args);
33968c2ecf20Sopenharmony_ci			if (!p) {
33978c2ecf20Sopenharmony_ci				ret = -ENOMEM;
33988c2ecf20Sopenharmony_ci				goto out;
33998c2ecf20Sopenharmony_ci			}
34008c2ecf20Sopenharmony_ci			ret = srp_parse_in(net, &target->rdma_cm.src.ss, p,
34018c2ecf20Sopenharmony_ci					   NULL);
34028c2ecf20Sopenharmony_ci			if (ret < 0) {
34038c2ecf20Sopenharmony_ci				pr_warn("bad source parameter '%s'\n", p);
34048c2ecf20Sopenharmony_ci				kfree(p);
34058c2ecf20Sopenharmony_ci				goto out;
34068c2ecf20Sopenharmony_ci			}
34078c2ecf20Sopenharmony_ci			target->rdma_cm.src_specified = true;
34088c2ecf20Sopenharmony_ci			kfree(p);
34098c2ecf20Sopenharmony_ci			break;
34108c2ecf20Sopenharmony_ci
34118c2ecf20Sopenharmony_ci		case SRP_OPT_IP_DEST:
34128c2ecf20Sopenharmony_ci			p = match_strdup(args);
34138c2ecf20Sopenharmony_ci			if (!p) {
34148c2ecf20Sopenharmony_ci				ret = -ENOMEM;
34158c2ecf20Sopenharmony_ci				goto out;
34168c2ecf20Sopenharmony_ci			}
34178c2ecf20Sopenharmony_ci			ret = srp_parse_in(net, &target->rdma_cm.dst.ss, p,
34188c2ecf20Sopenharmony_ci					   &has_port);
34198c2ecf20Sopenharmony_ci			if (!has_port)
34208c2ecf20Sopenharmony_ci				ret = -EINVAL;
34218c2ecf20Sopenharmony_ci			if (ret < 0) {
34228c2ecf20Sopenharmony_ci				pr_warn("bad dest parameter '%s'\n", p);
34238c2ecf20Sopenharmony_ci				kfree(p);
34248c2ecf20Sopenharmony_ci				goto out;
34258c2ecf20Sopenharmony_ci			}
34268c2ecf20Sopenharmony_ci			target->using_rdma_cm = true;
34278c2ecf20Sopenharmony_ci			kfree(p);
34288c2ecf20Sopenharmony_ci			break;
34298c2ecf20Sopenharmony_ci
34308c2ecf20Sopenharmony_ci		case SRP_OPT_MAX_SECT:
34318c2ecf20Sopenharmony_ci			ret = match_int(args, &token);
34328c2ecf20Sopenharmony_ci			if (ret) {
34338c2ecf20Sopenharmony_ci				pr_warn("bad max sect parameter '%s'\n", p);
34348c2ecf20Sopenharmony_ci				goto out;
34358c2ecf20Sopenharmony_ci			}
34368c2ecf20Sopenharmony_ci			target->scsi_host->max_sectors = token;
34378c2ecf20Sopenharmony_ci			break;
34388c2ecf20Sopenharmony_ci
34398c2ecf20Sopenharmony_ci		case SRP_OPT_QUEUE_SIZE:
34408c2ecf20Sopenharmony_ci			ret = match_int(args, &token);
34418c2ecf20Sopenharmony_ci			if (ret) {
34428c2ecf20Sopenharmony_ci				pr_warn("match_int() failed for queue_size parameter '%s', Error %d\n",
34438c2ecf20Sopenharmony_ci					p, ret);
34448c2ecf20Sopenharmony_ci				goto out;
34458c2ecf20Sopenharmony_ci			}
34468c2ecf20Sopenharmony_ci			if (token < 1) {
34478c2ecf20Sopenharmony_ci				pr_warn("bad queue_size parameter '%s'\n", p);
34488c2ecf20Sopenharmony_ci				ret = -EINVAL;
34498c2ecf20Sopenharmony_ci				goto out;
34508c2ecf20Sopenharmony_ci			}
34518c2ecf20Sopenharmony_ci			target->scsi_host->can_queue = token;
34528c2ecf20Sopenharmony_ci			target->queue_size = token + SRP_RSP_SQ_SIZE +
34538c2ecf20Sopenharmony_ci					     SRP_TSK_MGMT_SQ_SIZE;
34548c2ecf20Sopenharmony_ci			if (!(opt_mask & SRP_OPT_MAX_CMD_PER_LUN))
34558c2ecf20Sopenharmony_ci				target->scsi_host->cmd_per_lun = token;
34568c2ecf20Sopenharmony_ci			break;
34578c2ecf20Sopenharmony_ci
34588c2ecf20Sopenharmony_ci		case SRP_OPT_MAX_CMD_PER_LUN:
34598c2ecf20Sopenharmony_ci			ret = match_int(args, &token);
34608c2ecf20Sopenharmony_ci			if (ret) {
34618c2ecf20Sopenharmony_ci				pr_warn("match_int() failed for max cmd_per_lun parameter '%s', Error %d\n",
34628c2ecf20Sopenharmony_ci					p, ret);
34638c2ecf20Sopenharmony_ci				goto out;
34648c2ecf20Sopenharmony_ci			}
34658c2ecf20Sopenharmony_ci			if (token < 1) {
34668c2ecf20Sopenharmony_ci				pr_warn("bad max cmd_per_lun parameter '%s'\n",
34678c2ecf20Sopenharmony_ci					p);
34688c2ecf20Sopenharmony_ci				ret = -EINVAL;
34698c2ecf20Sopenharmony_ci				goto out;
34708c2ecf20Sopenharmony_ci			}
34718c2ecf20Sopenharmony_ci			target->scsi_host->cmd_per_lun = token;
34728c2ecf20Sopenharmony_ci			break;
34738c2ecf20Sopenharmony_ci
34748c2ecf20Sopenharmony_ci		case SRP_OPT_TARGET_CAN_QUEUE:
34758c2ecf20Sopenharmony_ci			ret = match_int(args, &token);
34768c2ecf20Sopenharmony_ci			if (ret) {
34778c2ecf20Sopenharmony_ci				pr_warn("match_int() failed for max target_can_queue parameter '%s', Error %d\n",
34788c2ecf20Sopenharmony_ci					p, ret);
34798c2ecf20Sopenharmony_ci				goto out;
34808c2ecf20Sopenharmony_ci			}
34818c2ecf20Sopenharmony_ci			if (token < 1) {
34828c2ecf20Sopenharmony_ci				pr_warn("bad max target_can_queue parameter '%s'\n",
34838c2ecf20Sopenharmony_ci					p);
34848c2ecf20Sopenharmony_ci				ret = -EINVAL;
34858c2ecf20Sopenharmony_ci				goto out;
34868c2ecf20Sopenharmony_ci			}
34878c2ecf20Sopenharmony_ci			target->target_can_queue = token;
34888c2ecf20Sopenharmony_ci			break;
34898c2ecf20Sopenharmony_ci
34908c2ecf20Sopenharmony_ci		case SRP_OPT_IO_CLASS:
34918c2ecf20Sopenharmony_ci			ret = match_hex(args, &token);
34928c2ecf20Sopenharmony_ci			if (ret) {
34938c2ecf20Sopenharmony_ci				pr_warn("bad IO class parameter '%s'\n", p);
34948c2ecf20Sopenharmony_ci				goto out;
34958c2ecf20Sopenharmony_ci			}
34968c2ecf20Sopenharmony_ci			if (token != SRP_REV10_IB_IO_CLASS &&
34978c2ecf20Sopenharmony_ci			    token != SRP_REV16A_IB_IO_CLASS) {
34988c2ecf20Sopenharmony_ci				pr_warn("unknown IO class parameter value %x specified (use %x or %x).\n",
34998c2ecf20Sopenharmony_ci					token, SRP_REV10_IB_IO_CLASS,
35008c2ecf20Sopenharmony_ci					SRP_REV16A_IB_IO_CLASS);
35018c2ecf20Sopenharmony_ci				ret = -EINVAL;
35028c2ecf20Sopenharmony_ci				goto out;
35038c2ecf20Sopenharmony_ci			}
35048c2ecf20Sopenharmony_ci			target->io_class = token;
35058c2ecf20Sopenharmony_ci			break;
35068c2ecf20Sopenharmony_ci
35078c2ecf20Sopenharmony_ci		case SRP_OPT_INITIATOR_EXT:
35088c2ecf20Sopenharmony_ci			p = match_strdup(args);
35098c2ecf20Sopenharmony_ci			if (!p) {
35108c2ecf20Sopenharmony_ci				ret = -ENOMEM;
35118c2ecf20Sopenharmony_ci				goto out;
35128c2ecf20Sopenharmony_ci			}
35138c2ecf20Sopenharmony_ci			ret = kstrtoull(p, 16, &ull);
35148c2ecf20Sopenharmony_ci			if (ret) {
35158c2ecf20Sopenharmony_ci				pr_warn("bad initiator_ext value '%s'\n", p);
35168c2ecf20Sopenharmony_ci				kfree(p);
35178c2ecf20Sopenharmony_ci				goto out;
35188c2ecf20Sopenharmony_ci			}
35198c2ecf20Sopenharmony_ci			target->initiator_ext = cpu_to_be64(ull);
35208c2ecf20Sopenharmony_ci			kfree(p);
35218c2ecf20Sopenharmony_ci			break;
35228c2ecf20Sopenharmony_ci
35238c2ecf20Sopenharmony_ci		case SRP_OPT_CMD_SG_ENTRIES:
35248c2ecf20Sopenharmony_ci			ret = match_int(args, &token);
35258c2ecf20Sopenharmony_ci			if (ret) {
35268c2ecf20Sopenharmony_ci				pr_warn("match_int() failed for max cmd_sg_entries parameter '%s', Error %d\n",
35278c2ecf20Sopenharmony_ci					p, ret);
35288c2ecf20Sopenharmony_ci				goto out;
35298c2ecf20Sopenharmony_ci			}
35308c2ecf20Sopenharmony_ci			if (token < 1 || token > 255) {
35318c2ecf20Sopenharmony_ci				pr_warn("bad max cmd_sg_entries parameter '%s'\n",
35328c2ecf20Sopenharmony_ci					p);
35338c2ecf20Sopenharmony_ci				ret = -EINVAL;
35348c2ecf20Sopenharmony_ci				goto out;
35358c2ecf20Sopenharmony_ci			}
35368c2ecf20Sopenharmony_ci			target->cmd_sg_cnt = token;
35378c2ecf20Sopenharmony_ci			break;
35388c2ecf20Sopenharmony_ci
35398c2ecf20Sopenharmony_ci		case SRP_OPT_ALLOW_EXT_SG:
35408c2ecf20Sopenharmony_ci			ret = match_int(args, &token);
35418c2ecf20Sopenharmony_ci			if (ret) {
35428c2ecf20Sopenharmony_ci				pr_warn("bad allow_ext_sg parameter '%s'\n", p);
35438c2ecf20Sopenharmony_ci				goto out;
35448c2ecf20Sopenharmony_ci			}
35458c2ecf20Sopenharmony_ci			target->allow_ext_sg = !!token;
35468c2ecf20Sopenharmony_ci			break;
35478c2ecf20Sopenharmony_ci
35488c2ecf20Sopenharmony_ci		case SRP_OPT_SG_TABLESIZE:
35498c2ecf20Sopenharmony_ci			ret = match_int(args, &token);
35508c2ecf20Sopenharmony_ci			if (ret) {
35518c2ecf20Sopenharmony_ci				pr_warn("match_int() failed for max sg_tablesize parameter '%s', Error %d\n",
35528c2ecf20Sopenharmony_ci					p, ret);
35538c2ecf20Sopenharmony_ci				goto out;
35548c2ecf20Sopenharmony_ci			}
35558c2ecf20Sopenharmony_ci			if (token < 1 || token > SG_MAX_SEGMENTS) {
35568c2ecf20Sopenharmony_ci				pr_warn("bad max sg_tablesize parameter '%s'\n",
35578c2ecf20Sopenharmony_ci					p);
35588c2ecf20Sopenharmony_ci				ret = -EINVAL;
35598c2ecf20Sopenharmony_ci				goto out;
35608c2ecf20Sopenharmony_ci			}
35618c2ecf20Sopenharmony_ci			target->sg_tablesize = token;
35628c2ecf20Sopenharmony_ci			break;
35638c2ecf20Sopenharmony_ci
35648c2ecf20Sopenharmony_ci		case SRP_OPT_COMP_VECTOR:
35658c2ecf20Sopenharmony_ci			ret = match_int(args, &token);
35668c2ecf20Sopenharmony_ci			if (ret) {
35678c2ecf20Sopenharmony_ci				pr_warn("match_int() failed for comp_vector parameter '%s', Error %d\n",
35688c2ecf20Sopenharmony_ci					p, ret);
35698c2ecf20Sopenharmony_ci				goto out;
35708c2ecf20Sopenharmony_ci			}
35718c2ecf20Sopenharmony_ci			if (token < 0) {
35728c2ecf20Sopenharmony_ci				pr_warn("bad comp_vector parameter '%s'\n", p);
35738c2ecf20Sopenharmony_ci				ret = -EINVAL;
35748c2ecf20Sopenharmony_ci				goto out;
35758c2ecf20Sopenharmony_ci			}
35768c2ecf20Sopenharmony_ci			target->comp_vector = token;
35778c2ecf20Sopenharmony_ci			break;
35788c2ecf20Sopenharmony_ci
35798c2ecf20Sopenharmony_ci		case SRP_OPT_TL_RETRY_COUNT:
35808c2ecf20Sopenharmony_ci			ret = match_int(args, &token);
35818c2ecf20Sopenharmony_ci			if (ret) {
35828c2ecf20Sopenharmony_ci				pr_warn("match_int() failed for tl_retry_count parameter '%s', Error %d\n",
35838c2ecf20Sopenharmony_ci					p, ret);
35848c2ecf20Sopenharmony_ci				goto out;
35858c2ecf20Sopenharmony_ci			}
35868c2ecf20Sopenharmony_ci			if (token < 2 || token > 7) {
35878c2ecf20Sopenharmony_ci				pr_warn("bad tl_retry_count parameter '%s' (must be a number between 2 and 7)\n",
35888c2ecf20Sopenharmony_ci					p);
35898c2ecf20Sopenharmony_ci				ret = -EINVAL;
35908c2ecf20Sopenharmony_ci				goto out;
35918c2ecf20Sopenharmony_ci			}
35928c2ecf20Sopenharmony_ci			target->tl_retry_count = token;
35938c2ecf20Sopenharmony_ci			break;
35948c2ecf20Sopenharmony_ci
35958c2ecf20Sopenharmony_ci		case SRP_OPT_MAX_IT_IU_SIZE:
35968c2ecf20Sopenharmony_ci			ret = match_int(args, &token);
35978c2ecf20Sopenharmony_ci			if (ret) {
35988c2ecf20Sopenharmony_ci				pr_warn("match_int() failed for max it_iu_size parameter '%s', Error %d\n",
35998c2ecf20Sopenharmony_ci					p, ret);
36008c2ecf20Sopenharmony_ci				goto out;
36018c2ecf20Sopenharmony_ci			}
36028c2ecf20Sopenharmony_ci			if (token < 0) {
36038c2ecf20Sopenharmony_ci				pr_warn("bad maximum initiator to target IU size '%s'\n", p);
36048c2ecf20Sopenharmony_ci				ret = -EINVAL;
36058c2ecf20Sopenharmony_ci				goto out;
36068c2ecf20Sopenharmony_ci			}
36078c2ecf20Sopenharmony_ci			target->max_it_iu_size = token;
36088c2ecf20Sopenharmony_ci			break;
36098c2ecf20Sopenharmony_ci
36108c2ecf20Sopenharmony_ci		case SRP_OPT_CH_COUNT:
36118c2ecf20Sopenharmony_ci			ret = match_int(args, &token);
36128c2ecf20Sopenharmony_ci			if (ret) {
36138c2ecf20Sopenharmony_ci				pr_warn("match_int() failed for channel count parameter '%s', Error %d\n",
36148c2ecf20Sopenharmony_ci					p, ret);
36158c2ecf20Sopenharmony_ci				goto out;
36168c2ecf20Sopenharmony_ci			}
36178c2ecf20Sopenharmony_ci			if (token < 1) {
36188c2ecf20Sopenharmony_ci				pr_warn("bad channel count %s\n", p);
36198c2ecf20Sopenharmony_ci				ret = -EINVAL;
36208c2ecf20Sopenharmony_ci				goto out;
36218c2ecf20Sopenharmony_ci			}
36228c2ecf20Sopenharmony_ci			target->ch_count = token;
36238c2ecf20Sopenharmony_ci			break;
36248c2ecf20Sopenharmony_ci
36258c2ecf20Sopenharmony_ci		default:
36268c2ecf20Sopenharmony_ci			pr_warn("unknown parameter or missing value '%s' in target creation request\n",
36278c2ecf20Sopenharmony_ci				p);
36288c2ecf20Sopenharmony_ci			ret = -EINVAL;
36298c2ecf20Sopenharmony_ci			goto out;
36308c2ecf20Sopenharmony_ci		}
36318c2ecf20Sopenharmony_ci	}
36328c2ecf20Sopenharmony_ci
36338c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(srp_opt_mandatory); i++) {
36348c2ecf20Sopenharmony_ci		if ((opt_mask & srp_opt_mandatory[i]) == srp_opt_mandatory[i]) {
36358c2ecf20Sopenharmony_ci			ret = 0;
36368c2ecf20Sopenharmony_ci			break;
36378c2ecf20Sopenharmony_ci		}
36388c2ecf20Sopenharmony_ci	}
36398c2ecf20Sopenharmony_ci	if (ret)
36408c2ecf20Sopenharmony_ci		pr_warn("target creation request is missing one or more parameters\n");
36418c2ecf20Sopenharmony_ci
36428c2ecf20Sopenharmony_ci	if (target->scsi_host->cmd_per_lun > target->scsi_host->can_queue
36438c2ecf20Sopenharmony_ci	    && (opt_mask & SRP_OPT_MAX_CMD_PER_LUN))
36448c2ecf20Sopenharmony_ci		pr_warn("cmd_per_lun = %d > queue_size = %d\n",
36458c2ecf20Sopenharmony_ci			target->scsi_host->cmd_per_lun,
36468c2ecf20Sopenharmony_ci			target->scsi_host->can_queue);
36478c2ecf20Sopenharmony_ci
36488c2ecf20Sopenharmony_ciout:
36498c2ecf20Sopenharmony_ci	kfree(options);
36508c2ecf20Sopenharmony_ci	return ret;
36518c2ecf20Sopenharmony_ci}
36528c2ecf20Sopenharmony_ci
36538c2ecf20Sopenharmony_cistatic ssize_t srp_create_target(struct device *dev,
36548c2ecf20Sopenharmony_ci				 struct device_attribute *attr,
36558c2ecf20Sopenharmony_ci				 const char *buf, size_t count)
36568c2ecf20Sopenharmony_ci{
36578c2ecf20Sopenharmony_ci	struct srp_host *host =
36588c2ecf20Sopenharmony_ci		container_of(dev, struct srp_host, dev);
36598c2ecf20Sopenharmony_ci	struct Scsi_Host *target_host;
36608c2ecf20Sopenharmony_ci	struct srp_target_port *target;
36618c2ecf20Sopenharmony_ci	struct srp_rdma_ch *ch;
36628c2ecf20Sopenharmony_ci	struct srp_device *srp_dev = host->srp_dev;
36638c2ecf20Sopenharmony_ci	struct ib_device *ibdev = srp_dev->dev;
36648c2ecf20Sopenharmony_ci	int ret, i, ch_idx;
36658c2ecf20Sopenharmony_ci	unsigned int max_sectors_per_mr, mr_per_cmd = 0;
36668c2ecf20Sopenharmony_ci	bool multich = false;
36678c2ecf20Sopenharmony_ci	uint32_t max_iu_len;
36688c2ecf20Sopenharmony_ci
36698c2ecf20Sopenharmony_ci	target_host = scsi_host_alloc(&srp_template,
36708c2ecf20Sopenharmony_ci				      sizeof (struct srp_target_port));
36718c2ecf20Sopenharmony_ci	if (!target_host)
36728c2ecf20Sopenharmony_ci		return -ENOMEM;
36738c2ecf20Sopenharmony_ci
36748c2ecf20Sopenharmony_ci	target_host->transportt  = ib_srp_transport_template;
36758c2ecf20Sopenharmony_ci	target_host->max_channel = 0;
36768c2ecf20Sopenharmony_ci	target_host->max_id      = 1;
36778c2ecf20Sopenharmony_ci	target_host->max_lun     = -1LL;
36788c2ecf20Sopenharmony_ci	target_host->max_cmd_len = sizeof ((struct srp_cmd *) (void *) 0L)->cdb;
36798c2ecf20Sopenharmony_ci	target_host->max_segment_size = ib_dma_max_seg_size(ibdev);
36808c2ecf20Sopenharmony_ci
36818c2ecf20Sopenharmony_ci	if (!(ibdev->attrs.device_cap_flags & IB_DEVICE_SG_GAPS_REG))
36828c2ecf20Sopenharmony_ci		target_host->virt_boundary_mask = ~srp_dev->mr_page_mask;
36838c2ecf20Sopenharmony_ci
36848c2ecf20Sopenharmony_ci	target = host_to_target(target_host);
36858c2ecf20Sopenharmony_ci
36868c2ecf20Sopenharmony_ci	target->net		= kobj_ns_grab_current(KOBJ_NS_TYPE_NET);
36878c2ecf20Sopenharmony_ci	target->io_class	= SRP_REV16A_IB_IO_CLASS;
36888c2ecf20Sopenharmony_ci	target->scsi_host	= target_host;
36898c2ecf20Sopenharmony_ci	target->srp_host	= host;
36908c2ecf20Sopenharmony_ci	target->lkey		= host->srp_dev->pd->local_dma_lkey;
36918c2ecf20Sopenharmony_ci	target->global_rkey	= host->srp_dev->global_rkey;
36928c2ecf20Sopenharmony_ci	target->cmd_sg_cnt	= cmd_sg_entries;
36938c2ecf20Sopenharmony_ci	target->sg_tablesize	= indirect_sg_entries ? : cmd_sg_entries;
36948c2ecf20Sopenharmony_ci	target->allow_ext_sg	= allow_ext_sg;
36958c2ecf20Sopenharmony_ci	target->tl_retry_count	= 7;
36968c2ecf20Sopenharmony_ci	target->queue_size	= SRP_DEFAULT_QUEUE_SIZE;
36978c2ecf20Sopenharmony_ci
36988c2ecf20Sopenharmony_ci	/*
36998c2ecf20Sopenharmony_ci	 * Avoid that the SCSI host can be removed by srp_remove_target()
37008c2ecf20Sopenharmony_ci	 * before this function returns.
37018c2ecf20Sopenharmony_ci	 */
37028c2ecf20Sopenharmony_ci	scsi_host_get(target->scsi_host);
37038c2ecf20Sopenharmony_ci
37048c2ecf20Sopenharmony_ci	ret = mutex_lock_interruptible(&host->add_target_mutex);
37058c2ecf20Sopenharmony_ci	if (ret < 0)
37068c2ecf20Sopenharmony_ci		goto put;
37078c2ecf20Sopenharmony_ci
37088c2ecf20Sopenharmony_ci	ret = srp_parse_options(target->net, buf, target);
37098c2ecf20Sopenharmony_ci	if (ret)
37108c2ecf20Sopenharmony_ci		goto out;
37118c2ecf20Sopenharmony_ci
37128c2ecf20Sopenharmony_ci	if (!srp_conn_unique(target->srp_host, target)) {
37138c2ecf20Sopenharmony_ci		if (target->using_rdma_cm) {
37148c2ecf20Sopenharmony_ci			shost_printk(KERN_INFO, target->scsi_host,
37158c2ecf20Sopenharmony_ci				     PFX "Already connected to target port with id_ext=%016llx;ioc_guid=%016llx;dest=%pIS\n",
37168c2ecf20Sopenharmony_ci				     be64_to_cpu(target->id_ext),
37178c2ecf20Sopenharmony_ci				     be64_to_cpu(target->ioc_guid),
37188c2ecf20Sopenharmony_ci				     &target->rdma_cm.dst);
37198c2ecf20Sopenharmony_ci		} else {
37208c2ecf20Sopenharmony_ci			shost_printk(KERN_INFO, target->scsi_host,
37218c2ecf20Sopenharmony_ci				     PFX "Already connected to target port with id_ext=%016llx;ioc_guid=%016llx;initiator_ext=%016llx\n",
37228c2ecf20Sopenharmony_ci				     be64_to_cpu(target->id_ext),
37238c2ecf20Sopenharmony_ci				     be64_to_cpu(target->ioc_guid),
37248c2ecf20Sopenharmony_ci				     be64_to_cpu(target->initiator_ext));
37258c2ecf20Sopenharmony_ci		}
37268c2ecf20Sopenharmony_ci		ret = -EEXIST;
37278c2ecf20Sopenharmony_ci		goto out;
37288c2ecf20Sopenharmony_ci	}
37298c2ecf20Sopenharmony_ci
37308c2ecf20Sopenharmony_ci	if (!srp_dev->has_fr && !target->allow_ext_sg &&
37318c2ecf20Sopenharmony_ci	    target->cmd_sg_cnt < target->sg_tablesize) {
37328c2ecf20Sopenharmony_ci		pr_warn("No MR pool and no external indirect descriptors, limiting sg_tablesize to cmd_sg_cnt\n");
37338c2ecf20Sopenharmony_ci		target->sg_tablesize = target->cmd_sg_cnt;
37348c2ecf20Sopenharmony_ci	}
37358c2ecf20Sopenharmony_ci
37368c2ecf20Sopenharmony_ci	if (srp_dev->use_fast_reg) {
37378c2ecf20Sopenharmony_ci		bool gaps_reg = (ibdev->attrs.device_cap_flags &
37388c2ecf20Sopenharmony_ci				 IB_DEVICE_SG_GAPS_REG);
37398c2ecf20Sopenharmony_ci
37408c2ecf20Sopenharmony_ci		max_sectors_per_mr = srp_dev->max_pages_per_mr <<
37418c2ecf20Sopenharmony_ci				  (ilog2(srp_dev->mr_page_size) - 9);
37428c2ecf20Sopenharmony_ci		if (!gaps_reg) {
37438c2ecf20Sopenharmony_ci			/*
37448c2ecf20Sopenharmony_ci			 * FR can only map one HCA page per entry. If the start
37458c2ecf20Sopenharmony_ci			 * address is not aligned on a HCA page boundary two
37468c2ecf20Sopenharmony_ci			 * entries will be used for the head and the tail
37478c2ecf20Sopenharmony_ci			 * although these two entries combined contain at most
37488c2ecf20Sopenharmony_ci			 * one HCA page of data. Hence the "+ 1" in the
37498c2ecf20Sopenharmony_ci			 * calculation below.
37508c2ecf20Sopenharmony_ci			 *
37518c2ecf20Sopenharmony_ci			 * The indirect data buffer descriptor is contiguous
37528c2ecf20Sopenharmony_ci			 * so the memory for that buffer will only be
37538c2ecf20Sopenharmony_ci			 * registered if register_always is true. Hence add
37548c2ecf20Sopenharmony_ci			 * one to mr_per_cmd if register_always has been set.
37558c2ecf20Sopenharmony_ci			 */
37568c2ecf20Sopenharmony_ci			mr_per_cmd = register_always +
37578c2ecf20Sopenharmony_ci				(target->scsi_host->max_sectors + 1 +
37588c2ecf20Sopenharmony_ci				 max_sectors_per_mr - 1) / max_sectors_per_mr;
37598c2ecf20Sopenharmony_ci		} else {
37608c2ecf20Sopenharmony_ci			mr_per_cmd = register_always +
37618c2ecf20Sopenharmony_ci				(target->sg_tablesize +
37628c2ecf20Sopenharmony_ci				 srp_dev->max_pages_per_mr - 1) /
37638c2ecf20Sopenharmony_ci				srp_dev->max_pages_per_mr;
37648c2ecf20Sopenharmony_ci		}
37658c2ecf20Sopenharmony_ci		pr_debug("max_sectors = %u; max_pages_per_mr = %u; mr_page_size = %u; max_sectors_per_mr = %u; mr_per_cmd = %u\n",
37668c2ecf20Sopenharmony_ci			 target->scsi_host->max_sectors, srp_dev->max_pages_per_mr, srp_dev->mr_page_size,
37678c2ecf20Sopenharmony_ci			 max_sectors_per_mr, mr_per_cmd);
37688c2ecf20Sopenharmony_ci	}
37698c2ecf20Sopenharmony_ci
37708c2ecf20Sopenharmony_ci	target_host->sg_tablesize = target->sg_tablesize;
37718c2ecf20Sopenharmony_ci	target->mr_pool_size = target->scsi_host->can_queue * mr_per_cmd;
37728c2ecf20Sopenharmony_ci	target->mr_per_cmd = mr_per_cmd;
37738c2ecf20Sopenharmony_ci	target->indirect_size = target->sg_tablesize *
37748c2ecf20Sopenharmony_ci				sizeof (struct srp_direct_buf);
37758c2ecf20Sopenharmony_ci	max_iu_len = srp_max_it_iu_len(target->cmd_sg_cnt,
37768c2ecf20Sopenharmony_ci				       srp_use_imm_data,
37778c2ecf20Sopenharmony_ci				       target->max_it_iu_size);
37788c2ecf20Sopenharmony_ci
37798c2ecf20Sopenharmony_ci	INIT_WORK(&target->tl_err_work, srp_tl_err_work);
37808c2ecf20Sopenharmony_ci	INIT_WORK(&target->remove_work, srp_remove_work);
37818c2ecf20Sopenharmony_ci	spin_lock_init(&target->lock);
37828c2ecf20Sopenharmony_ci	ret = rdma_query_gid(ibdev, host->port, 0, &target->sgid);
37838c2ecf20Sopenharmony_ci	if (ret)
37848c2ecf20Sopenharmony_ci		goto out;
37858c2ecf20Sopenharmony_ci
37868c2ecf20Sopenharmony_ci	ret = -ENOMEM;
37878c2ecf20Sopenharmony_ci	if (target->ch_count == 0) {
37888c2ecf20Sopenharmony_ci		target->ch_count =
37898c2ecf20Sopenharmony_ci			min(ch_count ?:
37908c2ecf20Sopenharmony_ci				max(4 * num_online_nodes(),
37918c2ecf20Sopenharmony_ci				    ibdev->num_comp_vectors),
37928c2ecf20Sopenharmony_ci				num_online_cpus());
37938c2ecf20Sopenharmony_ci	}
37948c2ecf20Sopenharmony_ci
37958c2ecf20Sopenharmony_ci	target->ch = kcalloc(target->ch_count, sizeof(*target->ch),
37968c2ecf20Sopenharmony_ci			     GFP_KERNEL);
37978c2ecf20Sopenharmony_ci	if (!target->ch)
37988c2ecf20Sopenharmony_ci		goto out;
37998c2ecf20Sopenharmony_ci
38008c2ecf20Sopenharmony_ci	for (ch_idx = 0; ch_idx < target->ch_count; ++ch_idx) {
38018c2ecf20Sopenharmony_ci		ch = &target->ch[ch_idx];
38028c2ecf20Sopenharmony_ci		ch->target = target;
38038c2ecf20Sopenharmony_ci		ch->comp_vector = ch_idx % ibdev->num_comp_vectors;
38048c2ecf20Sopenharmony_ci		spin_lock_init(&ch->lock);
38058c2ecf20Sopenharmony_ci		INIT_LIST_HEAD(&ch->free_tx);
38068c2ecf20Sopenharmony_ci		ret = srp_new_cm_id(ch);
38078c2ecf20Sopenharmony_ci		if (ret)
38088c2ecf20Sopenharmony_ci			goto err_disconnect;
38098c2ecf20Sopenharmony_ci
38108c2ecf20Sopenharmony_ci		ret = srp_create_ch_ib(ch);
38118c2ecf20Sopenharmony_ci		if (ret)
38128c2ecf20Sopenharmony_ci			goto err_disconnect;
38138c2ecf20Sopenharmony_ci
38148c2ecf20Sopenharmony_ci		ret = srp_connect_ch(ch, max_iu_len, multich);
38158c2ecf20Sopenharmony_ci		if (ret) {
38168c2ecf20Sopenharmony_ci			char dst[64];
38178c2ecf20Sopenharmony_ci
38188c2ecf20Sopenharmony_ci			if (target->using_rdma_cm)
38198c2ecf20Sopenharmony_ci				snprintf(dst, sizeof(dst), "%pIS",
38208c2ecf20Sopenharmony_ci					&target->rdma_cm.dst);
38218c2ecf20Sopenharmony_ci			else
38228c2ecf20Sopenharmony_ci				snprintf(dst, sizeof(dst), "%pI6",
38238c2ecf20Sopenharmony_ci					target->ib_cm.orig_dgid.raw);
38248c2ecf20Sopenharmony_ci			shost_printk(KERN_ERR, target->scsi_host,
38258c2ecf20Sopenharmony_ci				PFX "Connection %d/%d to %s failed\n",
38268c2ecf20Sopenharmony_ci				ch_idx,
38278c2ecf20Sopenharmony_ci				target->ch_count, dst);
38288c2ecf20Sopenharmony_ci			if (ch_idx == 0) {
38298c2ecf20Sopenharmony_ci				goto free_ch;
38308c2ecf20Sopenharmony_ci			} else {
38318c2ecf20Sopenharmony_ci				srp_free_ch_ib(target, ch);
38328c2ecf20Sopenharmony_ci				target->ch_count = ch - target->ch;
38338c2ecf20Sopenharmony_ci				goto connected;
38348c2ecf20Sopenharmony_ci			}
38358c2ecf20Sopenharmony_ci		}
38368c2ecf20Sopenharmony_ci		multich = true;
38378c2ecf20Sopenharmony_ci	}
38388c2ecf20Sopenharmony_ci
38398c2ecf20Sopenharmony_ciconnected:
38408c2ecf20Sopenharmony_ci	target->scsi_host->nr_hw_queues = target->ch_count;
38418c2ecf20Sopenharmony_ci
38428c2ecf20Sopenharmony_ci	ret = srp_add_target(host, target);
38438c2ecf20Sopenharmony_ci	if (ret)
38448c2ecf20Sopenharmony_ci		goto err_disconnect;
38458c2ecf20Sopenharmony_ci
38468c2ecf20Sopenharmony_ci	if (target->state != SRP_TARGET_REMOVED) {
38478c2ecf20Sopenharmony_ci		if (target->using_rdma_cm) {
38488c2ecf20Sopenharmony_ci			shost_printk(KERN_DEBUG, target->scsi_host, PFX
38498c2ecf20Sopenharmony_ci				     "new target: id_ext %016llx ioc_guid %016llx sgid %pI6 dest %pIS\n",
38508c2ecf20Sopenharmony_ci				     be64_to_cpu(target->id_ext),
38518c2ecf20Sopenharmony_ci				     be64_to_cpu(target->ioc_guid),
38528c2ecf20Sopenharmony_ci				     target->sgid.raw, &target->rdma_cm.dst);
38538c2ecf20Sopenharmony_ci		} else {
38548c2ecf20Sopenharmony_ci			shost_printk(KERN_DEBUG, target->scsi_host, PFX
38558c2ecf20Sopenharmony_ci				     "new target: id_ext %016llx ioc_guid %016llx pkey %04x service_id %016llx sgid %pI6 dgid %pI6\n",
38568c2ecf20Sopenharmony_ci				     be64_to_cpu(target->id_ext),
38578c2ecf20Sopenharmony_ci				     be64_to_cpu(target->ioc_guid),
38588c2ecf20Sopenharmony_ci				     be16_to_cpu(target->ib_cm.pkey),
38598c2ecf20Sopenharmony_ci				     be64_to_cpu(target->ib_cm.service_id),
38608c2ecf20Sopenharmony_ci				     target->sgid.raw,
38618c2ecf20Sopenharmony_ci				     target->ib_cm.orig_dgid.raw);
38628c2ecf20Sopenharmony_ci		}
38638c2ecf20Sopenharmony_ci	}
38648c2ecf20Sopenharmony_ci
38658c2ecf20Sopenharmony_ci	ret = count;
38668c2ecf20Sopenharmony_ci
38678c2ecf20Sopenharmony_ciout:
38688c2ecf20Sopenharmony_ci	mutex_unlock(&host->add_target_mutex);
38698c2ecf20Sopenharmony_ci
38708c2ecf20Sopenharmony_ciput:
38718c2ecf20Sopenharmony_ci	scsi_host_put(target->scsi_host);
38728c2ecf20Sopenharmony_ci	if (ret < 0) {
38738c2ecf20Sopenharmony_ci		/*
38748c2ecf20Sopenharmony_ci		 * If a call to srp_remove_target() has not been scheduled,
38758c2ecf20Sopenharmony_ci		 * drop the network namespace reference now that was obtained
38768c2ecf20Sopenharmony_ci		 * earlier in this function.
38778c2ecf20Sopenharmony_ci		 */
38788c2ecf20Sopenharmony_ci		if (target->state != SRP_TARGET_REMOVED)
38798c2ecf20Sopenharmony_ci			kobj_ns_drop(KOBJ_NS_TYPE_NET, target->net);
38808c2ecf20Sopenharmony_ci		scsi_host_put(target->scsi_host);
38818c2ecf20Sopenharmony_ci	}
38828c2ecf20Sopenharmony_ci
38838c2ecf20Sopenharmony_ci	return ret;
38848c2ecf20Sopenharmony_ci
38858c2ecf20Sopenharmony_cierr_disconnect:
38868c2ecf20Sopenharmony_ci	srp_disconnect_target(target);
38878c2ecf20Sopenharmony_ci
38888c2ecf20Sopenharmony_cifree_ch:
38898c2ecf20Sopenharmony_ci	for (i = 0; i < target->ch_count; i++) {
38908c2ecf20Sopenharmony_ci		ch = &target->ch[i];
38918c2ecf20Sopenharmony_ci		srp_free_ch_ib(target, ch);
38928c2ecf20Sopenharmony_ci	}
38938c2ecf20Sopenharmony_ci
38948c2ecf20Sopenharmony_ci	kfree(target->ch);
38958c2ecf20Sopenharmony_ci	goto out;
38968c2ecf20Sopenharmony_ci}
38978c2ecf20Sopenharmony_ci
38988c2ecf20Sopenharmony_cistatic DEVICE_ATTR(add_target, S_IWUSR, NULL, srp_create_target);
38998c2ecf20Sopenharmony_ci
39008c2ecf20Sopenharmony_cistatic ssize_t show_ibdev(struct device *dev, struct device_attribute *attr,
39018c2ecf20Sopenharmony_ci			  char *buf)
39028c2ecf20Sopenharmony_ci{
39038c2ecf20Sopenharmony_ci	struct srp_host *host = container_of(dev, struct srp_host, dev);
39048c2ecf20Sopenharmony_ci
39058c2ecf20Sopenharmony_ci	return sprintf(buf, "%s\n", dev_name(&host->srp_dev->dev->dev));
39068c2ecf20Sopenharmony_ci}
39078c2ecf20Sopenharmony_ci
39088c2ecf20Sopenharmony_cistatic DEVICE_ATTR(ibdev, S_IRUGO, show_ibdev, NULL);
39098c2ecf20Sopenharmony_ci
39108c2ecf20Sopenharmony_cistatic ssize_t show_port(struct device *dev, struct device_attribute *attr,
39118c2ecf20Sopenharmony_ci			 char *buf)
39128c2ecf20Sopenharmony_ci{
39138c2ecf20Sopenharmony_ci	struct srp_host *host = container_of(dev, struct srp_host, dev);
39148c2ecf20Sopenharmony_ci
39158c2ecf20Sopenharmony_ci	return sprintf(buf, "%d\n", host->port);
39168c2ecf20Sopenharmony_ci}
39178c2ecf20Sopenharmony_ci
39188c2ecf20Sopenharmony_cistatic DEVICE_ATTR(port, S_IRUGO, show_port, NULL);
39198c2ecf20Sopenharmony_ci
39208c2ecf20Sopenharmony_cistatic struct srp_host *srp_add_port(struct srp_device *device, u8 port)
39218c2ecf20Sopenharmony_ci{
39228c2ecf20Sopenharmony_ci	struct srp_host *host;
39238c2ecf20Sopenharmony_ci
39248c2ecf20Sopenharmony_ci	host = kzalloc(sizeof *host, GFP_KERNEL);
39258c2ecf20Sopenharmony_ci	if (!host)
39268c2ecf20Sopenharmony_ci		return NULL;
39278c2ecf20Sopenharmony_ci
39288c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&host->target_list);
39298c2ecf20Sopenharmony_ci	spin_lock_init(&host->target_lock);
39308c2ecf20Sopenharmony_ci	init_completion(&host->released);
39318c2ecf20Sopenharmony_ci	mutex_init(&host->add_target_mutex);
39328c2ecf20Sopenharmony_ci	host->srp_dev = device;
39338c2ecf20Sopenharmony_ci	host->port = port;
39348c2ecf20Sopenharmony_ci
39358c2ecf20Sopenharmony_ci	host->dev.class = &srp_class;
39368c2ecf20Sopenharmony_ci	host->dev.parent = device->dev->dev.parent;
39378c2ecf20Sopenharmony_ci	dev_set_name(&host->dev, "srp-%s-%d", dev_name(&device->dev->dev),
39388c2ecf20Sopenharmony_ci		     port);
39398c2ecf20Sopenharmony_ci
39408c2ecf20Sopenharmony_ci	if (device_register(&host->dev))
39418c2ecf20Sopenharmony_ci		goto free_host;
39428c2ecf20Sopenharmony_ci	if (device_create_file(&host->dev, &dev_attr_add_target))
39438c2ecf20Sopenharmony_ci		goto err_class;
39448c2ecf20Sopenharmony_ci	if (device_create_file(&host->dev, &dev_attr_ibdev))
39458c2ecf20Sopenharmony_ci		goto err_class;
39468c2ecf20Sopenharmony_ci	if (device_create_file(&host->dev, &dev_attr_port))
39478c2ecf20Sopenharmony_ci		goto err_class;
39488c2ecf20Sopenharmony_ci
39498c2ecf20Sopenharmony_ci	return host;
39508c2ecf20Sopenharmony_ci
39518c2ecf20Sopenharmony_cierr_class:
39528c2ecf20Sopenharmony_ci	device_unregister(&host->dev);
39538c2ecf20Sopenharmony_ci
39548c2ecf20Sopenharmony_cifree_host:
39558c2ecf20Sopenharmony_ci	kfree(host);
39568c2ecf20Sopenharmony_ci
39578c2ecf20Sopenharmony_ci	return NULL;
39588c2ecf20Sopenharmony_ci}
39598c2ecf20Sopenharmony_ci
39608c2ecf20Sopenharmony_cistatic void srp_rename_dev(struct ib_device *device, void *client_data)
39618c2ecf20Sopenharmony_ci{
39628c2ecf20Sopenharmony_ci	struct srp_device *srp_dev = client_data;
39638c2ecf20Sopenharmony_ci	struct srp_host *host, *tmp_host;
39648c2ecf20Sopenharmony_ci
39658c2ecf20Sopenharmony_ci	list_for_each_entry_safe(host, tmp_host, &srp_dev->dev_list, list) {
39668c2ecf20Sopenharmony_ci		char name[IB_DEVICE_NAME_MAX + 8];
39678c2ecf20Sopenharmony_ci
39688c2ecf20Sopenharmony_ci		snprintf(name, sizeof(name), "srp-%s-%d",
39698c2ecf20Sopenharmony_ci			 dev_name(&device->dev), host->port);
39708c2ecf20Sopenharmony_ci		device_rename(&host->dev, name);
39718c2ecf20Sopenharmony_ci	}
39728c2ecf20Sopenharmony_ci}
39738c2ecf20Sopenharmony_ci
39748c2ecf20Sopenharmony_cistatic int srp_add_one(struct ib_device *device)
39758c2ecf20Sopenharmony_ci{
39768c2ecf20Sopenharmony_ci	struct srp_device *srp_dev;
39778c2ecf20Sopenharmony_ci	struct ib_device_attr *attr = &device->attrs;
39788c2ecf20Sopenharmony_ci	struct srp_host *host;
39798c2ecf20Sopenharmony_ci	int mr_page_shift;
39808c2ecf20Sopenharmony_ci	unsigned int p;
39818c2ecf20Sopenharmony_ci	u64 max_pages_per_mr;
39828c2ecf20Sopenharmony_ci	unsigned int flags = 0;
39838c2ecf20Sopenharmony_ci
39848c2ecf20Sopenharmony_ci	srp_dev = kzalloc(sizeof(*srp_dev), GFP_KERNEL);
39858c2ecf20Sopenharmony_ci	if (!srp_dev)
39868c2ecf20Sopenharmony_ci		return -ENOMEM;
39878c2ecf20Sopenharmony_ci
39888c2ecf20Sopenharmony_ci	/*
39898c2ecf20Sopenharmony_ci	 * Use the smallest page size supported by the HCA, down to a
39908c2ecf20Sopenharmony_ci	 * minimum of 4096 bytes. We're unlikely to build large sglists
39918c2ecf20Sopenharmony_ci	 * out of smaller entries.
39928c2ecf20Sopenharmony_ci	 */
39938c2ecf20Sopenharmony_ci	mr_page_shift		= max(12, ffs(attr->page_size_cap) - 1);
39948c2ecf20Sopenharmony_ci	srp_dev->mr_page_size	= 1 << mr_page_shift;
39958c2ecf20Sopenharmony_ci	srp_dev->mr_page_mask	= ~((u64) srp_dev->mr_page_size - 1);
39968c2ecf20Sopenharmony_ci	max_pages_per_mr	= attr->max_mr_size;
39978c2ecf20Sopenharmony_ci	do_div(max_pages_per_mr, srp_dev->mr_page_size);
39988c2ecf20Sopenharmony_ci	pr_debug("%s: %llu / %u = %llu <> %u\n", __func__,
39998c2ecf20Sopenharmony_ci		 attr->max_mr_size, srp_dev->mr_page_size,
40008c2ecf20Sopenharmony_ci		 max_pages_per_mr, SRP_MAX_PAGES_PER_MR);
40018c2ecf20Sopenharmony_ci	srp_dev->max_pages_per_mr = min_t(u64, SRP_MAX_PAGES_PER_MR,
40028c2ecf20Sopenharmony_ci					  max_pages_per_mr);
40038c2ecf20Sopenharmony_ci
40048c2ecf20Sopenharmony_ci	srp_dev->has_fr = (attr->device_cap_flags &
40058c2ecf20Sopenharmony_ci			   IB_DEVICE_MEM_MGT_EXTENSIONS);
40068c2ecf20Sopenharmony_ci	if (!never_register && !srp_dev->has_fr)
40078c2ecf20Sopenharmony_ci		dev_warn(&device->dev, "FR is not supported\n");
40088c2ecf20Sopenharmony_ci	else if (!never_register &&
40098c2ecf20Sopenharmony_ci		 attr->max_mr_size >= 2 * srp_dev->mr_page_size)
40108c2ecf20Sopenharmony_ci		srp_dev->use_fast_reg = srp_dev->has_fr;
40118c2ecf20Sopenharmony_ci
40128c2ecf20Sopenharmony_ci	if (never_register || !register_always || !srp_dev->has_fr)
40138c2ecf20Sopenharmony_ci		flags |= IB_PD_UNSAFE_GLOBAL_RKEY;
40148c2ecf20Sopenharmony_ci
40158c2ecf20Sopenharmony_ci	if (srp_dev->use_fast_reg) {
40168c2ecf20Sopenharmony_ci		srp_dev->max_pages_per_mr =
40178c2ecf20Sopenharmony_ci			min_t(u32, srp_dev->max_pages_per_mr,
40188c2ecf20Sopenharmony_ci			      attr->max_fast_reg_page_list_len);
40198c2ecf20Sopenharmony_ci	}
40208c2ecf20Sopenharmony_ci	srp_dev->mr_max_size	= srp_dev->mr_page_size *
40218c2ecf20Sopenharmony_ci				   srp_dev->max_pages_per_mr;
40228c2ecf20Sopenharmony_ci	pr_debug("%s: mr_page_shift = %d, device->max_mr_size = %#llx, device->max_fast_reg_page_list_len = %u, max_pages_per_mr = %d, mr_max_size = %#x\n",
40238c2ecf20Sopenharmony_ci		 dev_name(&device->dev), mr_page_shift, attr->max_mr_size,
40248c2ecf20Sopenharmony_ci		 attr->max_fast_reg_page_list_len,
40258c2ecf20Sopenharmony_ci		 srp_dev->max_pages_per_mr, srp_dev->mr_max_size);
40268c2ecf20Sopenharmony_ci
40278c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&srp_dev->dev_list);
40288c2ecf20Sopenharmony_ci
40298c2ecf20Sopenharmony_ci	srp_dev->dev = device;
40308c2ecf20Sopenharmony_ci	srp_dev->pd  = ib_alloc_pd(device, flags);
40318c2ecf20Sopenharmony_ci	if (IS_ERR(srp_dev->pd)) {
40328c2ecf20Sopenharmony_ci		int ret = PTR_ERR(srp_dev->pd);
40338c2ecf20Sopenharmony_ci
40348c2ecf20Sopenharmony_ci		kfree(srp_dev);
40358c2ecf20Sopenharmony_ci		return ret;
40368c2ecf20Sopenharmony_ci	}
40378c2ecf20Sopenharmony_ci
40388c2ecf20Sopenharmony_ci	if (flags & IB_PD_UNSAFE_GLOBAL_RKEY) {
40398c2ecf20Sopenharmony_ci		srp_dev->global_rkey = srp_dev->pd->unsafe_global_rkey;
40408c2ecf20Sopenharmony_ci		WARN_ON_ONCE(srp_dev->global_rkey == 0);
40418c2ecf20Sopenharmony_ci	}
40428c2ecf20Sopenharmony_ci
40438c2ecf20Sopenharmony_ci	rdma_for_each_port (device, p) {
40448c2ecf20Sopenharmony_ci		host = srp_add_port(srp_dev, p);
40458c2ecf20Sopenharmony_ci		if (host)
40468c2ecf20Sopenharmony_ci			list_add_tail(&host->list, &srp_dev->dev_list);
40478c2ecf20Sopenharmony_ci	}
40488c2ecf20Sopenharmony_ci
40498c2ecf20Sopenharmony_ci	ib_set_client_data(device, &srp_client, srp_dev);
40508c2ecf20Sopenharmony_ci	return 0;
40518c2ecf20Sopenharmony_ci}
40528c2ecf20Sopenharmony_ci
40538c2ecf20Sopenharmony_cistatic void srp_remove_one(struct ib_device *device, void *client_data)
40548c2ecf20Sopenharmony_ci{
40558c2ecf20Sopenharmony_ci	struct srp_device *srp_dev;
40568c2ecf20Sopenharmony_ci	struct srp_host *host, *tmp_host;
40578c2ecf20Sopenharmony_ci	struct srp_target_port *target;
40588c2ecf20Sopenharmony_ci
40598c2ecf20Sopenharmony_ci	srp_dev = client_data;
40608c2ecf20Sopenharmony_ci
40618c2ecf20Sopenharmony_ci	list_for_each_entry_safe(host, tmp_host, &srp_dev->dev_list, list) {
40628c2ecf20Sopenharmony_ci		device_unregister(&host->dev);
40638c2ecf20Sopenharmony_ci		/*
40648c2ecf20Sopenharmony_ci		 * Wait for the sysfs entry to go away, so that no new
40658c2ecf20Sopenharmony_ci		 * target ports can be created.
40668c2ecf20Sopenharmony_ci		 */
40678c2ecf20Sopenharmony_ci		wait_for_completion(&host->released);
40688c2ecf20Sopenharmony_ci
40698c2ecf20Sopenharmony_ci		/*
40708c2ecf20Sopenharmony_ci		 * Remove all target ports.
40718c2ecf20Sopenharmony_ci		 */
40728c2ecf20Sopenharmony_ci		spin_lock(&host->target_lock);
40738c2ecf20Sopenharmony_ci		list_for_each_entry(target, &host->target_list, list)
40748c2ecf20Sopenharmony_ci			srp_queue_remove_work(target);
40758c2ecf20Sopenharmony_ci		spin_unlock(&host->target_lock);
40768c2ecf20Sopenharmony_ci
40778c2ecf20Sopenharmony_ci		/*
40788c2ecf20Sopenharmony_ci		 * srp_queue_remove_work() queues a call to
40798c2ecf20Sopenharmony_ci		 * srp_remove_target(). The latter function cancels
40808c2ecf20Sopenharmony_ci		 * target->tl_err_work so waiting for the remove works to
40818c2ecf20Sopenharmony_ci		 * finish is sufficient.
40828c2ecf20Sopenharmony_ci		 */
40838c2ecf20Sopenharmony_ci		flush_workqueue(srp_remove_wq);
40848c2ecf20Sopenharmony_ci
40858c2ecf20Sopenharmony_ci		kfree(host);
40868c2ecf20Sopenharmony_ci	}
40878c2ecf20Sopenharmony_ci
40888c2ecf20Sopenharmony_ci	ib_dealloc_pd(srp_dev->pd);
40898c2ecf20Sopenharmony_ci
40908c2ecf20Sopenharmony_ci	kfree(srp_dev);
40918c2ecf20Sopenharmony_ci}
40928c2ecf20Sopenharmony_ci
40938c2ecf20Sopenharmony_cistatic struct srp_function_template ib_srp_transport_functions = {
40948c2ecf20Sopenharmony_ci	.has_rport_state	 = true,
40958c2ecf20Sopenharmony_ci	.reset_timer_if_blocked	 = true,
40968c2ecf20Sopenharmony_ci	.reconnect_delay	 = &srp_reconnect_delay,
40978c2ecf20Sopenharmony_ci	.fast_io_fail_tmo	 = &srp_fast_io_fail_tmo,
40988c2ecf20Sopenharmony_ci	.dev_loss_tmo		 = &srp_dev_loss_tmo,
40998c2ecf20Sopenharmony_ci	.reconnect		 = srp_rport_reconnect,
41008c2ecf20Sopenharmony_ci	.rport_delete		 = srp_rport_delete,
41018c2ecf20Sopenharmony_ci	.terminate_rport_io	 = srp_terminate_io,
41028c2ecf20Sopenharmony_ci};
41038c2ecf20Sopenharmony_ci
41048c2ecf20Sopenharmony_cistatic int __init srp_init_module(void)
41058c2ecf20Sopenharmony_ci{
41068c2ecf20Sopenharmony_ci	int ret;
41078c2ecf20Sopenharmony_ci
41088c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct srp_imm_buf) != 4);
41098c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct srp_login_req) != 64);
41108c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct srp_login_req_rdma) != 56);
41118c2ecf20Sopenharmony_ci	BUILD_BUG_ON(sizeof(struct srp_cmd) != 48);
41128c2ecf20Sopenharmony_ci
41138c2ecf20Sopenharmony_ci	if (srp_sg_tablesize) {
41148c2ecf20Sopenharmony_ci		pr_warn("srp_sg_tablesize is deprecated, please use cmd_sg_entries\n");
41158c2ecf20Sopenharmony_ci		if (!cmd_sg_entries)
41168c2ecf20Sopenharmony_ci			cmd_sg_entries = srp_sg_tablesize;
41178c2ecf20Sopenharmony_ci	}
41188c2ecf20Sopenharmony_ci
41198c2ecf20Sopenharmony_ci	if (!cmd_sg_entries)
41208c2ecf20Sopenharmony_ci		cmd_sg_entries = SRP_DEF_SG_TABLESIZE;
41218c2ecf20Sopenharmony_ci
41228c2ecf20Sopenharmony_ci	if (cmd_sg_entries > 255) {
41238c2ecf20Sopenharmony_ci		pr_warn("Clamping cmd_sg_entries to 255\n");
41248c2ecf20Sopenharmony_ci		cmd_sg_entries = 255;
41258c2ecf20Sopenharmony_ci	}
41268c2ecf20Sopenharmony_ci
41278c2ecf20Sopenharmony_ci	if (!indirect_sg_entries)
41288c2ecf20Sopenharmony_ci		indirect_sg_entries = cmd_sg_entries;
41298c2ecf20Sopenharmony_ci	else if (indirect_sg_entries < cmd_sg_entries) {
41308c2ecf20Sopenharmony_ci		pr_warn("Bumping up indirect_sg_entries to match cmd_sg_entries (%u)\n",
41318c2ecf20Sopenharmony_ci			cmd_sg_entries);
41328c2ecf20Sopenharmony_ci		indirect_sg_entries = cmd_sg_entries;
41338c2ecf20Sopenharmony_ci	}
41348c2ecf20Sopenharmony_ci
41358c2ecf20Sopenharmony_ci	if (indirect_sg_entries > SG_MAX_SEGMENTS) {
41368c2ecf20Sopenharmony_ci		pr_warn("Clamping indirect_sg_entries to %u\n",
41378c2ecf20Sopenharmony_ci			SG_MAX_SEGMENTS);
41388c2ecf20Sopenharmony_ci		indirect_sg_entries = SG_MAX_SEGMENTS;
41398c2ecf20Sopenharmony_ci	}
41408c2ecf20Sopenharmony_ci
41418c2ecf20Sopenharmony_ci	srp_remove_wq = create_workqueue("srp_remove");
41428c2ecf20Sopenharmony_ci	if (!srp_remove_wq) {
41438c2ecf20Sopenharmony_ci		ret = -ENOMEM;
41448c2ecf20Sopenharmony_ci		goto out;
41458c2ecf20Sopenharmony_ci	}
41468c2ecf20Sopenharmony_ci
41478c2ecf20Sopenharmony_ci	ret = -ENOMEM;
41488c2ecf20Sopenharmony_ci	ib_srp_transport_template =
41498c2ecf20Sopenharmony_ci		srp_attach_transport(&ib_srp_transport_functions);
41508c2ecf20Sopenharmony_ci	if (!ib_srp_transport_template)
41518c2ecf20Sopenharmony_ci		goto destroy_wq;
41528c2ecf20Sopenharmony_ci
41538c2ecf20Sopenharmony_ci	ret = class_register(&srp_class);
41548c2ecf20Sopenharmony_ci	if (ret) {
41558c2ecf20Sopenharmony_ci		pr_err("couldn't register class infiniband_srp\n");
41568c2ecf20Sopenharmony_ci		goto release_tr;
41578c2ecf20Sopenharmony_ci	}
41588c2ecf20Sopenharmony_ci
41598c2ecf20Sopenharmony_ci	ib_sa_register_client(&srp_sa_client);
41608c2ecf20Sopenharmony_ci
41618c2ecf20Sopenharmony_ci	ret = ib_register_client(&srp_client);
41628c2ecf20Sopenharmony_ci	if (ret) {
41638c2ecf20Sopenharmony_ci		pr_err("couldn't register IB client\n");
41648c2ecf20Sopenharmony_ci		goto unreg_sa;
41658c2ecf20Sopenharmony_ci	}
41668c2ecf20Sopenharmony_ci
41678c2ecf20Sopenharmony_ciout:
41688c2ecf20Sopenharmony_ci	return ret;
41698c2ecf20Sopenharmony_ci
41708c2ecf20Sopenharmony_ciunreg_sa:
41718c2ecf20Sopenharmony_ci	ib_sa_unregister_client(&srp_sa_client);
41728c2ecf20Sopenharmony_ci	class_unregister(&srp_class);
41738c2ecf20Sopenharmony_ci
41748c2ecf20Sopenharmony_cirelease_tr:
41758c2ecf20Sopenharmony_ci	srp_release_transport(ib_srp_transport_template);
41768c2ecf20Sopenharmony_ci
41778c2ecf20Sopenharmony_cidestroy_wq:
41788c2ecf20Sopenharmony_ci	destroy_workqueue(srp_remove_wq);
41798c2ecf20Sopenharmony_ci	goto out;
41808c2ecf20Sopenharmony_ci}
41818c2ecf20Sopenharmony_ci
41828c2ecf20Sopenharmony_cistatic void __exit srp_cleanup_module(void)
41838c2ecf20Sopenharmony_ci{
41848c2ecf20Sopenharmony_ci	ib_unregister_client(&srp_client);
41858c2ecf20Sopenharmony_ci	ib_sa_unregister_client(&srp_sa_client);
41868c2ecf20Sopenharmony_ci	class_unregister(&srp_class);
41878c2ecf20Sopenharmony_ci	srp_release_transport(ib_srp_transport_template);
41888c2ecf20Sopenharmony_ci	destroy_workqueue(srp_remove_wq);
41898c2ecf20Sopenharmony_ci}
41908c2ecf20Sopenharmony_ci
41918c2ecf20Sopenharmony_cimodule_init(srp_init_module);
41928c2ecf20Sopenharmony_cimodule_exit(srp_cleanup_module);
4193