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